]>
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> | |
98 | ||
0420d888 UD |
99 | #if PACKETSZ > 65536 |
100 | #define MAXPACKET PACKETSZ | |
101 | #else | |
102 | #define MAXPACKET 65536 | |
103 | #endif | |
104 | ||
b43b13ac | 105 | |
e685e07d | 106 | /* From ev_streams.c. */ |
e62b2105 | 107 | |
25337753 UD |
108 | static inline void |
109 | __attribute ((always_inline)) | |
110 | evConsIovec(void *buf, size_t cnt, struct iovec *vec) { | |
111 | memset(vec, 0xf5, sizeof (*vec)); | |
112 | vec->iov_base = buf; | |
113 | vec->iov_len = cnt; | |
e685e07d | 114 | } |
28f540f4 | 115 | |
e685e07d | 116 | /* From ev_timers.c. */ |
30f9ca19 | 117 | |
b43b13ac | 118 | #define BILLION 1000000000 |
e685e07d | 119 | |
25337753 UD |
120 | static inline void |
121 | evConsTime(struct timespec *res, time_t sec, long nsec) { | |
122 | res->tv_sec = sec; | |
123 | res->tv_nsec = nsec; | |
b43b13ac | 124 | } |
28f540f4 | 125 | |
25337753 UD |
126 | static inline void |
127 | evAddTime(struct timespec *res, const struct timespec *addend1, | |
128 | const struct timespec *addend2) { | |
129 | res->tv_sec = addend1->tv_sec + addend2->tv_sec; | |
130 | res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec; | |
131 | if (res->tv_nsec >= BILLION) { | |
132 | res->tv_sec++; | |
133 | res->tv_nsec -= BILLION; | |
b43b13ac | 134 | } |
b43b13ac UD |
135 | } |
136 | ||
25337753 UD |
137 | static inline void |
138 | evSubTime(struct timespec *res, const struct timespec *minuend, | |
139 | const struct timespec *subtrahend) { | |
140 | res->tv_sec = minuend->tv_sec - subtrahend->tv_sec; | |
141 | if (minuend->tv_nsec >= subtrahend->tv_nsec) | |
142 | res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec; | |
b43b13ac | 143 | else { |
25337753 UD |
144 | res->tv_nsec = (BILLION |
145 | - subtrahend->tv_nsec + minuend->tv_nsec); | |
146 | res->tv_sec--; | |
b43b13ac | 147 | } |
b43b13ac UD |
148 | } |
149 | ||
e685e07d | 150 | static inline int |
b43b13ac UD |
151 | evCmpTime(struct timespec a, struct timespec b) { |
152 | long x = a.tv_sec - b.tv_sec; | |
153 | ||
154 | if (x == 0L) | |
155 | x = a.tv_nsec - b.tv_nsec; | |
156 | return (x < 0L ? (-1) : x > 0L ? (1) : (0)); | |
157 | } | |
158 | ||
25337753 UD |
159 | static inline void |
160 | evNowTime(struct timespec *res) { | |
b43b13ac UD |
161 | struct timeval now; |
162 | ||
163 | if (gettimeofday(&now, NULL) < 0) | |
25337753 UD |
164 | evConsTime(res, 0, 0); |
165 | else | |
166 | TIMEVAL_TO_TIMESPEC (&now, res); | |
b43b13ac | 167 | } |
b43b13ac | 168 | |
28f540f4 | 169 | |
e685e07d UD |
170 | /* Options. Leave them on. */ |
171 | /* #undef DEBUG */ | |
172 | #include "res_debug.h" | |
b43b13ac | 173 | |
e685e07d | 174 | #define EXT(res) ((res)->_u._ext) |
28f540f4 | 175 | |
e685e07d UD |
176 | /* Forward. */ |
177 | ||
178 | static int send_vc(res_state, const u_char *, int, | |
0420d888 | 179 | u_char **, int *, int *, int, u_char **); |
e685e07d | 180 | static int send_dg(res_state, const u_char *, int, |
0420d888 UD |
181 | u_char **, int *, int *, int, |
182 | int *, int *, u_char **); | |
e685e07d UD |
183 | #ifdef DEBUG |
184 | static void Aerror(const res_state, FILE *, const char *, int, | |
020a9a23 | 185 | const struct sockaddr *); |
e685e07d UD |
186 | static void Perror(const res_state, FILE *, const char *, int); |
187 | #endif | |
438e8239 | 188 | static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *); |
e685e07d UD |
189 | |
190 | /* Reachover. */ | |
191 | ||
438e8239 | 192 | static void convaddr4to6(struct sockaddr_in6 *sa); |
b43b13ac | 193 | void res_pquery(const res_state, const u_char *, int, FILE *); |
28f540f4 | 194 | |
e685e07d UD |
195 | /* Public. */ |
196 | ||
28f540f4 RM |
197 | /* int |
198 | * res_isourserver(ina) | |
199 | * looks up "ina" in _res.ns_addr_list[] | |
200 | * returns: | |
201 | * 0 : not found | |
202 | * >0 : found | |
203 | * author: | |
204 | * paul vixie, 29may94 | |
205 | */ | |
206 | int | |
438e8239 | 207 | res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp) |
438e8239 | 208 | { |
b43b13ac | 209 | int ns; |
28f540f4 | 210 | |
438e8239 | 211 | if (inp->sin6_family == AF_INET) { |
e62b2105 UD |
212 | struct sockaddr_in *in4p = (struct sockaddr_in *) inp; |
213 | in_port_t port = in4p->sin_port; | |
214 | in_addr_t addr = in4p->sin_addr.s_addr; | |
438e8239 UD |
215 | |
216 | for (ns = 0; ns < MAXNS; ns++) { | |
217 | const struct sockaddr_in *srv = | |
218 | (struct sockaddr_in *)EXT(statp).nsaddrs[ns]; | |
219 | ||
220 | if ((srv != NULL) && (srv->sin_family == AF_INET) && | |
e62b2105 | 221 | (srv->sin_port == port) && |
438e8239 | 222 | (srv->sin_addr.s_addr == INADDR_ANY || |
e62b2105 | 223 | srv->sin_addr.s_addr == addr)) |
438e8239 UD |
224 | return (1); |
225 | } | |
226 | } else if (inp->sin6_family == AF_INET6) { | |
227 | for (ns = 0; ns < MAXNS; ns++) { | |
228 | const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns]; | |
229 | if ((srv != NULL) && (srv->sin6_family == AF_INET6) && | |
230 | (srv->sin6_port == inp->sin6_port) && | |
231 | !(memcmp(&srv->sin6_addr, &in6addr_any, | |
232 | sizeof (struct in6_addr)) && | |
233 | memcmp(&srv->sin6_addr, &inp->sin6_addr, | |
234 | sizeof (struct in6_addr)))) | |
235 | return (1); | |
236 | } | |
237 | } | |
b43b13ac | 238 | return (0); |
28f540f4 RM |
239 | } |
240 | ||
241 | /* int | |
242 | * res_nameinquery(name, type, class, buf, eom) | |
243 | * look for (name,type,class) in the query section of packet (buf,eom) | |
66715f83 | 244 | * requires: |
b43b13ac | 245 | * buf + HFIXEDSZ <= eom |
28f540f4 RM |
246 | * returns: |
247 | * -1 : format error | |
248 | * 0 : not found | |
249 | * >0 : found | |
250 | * author: | |
251 | * paul vixie, 29may94 | |
252 | */ | |
253 | int | |
b43b13ac UD |
254 | res_nameinquery(const char *name, int type, int class, |
255 | const u_char *buf, const u_char *eom) | |
28f540f4 | 256 | { |
b43b13ac | 257 | const u_char *cp = buf + HFIXEDSZ; |
28f540f4 RM |
258 | int qdcount = ntohs(((HEADER*)buf)->qdcount); |
259 | ||
260 | while (qdcount-- > 0) { | |
261 | char tname[MAXDNAME+1]; | |
b43b13ac | 262 | int n, ttype, tclass; |
28f540f4 RM |
263 | |
264 | n = dn_expand(buf, eom, cp, tname, sizeof tname); | |
265 | if (n < 0) | |
266 | return (-1); | |
267 | cp += n; | |
66715f83 UD |
268 | if (cp + 2 * INT16SZ > eom) |
269 | return (-1); | |
a334319f UD |
270 | ttype = ns_get16(cp); cp += INT16SZ; |
271 | tclass = ns_get16(cp); cp += INT16SZ; | |
b43b13ac UD |
272 | if (ttype == type && tclass == class && |
273 | ns_samename(tname, name) == 1) | |
28f540f4 RM |
274 | return (1); |
275 | } | |
276 | return (0); | |
277 | } | |
6f9d8e68 | 278 | libresolv_hidden_def (res_nameinquery) |
28f540f4 RM |
279 | |
280 | /* int | |
281 | * res_queriesmatch(buf1, eom1, buf2, eom2) | |
282 | * is there a 1:1 mapping of (name,type,class) | |
283 | * in (buf1,eom1) and (buf2,eom2)? | |
284 | * returns: | |
285 | * -1 : format error | |
286 | * 0 : not a 1:1 mapping | |
287 | * >0 : is a 1:1 mapping | |
288 | * author: | |
289 | * paul vixie, 29may94 | |
290 | */ | |
291 | int | |
b43b13ac UD |
292 | res_queriesmatch(const u_char *buf1, const u_char *eom1, |
293 | const u_char *buf2, const u_char *eom2) | |
28f540f4 | 294 | { |
a334319f UD |
295 | const u_char *cp = buf1 + HFIXEDSZ; |
296 | int qdcount = ntohs(((HEADER*)buf1)->qdcount); | |
297 | ||
66715f83 UD |
298 | if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) |
299 | return (-1); | |
300 | ||
b43b13ac UD |
301 | /* |
302 | * Only header section present in replies to | |
303 | * dynamic update packets. | |
304 | */ | |
e685e07d UD |
305 | if ((((HEADER *)buf1)->opcode == ns_o_update) && |
306 | (((HEADER *)buf2)->opcode == ns_o_update)) | |
b43b13ac UD |
307 | return (1); |
308 | ||
a334319f | 309 | if (qdcount != ntohs(((HEADER*)buf2)->qdcount)) |
28f540f4 RM |
310 | return (0); |
311 | while (qdcount-- > 0) { | |
312 | char tname[MAXDNAME+1]; | |
b43b13ac | 313 | int n, ttype, tclass; |
28f540f4 RM |
314 | |
315 | n = dn_expand(buf1, eom1, cp, tname, sizeof tname); | |
316 | if (n < 0) | |
317 | return (-1); | |
318 | cp += n; | |
66715f83 UD |
319 | if (cp + 2 * INT16SZ > eom1) |
320 | return (-1); | |
a334319f UD |
321 | ttype = ns_get16(cp); cp += INT16SZ; |
322 | tclass = ns_get16(cp); cp += INT16SZ; | |
28f540f4 RM |
323 | if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) |
324 | return (0); | |
325 | } | |
326 | return (1); | |
327 | } | |
6f9d8e68 | 328 | libresolv_hidden_def (res_queriesmatch) |
28f540f4 RM |
329 | |
330 | int | |
0420d888 UD |
331 | __libc_res_nsend(res_state statp, const u_char *buf, int buflen, |
332 | u_char *ans, int anssiz, u_char **ansp) | |
28f540f4 | 333 | { |
e685e07d | 334 | int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; |
28f540f4 | 335 | |
e685e07d UD |
336 | if (statp->nscount == 0) { |
337 | __set_errno (ESRCH); | |
338 | return (-1); | |
339 | } | |
0420d888 | 340 | |
66715f83 UD |
341 | if (anssiz < HFIXEDSZ) { |
342 | __set_errno (EINVAL); | |
343 | return (-1); | |
344 | } | |
0420d888 UD |
345 | |
346 | if ((statp->qhook || statp->rhook) && anssiz < MAXPACKET && ansp) { | |
347 | u_char *buf = malloc (MAXPACKET); | |
348 | if (buf == NULL) | |
349 | return (-1); | |
350 | memcpy (buf, ans, HFIXEDSZ); | |
351 | *ansp = buf; | |
352 | ans = buf; | |
353 | anssiz = MAXPACKET; | |
354 | } | |
355 | ||
b43b13ac | 356 | DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), |
3d61b63c | 357 | (stdout, ";; res_send()\n"), buf, buflen); |
b43b13ac | 358 | v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; |
28f540f4 | 359 | gotsomewhere = 0; |
28f540f4 | 360 | terrno = ETIMEDOUT; |
28f540f4 | 361 | |
b43b13ac | 362 | /* |
e685e07d UD |
363 | * If the ns_addr_list in the resolver context has changed, then |
364 | * invalidate our cached copy and the associated timing data. | |
b43b13ac | 365 | */ |
03fbfeb5 | 366 | if (EXT(statp).nsinit) { |
e685e07d UD |
367 | int needclose = 0; |
368 | ||
369 | if (EXT(statp).nscount != statp->nscount) | |
370 | needclose++; | |
371 | else | |
b64e1566 UD |
372 | for (ns = 0; ns < MAXNS; ns++) { |
373 | unsigned int map = EXT(statp).nsmap[ns]; | |
374 | if (map < MAXNS | |
375 | && !sock_eq((struct sockaddr_in6 *) | |
376 | &statp->nsaddr_list[map], | |
377 | EXT(statp).nsaddrs[ns])) | |
438e8239 | 378 | { |
e685e07d UD |
379 | needclose++; |
380 | break; | |
381 | } | |
b64e1566 | 382 | } |
e685e07d | 383 | if (needclose) |
a334319f | 384 | res_nclose(statp); |
e685e07d UD |
385 | } |
386 | ||
387 | /* | |
388 | * Maybe initialize our private copy of the ns_addr_list. | |
389 | */ | |
03fbfeb5 | 390 | if (EXT(statp).nsinit == 0) { |
b64e1566 UD |
391 | unsigned char map[MAXNS]; |
392 | ||
393 | memset (map, MAXNS, sizeof (map)); | |
394 | for (n = 0; n < MAXNS; n++) { | |
395 | ns = EXT(statp).nsmap[n]; | |
396 | if (ns < statp->nscount) | |
397 | map[ns] = n; | |
398 | else if (ns < MAXNS) { | |
399 | free(EXT(statp).nsaddrs[n]); | |
400 | EXT(statp).nsaddrs[n] = NULL; | |
401 | EXT(statp).nsmap[n] = MAXNS; | |
402 | } | |
403 | } | |
404 | n = statp->nscount; | |
405 | if (statp->nscount > EXT(statp).nscount) | |
406 | for (n = EXT(statp).nscount, ns = 0; | |
407 | n < statp->nscount; n++) { | |
408 | while (ns < MAXNS | |
409 | && EXT(statp).nsmap[ns] != MAXNS) | |
410 | ns++; | |
411 | if (ns == MAXNS) | |
412 | break; | |
413 | EXT(statp).nsmap[ns] = n; | |
414 | map[n] = ns++; | |
415 | } | |
416 | EXT(statp).nscount = n; | |
417 | for (ns = 0; ns < EXT(statp).nscount; ns++) { | |
418 | n = map[ns]; | |
438e8239 UD |
419 | if (EXT(statp).nsaddrs[n] == NULL) |
420 | EXT(statp).nsaddrs[n] = | |
421 | malloc(sizeof (struct sockaddr_in6)); | |
422 | if (EXT(statp).nsaddrs[n] != NULL) { | |
423 | memcpy(EXT(statp).nsaddrs[n], | |
424 | &statp->nsaddr_list[ns], | |
425 | sizeof (struct sockaddr_in)); | |
438e8239 UD |
426 | EXT(statp).nssocks[n] = -1; |
427 | n++; | |
428 | } | |
b64e1566 | 429 | } |
b64e1566 | 430 | EXT(statp).nsinit = 1; |
e685e07d UD |
431 | } |
432 | ||
433 | /* | |
434 | * Some resolvers want to even out the load on their nameservers. | |
435 | * Note that RES_BLAST overrides RES_ROTATE. | |
436 | */ | |
437 | if ((statp->options & RES_ROTATE) != 0 && | |
438 | (statp->options & RES_BLAST) == 0) { | |
438e8239 | 439 | struct sockaddr_in6 *ina; |
b64e1566 | 440 | unsigned int map; |
438e8239 | 441 | |
b64e1566 UD |
442 | n = 0; |
443 | while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS) | |
444 | n++; | |
445 | if (n < MAXNS) { | |
446 | ina = EXT(statp).nsaddrs[n]; | |
447 | map = EXT(statp).nsmap[n]; | |
448 | for (;;) { | |
449 | ns = n + 1; | |
450 | while (ns < MAXNS | |
451 | && EXT(statp).nsmap[ns] == MAXNS) | |
452 | ns++; | |
453 | if (ns == MAXNS) | |
454 | break; | |
455 | EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns]; | |
456 | EXT(statp).nsmap[n] = EXT(statp).nsmap[ns]; | |
457 | n = ns; | |
458 | } | |
459 | EXT(statp).nsaddrs[n] = ina; | |
460 | EXT(statp).nsmap[n] = map; | |
461 | } | |
b43b13ac | 462 | } |
30f9ca19 | 463 | |
28f540f4 | 464 | /* |
e685e07d | 465 | * Send request, RETRY times, or until successful. |
28f540f4 | 466 | */ |
b43b13ac | 467 | for (try = 0; try < statp->retry; try++) { |
438e8239 | 468 | for (ns = 0; ns < MAXNS; ns++) |
438e8239 | 469 | { |
438e8239 UD |
470 | struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns]; |
471 | ||
472 | if (nsap == NULL) | |
473 | goto next_ns; | |
b43b13ac | 474 | same_ns: |
b43b13ac | 475 | if (statp->qhook) { |
28f540f4 RM |
476 | int done = 0, loops = 0; |
477 | ||
478 | do { | |
479 | res_sendhookact act; | |
480 | ||
25337753 UD |
481 | struct sockaddr_in *nsap4; |
482 | nsap4 = (struct sockaddr_in *) nsap; | |
483 | act = (*statp->qhook)(&nsap4, &buf, &buflen, | |
438e8239 | 484 | ans, anssiz, &resplen); |
25337753 | 485 | nsap = (struct sockaddr_in6 *) nsap4; |
28f540f4 RM |
486 | switch (act) { |
487 | case res_goahead: | |
488 | done = 1; | |
489 | break; | |
490 | case res_nextns: | |
a334319f | 491 | res_nclose(statp); |
28f540f4 RM |
492 | goto next_ns; |
493 | case res_done: | |
b43b13ac | 494 | return (resplen); |
28f540f4 RM |
495 | case res_modified: |
496 | /* give the hook another try */ | |
497 | if (++loops < 42) /*doug adams*/ | |
498 | break; | |
499 | /*FALLTHROUGH*/ | |
500 | case res_error: | |
501 | /*FALLTHROUGH*/ | |
502 | default: | |
b43b13ac | 503 | return (-1); |
28f540f4 RM |
504 | } |
505 | } while (!done); | |
506 | } | |
507 | ||
3bc99c11 | 508 | #ifdef DEBUG |
020a9a23 | 509 | char tmpbuf[40]; |
3bc99c11 | 510 | #endif |
020a9a23 UD |
511 | Dprint(statp->options & RES_DEBUG, |
512 | (stdout, ";; Querying server (# %d) address = %s\n", | |
513 | ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr, | |
514 | tmpbuf, sizeof (tmpbuf)))); | |
28f540f4 RM |
515 | |
516 | if (v_circuit) { | |
b43b13ac UD |
517 | /* Use VC; at most one attempt per server. */ |
518 | try = statp->retry; | |
0420d888 UD |
519 | n = send_vc(statp, buf, buflen, &ans, &anssiz, &terrno, |
520 | ns, ansp); | |
e685e07d UD |
521 | if (n < 0) |
522 | return (-1); | |
523 | if (n == 0) | |
28f540f4 | 524 | goto next_ns; |
e685e07d | 525 | resplen = n; |
28f540f4 | 526 | } else { |
e685e07d | 527 | /* Use datagrams. */ |
0420d888 UD |
528 | n = send_dg(statp, buf, buflen, &ans, &anssiz, &terrno, |
529 | ns, &v_circuit, &gotsomewhere, ansp); | |
e685e07d UD |
530 | if (n < 0) |
531 | return (-1); | |
532 | if (n == 0) | |
b43b13ac | 533 | goto next_ns; |
e685e07d | 534 | if (v_circuit) |
28f540f4 | 535 | goto same_ns; |
e685e07d UD |
536 | resplen = n; |
537 | } | |
538 | ||
b43b13ac UD |
539 | Dprint((statp->options & RES_DEBUG) || |
540 | ((statp->pfcode & RES_PRF_REPLY) && | |
541 | (statp->pfcode & RES_PRF_HEAD1)), | |
a4219bc4 | 542 | (stdout, ";; got answer:\n")); |
e685e07d | 543 | |
b43b13ac UD |
544 | DprintQ((statp->options & RES_DEBUG) || |
545 | (statp->pfcode & RES_PRF_REPLY), | |
020a9a23 | 546 | (stdout, "%s", ""), |
e685e07d UD |
547 | ans, (resplen > anssiz) ? anssiz : resplen); |
548 | ||
28f540f4 | 549 | /* |
28f540f4 RM |
550 | * If we have temporarily opened a virtual circuit, |
551 | * or if we haven't been asked to keep a socket open, | |
552 | * close the socket. | |
553 | */ | |
e685e07d UD |
554 | if ((v_circuit && (statp->options & RES_USEVC) == 0) || |
555 | (statp->options & RES_STAYOPEN) == 0) { | |
a334319f | 556 | res_nclose(statp); |
28f540f4 | 557 | } |
b43b13ac | 558 | if (statp->rhook) { |
28f540f4 RM |
559 | int done = 0, loops = 0; |
560 | ||
561 | do { | |
562 | res_sendhookact act; | |
563 | ||
438e8239 UD |
564 | act = (*statp->rhook)((struct sockaddr_in *) |
565 | nsap, buf, buflen, | |
566 | ans, anssiz, &resplen); | |
28f540f4 RM |
567 | switch (act) { |
568 | case res_goahead: | |
569 | case res_done: | |
570 | done = 1; | |
571 | break; | |
572 | case res_nextns: | |
a334319f | 573 | res_nclose(statp); |
28f540f4 RM |
574 | goto next_ns; |
575 | case res_modified: | |
576 | /* give the hook another try */ | |
577 | if (++loops < 42) /*doug adams*/ | |
578 | break; | |
579 | /*FALLTHROUGH*/ | |
580 | case res_error: | |
581 | /*FALLTHROUGH*/ | |
582 | default: | |
b43b13ac | 583 | return (-1); |
28f540f4 RM |
584 | } |
585 | } while (!done); | |
586 | ||
587 | } | |
b43b13ac UD |
588 | return (resplen); |
589 | next_ns: ; | |
28f540f4 RM |
590 | } /*foreach ns*/ |
591 | } /*foreach retry*/ | |
a334319f | 592 | res_nclose(statp); |
7ef90c15 | 593 | if (!v_circuit) { |
28f540f4 | 594 | if (!gotsomewhere) |
b43b13ac | 595 | __set_errno (ECONNREFUSED); /* no nameservers found */ |
28f540f4 | 596 | else |
b43b13ac | 597 | __set_errno (ETIMEDOUT); /* no answer obtained */ |
7ef90c15 | 598 | } else |
c4029823 | 599 | __set_errno (terrno); |
b43b13ac | 600 | return (-1); |
28f540f4 RM |
601 | } |
602 | ||
0420d888 UD |
603 | int |
604 | res_nsend(res_state statp, | |
605 | const u_char *buf, int buflen, u_char *ans, int anssiz) | |
606 | { | |
607 | return __libc_res_nsend(statp, buf, buflen, ans, anssiz, NULL); | |
608 | } | |
6f9d8e68 | 609 | libresolv_hidden_def (res_nsend) |
0420d888 | 610 | |
e685e07d UD |
611 | /* Private */ |
612 | ||
613 | static int | |
614 | send_vc(res_state statp, | |
0420d888 UD |
615 | const u_char *buf, int buflen, u_char **ansp, int *anssizp, |
616 | int *terrno, int ns, u_char **anscp) | |
e685e07d UD |
617 | { |
618 | const HEADER *hp = (HEADER *) buf; | |
0420d888 UD |
619 | u_char *ans = *ansp; |
620 | int anssiz = *anssizp; | |
e685e07d | 621 | HEADER *anhp = (HEADER *) ans; |
438e8239 | 622 | struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns]; |
e685e07d UD |
623 | int truncating, connreset, resplen, n; |
624 | struct iovec iov[2]; | |
625 | u_short len; | |
626 | u_char *cp; | |
627 | ||
628 | connreset = 0; | |
629 | same_ns: | |
630 | truncating = 0; | |
631 | ||
632 | /* Are we still talking to whom we want to talk to? */ | |
633 | if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { | |
438e8239 | 634 | struct sockaddr_in6 peer; |
a334319f | 635 | int size = sizeof peer; |
e685e07d UD |
636 | |
637 | if (getpeername(statp->_vcsock, | |
638 | (struct sockaddr *)&peer, &size) < 0 || | |
639 | !sock_eq(&peer, nsap)) { | |
a334319f | 640 | res_nclose(statp); |
e685e07d UD |
641 | statp->_flags &= ~RES_F_VC; |
642 | } | |
643 | } | |
644 | ||
645 | if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { | |
646 | if (statp->_vcsock >= 0) | |
a334319f | 647 | res_nclose(statp); |
e685e07d | 648 | |
438e8239 | 649 | statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0); |
e685e07d UD |
650 | if (statp->_vcsock < 0) { |
651 | *terrno = errno; | |
652 | Perror(statp, stderr, "socket(vc)", errno); | |
653 | return (-1); | |
654 | } | |
655 | __set_errno (0); | |
656 | if (connect(statp->_vcsock, (struct sockaddr *)nsap, | |
a334319f | 657 | sizeof *nsap) < 0) { |
e685e07d | 658 | *terrno = errno; |
020a9a23 UD |
659 | Aerror(statp, stderr, "connect/vc", errno, |
660 | (struct sockaddr *) nsap); | |
a334319f | 661 | res_nclose(statp); |
e685e07d UD |
662 | return (0); |
663 | } | |
664 | statp->_flags |= RES_F_VC; | |
28f540f4 | 665 | } |
e685e07d UD |
666 | |
667 | /* | |
668 | * Send length & message | |
669 | */ | |
a334319f | 670 | putshort((u_short)buflen, (u_char*)&len); |
25337753 UD |
671 | evConsIovec(&len, INT16SZ, &iov[0]); |
672 | evConsIovec((void*)buf, buflen, &iov[1]); | |
673 | if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, 2)) | |
674 | != (INT16SZ + buflen)) { | |
e685e07d UD |
675 | *terrno = errno; |
676 | Perror(statp, stderr, "write failed", errno); | |
a334319f | 677 | res_nclose(statp); |
e685e07d UD |
678 | return (0); |
679 | } | |
680 | /* | |
681 | * Receive length & response | |
682 | */ | |
683 | read_len: | |
684 | cp = ans; | |
685 | len = INT16SZ; | |
25337753 UD |
686 | while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, (char *)cp, |
687 | (int)len))) > 0) { | |
e685e07d UD |
688 | cp += n; |
689 | if ((len -= n) <= 0) | |
690 | break; | |
691 | } | |
692 | if (n <= 0) { | |
693 | *terrno = errno; | |
694 | Perror(statp, stderr, "read failed", errno); | |
a334319f | 695 | res_nclose(statp); |
e685e07d UD |
696 | /* |
697 | * A long running process might get its TCP | |
698 | * connection reset if the remote server was | |
699 | * restarted. Requery the server instead of | |
700 | * trying a new one. When there is only one | |
701 | * server, this means that a query might work | |
702 | * instead of failing. We only allow one reset | |
703 | * per query to prevent looping. | |
704 | */ | |
705 | if (*terrno == ECONNRESET && !connreset) { | |
706 | connreset = 1; | |
a334319f | 707 | res_nclose(statp); |
e685e07d UD |
708 | goto same_ns; |
709 | } | |
a334319f | 710 | res_nclose(statp); |
e685e07d UD |
711 | return (0); |
712 | } | |
713 | resplen = ns_get16(ans); | |
714 | if (resplen > anssiz) { | |
0420d888 UD |
715 | if (anscp) { |
716 | ans = malloc (MAXPACKET); | |
717 | if (ans == NULL) { | |
718 | *terrno = ENOMEM; | |
a334319f | 719 | res_nclose(statp); |
0420d888 UD |
720 | return (0); |
721 | } | |
722 | anssiz = MAXPACKET; | |
723 | *anssizp = MAXPACKET; | |
724 | *ansp = ans; | |
725 | *anscp = ans; | |
726 | anhp = (HEADER *) ans; | |
727 | len = resplen; | |
728 | } else { | |
729 | Dprint(statp->options & RES_DEBUG, | |
730 | (stdout, ";; response truncated\n") | |
731 | ); | |
732 | truncating = 1; | |
733 | len = anssiz; | |
734 | } | |
e685e07d UD |
735 | } else |
736 | len = resplen; | |
737 | if (len < HFIXEDSZ) { | |
738 | /* | |
739 | * Undersized message. | |
740 | */ | |
741 | Dprint(statp->options & RES_DEBUG, | |
742 | (stdout, ";; undersized: %d\n", len)); | |
743 | *terrno = EMSGSIZE; | |
a334319f | 744 | res_nclose(statp); |
e685e07d UD |
745 | return (0); |
746 | } | |
747 | cp = ans; | |
748 | while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){ | |
749 | cp += n; | |
750 | len -= n; | |
751 | } | |
752 | if (n <= 0) { | |
753 | *terrno = errno; | |
754 | Perror(statp, stderr, "read(vc)", errno); | |
a334319f | 755 | res_nclose(statp); |
e685e07d UD |
756 | return (0); |
757 | } | |
758 | if (truncating) { | |
759 | /* | |
760 | * Flush rest of answer so connection stays in synch. | |
761 | */ | |
762 | anhp->tc = 1; | |
763 | len = resplen - anssiz; | |
764 | while (len != 0) { | |
765 | char junk[PACKETSZ]; | |
766 | ||
767 | n = read(statp->_vcsock, junk, | |
768 | (len > sizeof junk) ? sizeof junk : len); | |
769 | if (n > 0) | |
770 | len -= n; | |
771 | else | |
772 | break; | |
773 | } | |
774 | } | |
775 | /* | |
776 | * If the calling applicating has bailed out of | |
777 | * a previous call and failed to arrange to have | |
778 | * the circuit closed or the server has got | |
779 | * itself confused, then drop the packet and | |
780 | * wait for the correct one. | |
781 | */ | |
782 | if (hp->id != anhp->id) { | |
783 | DprintQ((statp->options & RES_DEBUG) || | |
784 | (statp->pfcode & RES_PRF_REPLY), | |
785 | (stdout, ";; old answer (unexpected):\n"), | |
786 | ans, (resplen > anssiz) ? anssiz: resplen); | |
787 | goto read_len; | |
788 | } | |
789 | ||
790 | /* | |
791 | * All is well, or the error is fatal. Signal that the | |
792 | * next nameserver ought not be tried. | |
793 | */ | |
794 | return (resplen); | |
28f540f4 | 795 | } |
845dcb57 | 796 | |
b43b13ac | 797 | static int |
e685e07d | 798 | send_dg(res_state statp, |
0420d888 UD |
799 | const u_char *buf, int buflen, u_char **ansp, int *anssizp, |
800 | int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp) | |
e685e07d UD |
801 | { |
802 | const HEADER *hp = (HEADER *) buf; | |
0420d888 UD |
803 | u_char *ans = *ansp; |
804 | int anssiz = *anssizp; | |
e685e07d | 805 | HEADER *anhp = (HEADER *) ans; |
438e8239 | 806 | struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns]; |
e685e07d | 807 | struct timespec now, timeout, finish; |
e685e07d UD |
808 | struct pollfd pfd[1]; |
809 | int ptimeout; | |
438e8239 UD |
810 | struct sockaddr_in6 from; |
811 | static int socket_pf = 0; | |
a334319f | 812 | int fromlen, resplen, seconds, n; |
e685e07d UD |
813 | |
814 | if (EXT(statp).nssocks[ns] == -1) { | |
438e8239 UD |
815 | /* only try IPv6 if IPv6 NS and if not failed before */ |
816 | if ((EXT(statp).nscount6 > 0) && (socket_pf != PF_INET)) { | |
817 | EXT(statp).nssocks[ns] = | |
818 | socket(PF_INET6, SOCK_DGRAM, 0); | |
819 | socket_pf = EXT(statp).nssocks[ns] < 0 ? PF_INET | |
820 | : PF_INET6; | |
821 | } | |
822 | if (EXT(statp).nssocks[ns] < 0) | |
823 | EXT(statp).nssocks[ns] = socket(PF_INET, SOCK_DGRAM, 0); | |
e685e07d UD |
824 | if (EXT(statp).nssocks[ns] < 0) { |
825 | *terrno = errno; | |
826 | Perror(statp, stderr, "socket(dg)", errno); | |
827 | return (-1); | |
828 | } | |
438e8239 UD |
829 | /* If IPv6 socket and nsap is IPv4, make it IPv4-mapped */ |
830 | if ((socket_pf == PF_INET6) && (nsap->sin6_family == AF_INET)) | |
831 | convaddr4to6(nsap); | |
e685e07d UD |
832 | /* |
833 | * On a 4.3BSD+ machine (client and server, | |
834 | * actually), sending to a nameserver datagram | |
835 | * port with no nameserver will cause an | |
836 | * ICMP port unreachable message to be returned. | |
837 | * If our datagram socket is "connected" to the | |
838 | * server, we get an ECONNREFUSED error on the next | |
839 | * socket operation, and select returns if the | |
840 | * error message is received. We can thus detect | |
841 | * the absence of a nameserver without timing out. | |
842 | */ | |
843 | if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap, | |
844 | sizeof *nsap) < 0) { | |
020a9a23 UD |
845 | Aerror(statp, stderr, "connect(dg)", errno, |
846 | (struct sockaddr *) nsap); | |
a334319f | 847 | res_nclose(statp); |
e685e07d UD |
848 | return (0); |
849 | } | |
f433b06b UD |
850 | /* Make socket non-blocking. */ |
851 | int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL); | |
852 | if (fl != -1) | |
853 | __fcntl (EXT(statp).nssocks[ns], F_SETFL, | |
854 | fl | O_NONBLOCK); | |
e685e07d UD |
855 | Dprint(statp->options & RES_DEBUG, |
856 | (stdout, ";; new DG socket\n")) | |
857 | } | |
17a10319 | 858 | |
f433b06b UD |
859 | /* |
860 | * Compute time for the total operation. | |
861 | */ | |
862 | seconds = (statp->retrans << ns); | |
863 | if (ns > 0) | |
864 | seconds /= statp->nscount; | |
865 | if (seconds <= 0) | |
866 | seconds = 1; | |
867 | evNowTime(&now); | |
868 | evConsTime(&timeout, seconds, 0); | |
869 | evAddTime(&finish, &now, &timeout); | |
870 | int need_recompute = 0; | |
17a10319 UD |
871 | int nwritten = 0; |
872 | pfd[0].fd = EXT(statp).nssocks[ns]; | |
873 | pfd[0].events = POLLOUT; | |
874 | wait: | |
875 | if (need_recompute) { | |
876 | evNowTime(&now); | |
877 | if (evCmpTime(finish, now) <= 0) { | |
a334319f UD |
878 | Perror(statp, stderr, "select", errno); |
879 | res_nclose(statp); | |
17a10319 UD |
880 | return (0); |
881 | } | |
882 | evSubTime(&timeout, &finish, &now); | |
883 | } | |
f433b06b UD |
884 | /* Convert struct timespec in milliseconds. */ |
885 | ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000; | |
886 | ||
17a10319 UD |
887 | n = 0; |
888 | if (nwritten == 0) | |
889 | n = __poll (pfd, 1, 0); | |
f433b06b UD |
890 | if (__builtin_expect (n == 0, 0)) { |
891 | n = __poll (pfd, 1, ptimeout); | |
892 | need_recompute = 1; | |
893 | } | |
f433b06b UD |
894 | if (n == 0) { |
895 | Dprint(statp->options & RES_DEBUG, (stdout, | |
896 | ";; timeout sending\n")); | |
897 | *gotsomewhere = 1; | |
898 | return (0); | |
899 | } | |
900 | if (n < 0) { | |
a334319f UD |
901 | if (errno == EINTR) { |
902 | recompute_resend: | |
903 | evNowTime(&now); | |
904 | if (evCmpTime(finish, now) > 0) { | |
905 | evSubTime(&timeout, &finish, &now); | |
906 | goto wait; | |
907 | } | |
908 | } | |
909 | Perror(statp, stderr, "poll", errno); | |
910 | res_nclose(statp); | |
911 | return (0); | |
f433b06b UD |
912 | } |
913 | __set_errno (0); | |
17a10319 | 914 | if (pfd[0].revents & POLLOUT) { |
a334319f | 915 | if (send(pfd[0].fd, (char*)buf, buflen, 0) != buflen) { |
17a10319 UD |
916 | if (errno == EINTR || errno == EAGAIN) |
917 | goto recompute_resend; | |
918 | Perror(statp, stderr, "send", errno); | |
a334319f UD |
919 | res_nclose(statp); |
920 | return (0); | |
f433b06b | 921 | } |
17a10319 UD |
922 | pfd[0].events = POLLIN; |
923 | ++nwritten; | |
924 | goto wait; | |
8aeb5058 | 925 | } else if (pfd[0].revents & POLLIN) { |
17a10319 UD |
926 | fromlen = sizeof(struct sockaddr_in6); |
927 | if (anssiz < MAXPACKET | |
928 | && anscp | |
929 | && (ioctl (pfd[0].fd, FIONREAD, &resplen) < 0 | |
930 | || anssiz < resplen)) { | |
931 | ans = malloc (MAXPACKET); | |
932 | if (ans == NULL) | |
933 | ans = *ansp; | |
934 | else { | |
935 | anssiz = MAXPACKET; | |
936 | *anssizp = MAXPACKET; | |
937 | *ansp = ans; | |
938 | *anscp = ans; | |
939 | anhp = (HEADER *) ans; | |
940 | } | |
941 | } | |
942 | resplen = recvfrom(pfd[0].fd, (char*)ans, anssiz,0, | |
943 | (struct sockaddr *)&from, &fromlen); | |
944 | if (resplen <= 0) { | |
945 | if (errno == EINTR || errno == EAGAIN) { | |
946 | need_recompute = 1; | |
947 | goto wait; | |
948 | } | |
949 | Perror(statp, stderr, "recvfrom", errno); | |
a334319f UD |
950 | res_nclose(statp); |
951 | return (0); | |
17a10319 | 952 | } |
e685e07d | 953 | *gotsomewhere = 1; |
17a10319 UD |
954 | if (resplen < HFIXEDSZ) { |
955 | /* | |
956 | * Undersized message. | |
957 | */ | |
958 | Dprint(statp->options & RES_DEBUG, | |
959 | (stdout, ";; undersized: %d\n", | |
960 | resplen)); | |
961 | *terrno = EMSGSIZE; | |
a334319f UD |
962 | res_nclose(statp); |
963 | return (0); | |
17a10319 UD |
964 | } |
965 | if (hp->id != anhp->id) { | |
966 | /* | |
967 | * response from old query, ignore it. | |
968 | * XXX - potential security hazard could | |
969 | * be detected here. | |
970 | */ | |
971 | DprintQ((statp->options & RES_DEBUG) || | |
972 | (statp->pfcode & RES_PRF_REPLY), | |
973 | (stdout, ";; old answer:\n"), | |
974 | ans, (resplen > anssiz) ? anssiz : resplen); | |
f433b06b | 975 | goto wait; |
e685e07d | 976 | } |
17a10319 UD |
977 | if (!(statp->options & RES_INSECURE1) && |
978 | !res_ourserver_p(statp, &from)) { | |
979 | /* | |
980 | * response from wrong server? ignore it. | |
981 | * XXX - potential security hazard could | |
982 | * be detected here. | |
983 | */ | |
984 | DprintQ((statp->options & RES_DEBUG) || | |
985 | (statp->pfcode & RES_PRF_REPLY), | |
986 | (stdout, ";; not our server:\n"), | |
987 | ans, (resplen > anssiz) ? anssiz : resplen); | |
988 | goto wait; | |
0420d888 | 989 | } |
17a10319 UD |
990 | if (!(statp->options & RES_INSECURE2) && |
991 | !res_queriesmatch(buf, buf + buflen, | |
992 | ans, ans + anssiz)) { | |
993 | /* | |
994 | * response contains wrong query? ignore it. | |
995 | * XXX - potential security hazard could | |
996 | * be detected here. | |
997 | */ | |
998 | DprintQ((statp->options & RES_DEBUG) || | |
999 | (statp->pfcode & RES_PRF_REPLY), | |
1000 | (stdout, ";; wrong query name:\n"), | |
1001 | ans, (resplen > anssiz) ? anssiz : resplen); | |
f433b06b UD |
1002 | goto wait; |
1003 | } | |
17a10319 UD |
1004 | if (anhp->rcode == SERVFAIL || |
1005 | anhp->rcode == NOTIMP || | |
1006 | anhp->rcode == REFUSED) { | |
1007 | DprintQ(statp->options & RES_DEBUG, | |
1008 | (stdout, "server rejected query:\n"), | |
1009 | ans, (resplen > anssiz) ? anssiz : resplen); | |
a334319f | 1010 | res_nclose(statp); |
17a10319 UD |
1011 | /* don't retry if called from dig */ |
1012 | if (!statp->pfcode) | |
1013 | return (0); | |
1014 | } | |
1015 | if (!(statp->options & RES_IGNTC) && anhp->tc) { | |
1016 | /* | |
1017 | * To get the rest of answer, | |
1018 | * use TCP with same server. | |
1019 | */ | |
1020 | Dprint(statp->options & RES_DEBUG, | |
1021 | (stdout, ";; truncated answer\n")); | |
1022 | *v_circuit = 1; | |
a334319f | 1023 | res_nclose(statp); |
17a10319 UD |
1024 | return (1); |
1025 | } | |
e685e07d | 1026 | /* |
17a10319 UD |
1027 | * All is well, or the error is fatal. Signal that the |
1028 | * next nameserver ought not be tried. | |
e685e07d | 1029 | */ |
17a10319 | 1030 | return (resplen); |
8aeb5058 UD |
1031 | } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { |
1032 | /* Something went wrong. We can stop trying. */ | |
a334319f UD |
1033 | res_nclose(statp); |
1034 | return (0); | |
e685e07d | 1035 | } |
e685e07d UD |
1036 | } |
1037 | ||
1038 | #ifdef DEBUG | |
1039 | static void | |
1040 | Aerror(const res_state statp, FILE *file, const char *string, int error, | |
020a9a23 | 1041 | const struct sockaddr *address) |
e685e07d UD |
1042 | { |
1043 | int save = errno; | |
1044 | ||
1045 | if ((statp->options & RES_DEBUG) != 0) { | |
020a9a23 | 1046 | char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"]; |
e685e07d UD |
1047 | |
1048 | fprintf(file, "res_send: %s ([%s].%u): %s\n", | |
1049 | string, | |
a334319f UD |
1050 | inet_ntop(address->sa_family, address->sa_data, |
1051 | tmp, sizeof tmp), | |
020a9a23 UD |
1052 | (address->sa_family == AF_INET |
1053 | ? ntohs(((struct sockaddr_in *) address)->sin_port) | |
1054 | : address->sa_family == AF_INET6 | |
1055 | ? ntohs(((struct sockaddr_in6 *) address)->sin6_port) | |
1056 | : 0), | |
e685e07d UD |
1057 | strerror(error)); |
1058 | } | |
1059 | __set_errno (save); | |
1060 | } | |
1061 | ||
1062 | static void | |
1063 | Perror(const res_state statp, FILE *file, const char *string, int error) { | |
1064 | int save = errno; | |
1065 | ||
1066 | if ((statp->options & RES_DEBUG) != 0) | |
1067 | fprintf(file, "res_send: %s: %s\n", | |
1068 | string, strerror(error)); | |
1069 | __set_errno (save); | |
1070 | } | |
1071 | #endif | |
1072 | ||
1073 | static int | |
438e8239 UD |
1074 | sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) { |
1075 | if (a1->sin6_family == a2->sin6_family) { | |
1076 | if (a1->sin6_family == AF_INET) | |
1077 | return ((((struct sockaddr_in *)a1)->sin_port == | |
1078 | ((struct sockaddr_in *)a2)->sin_port) && | |
1079 | (((struct sockaddr_in *)a1)->sin_addr.s_addr == | |
1080 | ((struct sockaddr_in *)a2)->sin_addr.s_addr)); | |
1081 | else | |
1082 | return ((a1->sin6_port == a2->sin6_port) && | |
1083 | !memcmp(&a1->sin6_addr, &a2->sin6_addr, | |
1084 | sizeof (struct in6_addr))); | |
1085 | } | |
1086 | if (a1->sin6_family == AF_INET) { | |
1087 | struct sockaddr_in6 *sap = a1; | |
1088 | a1 = a2; | |
1089 | a2 = sap; | |
1090 | } /* assumes that AF_INET and AF_INET6 are the only possibilities */ | |
1091 | return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) && | |
1092 | IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) && | |
1093 | (a1->sin6_addr.s6_addr32[3] == | |
1094 | ((struct sockaddr_in *)a2)->sin_addr.s_addr)); | |
1095 | } | |
438e8239 | 1096 | |
438e8239 UD |
1097 | /* |
1098 | * Converts IPv4 family, address and port to | |
1099 | * IPv6 family, IPv4-mapped IPv6 address and port. | |
1100 | */ | |
1101 | static void | |
1102 | convaddr4to6(struct sockaddr_in6 *sa) | |
1103 | { | |
e62b2105 UD |
1104 | struct sockaddr_in *sa4p = (struct sockaddr_in *) sa; |
1105 | in_port_t port = sa4p->sin_port; | |
1106 | in_addr_t addr = sa4p->sin_addr.s_addr; | |
438e8239 UD |
1107 | |
1108 | sa->sin6_family = AF_INET6; | |
e62b2105 | 1109 | sa->sin6_port = port; |
438e8239 UD |
1110 | sa->sin6_addr.s6_addr32[0] = 0; |
1111 | sa->sin6_addr.s6_addr32[1] = 0; | |
1112 | sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF); | |
e62b2105 | 1113 | sa->sin6_addr.s6_addr32[3] = addr; |
438e8239 | 1114 | } |