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