]>
Commit | Line | Data |
---|---|---|
28f540f4 | 1 | /* |
28f540f4 RM |
2 | * Copyright (c) 1985, 1989, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
e62b2105 | 4 | * |
28f540f4 RM |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
28f540f4 RM |
13 | * 4. Neither the name of the University nor the names of its contributors |
14 | * may be used to endorse or promote products derived from this software | |
15 | * without specific prior written permission. | |
e62b2105 | 16 | * |
28f540f4 RM |
17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
27 | * SUCH DAMAGE. | |
b43b13ac UD |
28 | */ |
29 | ||
30 | /* | |
28f540f4 | 31 | * Portions Copyright (c) 1993 by Digital Equipment Corporation. |
e62b2105 | 32 | * |
28f540f4 RM |
33 | * Permission to use, copy, modify, and distribute this software for any |
34 | * purpose with or without fee is hereby granted, provided that the above | |
35 | * copyright notice and this permission notice appear in all copies, and that | |
36 | * the name of Digital Equipment Corporation not be used in advertising or | |
37 | * publicity pertaining to distribution of the document or software without | |
38 | * specific, written prior permission. | |
e62b2105 | 39 | * |
28f540f4 RM |
40 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL |
41 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES | |
42 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT | |
43 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
44 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
45 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
46 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
47 | * SOFTWARE. | |
b43b13ac UD |
48 | */ |
49 | ||
50 | /* | |
51 | * Portions Copyright (c) 1996-1999 by Internet Software Consortium. | |
52 | * | |
53 | * Permission to use, copy, modify, and distribute this software for any | |
54 | * purpose with or without fee is hereby granted, provided that the above | |
55 | * copyright notice and this permission notice appear in all copies. | |
56 | * | |
57 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | |
58 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
59 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | |
60 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
61 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
62 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
63 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
64 | * SOFTWARE. | |
28f540f4 RM |
65 | */ |
66 | ||
67 | #if defined(LIBC_SCCS) && !defined(lint) | |
b43b13ac | 68 | static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; |
e685e07d | 69 | static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixie Exp $"; |
28f540f4 RM |
70 | #endif /* LIBC_SCCS and not lint */ |
71 | ||
28f540f4 RM |
72 | /* |
73 | * Send query to name server and wait for reply. | |
74 | */ | |
75 | ||
17a10319 | 76 | #include <assert.h> |
df21c858 | 77 | #include <sys/types.h> |
28f540f4 RM |
78 | #include <sys/param.h> |
79 | #include <sys/time.h> | |
80 | #include <sys/socket.h> | |
81 | #include <sys/uio.h> | |
e685e07d | 82 | #include <sys/poll.h> |
b43b13ac | 83 | |
28f540f4 RM |
84 | #include <netinet/in.h> |
85 | #include <arpa/nameser.h> | |
86 | #include <arpa/inet.h> | |
0420d888 | 87 | #include <sys/ioctl.h> |
28f540f4 | 88 | |
28f540f4 | 89 | #include <errno.h> |
f433b06b | 90 | #include <fcntl.h> |
b43b13ac | 91 | #include <netdb.h> |
28f540f4 | 92 | #include <resolv.h> |
b43b13ac UD |
93 | #include <signal.h> |
94 | #include <stdio.h> | |
95 | #include <stdlib.h> | |
96 | #include <string.h> | |
97 | #include <unistd.h> | |
9744268c | 98 | #include <kernel-features.h> |
48e435cd | 99 | #include <libc-internal.h> |
b43b13ac | 100 | |
0420d888 UD |
101 | #if PACKETSZ > 65536 |
102 | #define MAXPACKET PACKETSZ | |
103 | #else | |
104 | #define MAXPACKET 65536 | |
105 | #endif | |
106 | ||
e685e07d | 107 | /* From ev_streams.c. */ |
e62b2105 | 108 | |
25337753 UD |
109 | static inline void |
110 | __attribute ((always_inline)) | |
111 | evConsIovec(void *buf, size_t cnt, struct iovec *vec) { | |
112 | memset(vec, 0xf5, sizeof (*vec)); | |
113 | vec->iov_base = buf; | |
114 | vec->iov_len = cnt; | |
e685e07d | 115 | } |
28f540f4 | 116 | |
e685e07d | 117 | /* From ev_timers.c. */ |
30f9ca19 | 118 | |
b43b13ac | 119 | #define BILLION 1000000000 |
e685e07d | 120 | |
25337753 UD |
121 | static inline void |
122 | evConsTime(struct timespec *res, time_t sec, long nsec) { | |
123 | res->tv_sec = sec; | |
124 | res->tv_nsec = nsec; | |
b43b13ac | 125 | } |
28f540f4 | 126 | |
25337753 UD |
127 | static inline void |
128 | evAddTime(struct timespec *res, const struct timespec *addend1, | |
129 | const struct timespec *addend2) { | |
130 | res->tv_sec = addend1->tv_sec + addend2->tv_sec; | |
131 | res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec; | |
132 | if (res->tv_nsec >= BILLION) { | |
133 | res->tv_sec++; | |
134 | res->tv_nsec -= BILLION; | |
b43b13ac | 135 | } |
b43b13ac UD |
136 | } |
137 | ||
25337753 UD |
138 | static inline void |
139 | evSubTime(struct timespec *res, const struct timespec *minuend, | |
140 | const struct timespec *subtrahend) { | |
141 | res->tv_sec = minuend->tv_sec - subtrahend->tv_sec; | |
142 | if (minuend->tv_nsec >= subtrahend->tv_nsec) | |
143 | res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec; | |
b43b13ac | 144 | else { |
25337753 UD |
145 | res->tv_nsec = (BILLION |
146 | - subtrahend->tv_nsec + minuend->tv_nsec); | |
147 | res->tv_sec--; | |
b43b13ac | 148 | } |
b43b13ac UD |
149 | } |
150 | ||
f1d70dad | 151 | static int |
b43b13ac UD |
152 | evCmpTime(struct timespec a, struct timespec b) { |
153 | long x = a.tv_sec - b.tv_sec; | |
154 | ||
155 | if (x == 0L) | |
156 | x = a.tv_nsec - b.tv_nsec; | |
157 | return (x < 0L ? (-1) : x > 0L ? (1) : (0)); | |
158 | } | |
159 | ||
f1d70dad | 160 | static void |
25337753 | 161 | evNowTime(struct timespec *res) { |
b43b13ac UD |
162 | struct timeval now; |
163 | ||
164 | if (gettimeofday(&now, NULL) < 0) | |
25337753 UD |
165 | evConsTime(res, 0, 0); |
166 | else | |
167 | TIMEVAL_TO_TIMESPEC (&now, res); | |
b43b13ac | 168 | } |
b43b13ac | 169 | |
28f540f4 | 170 | |
e685e07d UD |
171 | /* Options. Leave them on. */ |
172 | /* #undef DEBUG */ | |
173 | #include "res_debug.h" | |
b43b13ac | 174 | |
e685e07d | 175 | #define EXT(res) ((res)->_u._ext) |
28f540f4 | 176 | |
e685e07d UD |
177 | /* Forward. */ |
178 | ||
2212c142 | 179 | static struct sockaddr *get_nsaddr (res_state, int); |
e685e07d | 180 | static int send_vc(res_state, const u_char *, int, |
1eb946b9 UD |
181 | const u_char *, int, |
182 | u_char **, int *, int *, int, u_char **, | |
ab09bf61 | 183 | u_char **, int *, int *, int *); |
e685e07d | 184 | static int send_dg(res_state, const u_char *, int, |
1eb946b9 | 185 | const u_char *, int, |
0420d888 | 186 | u_char **, int *, int *, int, |
1eb946b9 | 187 | int *, int *, u_char **, |
ab09bf61 | 188 | u_char **, int *, int *, int *); |
e685e07d UD |
189 | #ifdef DEBUG |
190 | static void Aerror(const res_state, FILE *, const char *, int, | |
020a9a23 | 191 | const struct sockaddr *); |
e685e07d UD |
192 | static void Perror(const res_state, FILE *, const char *, int); |
193 | #endif | |
438e8239 | 194 | static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *); |
e685e07d | 195 | |
e685e07d UD |
196 | /* Public. */ |
197 | ||
28f540f4 RM |
198 | /* int |
199 | * res_isourserver(ina) | |
200 | * looks up "ina" in _res.ns_addr_list[] | |
201 | * returns: | |
202 | * 0 : not found | |
203 | * >0 : found | |
204 | * author: | |
205 | * paul vixie, 29may94 | |
206 | */ | |
207 | int | |
438e8239 | 208 | res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp) |
438e8239 | 209 | { |
b43b13ac | 210 | int ns; |
28f540f4 | 211 | |
3a85895f PB |
212 | if (inp->sin6_family == AF_INET) { |
213 | struct sockaddr_in *in4p = (struct sockaddr_in *) inp; | |
e62b2105 UD |
214 | in_port_t port = in4p->sin_port; |
215 | in_addr_t addr = in4p->sin_addr.s_addr; | |
438e8239 | 216 | |
2212c142 | 217 | for (ns = 0; ns < statp->nscount; ns++) { |
3a85895f | 218 | const struct sockaddr_in *srv = |
2212c142 | 219 | (struct sockaddr_in *) get_nsaddr (statp, ns); |
438e8239 | 220 | |
2212c142 | 221 | if ((srv->sin_family == AF_INET) && |
3a85895f PB |
222 | (srv->sin_port == port) && |
223 | (srv->sin_addr.s_addr == INADDR_ANY || | |
224 | srv->sin_addr.s_addr == addr)) | |
225 | return (1); | |
226 | } | |
227 | } else if (inp->sin6_family == AF_INET6) { | |
2212c142 AS |
228 | for (ns = 0; ns < statp->nscount; ns++) { |
229 | const struct sockaddr_in6 *srv | |
230 | = (struct sockaddr_in6 *) get_nsaddr (statp, ns); | |
231 | if ((srv->sin6_family == AF_INET6) && | |
3a85895f PB |
232 | (srv->sin6_port == inp->sin6_port) && |
233 | !(memcmp(&srv->sin6_addr, &in6addr_any, | |
234 | sizeof (struct in6_addr)) && | |
235 | memcmp(&srv->sin6_addr, &inp->sin6_addr, | |
236 | sizeof (struct in6_addr)))) | |
237 | return (1); | |
238 | } | |
239 | } | |
b43b13ac | 240 | return (0); |
28f540f4 RM |
241 | } |
242 | ||
243 | /* int | |
244 | * res_nameinquery(name, type, class, buf, eom) | |
245 | * look for (name,type,class) in the query section of packet (buf,eom) | |
66715f83 | 246 | * requires: |
b43b13ac | 247 | * buf + HFIXEDSZ <= eom |
28f540f4 RM |
248 | * returns: |
249 | * -1 : format error | |
250 | * 0 : not found | |
251 | * >0 : found | |
252 | * author: | |
253 | * paul vixie, 29may94 | |
254 | */ | |
255 | int | |
b43b13ac UD |
256 | res_nameinquery(const char *name, int type, int class, |
257 | const u_char *buf, const u_char *eom) | |
28f540f4 | 258 | { |
b43b13ac | 259 | const u_char *cp = buf + HFIXEDSZ; |
28f540f4 RM |
260 | int qdcount = ntohs(((HEADER*)buf)->qdcount); |
261 | ||
262 | while (qdcount-- > 0) { | |
263 | char tname[MAXDNAME+1]; | |
b43b13ac | 264 | int n, ttype, tclass; |
28f540f4 RM |
265 | |
266 | n = dn_expand(buf, eom, cp, tname, sizeof tname); | |
267 | if (n < 0) | |
268 | return (-1); | |
269 | cp += n; | |
66715f83 UD |
270 | if (cp + 2 * INT16SZ > eom) |
271 | return (-1); | |
697e1628 UD |
272 | NS_GET16(ttype, cp); |
273 | NS_GET16(tclass, cp); | |
b43b13ac UD |
274 | if (ttype == type && tclass == class && |
275 | ns_samename(tname, name) == 1) | |
28f540f4 RM |
276 | return (1); |
277 | } | |
278 | return (0); | |
279 | } | |
6f9d8e68 | 280 | libresolv_hidden_def (res_nameinquery) |
28f540f4 RM |
281 | |
282 | /* int | |
283 | * res_queriesmatch(buf1, eom1, buf2, eom2) | |
284 | * is there a 1:1 mapping of (name,type,class) | |
285 | * in (buf1,eom1) and (buf2,eom2)? | |
286 | * returns: | |
287 | * -1 : format error | |
288 | * 0 : not a 1:1 mapping | |
289 | * >0 : is a 1:1 mapping | |
290 | * author: | |
291 | * paul vixie, 29may94 | |
292 | */ | |
293 | int | |
b43b13ac UD |
294 | res_queriesmatch(const u_char *buf1, const u_char *eom1, |
295 | const u_char *buf2, const u_char *eom2) | |
28f540f4 | 296 | { |
66715f83 UD |
297 | if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) |
298 | return (-1); | |
299 | ||
b43b13ac UD |
300 | /* |
301 | * Only header section present in replies to | |
302 | * dynamic update packets. | |
303 | */ | |
e685e07d UD |
304 | if ((((HEADER *)buf1)->opcode == ns_o_update) && |
305 | (((HEADER *)buf2)->opcode == ns_o_update)) | |
b43b13ac UD |
306 | return (1); |
307 | ||
697e1628 | 308 | /* Note that we initially do not convert QDCOUNT to the host byte |
8e45b1ac | 309 | order. We can compare it with the second buffer's QDCOUNT |
697e1628 UD |
310 | value without doing this. */ |
311 | int qdcount = ((HEADER*)buf1)->qdcount; | |
312 | if (qdcount != ((HEADER*)buf2)->qdcount) | |
28f540f4 | 313 | return (0); |
697e1628 UD |
314 | |
315 | qdcount = htons (qdcount); | |
316 | const u_char *cp = buf1 + HFIXEDSZ; | |
317 | ||
28f540f4 RM |
318 | while (qdcount-- > 0) { |
319 | char tname[MAXDNAME+1]; | |
b43b13ac | 320 | int n, ttype, tclass; |
28f540f4 RM |
321 | |
322 | n = dn_expand(buf1, eom1, cp, tname, sizeof tname); | |
323 | if (n < 0) | |
324 | return (-1); | |
325 | cp += n; | |
66715f83 UD |
326 | if (cp + 2 * INT16SZ > eom1) |
327 | return (-1); | |
697e1628 UD |
328 | NS_GET16(ttype, cp); |
329 | NS_GET16(tclass, cp); | |
28f540f4 RM |
330 | if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) |
331 | return (0); | |
332 | } | |
333 | return (1); | |
334 | } | |
6f9d8e68 | 335 | libresolv_hidden_def (res_queriesmatch) |
28f540f4 RM |
336 | |
337 | int | |
0420d888 | 338 | __libc_res_nsend(res_state statp, const u_char *buf, int buflen, |
1eb946b9 UD |
339 | const u_char *buf2, int buflen2, |
340 | u_char *ans, int anssiz, u_char **ansp, u_char **ansp2, | |
ab09bf61 | 341 | int *nansp2, int *resplen2, int *ansp2_malloced) |
28f540f4 | 342 | { |
b7da31a1 | 343 | int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; |
28f540f4 | 344 | |
e685e07d UD |
345 | if (statp->nscount == 0) { |
346 | __set_errno (ESRCH); | |
347 | return (-1); | |
348 | } | |
0420d888 | 349 | |
1eb946b9 | 350 | if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) { |
66715f83 UD |
351 | __set_errno (EINVAL); |
352 | return (-1); | |
353 | } | |
0420d888 | 354 | |
1eb946b9 | 355 | #ifdef USE_HOOKS |
a1ffb40e | 356 | if (__glibc_unlikely (statp->qhook || statp->rhook)) { |
1eb946b9 UD |
357 | if (anssiz < MAXPACKET && ansp) { |
358 | u_char *buf = malloc (MAXPACKET); | |
359 | if (buf == NULL) | |
360 | return (-1); | |
361 | memcpy (buf, ans, HFIXEDSZ); | |
362 | *ansp = buf; | |
363 | ans = buf; | |
364 | anssiz = MAXPACKET; | |
365 | } | |
0420d888 | 366 | } |
1eb946b9 | 367 | #endif |
0420d888 | 368 | |
b43b13ac | 369 | DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), |
3d61b63c | 370 | (stdout, ";; res_send()\n"), buf, buflen); |
1eb946b9 UD |
371 | v_circuit = ((statp->options & RES_USEVC) |
372 | || buflen > PACKETSZ | |
373 | || buflen2 > PACKETSZ); | |
28f540f4 | 374 | gotsomewhere = 0; |
28f540f4 | 375 | terrno = ETIMEDOUT; |
28f540f4 | 376 | |
b43b13ac | 377 | /* |
e685e07d UD |
378 | * If the ns_addr_list in the resolver context has changed, then |
379 | * invalidate our cached copy and the associated timing data. | |
b43b13ac | 380 | */ |
2212c142 | 381 | if (EXT(statp).nscount != 0) { |
e685e07d UD |
382 | int needclose = 0; |
383 | ||
384 | if (EXT(statp).nscount != statp->nscount) | |
385 | needclose++; | |
386 | else | |
2212c142 AS |
387 | for (ns = 0; ns < statp->nscount; ns++) { |
388 | if (statp->nsaddr_list[ns].sin_family != 0 | |
b64e1566 | 389 | && !sock_eq((struct sockaddr_in6 *) |
2212c142 | 390 | &statp->nsaddr_list[ns], |
b64e1566 | 391 | EXT(statp).nsaddrs[ns])) |
438e8239 | 392 | { |
e685e07d UD |
393 | needclose++; |
394 | break; | |
395 | } | |
b64e1566 | 396 | } |
2212c142 | 397 | if (needclose) { |
cb07f6f6 | 398 | __res_iclose(statp, false); |
2212c142 AS |
399 | EXT(statp).nscount = 0; |
400 | } | |
e685e07d UD |
401 | } |
402 | ||
403 | /* | |
404 | * Maybe initialize our private copy of the ns_addr_list. | |
405 | */ | |
2212c142 AS |
406 | if (EXT(statp).nscount == 0) { |
407 | for (ns = 0; ns < statp->nscount; ns++) { | |
408 | EXT(statp).nssocks[ns] = -1; | |
409 | if (statp->nsaddr_list[ns].sin_family == 0) | |
410 | continue; | |
411 | if (EXT(statp).nsaddrs[ns] == NULL) | |
412 | EXT(statp).nsaddrs[ns] = | |
438e8239 | 413 | malloc(sizeof (struct sockaddr_in6)); |
2212c142 AS |
414 | if (EXT(statp).nsaddrs[ns] != NULL) |
415 | memset (mempcpy(EXT(statp).nsaddrs[ns], | |
cabba934 | 416 | &statp->nsaddr_list[ns], |
0f8f993c UD |
417 | sizeof (struct sockaddr_in)), |
418 | '\0', | |
419 | sizeof (struct sockaddr_in6) | |
420 | - sizeof (struct sockaddr_in)); | |
b64e1566 | 421 | } |
2212c142 | 422 | EXT(statp).nscount = statp->nscount; |
e685e07d UD |
423 | } |
424 | ||
425 | /* | |
426 | * Some resolvers want to even out the load on their nameservers. | |
427 | * Note that RES_BLAST overrides RES_ROTATE. | |
428 | */ | |
1eb946b9 | 429 | if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) && |
e685e07d | 430 | (statp->options & RES_BLAST) == 0) { |
2212c142 AS |
431 | struct sockaddr_in ina; |
432 | struct sockaddr_in6 *inp; | |
433 | int lastns = statp->nscount - 1; | |
434 | int fd; | |
435 | ||
436 | inp = EXT(statp).nsaddrs[0]; | |
437 | ina = statp->nsaddr_list[0]; | |
438 | fd = EXT(statp).nssocks[0]; | |
439 | for (ns = 0; ns < lastns; ns++) { | |
440 | EXT(statp).nsaddrs[ns] = EXT(statp).nsaddrs[ns + 1]; | |
441 | statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; | |
442 | EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; | |
b64e1566 | 443 | } |
2212c142 AS |
444 | EXT(statp).nsaddrs[lastns] = inp; |
445 | statp->nsaddr_list[lastns] = ina; | |
446 | EXT(statp).nssocks[lastns] = fd; | |
b43b13ac | 447 | } |
30f9ca19 | 448 | |
28f540f4 | 449 | /* |
e685e07d | 450 | * Send request, RETRY times, or until successful. |
28f540f4 | 451 | */ |
b43b13ac | 452 | for (try = 0; try < statp->retry; try++) { |
2212c142 | 453 | for (ns = 0; ns < statp->nscount; ns++) |
438e8239 | 454 | { |
a092b645 YD |
455 | #ifdef DEBUG |
456 | char tmpbuf[40]; | |
457 | #endif | |
2212c142 AS |
458 | #if defined USE_HOOKS || defined DEBUG |
459 | struct sockaddr *nsap = get_nsaddr (statp, ns); | |
460 | #endif | |
438e8239 | 461 | |
1eb946b9 UD |
462 | same_ns: |
463 | #ifdef USE_HOOKS | |
a1ffb40e | 464 | if (__glibc_unlikely (statp->qhook != NULL)) { |
28f540f4 RM |
465 | int done = 0, loops = 0; |
466 | ||
467 | do { | |
468 | res_sendhookact act; | |
469 | ||
25337753 UD |
470 | struct sockaddr_in *nsap4; |
471 | nsap4 = (struct sockaddr_in *) nsap; | |
472 | act = (*statp->qhook)(&nsap4, &buf, &buflen, | |
438e8239 | 473 | ans, anssiz, &resplen); |
25337753 | 474 | nsap = (struct sockaddr_in6 *) nsap4; |
28f540f4 RM |
475 | switch (act) { |
476 | case res_goahead: | |
477 | done = 1; | |
478 | break; | |
479 | case res_nextns: | |
cb07f6f6 | 480 | __res_iclose(statp, false); |
28f540f4 RM |
481 | goto next_ns; |
482 | case res_done: | |
b43b13ac | 483 | return (resplen); |
28f540f4 RM |
484 | case res_modified: |
485 | /* give the hook another try */ | |
486 | if (++loops < 42) /*doug adams*/ | |
487 | break; | |
488 | /*FALLTHROUGH*/ | |
489 | case res_error: | |
490 | /*FALLTHROUGH*/ | |
491 | default: | |
b43b13ac | 492 | return (-1); |
28f540f4 RM |
493 | } |
494 | } while (!done); | |
495 | } | |
1eb946b9 | 496 | #endif |
28f540f4 | 497 | |
020a9a23 UD |
498 | Dprint(statp->options & RES_DEBUG, |
499 | (stdout, ";; Querying server (# %d) address = %s\n", | |
2212c142 AS |
500 | ns + 1, inet_ntop(nsap->sa_family, |
501 | (nsap->sa_family == AF_INET6 | |
502 | ? &((struct sockaddr_in6 *) nsap)->sin6_addr | |
94308fd0 | 503 | : &((struct sockaddr_in *) nsap)->sin_addr), |
020a9a23 | 504 | tmpbuf, sizeof (tmpbuf)))); |
28f540f4 | 505 | |
a1ffb40e | 506 | if (__glibc_unlikely (v_circuit)) { |
b43b13ac UD |
507 | /* Use VC; at most one attempt per server. */ |
508 | try = statp->retry; | |
1eb946b9 UD |
509 | n = send_vc(statp, buf, buflen, buf2, buflen2, |
510 | &ans, &anssiz, &terrno, | |
ab09bf61 AS |
511 | ns, ansp, ansp2, nansp2, resplen2, |
512 | ansp2_malloced); | |
e685e07d UD |
513 | if (n < 0) |
514 | return (-1); | |
57912a71 | 515 | if (n == 0 && (buf2 == NULL || *resplen2 == 0)) |
28f540f4 | 516 | goto next_ns; |
28f540f4 | 517 | } else { |
e685e07d | 518 | /* Use datagrams. */ |
1eb946b9 UD |
519 | n = send_dg(statp, buf, buflen, buf2, buflen2, |
520 | &ans, &anssiz, &terrno, | |
521 | ns, &v_circuit, &gotsomewhere, ansp, | |
ab09bf61 | 522 | ansp2, nansp2, resplen2, ansp2_malloced); |
e685e07d UD |
523 | if (n < 0) |
524 | return (-1); | |
57912a71 | 525 | if (n == 0 && (buf2 == NULL || *resplen2 == 0)) |
b43b13ac | 526 | goto next_ns; |
e685e07d | 527 | if (v_circuit) |
1eb946b9 | 528 | // XXX Check whether both requests failed or |
b7da31a1 | 529 | // XXX whether one has been answered successfully |
28f540f4 | 530 | goto same_ns; |
e685e07d UD |
531 | } |
532 | ||
1eb946b9 UD |
533 | resplen = n; |
534 | ||
b43b13ac UD |
535 | Dprint((statp->options & RES_DEBUG) || |
536 | ((statp->pfcode & RES_PRF_REPLY) && | |
537 | (statp->pfcode & RES_PRF_HEAD1)), | |
a4219bc4 | 538 | (stdout, ";; got answer:\n")); |
e685e07d | 539 | |
b43b13ac UD |
540 | DprintQ((statp->options & RES_DEBUG) || |
541 | (statp->pfcode & RES_PRF_REPLY), | |
020a9a23 | 542 | (stdout, "%s", ""), |
e685e07d | 543 | ans, (resplen > anssiz) ? anssiz : resplen); |
a092b645 | 544 | if (buf2 != NULL) { |
1eb946b9 UD |
545 | DprintQ((statp->options & RES_DEBUG) || |
546 | (statp->pfcode & RES_PRF_REPLY), | |
547 | (stdout, "%s", ""), | |
b7da31a1 | 548 | *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2); |
a092b645 | 549 | } |
e685e07d | 550 | |
28f540f4 | 551 | /* |
28f540f4 RM |
552 | * If we have temporarily opened a virtual circuit, |
553 | * or if we haven't been asked to keep a socket open, | |
554 | * close the socket. | |
555 | */ | |
e685e07d UD |
556 | if ((v_circuit && (statp->options & RES_USEVC) == 0) || |
557 | (statp->options & RES_STAYOPEN) == 0) { | |
cb07f6f6 | 558 | __res_iclose(statp, false); |
28f540f4 | 559 | } |
1eb946b9 | 560 | #ifdef USE_HOOKS |
a1ffb40e | 561 | if (__glibc_unlikely (statp->rhook)) { |
28f540f4 RM |
562 | int done = 0, loops = 0; |
563 | ||
564 | do { | |
565 | res_sendhookact act; | |
566 | ||
438e8239 UD |
567 | act = (*statp->rhook)((struct sockaddr_in *) |
568 | nsap, buf, buflen, | |
569 | ans, anssiz, &resplen); | |
28f540f4 RM |
570 | switch (act) { |
571 | case res_goahead: | |
572 | case res_done: | |
573 | done = 1; | |
574 | break; | |
575 | case res_nextns: | |
cb07f6f6 | 576 | __res_iclose(statp, false); |
28f540f4 RM |
577 | goto next_ns; |
578 | case res_modified: | |
579 | /* give the hook another try */ | |
580 | if (++loops < 42) /*doug adams*/ | |
581 | break; | |
582 | /*FALLTHROUGH*/ | |
583 | case res_error: | |
584 | /*FALLTHROUGH*/ | |
585 | default: | |
b43b13ac | 586 | return (-1); |
28f540f4 RM |
587 | } |
588 | } while (!done); | |
589 | ||
590 | } | |
1eb946b9 | 591 | #endif |
b43b13ac UD |
592 | return (resplen); |
593 | next_ns: ; | |
28f540f4 RM |
594 | } /*foreach ns*/ |
595 | } /*foreach retry*/ | |
cb07f6f6 | 596 | __res_iclose(statp, false); |
7ef90c15 | 597 | if (!v_circuit) { |
28f540f4 | 598 | if (!gotsomewhere) |
b43b13ac | 599 | __set_errno (ECONNREFUSED); /* no nameservers found */ |
28f540f4 | 600 | else |
b43b13ac | 601 | __set_errno (ETIMEDOUT); /* no answer obtained */ |
7ef90c15 | 602 | } else |
c4029823 | 603 | __set_errno (terrno); |
b43b13ac | 604 | return (-1); |
28f540f4 RM |
605 | } |
606 | ||
0420d888 UD |
607 | int |
608 | res_nsend(res_state statp, | |
609 | const u_char *buf, int buflen, u_char *ans, int anssiz) | |
610 | { | |
1eb946b9 | 611 | return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz, |
ab09bf61 | 612 | NULL, NULL, NULL, NULL, NULL); |
0420d888 | 613 | } |
6f9d8e68 | 614 | libresolv_hidden_def (res_nsend) |
0420d888 | 615 | |
e685e07d UD |
616 | /* Private */ |
617 | ||
2212c142 AS |
618 | static struct sockaddr * |
619 | get_nsaddr (res_state statp, int n) | |
620 | { | |
621 | ||
622 | if (statp->nsaddr_list[n].sin_family == 0 && EXT(statp).nsaddrs[n] != NULL) | |
623 | /* EXT(statp).nsaddrs[n] holds an address that is larger than | |
624 | struct sockaddr, and user code did not update | |
625 | statp->nsaddr_list[n]. */ | |
626 | return (struct sockaddr *) EXT(statp).nsaddrs[n]; | |
627 | else | |
628 | /* User code updated statp->nsaddr_list[n], or statp->nsaddr_list[n] | |
629 | has the same content as EXT(statp).nsaddrs[n]. */ | |
630 | return (struct sockaddr *) (void *) &statp->nsaddr_list[n]; | |
631 | } | |
632 | ||
e685e07d UD |
633 | static int |
634 | send_vc(res_state statp, | |
1eb946b9 UD |
635 | const u_char *buf, int buflen, const u_char *buf2, int buflen2, |
636 | u_char **ansp, int *anssizp, | |
637 | int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2, | |
ab09bf61 | 638 | int *resplen2, int *ansp2_malloced) |
e685e07d UD |
639 | { |
640 | const HEADER *hp = (HEADER *) buf; | |
1eb946b9 | 641 | const HEADER *hp2 = (HEADER *) buf2; |
0420d888 | 642 | u_char *ans = *ansp; |
1eb946b9 UD |
643 | int orig_anssizp = *anssizp; |
644 | // XXX REMOVE | |
645 | // int anssiz = *anssizp; | |
e685e07d | 646 | HEADER *anhp = (HEADER *) ans; |
2212c142 | 647 | struct sockaddr *nsap = get_nsaddr (statp, ns); |
48e435cd SL |
648 | int truncating, connreset, n; |
649 | /* On some architectures compiler might emit a warning indicating | |
650 | 'resplen' may be used uninitialized. However if buf2 == NULL | |
651 | then this code won't be executed; if buf2 != NULL, then first | |
652 | time round the loop recvresp1 and recvresp2 will be 0 so this | |
653 | code won't be executed but "thisresplenp = &resplen;" followed | |
654 | by "*thisresplenp = rlen;" will be executed so that subsequent | |
655 | times round the loop resplen has been initialized. So this is | |
656 | a false-positive. | |
657 | */ | |
658 | #if __GNUC_PREREQ (4, 7) | |
659 | DIAG_PUSH_NEEDS_COMMENT; | |
660 | DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); | |
661 | #endif | |
662 | int resplen; | |
663 | #if __GNUC_PREREQ (4, 7) | |
664 | DIAG_POP_NEEDS_COMMENT; | |
665 | #endif | |
1eb946b9 | 666 | struct iovec iov[4]; |
e685e07d | 667 | u_short len; |
1eb946b9 | 668 | u_short len2; |
e685e07d UD |
669 | u_char *cp; |
670 | ||
b7da31a1 UD |
671 | if (resplen2 != NULL) |
672 | *resplen2 = 0; | |
e685e07d UD |
673 | connreset = 0; |
674 | same_ns: | |
675 | truncating = 0; | |
676 | ||
677 | /* Are we still talking to whom we want to talk to? */ | |
678 | if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { | |
438e8239 | 679 | struct sockaddr_in6 peer; |
9cfe5381 | 680 | socklen_t size = sizeof peer; |
e685e07d UD |
681 | |
682 | if (getpeername(statp->_vcsock, | |
683 | (struct sockaddr *)&peer, &size) < 0 || | |
2212c142 AS |
684 | !sock_eq(&peer, (struct sockaddr_in6 *) nsap)) { |
685 | __res_iclose(statp, false); | |
e685e07d UD |
686 | statp->_flags &= ~RES_F_VC; |
687 | } | |
688 | } | |
689 | ||
690 | if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { | |
691 | if (statp->_vcsock >= 0) | |
cb07f6f6 | 692 | __res_iclose(statp, false); |
e685e07d | 693 | |
2212c142 | 694 | statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0); |
e685e07d UD |
695 | if (statp->_vcsock < 0) { |
696 | *terrno = errno; | |
697 | Perror(statp, stderr, "socket(vc)", errno); | |
698 | return (-1); | |
699 | } | |
700 | __set_errno (0); | |
2212c142 AS |
701 | if (connect(statp->_vcsock, nsap, |
702 | nsap->sa_family == AF_INET | |
9fc42dfd UD |
703 | ? sizeof (struct sockaddr_in) |
704 | : sizeof (struct sockaddr_in6)) < 0) { | |
e685e07d | 705 | *terrno = errno; |
2212c142 | 706 | Aerror(statp, stderr, "connect/vc", errno, nsap); |
cb07f6f6 | 707 | __res_iclose(statp, false); |
e685e07d UD |
708 | return (0); |
709 | } | |
710 | statp->_flags |= RES_F_VC; | |
28f540f4 | 711 | } |
e685e07d UD |
712 | |
713 | /* | |
714 | * Send length & message | |
715 | */ | |
1eb946b9 | 716 | len = htons ((u_short) buflen); |
25337753 UD |
717 | evConsIovec(&len, INT16SZ, &iov[0]); |
718 | evConsIovec((void*)buf, buflen, &iov[1]); | |
1eb946b9 UD |
719 | int niov = 2; |
720 | ssize_t explen = INT16SZ + buflen; | |
721 | if (buf2 != NULL) { | |
722 | len2 = htons ((u_short) buflen2); | |
723 | evConsIovec(&len2, INT16SZ, &iov[2]); | |
724 | evConsIovec((void*)buf2, buflen2, &iov[3]); | |
725 | niov = 4; | |
726 | explen += INT16SZ + buflen2; | |
727 | } | |
728 | if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) { | |
e685e07d UD |
729 | *terrno = errno; |
730 | Perror(statp, stderr, "write failed", errno); | |
cb07f6f6 | 731 | __res_iclose(statp, false); |
e685e07d UD |
732 | return (0); |
733 | } | |
734 | /* | |
735 | * Receive length & response | |
736 | */ | |
1eb946b9 UD |
737 | int recvresp1 = 0; |
738 | int recvresp2 = buf2 == NULL; | |
b7da31a1 | 739 | uint16_t rlen16; |
e39e6946 UD |
740 | read_len: |
741 | cp = (u_char *)&rlen16; | |
b7da31a1 | 742 | len = sizeof(rlen16); |
e39e6946 | 743 | while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp, |
25337753 | 744 | (int)len))) > 0) { |
e685e07d UD |
745 | cp += n; |
746 | if ((len -= n) <= 0) | |
747 | break; | |
748 | } | |
749 | if (n <= 0) { | |
750 | *terrno = errno; | |
751 | Perror(statp, stderr, "read failed", errno); | |
cb07f6f6 | 752 | __res_iclose(statp, false); |
e685e07d UD |
753 | /* |
754 | * A long running process might get its TCP | |
755 | * connection reset if the remote server was | |
756 | * restarted. Requery the server instead of | |
757 | * trying a new one. When there is only one | |
758 | * server, this means that a query might work | |
759 | * instead of failing. We only allow one reset | |
760 | * per query to prevent looping. | |
761 | */ | |
762 | if (*terrno == ECONNRESET && !connreset) { | |
763 | connreset = 1; | |
e685e07d UD |
764 | goto same_ns; |
765 | } | |
e685e07d UD |
766 | return (0); |
767 | } | |
b7da31a1 | 768 | int rlen = ntohs (rlen16); |
1eb946b9 UD |
769 | |
770 | int *thisanssizp; | |
771 | u_char **thisansp; | |
772 | int *thisresplenp; | |
773 | if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { | |
774 | thisanssizp = anssizp; | |
775 | thisansp = anscp ?: ansp; | |
776 | assert (anscp != NULL || ansp2 == NULL); | |
777 | thisresplenp = &resplen; | |
778 | } else { | |
779 | if (*anssizp != MAXPACKET) { | |
780 | /* No buffer allocated for the first | |
781 | reply. We can try to use the rest | |
782 | of the user-provided buffer. */ | |
48e435cd SL |
783 | #if __GNUC_PREREQ (4, 7) |
784 | DIAG_PUSH_NEEDS_COMMENT; | |
785 | DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); | |
786 | #endif | |
27822ce6 | 787 | #if _STRING_ARCH_unaligned |
1eb946b9 UD |
788 | *anssizp2 = orig_anssizp - resplen; |
789 | *ansp2 = *ansp + resplen; | |
e39e6946 UD |
790 | #else |
791 | int aligned_resplen | |
792 | = ((resplen + __alignof__ (HEADER) - 1) | |
ad12e635 | 793 | & ~(__alignof__ (HEADER) - 1)); |
e39e6946 UD |
794 | *anssizp2 = orig_anssizp - aligned_resplen; |
795 | *ansp2 = *ansp + aligned_resplen; | |
48e435cd SL |
796 | #endif |
797 | #if __GNUC_PREREQ (4, 7) | |
798 | DIAG_POP_NEEDS_COMMENT; | |
e39e6946 | 799 | #endif |
1eb946b9 UD |
800 | } else { |
801 | /* The first reply did not fit into the | |
802 | user-provided buffer. Maybe the second | |
803 | answer will. */ | |
804 | *anssizp2 = orig_anssizp; | |
805 | *ansp2 = *ansp; | |
806 | } | |
807 | ||
808 | thisanssizp = anssizp2; | |
809 | thisansp = ansp2; | |
810 | thisresplenp = resplen2; | |
811 | } | |
812 | anhp = (HEADER *) *thisansp; | |
813 | ||
b7da31a1 UD |
814 | *thisresplenp = rlen; |
815 | if (rlen > *thisanssizp) { | |
1eb946b9 UD |
816 | /* Yes, we test ANSCP here. If we have two buffers |
817 | both will be allocatable. */ | |
a1ffb40e | 818 | if (__glibc_likely (anscp != NULL)) { |
1eb946b9 UD |
819 | u_char *newp = malloc (MAXPACKET); |
820 | if (newp == NULL) { | |
0420d888 | 821 | *terrno = ENOMEM; |
cb07f6f6 | 822 | __res_iclose(statp, false); |
0420d888 UD |
823 | return (0); |
824 | } | |
1eb946b9 UD |
825 | *thisanssizp = MAXPACKET; |
826 | *thisansp = newp; | |
ab09bf61 AS |
827 | if (thisansp == ansp2) |
828 | *ansp2_malloced = 1; | |
1eb946b9 | 829 | anhp = (HEADER *) newp; |
b7da31a1 | 830 | len = rlen; |
0420d888 UD |
831 | } else { |
832 | Dprint(statp->options & RES_DEBUG, | |
833 | (stdout, ";; response truncated\n") | |
834 | ); | |
835 | truncating = 1; | |
1eb946b9 | 836 | len = *thisanssizp; |
0420d888 | 837 | } |
e685e07d | 838 | } else |
b7da31a1 | 839 | len = rlen; |
1eb946b9 | 840 | |
a1ffb40e | 841 | if (__glibc_unlikely (len < HFIXEDSZ)) { |
e685e07d UD |
842 | /* |
843 | * Undersized message. | |
844 | */ | |
845 | Dprint(statp->options & RES_DEBUG, | |
846 | (stdout, ";; undersized: %d\n", len)); | |
847 | *terrno = EMSGSIZE; | |
cb07f6f6 | 848 | __res_iclose(statp, false); |
e685e07d UD |
849 | return (0); |
850 | } | |
1eb946b9 UD |
851 | |
852 | cp = *thisansp; | |
e685e07d UD |
853 | while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){ |
854 | cp += n; | |
855 | len -= n; | |
856 | } | |
a1ffb40e | 857 | if (__glibc_unlikely (n <= 0)) { |
e685e07d UD |
858 | *terrno = errno; |
859 | Perror(statp, stderr, "read(vc)", errno); | |
cb07f6f6 | 860 | __res_iclose(statp, false); |
e685e07d UD |
861 | return (0); |
862 | } | |
a1ffb40e | 863 | if (__glibc_unlikely (truncating)) { |
e685e07d UD |
864 | /* |
865 | * Flush rest of answer so connection stays in synch. | |
866 | */ | |
867 | anhp->tc = 1; | |
b7da31a1 | 868 | len = rlen - *thisanssizp; |
e685e07d UD |
869 | while (len != 0) { |
870 | char junk[PACKETSZ]; | |
871 | ||
872 | n = read(statp->_vcsock, junk, | |
873 | (len > sizeof junk) ? sizeof junk : len); | |
874 | if (n > 0) | |
875 | len -= n; | |
876 | else | |
877 | break; | |
878 | } | |
879 | } | |
880 | /* | |
c0c3f78a | 881 | * If the calling application has bailed out of |
e685e07d UD |
882 | * a previous call and failed to arrange to have |
883 | * the circuit closed or the server has got | |
884 | * itself confused, then drop the packet and | |
885 | * wait for the correct one. | |
886 | */ | |
1eb946b9 UD |
887 | if ((recvresp1 || hp->id != anhp->id) |
888 | && (recvresp2 || hp2->id != anhp->id)) { | |
e685e07d UD |
889 | DprintQ((statp->options & RES_DEBUG) || |
890 | (statp->pfcode & RES_PRF_REPLY), | |
891 | (stdout, ";; old answer (unexpected):\n"), | |
1eb946b9 | 892 | *thisansp, |
a092b645 | 893 | (rlen > *thisanssizp) ? *thisanssizp: rlen); |
e685e07d UD |
894 | goto read_len; |
895 | } | |
896 | ||
1eb946b9 UD |
897 | /* Mark which reply we received. */ |
898 | if (recvresp1 == 0 && hp->id == anhp->id) | |
899 | recvresp1 = 1; | |
900 | else | |
901 | recvresp2 = 1; | |
902 | /* Repeat waiting if we have a second answer to arrive. */ | |
903 | if ((recvresp1 & recvresp2) == 0) | |
904 | goto read_len; | |
905 | ||
e685e07d UD |
906 | /* |
907 | * All is well, or the error is fatal. Signal that the | |
908 | * next nameserver ought not be tried. | |
909 | */ | |
b7da31a1 | 910 | return resplen; |
28f540f4 | 911 | } |
845dcb57 | 912 | |
b43b13ac | 913 | static int |
44d20bca | 914 | reopen (res_state statp, int *terrno, int ns) |
e685e07d | 915 | { |
e685e07d | 916 | if (EXT(statp).nssocks[ns] == -1) { |
2212c142 | 917 | struct sockaddr *nsap = get_nsaddr (statp, ns); |
ace4e23f | 918 | socklen_t slen; |
44d20bca | 919 | |
438e8239 | 920 | /* only try IPv6 if IPv6 NS and if not failed before */ |
ace4e23f | 921 | if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) { |
52fb79d6 FW |
922 | EXT(statp).nssocks[ns] |
923 | = socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK, 0); | |
ae1ad3ae UD |
924 | if (EXT(statp).nssocks[ns] < 0) |
925 | statp->ipv6_unavail = errno == EAFNOSUPPORT; | |
ace4e23f UD |
926 | slen = sizeof (struct sockaddr_in6); |
927 | } else if (nsap->sa_family == AF_INET) { | |
52fb79d6 FW |
928 | EXT(statp).nssocks[ns] |
929 | = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, 0); | |
ace4e23f | 930 | slen = sizeof (struct sockaddr_in); |
9744268c | 931 | } |
e685e07d UD |
932 | if (EXT(statp).nssocks[ns] < 0) { |
933 | *terrno = errno; | |
934 | Perror(statp, stderr, "socket(dg)", errno); | |
935 | return (-1); | |
936 | } | |
ae1ad3ae | 937 | |
e685e07d UD |
938 | /* |
939 | * On a 4.3BSD+ machine (client and server, | |
940 | * actually), sending to a nameserver datagram | |
941 | * port with no nameserver will cause an | |
942 | * ICMP port unreachable message to be returned. | |
943 | * If our datagram socket is "connected" to the | |
944 | * server, we get an ECONNREFUSED error on the next | |
945 | * socket operation, and select returns if the | |
946 | * error message is received. We can thus detect | |
947 | * the absence of a nameserver without timing out. | |
948 | */ | |
ace4e23f UD |
949 | if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) { |
950 | Aerror(statp, stderr, "connect(dg)", errno, nsap); | |
cb07f6f6 | 951 | __res_iclose(statp, false); |
e685e07d UD |
952 | return (0); |
953 | } | |
e685e07d | 954 | } |
17a10319 | 955 | |
44d20bca UD |
956 | return 1; |
957 | } | |
958 | ||
959 | static int | |
960 | send_dg(res_state statp, | |
961 | const u_char *buf, int buflen, const u_char *buf2, int buflen2, | |
962 | u_char **ansp, int *anssizp, | |
963 | int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp, | |
ab09bf61 | 964 | u_char **ansp2, int *anssizp2, int *resplen2, int *ansp2_malloced) |
44d20bca UD |
965 | { |
966 | const HEADER *hp = (HEADER *) buf; | |
967 | const HEADER *hp2 = (HEADER *) buf2; | |
968 | u_char *ans = *ansp; | |
969 | int orig_anssizp = *anssizp; | |
970 | struct timespec now, timeout, finish; | |
971 | struct pollfd pfd[1]; | |
3a85895f | 972 | int ptimeout; |
44d20bca | 973 | struct sockaddr_in6 from; |
75ded9bc UD |
974 | int resplen = 0; |
975 | int n; | |
44d20bca | 976 | |
f433b06b UD |
977 | /* |
978 | * Compute time for the total operation. | |
979 | */ | |
ae061910 | 980 | int seconds = (statp->retrans << ns); |
f433b06b UD |
981 | if (ns > 0) |
982 | seconds /= statp->nscount; | |
983 | if (seconds <= 0) | |
984 | seconds = 1; | |
44d20bca | 985 | bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0; |
c030f70c UD |
986 | bool single_request = (((statp->options & RES_SNGLKUP) != 0) |
987 | | single_request_reopen); | |
ae061910 | 988 | int save_gotsomewhere = *gotsomewhere; |
44d20bca UD |
989 | |
990 | int retval; | |
991 | retry_reopen: | |
992 | retval = reopen (statp, terrno, ns); | |
993 | if (retval <= 0) | |
994 | return retval; | |
ae061910 | 995 | retry: |
f433b06b UD |
996 | evNowTime(&now); |
997 | evConsTime(&timeout, seconds, 0); | |
998 | evAddTime(&finish, &now, &timeout); | |
999 | int need_recompute = 0; | |
17a10319 | 1000 | int nwritten = 0; |
1eb946b9 UD |
1001 | int recvresp1 = 0; |
1002 | int recvresp2 = buf2 == NULL; | |
17a10319 UD |
1003 | pfd[0].fd = EXT(statp).nssocks[ns]; |
1004 | pfd[0].events = POLLOUT; | |
5908f779 UD |
1005 | if (resplen2 != NULL) |
1006 | *resplen2 = 0; | |
17a10319 UD |
1007 | wait: |
1008 | if (need_recompute) { | |
8e45b1ac | 1009 | recompute_resend: |
17a10319 UD |
1010 | evNowTime(&now); |
1011 | if (evCmpTime(finish, now) <= 0) { | |
8e45b1ac UD |
1012 | poll_err_out: |
1013 | Perror(statp, stderr, "poll", errno); | |
1014 | err_out: | |
cb07f6f6 | 1015 | __res_iclose(statp, false); |
17a10319 UD |
1016 | return (0); |
1017 | } | |
1018 | evSubTime(&timeout, &finish, &now); | |
ae061910 | 1019 | need_recompute = 0; |
17a10319 | 1020 | } |
3a85895f | 1021 | /* Convert struct timespec in milliseconds. */ |
f433b06b UD |
1022 | ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000; |
1023 | ||
17a10319 UD |
1024 | n = 0; |
1025 | if (nwritten == 0) | |
1026 | n = __poll (pfd, 1, 0); | |
a1ffb40e | 1027 | if (__glibc_unlikely (n == 0)) { |
f433b06b UD |
1028 | n = __poll (pfd, 1, ptimeout); |
1029 | need_recompute = 1; | |
1030 | } | |
f433b06b | 1031 | if (n == 0) { |
e2003883 | 1032 | Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); |
74b3cf22 | 1033 | if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2))) |
e2003883 | 1034 | { |
ae061910 UD |
1035 | /* There are quite a few broken name servers out |
1036 | there which don't handle two outstanding | |
1037 | requests from the same source. There are also | |
1038 | broken firewall settings. If we time out after | |
1039 | having received one answer switch to the mode | |
1040 | where we send the second request only once we | |
1041 | have received the first answer. */ | |
74b3cf22 UD |
1042 | if (!single_request) |
1043 | { | |
310647e9 | 1044 | statp->options |= RES_SNGLKUP; |
74b3cf22 UD |
1045 | single_request = true; |
1046 | *gotsomewhere = save_gotsomewhere; | |
1047 | goto retry; | |
1048 | } | |
44d20bca UD |
1049 | else if (!single_request_reopen) |
1050 | { | |
1051 | statp->options |= RES_SNGLKUPREOP; | |
1052 | single_request_reopen = true; | |
1053 | *gotsomewhere = save_gotsomewhere; | |
1054 | __res_iclose (statp, false); | |
1055 | goto retry_reopen; | |
1056 | } | |
74b3cf22 UD |
1057 | |
1058 | *resplen2 = 1; | |
1059 | return resplen; | |
e2003883 | 1060 | } |
5908f779 | 1061 | |
f433b06b UD |
1062 | *gotsomewhere = 1; |
1063 | return (0); | |
1064 | } | |
1065 | if (n < 0) { | |
8e45b1ac UD |
1066 | if (errno == EINTR) |
1067 | goto recompute_resend; | |
1068 | ||
1069 | goto poll_err_out; | |
f433b06b UD |
1070 | } |
1071 | __set_errno (0); | |
17a10319 | 1072 | if (pfd[0].revents & POLLOUT) { |
c030f70c UD |
1073 | #ifndef __ASSUME_SENDMMSG |
1074 | static int have_sendmmsg; | |
1075 | #else | |
1076 | # define have_sendmmsg 1 | |
1077 | #endif | |
1078 | if (have_sendmmsg >= 0 && nwritten == 0 && buf2 != NULL | |
1079 | && !single_request) | |
1080 | { | |
1081 | struct iovec iov[2]; | |
1082 | struct mmsghdr reqs[2]; | |
1083 | reqs[0].msg_hdr.msg_name = NULL; | |
1084 | reqs[0].msg_hdr.msg_namelen = 0; | |
1085 | reqs[0].msg_hdr.msg_iov = &iov[0]; | |
1086 | reqs[0].msg_hdr.msg_iovlen = 1; | |
1087 | iov[0].iov_base = (void *) buf; | |
1088 | iov[0].iov_len = buflen; | |
1089 | reqs[0].msg_hdr.msg_control = NULL; | |
1090 | reqs[0].msg_hdr.msg_controllen = 0; | |
1091 | ||
1092 | reqs[1].msg_hdr.msg_name = NULL; | |
1093 | reqs[1].msg_hdr.msg_namelen = 0; | |
1094 | reqs[1].msg_hdr.msg_iov = &iov[1]; | |
1095 | reqs[1].msg_hdr.msg_iovlen = 1; | |
1096 | iov[1].iov_base = (void *) buf2; | |
1097 | iov[1].iov_len = buflen2; | |
1098 | reqs[1].msg_hdr.msg_control = NULL; | |
1099 | reqs[1].msg_hdr.msg_controllen = 0; | |
1100 | ||
123be9de | 1101 | int ndg = __sendmmsg (pfd[0].fd, reqs, 2, MSG_NOSIGNAL); |
a1ffb40e | 1102 | if (__glibc_likely (ndg == 2)) |
c030f70c | 1103 | { |
966977f1 UD |
1104 | if (reqs[0].msg_len != buflen |
1105 | || reqs[1].msg_len != buflen2) | |
1106 | goto fail_sendmmsg; | |
1eb946b9 | 1107 | |
c030f70c UD |
1108 | pfd[0].events = POLLIN; |
1109 | nwritten += 2; | |
1110 | } | |
1111 | else if (ndg == 1 && reqs[0].msg_len == buflen) | |
1112 | goto just_one; | |
966977f1 | 1113 | else if (ndg < 0 && (errno == EINTR || errno == EAGAIN)) |
c030f70c UD |
1114 | goto recompute_resend; |
1115 | else | |
1116 | { | |
1117 | #ifndef __ASSUME_SENDMMSG | |
a1ffb40e | 1118 | if (__glibc_unlikely (have_sendmmsg == 0)) |
c030f70c | 1119 | { |
966977f1 | 1120 | if (ndg < 0 && errno == ENOSYS) |
c030f70c UD |
1121 | { |
1122 | have_sendmmsg = -1; | |
1123 | goto try_send; | |
1124 | } | |
1125 | have_sendmmsg = 1; | |
1126 | } | |
1127 | #endif | |
1128 | ||
966977f1 | 1129 | fail_sendmmsg: |
c030f70c | 1130 | Perror(statp, stderr, "sendmmsg", errno); |
8e45b1ac | 1131 | goto err_out; |
c030f70c UD |
1132 | } |
1133 | } | |
1eb946b9 | 1134 | else |
c030f70c UD |
1135 | { |
1136 | ssize_t sr; | |
1137 | #ifndef __ASSUME_SENDMMSG | |
1138 | try_send: | |
1139 | #endif | |
1140 | if (nwritten != 0) | |
1141 | sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL); | |
1142 | else | |
1143 | sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL); | |
1144 | ||
8e6d1083 | 1145 | if (sr != (nwritten != 0 ? buflen2 : buflen)) { |
c030f70c UD |
1146 | if (errno == EINTR || errno == EAGAIN) |
1147 | goto recompute_resend; | |
1148 | Perror(statp, stderr, "send", errno); | |
1149 | goto err_out; | |
1150 | } | |
1151 | just_one: | |
1152 | if (nwritten != 0 || buf2 == NULL || single_request) | |
1153 | pfd[0].events = POLLIN; | |
1154 | else | |
1155 | pfd[0].events = POLLIN | POLLOUT; | |
1156 | ++nwritten; | |
1157 | } | |
17a10319 | 1158 | goto wait; |
8aeb5058 | 1159 | } else if (pfd[0].revents & POLLIN) { |
1eb946b9 UD |
1160 | int *thisanssizp; |
1161 | u_char **thisansp; | |
1162 | int *thisresplenp; | |
1163 | ||
1164 | if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { | |
1165 | thisanssizp = anssizp; | |
1166 | thisansp = anscp ?: ansp; | |
1167 | assert (anscp != NULL || ansp2 == NULL); | |
1168 | thisresplenp = &resplen; | |
1169 | } else { | |
1170 | if (*anssizp != MAXPACKET) { | |
1171 | /* No buffer allocated for the first | |
1172 | reply. We can try to use the rest | |
1173 | of the user-provided buffer. */ | |
27822ce6 | 1174 | #if _STRING_ARCH_unaligned |
1eb946b9 UD |
1175 | *anssizp2 = orig_anssizp - resplen; |
1176 | *ansp2 = *ansp + resplen; | |
ad12e635 UD |
1177 | #else |
1178 | int aligned_resplen | |
1179 | = ((resplen + __alignof__ (HEADER) - 1) | |
1180 | & ~(__alignof__ (HEADER) - 1)); | |
1181 | *anssizp2 = orig_anssizp - aligned_resplen; | |
1182 | *ansp2 = *ansp + aligned_resplen; | |
1183 | #endif | |
1eb946b9 UD |
1184 | } else { |
1185 | /* The first reply did not fit into the | |
1186 | user-provided buffer. Maybe the second | |
1187 | answer will. */ | |
1188 | *anssizp2 = orig_anssizp; | |
1189 | *ansp2 = *ansp; | |
1190 | } | |
1191 | ||
1192 | thisanssizp = anssizp2; | |
1193 | thisansp = ansp2; | |
1194 | thisresplenp = resplen2; | |
1195 | } | |
1196 | ||
1197 | if (*thisanssizp < MAXPACKET | |
1198 | /* Yes, we test ANSCP here. If we have two buffers | |
1199 | both will be allocatable. */ | |
17a10319 | 1200 | && anscp |
c4e42566 | 1201 | #ifdef FIONREAD |
1eb946b9 | 1202 | && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 |
c4e42566 RM |
1203 | || *thisanssizp < *thisresplenp) |
1204 | #endif | |
1205 | ) { | |
1eb946b9 UD |
1206 | u_char *newp = malloc (MAXPACKET); |
1207 | if (newp != NULL) { | |
17a10319 | 1208 | *anssizp = MAXPACKET; |
1eb946b9 | 1209 | *thisansp = ans = newp; |
ab09bf61 AS |
1210 | if (thisansp == ansp2) |
1211 | *ansp2_malloced = 1; | |
17a10319 UD |
1212 | } |
1213 | } | |
1eb946b9 UD |
1214 | HEADER *anhp = (HEADER *) *thisansp; |
1215 | socklen_t fromlen = sizeof(struct sockaddr_in6); | |
1216 | assert (sizeof(from) <= fromlen); | |
1217 | *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp, | |
1218 | *thisanssizp, 0, | |
1219 | (struct sockaddr *)&from, &fromlen); | |
a1ffb40e | 1220 | if (__glibc_unlikely (*thisresplenp <= 0)) { |
17a10319 UD |
1221 | if (errno == EINTR || errno == EAGAIN) { |
1222 | need_recompute = 1; | |
1223 | goto wait; | |
1224 | } | |
1225 | Perror(statp, stderr, "recvfrom", errno); | |
8e45b1ac | 1226 | goto err_out; |
17a10319 | 1227 | } |
e685e07d | 1228 | *gotsomewhere = 1; |
a1ffb40e | 1229 | if (__glibc_unlikely (*thisresplenp < HFIXEDSZ)) { |
17a10319 UD |
1230 | /* |
1231 | * Undersized message. | |
1232 | */ | |
1233 | Dprint(statp->options & RES_DEBUG, | |
1234 | (stdout, ";; undersized: %d\n", | |
a092b645 | 1235 | *thisresplenp)); |
17a10319 | 1236 | *terrno = EMSGSIZE; |
8e45b1ac | 1237 | goto err_out; |
17a10319 | 1238 | } |
1eb946b9 UD |
1239 | if ((recvresp1 || hp->id != anhp->id) |
1240 | && (recvresp2 || hp2->id != anhp->id)) { | |
17a10319 UD |
1241 | /* |
1242 | * response from old query, ignore it. | |
1243 | * XXX - potential security hazard could | |
1244 | * be detected here. | |
1245 | */ | |
1246 | DprintQ((statp->options & RES_DEBUG) || | |
1247 | (statp->pfcode & RES_PRF_REPLY), | |
1248 | (stdout, ";; old answer:\n"), | |
94308fd0 | 1249 | *thisansp, |
a092b645 YD |
1250 | (*thisresplenp > *thisanssizp) |
1251 | ? *thisanssizp : *thisresplenp); | |
f433b06b | 1252 | goto wait; |
e685e07d | 1253 | } |
17a10319 UD |
1254 | if (!(statp->options & RES_INSECURE1) && |
1255 | !res_ourserver_p(statp, &from)) { | |
1256 | /* | |
1257 | * response from wrong server? ignore it. | |
1258 | * XXX - potential security hazard could | |
1259 | * be detected here. | |
1260 | */ | |
1261 | DprintQ((statp->options & RES_DEBUG) || | |
1262 | (statp->pfcode & RES_PRF_REPLY), | |
1263 | (stdout, ";; not our server:\n"), | |
94308fd0 | 1264 | *thisansp, |
a092b645 YD |
1265 | (*thisresplenp > *thisanssizp) |
1266 | ? *thisanssizp : *thisresplenp); | |
17a10319 | 1267 | goto wait; |
0420d888 | 1268 | } |
2bbb7d5b UD |
1269 | #ifdef RES_USE_EDNS0 |
1270 | if (anhp->rcode == FORMERR | |
1271 | && (statp->options & RES_USE_EDNS0) != 0U) { | |
1272 | /* | |
1eb946b9 | 1273 | * Do not retry if the server does not understand |
2bbb7d5b UD |
1274 | * EDNS0. The case has to be captured here, as |
1275 | * FORMERR packet do not carry query section, hence | |
1276 | * res_queriesmatch() returns 0. | |
1277 | */ | |
1278 | DprintQ(statp->options & RES_DEBUG, | |
1279 | (stdout, | |
1280 | "server rejected query with EDNS0:\n"), | |
94308fd0 | 1281 | *thisansp, |
a092b645 YD |
1282 | (*thisresplenp > *thisanssizp) |
1283 | ? *thisanssizp : *thisresplenp); | |
2bbb7d5b UD |
1284 | /* record the error */ |
1285 | statp->_flags |= RES_F_EDNS0ERR; | |
1286 | goto err_out; | |
3a85895f | 1287 | } |
2bbb7d5b | 1288 | #endif |
1eb946b9 UD |
1289 | if (!(statp->options & RES_INSECURE2) |
1290 | && (recvresp1 || !res_queriesmatch(buf, buf + buflen, | |
1291 | *thisansp, | |
1292 | *thisansp | |
1293 | + *thisanssizp)) | |
1294 | && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2, | |
1295 | *thisansp, | |
1296 | *thisansp | |
1297 | + *thisanssizp))) { | |
17a10319 UD |
1298 | /* |
1299 | * response contains wrong query? ignore it. | |
1300 | * XXX - potential security hazard could | |
1301 | * be detected here. | |
1302 | */ | |
1303 | DprintQ((statp->options & RES_DEBUG) || | |
1304 | (statp->pfcode & RES_PRF_REPLY), | |
1305 | (stdout, ";; wrong query name:\n"), | |
94308fd0 | 1306 | *thisansp, |
a092b645 YD |
1307 | (*thisresplenp > *thisanssizp) |
1308 | ? *thisanssizp : *thisresplenp); | |
f433b06b UD |
1309 | goto wait; |
1310 | } | |
17a10319 UD |
1311 | if (anhp->rcode == SERVFAIL || |
1312 | anhp->rcode == NOTIMP || | |
1313 | anhp->rcode == REFUSED) { | |
1314 | DprintQ(statp->options & RES_DEBUG, | |
1315 | (stdout, "server rejected query:\n"), | |
94308fd0 | 1316 | *thisansp, |
a092b645 YD |
1317 | (*thisresplenp > *thisanssizp) |
1318 | ? *thisanssizp : *thisresplenp); | |
e2003883 | 1319 | |
16b293a7 | 1320 | next_ns: |
4769ae77 UD |
1321 | if (recvresp1 || (buf2 != NULL && recvresp2)) { |
1322 | *resplen2 = 0; | |
e28b969b | 1323 | return resplen; |
4769ae77 | 1324 | } |
e2003883 UD |
1325 | if (buf2 != NULL) |
1326 | { | |
4769ae77 UD |
1327 | /* No data from the first reply. */ |
1328 | resplen = 0; | |
e2003883 | 1329 | /* We are waiting for a possible second reply. */ |
e2003883 UD |
1330 | if (hp->id == anhp->id) |
1331 | recvresp1 = 1; | |
1332 | else | |
1333 | recvresp2 = 1; | |
1334 | ||
1335 | goto wait; | |
1336 | } | |
1337 | ||
cb07f6f6 | 1338 | __res_iclose(statp, false); |
17a10319 UD |
1339 | /* don't retry if called from dig */ |
1340 | if (!statp->pfcode) | |
1341 | return (0); | |
1342 | } | |
359bb2ef UD |
1343 | if (anhp->rcode == NOERROR && anhp->ancount == 0 |
1344 | && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) { | |
1345 | DprintQ(statp->options & RES_DEBUG, | |
1346 | (stdout, "referred query:\n"), | |
94308fd0 | 1347 | *thisansp, |
a092b645 YD |
1348 | (*thisresplenp > *thisanssizp) |
1349 | ? *thisanssizp : *thisresplenp); | |
359bb2ef UD |
1350 | goto next_ns; |
1351 | } | |
17a10319 UD |
1352 | if (!(statp->options & RES_IGNTC) && anhp->tc) { |
1353 | /* | |
1354 | * To get the rest of answer, | |
1355 | * use TCP with same server. | |
1356 | */ | |
1357 | Dprint(statp->options & RES_DEBUG, | |
1358 | (stdout, ";; truncated answer\n")); | |
1359 | *v_circuit = 1; | |
cb07f6f6 | 1360 | __res_iclose(statp, false); |
1eb946b9 UD |
1361 | // XXX if we have received one reply we could |
1362 | // XXX use it and not repeat it over TCP... | |
17a10319 UD |
1363 | return (1); |
1364 | } | |
1eb946b9 UD |
1365 | /* Mark which reply we received. */ |
1366 | if (recvresp1 == 0 && hp->id == anhp->id) | |
1367 | recvresp1 = 1; | |
1368 | else | |
1369 | recvresp2 = 1; | |
1370 | /* Repeat waiting if we have a second answer to arrive. */ | |
ae061910 | 1371 | if ((recvresp1 & recvresp2) == 0) { |
c030f70c | 1372 | if (single_request) { |
ae061910 | 1373 | pfd[0].events = POLLOUT; |
44d20bca UD |
1374 | if (single_request_reopen) { |
1375 | __res_iclose (statp, false); | |
1376 | retval = reopen (statp, terrno, ns); | |
1377 | if (retval <= 0) | |
1378 | return retval; | |
f9d2d032 | 1379 | pfd[0].fd = EXT(statp).nssocks[ns]; |
44d20bca UD |
1380 | } |
1381 | } | |
1eb946b9 | 1382 | goto wait; |
ae061910 | 1383 | } |
e685e07d | 1384 | /* |
17a10319 UD |
1385 | * All is well, or the error is fatal. Signal that the |
1386 | * next nameserver ought not be tried. | |
e685e07d | 1387 | */ |
17a10319 | 1388 | return (resplen); |
8aeb5058 UD |
1389 | } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { |
1390 | /* Something went wrong. We can stop trying. */ | |
8e45b1ac | 1391 | goto err_out; |
e685e07d | 1392 | } |
9cfe5381 | 1393 | else { |
4769ae77 | 1394 | /* poll should not have returned > 0 in this case. */ |
9cfe5381 RM |
1395 | abort (); |
1396 | } | |
e685e07d UD |
1397 | } |
1398 | ||
1399 | #ifdef DEBUG | |
1400 | static void | |
1401 | Aerror(const res_state statp, FILE *file, const char *string, int error, | |
020a9a23 | 1402 | const struct sockaddr *address) |
e685e07d UD |
1403 | { |
1404 | int save = errno; | |
1405 | ||
1406 | if ((statp->options & RES_DEBUG) != 0) { | |
020a9a23 | 1407 | char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"]; |
e685e07d UD |
1408 | |
1409 | fprintf(file, "res_send: %s ([%s].%u): %s\n", | |
1410 | string, | |
e2a99d8e UD |
1411 | (address->sa_family == AF_INET |
1412 | ? inet_ntop(address->sa_family, | |
1413 | &((const struct sockaddr_in *) address)->sin_addr, | |
1414 | tmp, sizeof tmp) | |
1415 | : inet_ntop(address->sa_family, | |
1416 | &((const struct sockaddr_in6 *) address)->sin6_addr, | |
1417 | tmp, sizeof tmp)), | |
020a9a23 UD |
1418 | (address->sa_family == AF_INET |
1419 | ? ntohs(((struct sockaddr_in *) address)->sin_port) | |
1420 | : address->sa_family == AF_INET6 | |
1421 | ? ntohs(((struct sockaddr_in6 *) address)->sin6_port) | |
1422 | : 0), | |
e685e07d UD |
1423 | strerror(error)); |
1424 | } | |
1425 | __set_errno (save); | |
1426 | } | |
1427 | ||
1428 | static void | |
1429 | Perror(const res_state statp, FILE *file, const char *string, int error) { | |
1430 | int save = errno; | |
1431 | ||
1432 | if ((statp->options & RES_DEBUG) != 0) | |
1433 | fprintf(file, "res_send: %s: %s\n", | |
1434 | string, strerror(error)); | |
1435 | __set_errno (save); | |
1436 | } | |
1437 | #endif | |
1438 | ||
1439 | static int | |
438e8239 UD |
1440 | sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) { |
1441 | if (a1->sin6_family == a2->sin6_family) { | |
1442 | if (a1->sin6_family == AF_INET) | |
1443 | return ((((struct sockaddr_in *)a1)->sin_port == | |
1444 | ((struct sockaddr_in *)a2)->sin_port) && | |
1445 | (((struct sockaddr_in *)a1)->sin_addr.s_addr == | |
1446 | ((struct sockaddr_in *)a2)->sin_addr.s_addr)); | |
1447 | else | |
1448 | return ((a1->sin6_port == a2->sin6_port) && | |
1449 | !memcmp(&a1->sin6_addr, &a2->sin6_addr, | |
1450 | sizeof (struct in6_addr))); | |
1451 | } | |
1452 | if (a1->sin6_family == AF_INET) { | |
1453 | struct sockaddr_in6 *sap = a1; | |
1454 | a1 = a2; | |
1455 | a2 = sap; | |
1456 | } /* assumes that AF_INET and AF_INET6 are the only possibilities */ | |
1457 | return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) && | |
1458 | IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) && | |
1459 | (a1->sin6_addr.s6_addr32[3] == | |
1460 | ((struct sockaddr_in *)a2)->sin_addr.s_addr)); | |
1461 | } |