|
1 /* $NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $ */ |
|
2 |
|
3 /* |
|
4 * Copyright 2008 Android Open Source Project (source port randomization) |
|
5 * Copyright (c) 1985, 1989, 1993 |
|
6 * The Regents of the University of California. All rights reserved. |
|
7 * |
|
8 * Redistribution and use in source and binary forms, with or without |
|
9 * modification, are permitted provided that the following conditions |
|
10 * are met: |
|
11 * 1. Redistributions of source code must retain the above copyright |
|
12 * notice, this list of conditions and the following disclaimer. |
|
13 * 2. Redistributions in binary form must reproduce the above copyright |
|
14 * notice, this list of conditions and the following disclaimer in the |
|
15 * documentation and/or other materials provided with the distribution. |
|
16 * 3. All advertising materials mentioning features or use of this software |
|
17 * must display the following acknowledgement: |
|
18 * This product includes software developed by the University of |
|
19 * California, Berkeley and its contributors. |
|
20 * 4. Neither the name of the University nor the names of its contributors |
|
21 * may be used to endorse or promote products derived from this software |
|
22 * without specific prior written permission. |
|
23 * |
|
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
34 * SUCH DAMAGE. |
|
35 */ |
|
36 |
|
37 /* |
|
38 * Portions Copyright (c) 1993 by Digital Equipment Corporation. |
|
39 * |
|
40 * Permission to use, copy, modify, and distribute this software for any |
|
41 * purpose with or without fee is hereby granted, provided that the above |
|
42 * copyright notice and this permission notice appear in all copies, and that |
|
43 * the name of Digital Equipment Corporation not be used in advertising or |
|
44 * publicity pertaining to distribution of the document or software without |
|
45 * specific, written prior permission. |
|
46 * |
|
47 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL |
|
48 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES |
|
49 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT |
|
50 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
|
51 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
|
52 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS |
|
53 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
54 * SOFTWARE. |
|
55 */ |
|
56 |
|
57 /* |
|
58 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
|
59 * Portions Copyright (c) 1996-1999 by Internet Software Consortium. |
|
60 * |
|
61 * Permission to use, copy, modify, and distribute this software for any |
|
62 * purpose with or without fee is hereby granted, provided that the above |
|
63 * copyright notice and this permission notice appear in all copies. |
|
64 * |
|
65 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
|
66 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
67 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
|
68 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
69 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|
70 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
|
71 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
72 */ |
|
73 |
|
74 /* |
|
75 * This version of this file is derived from Android 2.3 "Gingerbread", |
|
76 * which contains uncredited changes by Android/Google developers. It has |
|
77 * been modified in 2011 for use in the Android build of Mozilla Firefox by |
|
78 * Mozilla contributors (including Michael Edwards <m.k.edwards@gmail.com>, |
|
79 * and Steve Workman <sjhworkman@gmail.com>). |
|
80 * These changes are offered under the same license as the original NetBSD |
|
81 * file, whose copyright and license are unchanged above. |
|
82 */ |
|
83 |
|
84 #define ANDROID_CHANGES 1 |
|
85 #define MOZILLA_NECKO_EXCLUDE_CODE 1 |
|
86 |
|
87 #include <sys/cdefs.h> |
|
88 #if defined(LIBC_SCCS) && !defined(lint) |
|
89 #ifdef notdef |
|
90 static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; |
|
91 static const char rcsid[] = "Id: res_send.c,v 1.5.2.2.4.5 2004/08/10 02:19:56 marka Exp"; |
|
92 #else |
|
93 __RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $"); |
|
94 #endif |
|
95 #endif /* LIBC_SCCS and not lint */ |
|
96 |
|
97 /* Set to 0 to not use the small/simple/limited DNS cache |
|
98 * Cache implemented higher up in Gecko */ |
|
99 #define USE_RESOLV_CACHE 0 |
|
100 |
|
101 /* |
|
102 * Send query to name server and wait for reply. |
|
103 */ |
|
104 |
|
105 #include <sys/types.h> |
|
106 #include <sys/param.h> |
|
107 #include <sys/time.h> |
|
108 #include <sys/socket.h> |
|
109 #include <sys/uio.h> |
|
110 |
|
111 #include <netinet/in.h> |
|
112 #include "arpa_nameser.h" |
|
113 #include <arpa/inet.h> |
|
114 |
|
115 #include <errno.h> |
|
116 #include <netdb.h> |
|
117 #ifdef ANDROID_CHANGES |
|
118 #include "resolv_private.h" |
|
119 #else |
|
120 #include <resolv.h> |
|
121 #endif |
|
122 #include <signal.h> |
|
123 #include <stdio.h> |
|
124 #include <stdlib.h> |
|
125 #include <string.h> |
|
126 #include <unistd.h> |
|
127 |
|
128 #include "eventlib.h" |
|
129 |
|
130 #if USE_RESOLV_CACHE |
|
131 # include <resolv_cache.h> |
|
132 #endif |
|
133 |
|
134 #ifndef DE_CONST |
|
135 #define DE_CONST(c,v) v = ((c) ? \ |
|
136 strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL) |
|
137 #endif |
|
138 |
|
139 /* Options. Leave them on. */ |
|
140 #ifndef DEBUG |
|
141 #define DEBUG |
|
142 #endif |
|
143 #include "res_debug.h" |
|
144 #include "res_private.h" |
|
145 |
|
146 #define EXT(res) ((res)->_u._ext) |
|
147 |
|
148 static const int highestFD = FD_SETSIZE - 1; |
|
149 |
|
150 /* Forward. */ |
|
151 |
|
152 static int get_salen __P((const struct sockaddr *)); |
|
153 static struct sockaddr * get_nsaddr __P((res_state, size_t)); |
|
154 static int send_vc(res_state, const u_char *, int, |
|
155 u_char *, int, int *, int); |
|
156 static int send_dg(res_state, const u_char *, int, |
|
157 u_char *, int, int *, int, |
|
158 int *, int *); |
|
159 static void Aerror(const res_state, FILE *, const char *, int, |
|
160 const struct sockaddr *, int); |
|
161 static void Perror(const res_state, FILE *, const char *, int); |
|
162 static int sock_eq(struct sockaddr *, struct sockaddr *); |
|
163 #ifdef NEED_PSELECT |
|
164 static int pselect(int, void *, void *, void *, |
|
165 struct timespec *, |
|
166 const sigset_t *); |
|
167 #endif |
|
168 void res_pquery(const res_state, const u_char *, int, FILE *); |
|
169 |
|
170 |
|
171 /* BIONIC-BEGIN: implement source port randomization */ |
|
172 typedef union { |
|
173 struct sockaddr sa; |
|
174 struct sockaddr_in sin; |
|
175 struct sockaddr_in6 sin6; |
|
176 } _sockaddr_union; |
|
177 |
|
178 static int |
|
179 random_bind( int s, int family ) |
|
180 { |
|
181 _sockaddr_union u; |
|
182 int j; |
|
183 socklen_t slen; |
|
184 |
|
185 /* clear all, this also sets the IP4/6 address to 'any' */ |
|
186 memset( &u, 0, sizeof u ); |
|
187 |
|
188 switch (family) { |
|
189 case AF_INET: |
|
190 u.sin.sin_family = family; |
|
191 slen = sizeof u.sin; |
|
192 break; |
|
193 case AF_INET6: |
|
194 u.sin6.sin6_family = family; |
|
195 slen = sizeof u.sin6; |
|
196 break; |
|
197 default: |
|
198 errno = EPROTO; |
|
199 return -1; |
|
200 } |
|
201 |
|
202 /* first try to bind to a random source port a few times */ |
|
203 for (j = 0; j < 10; j++) { |
|
204 /* find a random port between 1025 .. 65534 */ |
|
205 int port = 1025 + (res_randomid() % (65535-1025)); |
|
206 if (family == AF_INET) |
|
207 u.sin.sin_port = htons(port); |
|
208 else |
|
209 u.sin6.sin6_port = htons(port); |
|
210 |
|
211 if ( !bind( s, &u.sa, slen ) ) |
|
212 return 0; |
|
213 } |
|
214 |
|
215 /* nothing after 10 tries, our network table is probably busy */ |
|
216 /* let the system decide which port is best */ |
|
217 if (family == AF_INET) |
|
218 u.sin.sin_port = 0; |
|
219 else |
|
220 u.sin6.sin6_port = 0; |
|
221 |
|
222 return bind( s, &u.sa, slen ); |
|
223 } |
|
224 /* BIONIC-END */ |
|
225 |
|
226 static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; |
|
227 |
|
228 /* Public. */ |
|
229 |
|
230 /* int |
|
231 * res_isourserver(ina) |
|
232 * looks up "ina" in _res.ns_addr_list[] |
|
233 * returns: |
|
234 * 0 : not found |
|
235 * >0 : found |
|
236 * author: |
|
237 * paul vixie, 29may94 |
|
238 */ |
|
239 int |
|
240 res_ourserver_p(const res_state statp, const struct sockaddr *sa) { |
|
241 const struct sockaddr_in *inp, *srv; |
|
242 const struct sockaddr_in6 *in6p, *srv6; |
|
243 int ns; |
|
244 |
|
245 switch (sa->sa_family) { |
|
246 case AF_INET: |
|
247 inp = (const struct sockaddr_in *)(const void *)sa; |
|
248 for (ns = 0; ns < statp->nscount; ns++) { |
|
249 srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns); |
|
250 if (srv->sin_family == inp->sin_family && |
|
251 srv->sin_port == inp->sin_port && |
|
252 (srv->sin_addr.s_addr == INADDR_ANY || |
|
253 srv->sin_addr.s_addr == inp->sin_addr.s_addr)) |
|
254 return (1); |
|
255 } |
|
256 break; |
|
257 case AF_INET6: |
|
258 if (EXT(statp).ext == NULL) |
|
259 break; |
|
260 in6p = (const struct sockaddr_in6 *)(const void *)sa; |
|
261 for (ns = 0; ns < statp->nscount; ns++) { |
|
262 srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns); |
|
263 if (srv6->sin6_family == in6p->sin6_family && |
|
264 srv6->sin6_port == in6p->sin6_port && |
|
265 #ifdef HAVE_SIN6_SCOPE_ID |
|
266 (srv6->sin6_scope_id == 0 || |
|
267 srv6->sin6_scope_id == in6p->sin6_scope_id) && |
|
268 #endif |
|
269 (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || |
|
270 IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) |
|
271 return (1); |
|
272 } |
|
273 break; |
|
274 default: |
|
275 break; |
|
276 } |
|
277 return (0); |
|
278 } |
|
279 |
|
280 /* int |
|
281 * res_nameinquery(name, type, class, buf, eom) |
|
282 * look for (name,type,class) in the query section of packet (buf,eom) |
|
283 * requires: |
|
284 * buf + HFIXEDSZ <= eom |
|
285 * returns: |
|
286 * -1 : format error |
|
287 * 0 : not found |
|
288 * >0 : found |
|
289 * author: |
|
290 * paul vixie, 29may94 |
|
291 */ |
|
292 int |
|
293 res_nameinquery(const char *name, int type, int class, |
|
294 const u_char *buf, const u_char *eom) |
|
295 { |
|
296 const u_char *cp = buf + HFIXEDSZ; |
|
297 int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount); |
|
298 |
|
299 while (qdcount-- > 0) { |
|
300 char tname[MAXDNAME+1]; |
|
301 int n, ttype, tclass; |
|
302 |
|
303 n = dn_expand(buf, eom, cp, tname, sizeof tname); |
|
304 if (n < 0) |
|
305 return (-1); |
|
306 cp += n; |
|
307 if (cp + 2 * INT16SZ > eom) |
|
308 return (-1); |
|
309 ttype = ns_get16(cp); cp += INT16SZ; |
|
310 tclass = ns_get16(cp); cp += INT16SZ; |
|
311 if (ttype == type && tclass == class && |
|
312 ns_samename(tname, name) == 1) |
|
313 return (1); |
|
314 } |
|
315 return (0); |
|
316 } |
|
317 |
|
318 /* int |
|
319 * res_queriesmatch(buf1, eom1, buf2, eom2) |
|
320 * is there a 1:1 mapping of (name,type,class) |
|
321 * in (buf1,eom1) and (buf2,eom2)? |
|
322 * returns: |
|
323 * -1 : format error |
|
324 * 0 : not a 1:1 mapping |
|
325 * >0 : is a 1:1 mapping |
|
326 * author: |
|
327 * paul vixie, 29may94 |
|
328 */ |
|
329 int |
|
330 res_queriesmatch(const u_char *buf1, const u_char *eom1, |
|
331 const u_char *buf2, const u_char *eom2) |
|
332 { |
|
333 const u_char *cp = buf1 + HFIXEDSZ; |
|
334 int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount); |
|
335 |
|
336 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) |
|
337 return (-1); |
|
338 |
|
339 /* |
|
340 * Only header section present in replies to |
|
341 * dynamic update packets. |
|
342 */ |
|
343 if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) && |
|
344 (((const HEADER *)(const void *)buf2)->opcode == ns_o_update)) |
|
345 return (1); |
|
346 |
|
347 if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount)) |
|
348 return (0); |
|
349 while (qdcount-- > 0) { |
|
350 char tname[MAXDNAME+1]; |
|
351 int n, ttype, tclass; |
|
352 |
|
353 n = dn_expand(buf1, eom1, cp, tname, sizeof tname); |
|
354 if (n < 0) |
|
355 return (-1); |
|
356 cp += n; |
|
357 if (cp + 2 * INT16SZ > eom1) |
|
358 return (-1); |
|
359 ttype = ns_get16(cp); cp += INT16SZ; |
|
360 tclass = ns_get16(cp); cp += INT16SZ; |
|
361 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) |
|
362 return (0); |
|
363 } |
|
364 return (1); |
|
365 } |
|
366 |
|
367 |
|
368 int |
|
369 res_nsend(res_state statp, |
|
370 const u_char *buf, int buflen, u_char *ans, int anssiz) |
|
371 { |
|
372 int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; |
|
373 char abuf[NI_MAXHOST]; |
|
374 #if USE_RESOLV_CACHE |
|
375 struct resolv_cache* cache; |
|
376 ResolvCacheStatus cache_status = RESOLV_CACHE_UNSUPPORTED; |
|
377 #endif |
|
378 |
|
379 if (statp->nscount == 0) { |
|
380 errno = ESRCH; |
|
381 return (-1); |
|
382 } |
|
383 if (anssiz < HFIXEDSZ) { |
|
384 errno = EINVAL; |
|
385 return (-1); |
|
386 } |
|
387 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), |
|
388 (stdout, ";; res_send()\n"), buf, buflen); |
|
389 v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; |
|
390 gotsomewhere = 0; |
|
391 terrno = ETIMEDOUT; |
|
392 |
|
393 #if USE_RESOLV_CACHE |
|
394 cache = __get_res_cache(); |
|
395 if (cache != NULL) { |
|
396 int anslen = 0; |
|
397 cache_status = _resolv_cache_lookup( |
|
398 cache, buf, buflen, |
|
399 ans, anssiz, &anslen); |
|
400 |
|
401 if (cache_status == RESOLV_CACHE_FOUND) { |
|
402 return anslen; |
|
403 } |
|
404 } |
|
405 #endif |
|
406 |
|
407 /* |
|
408 * If the ns_addr_list in the resolver context has changed, then |
|
409 * invalidate our cached copy and the associated timing data. |
|
410 */ |
|
411 if (EXT(statp).nscount != 0) { |
|
412 int needclose = 0; |
|
413 struct sockaddr_storage peer; |
|
414 socklen_t peerlen; |
|
415 |
|
416 if (EXT(statp).nscount != statp->nscount) |
|
417 needclose++; |
|
418 else |
|
419 for (ns = 0; ns < statp->nscount; ns++) { |
|
420 if (statp->nsaddr_list[ns].sin_family && |
|
421 !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns], |
|
422 (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) { |
|
423 needclose++; |
|
424 break; |
|
425 } |
|
426 |
|
427 if (EXT(statp).nssocks[ns] == -1) |
|
428 continue; |
|
429 peerlen = sizeof(peer); |
|
430 if (getsockname(EXT(statp).nssocks[ns], |
|
431 (struct sockaddr *)(void *)&peer, &peerlen) < 0) { |
|
432 needclose++; |
|
433 break; |
|
434 } |
|
435 if (!sock_eq((struct sockaddr *)(void *)&peer, |
|
436 get_nsaddr(statp, (size_t)ns))) { |
|
437 needclose++; |
|
438 break; |
|
439 } |
|
440 } |
|
441 if (needclose) { |
|
442 res_nclose(statp); |
|
443 EXT(statp).nscount = 0; |
|
444 } |
|
445 } |
|
446 |
|
447 /* |
|
448 * Maybe initialize our private copy of the ns_addr_list. |
|
449 */ |
|
450 if (EXT(statp).nscount == 0) { |
|
451 for (ns = 0; ns < statp->nscount; ns++) { |
|
452 EXT(statp).nstimes[ns] = RES_MAXTIME; |
|
453 EXT(statp).nssocks[ns] = -1; |
|
454 if (!statp->nsaddr_list[ns].sin_family) |
|
455 continue; |
|
456 EXT(statp).ext->nsaddrs[ns].sin = |
|
457 statp->nsaddr_list[ns]; |
|
458 } |
|
459 EXT(statp).nscount = statp->nscount; |
|
460 } |
|
461 |
|
462 /* |
|
463 * Some resolvers want to even out the load on their nameservers. |
|
464 * Note that RES_BLAST overrides RES_ROTATE. |
|
465 */ |
|
466 if ((statp->options & RES_ROTATE) != 0U && |
|
467 (statp->options & RES_BLAST) == 0U) { |
|
468 union res_sockaddr_union inu; |
|
469 struct sockaddr_in ina; |
|
470 int lastns = statp->nscount - 1; |
|
471 int fd; |
|
472 u_int16_t nstime; |
|
473 |
|
474 if (EXT(statp).ext != NULL) |
|
475 inu = EXT(statp).ext->nsaddrs[0]; |
|
476 ina = statp->nsaddr_list[0]; |
|
477 fd = EXT(statp).nssocks[0]; |
|
478 nstime = EXT(statp).nstimes[0]; |
|
479 for (ns = 0; ns < lastns; ns++) { |
|
480 if (EXT(statp).ext != NULL) |
|
481 EXT(statp).ext->nsaddrs[ns] = |
|
482 EXT(statp).ext->nsaddrs[ns + 1]; |
|
483 statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; |
|
484 EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; |
|
485 EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; |
|
486 } |
|
487 if (EXT(statp).ext != NULL) |
|
488 EXT(statp).ext->nsaddrs[lastns] = inu; |
|
489 statp->nsaddr_list[lastns] = ina; |
|
490 EXT(statp).nssocks[lastns] = fd; |
|
491 EXT(statp).nstimes[lastns] = nstime; |
|
492 } |
|
493 |
|
494 /* |
|
495 * Send request, RETRY times, or until successful. |
|
496 */ |
|
497 for (try = 0; try < statp->retry; try++) { |
|
498 for (ns = 0; ns < statp->nscount; ns++) { |
|
499 struct sockaddr *nsap; |
|
500 int nsaplen; |
|
501 nsap = get_nsaddr(statp, (size_t)ns); |
|
502 nsaplen = get_salen(nsap); |
|
503 statp->_flags &= ~RES_F_LASTMASK; |
|
504 statp->_flags |= (ns << RES_F_LASTSHIFT); |
|
505 same_ns: |
|
506 if (statp->qhook) { |
|
507 int done = 0, loops = 0; |
|
508 |
|
509 do { |
|
510 res_sendhookact act; |
|
511 |
|
512 act = (*statp->qhook)(&nsap, &buf, &buflen, |
|
513 ans, anssiz, &resplen); |
|
514 switch (act) { |
|
515 case res_goahead: |
|
516 done = 1; |
|
517 break; |
|
518 case res_nextns: |
|
519 res_nclose(statp); |
|
520 goto next_ns; |
|
521 case res_done: |
|
522 return (resplen); |
|
523 case res_modified: |
|
524 /* give the hook another try */ |
|
525 if (++loops < 42) /*doug adams*/ |
|
526 break; |
|
527 /*FALLTHROUGH*/ |
|
528 case res_error: |
|
529 /*FALLTHROUGH*/ |
|
530 default: |
|
531 goto fail; |
|
532 } |
|
533 } while (!done); |
|
534 } |
|
535 |
|
536 Dprint(((statp->options & RES_DEBUG) && |
|
537 getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf), |
|
538 NULL, 0, niflags) == 0), |
|
539 (stdout, ";; Querying server (# %d) address = %s\n", |
|
540 ns + 1, abuf)); |
|
541 |
|
542 |
|
543 if (v_circuit) { |
|
544 /* Use VC; at most one attempt per server. */ |
|
545 try = statp->retry; |
|
546 n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, |
|
547 ns); |
|
548 if (n < 0) |
|
549 goto fail; |
|
550 if (n == 0) |
|
551 goto next_ns; |
|
552 resplen = n; |
|
553 } else { |
|
554 /* Use datagrams. */ |
|
555 n = send_dg(statp, buf, buflen, ans, anssiz, &terrno, |
|
556 ns, &v_circuit, &gotsomewhere); |
|
557 if (n < 0) |
|
558 goto fail; |
|
559 if (n == 0) |
|
560 goto next_ns; |
|
561 if (v_circuit) |
|
562 goto same_ns; |
|
563 resplen = n; |
|
564 } |
|
565 |
|
566 Dprint((statp->options & RES_DEBUG) || |
|
567 ((statp->pfcode & RES_PRF_REPLY) && |
|
568 (statp->pfcode & RES_PRF_HEAD1)), |
|
569 (stdout, ";; got answer:\n")); |
|
570 |
|
571 DprintQ((statp->options & RES_DEBUG) || |
|
572 (statp->pfcode & RES_PRF_REPLY), |
|
573 (stdout, "%s", ""), |
|
574 ans, (resplen > anssiz) ? anssiz : resplen); |
|
575 |
|
576 #if USE_RESOLV_CACHE |
|
577 if (cache_status == RESOLV_CACHE_NOTFOUND) { |
|
578 _resolv_cache_add(cache, buf, buflen, |
|
579 ans, resplen); |
|
580 } |
|
581 #endif |
|
582 /* |
|
583 * If we have temporarily opened a virtual circuit, |
|
584 * or if we haven't been asked to keep a socket open, |
|
585 * close the socket. |
|
586 */ |
|
587 if ((v_circuit && (statp->options & RES_USEVC) == 0U) || |
|
588 (statp->options & RES_STAYOPEN) == 0U) { |
|
589 res_nclose(statp); |
|
590 } |
|
591 if (statp->rhook) { |
|
592 int done = 0, loops = 0; |
|
593 |
|
594 do { |
|
595 res_sendhookact act; |
|
596 |
|
597 act = (*statp->rhook)(nsap, buf, buflen, |
|
598 ans, anssiz, &resplen); |
|
599 switch (act) { |
|
600 case res_goahead: |
|
601 case res_done: |
|
602 done = 1; |
|
603 break; |
|
604 case res_nextns: |
|
605 res_nclose(statp); |
|
606 goto next_ns; |
|
607 case res_modified: |
|
608 /* give the hook another try */ |
|
609 if (++loops < 42) /*doug adams*/ |
|
610 break; |
|
611 /*FALLTHROUGH*/ |
|
612 case res_error: |
|
613 /*FALLTHROUGH*/ |
|
614 default: |
|
615 goto fail; |
|
616 } |
|
617 } while (!done); |
|
618 |
|
619 } |
|
620 return (resplen); |
|
621 next_ns: ; |
|
622 } /*foreach ns*/ |
|
623 } /*foreach retry*/ |
|
624 res_nclose(statp); |
|
625 if (!v_circuit) { |
|
626 if (!gotsomewhere) |
|
627 errno = ECONNREFUSED; /* no nameservers found */ |
|
628 else |
|
629 errno = ETIMEDOUT; /* no answer obtained */ |
|
630 } else |
|
631 errno = terrno; |
|
632 return (-1); |
|
633 fail: |
|
634 res_nclose(statp); |
|
635 return (-1); |
|
636 } |
|
637 |
|
638 /* Private */ |
|
639 |
|
640 static int |
|
641 get_salen(sa) |
|
642 const struct sockaddr *sa; |
|
643 { |
|
644 |
|
645 #ifdef HAVE_SA_LEN |
|
646 /* There are people do not set sa_len. Be forgiving to them. */ |
|
647 if (sa->sa_len) |
|
648 return (sa->sa_len); |
|
649 #endif |
|
650 |
|
651 if (sa->sa_family == AF_INET) |
|
652 return (sizeof(struct sockaddr_in)); |
|
653 else if (sa->sa_family == AF_INET6) |
|
654 return (sizeof(struct sockaddr_in6)); |
|
655 else |
|
656 return (0); /* unknown, die on connect */ |
|
657 } |
|
658 |
|
659 /* |
|
660 * pick appropriate nsaddr_list for use. see res_init() for initialization. |
|
661 */ |
|
662 static struct sockaddr * |
|
663 get_nsaddr(statp, n) |
|
664 res_state statp; |
|
665 size_t n; |
|
666 { |
|
667 |
|
668 if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) { |
|
669 /* |
|
670 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger |
|
671 * than struct sockaddr, and |
|
672 * - user code did not update statp->nsaddr_list[n]. |
|
673 */ |
|
674 return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n]; |
|
675 } else { |
|
676 /* |
|
677 * - user code updated statp->nsaddr_list[n], or |
|
678 * - statp->nsaddr_list[n] has the same content as |
|
679 * EXT(statp).ext->nsaddrs[n]. |
|
680 */ |
|
681 return (struct sockaddr *)(void *)&statp->nsaddr_list[n]; |
|
682 } |
|
683 } |
|
684 |
|
685 static int |
|
686 send_vc(res_state statp, |
|
687 const u_char *buf, int buflen, u_char *ans, int anssiz, |
|
688 int *terrno, int ns) |
|
689 { |
|
690 const HEADER *hp = (const HEADER *)(const void *)buf; |
|
691 HEADER *anhp = (HEADER *)(void *)ans; |
|
692 struct sockaddr *nsap; |
|
693 int nsaplen; |
|
694 int truncating, connreset, resplen, n; |
|
695 struct iovec iov[2]; |
|
696 u_short len; |
|
697 u_char *cp; |
|
698 void *tmp; |
|
699 |
|
700 nsap = get_nsaddr(statp, (size_t)ns); |
|
701 nsaplen = get_salen(nsap); |
|
702 |
|
703 connreset = 0; |
|
704 same_ns: |
|
705 truncating = 0; |
|
706 |
|
707 /* Are we still talking to whom we want to talk to? */ |
|
708 if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { |
|
709 struct sockaddr_storage peer; |
|
710 socklen_t size = sizeof peer; |
|
711 |
|
712 if (getpeername(statp->_vcsock, |
|
713 (struct sockaddr *)(void *)&peer, &size) < 0 || |
|
714 !sock_eq((struct sockaddr *)(void *)&peer, nsap)) { |
|
715 res_nclose(statp); |
|
716 statp->_flags &= ~RES_F_VC; |
|
717 } |
|
718 } |
|
719 |
|
720 if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { |
|
721 if (statp->_vcsock >= 0) |
|
722 res_nclose(statp); |
|
723 |
|
724 statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0); |
|
725 if (statp->_vcsock > highestFD) { |
|
726 res_nclose(statp); |
|
727 errno = ENOTSOCK; |
|
728 } |
|
729 if (statp->_vcsock < 0) { |
|
730 switch (errno) { |
|
731 case EPROTONOSUPPORT: |
|
732 #ifdef EPFNOSUPPORT |
|
733 case EPFNOSUPPORT: |
|
734 #endif |
|
735 case EAFNOSUPPORT: |
|
736 Perror(statp, stderr, "socket(vc)", errno); |
|
737 return (0); |
|
738 default: |
|
739 *terrno = errno; |
|
740 Perror(statp, stderr, "socket(vc)", errno); |
|
741 return (-1); |
|
742 } |
|
743 } |
|
744 errno = 0; |
|
745 if (random_bind(statp->_vcsock,nsap->sa_family) < 0) { |
|
746 *terrno = errno; |
|
747 Aerror(statp, stderr, "bind/vc", errno, nsap, |
|
748 nsaplen); |
|
749 res_nclose(statp); |
|
750 return (0); |
|
751 } |
|
752 if (connect(statp->_vcsock, nsap, (socklen_t)nsaplen) < 0) { |
|
753 *terrno = errno; |
|
754 Aerror(statp, stderr, "connect/vc", errno, nsap, |
|
755 nsaplen); |
|
756 res_nclose(statp); |
|
757 return (0); |
|
758 } |
|
759 statp->_flags |= RES_F_VC; |
|
760 } |
|
761 |
|
762 /* |
|
763 * Send length & message |
|
764 */ |
|
765 ns_put16((u_short)buflen, (u_char*)(void *)&len); |
|
766 iov[0] = evConsIovec(&len, INT16SZ); |
|
767 DE_CONST(buf, tmp); |
|
768 iov[1] = evConsIovec(tmp, (size_t)buflen); |
|
769 if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { |
|
770 *terrno = errno; |
|
771 Perror(statp, stderr, "write failed", errno); |
|
772 res_nclose(statp); |
|
773 return (0); |
|
774 } |
|
775 /* |
|
776 * Receive length & response |
|
777 */ |
|
778 read_len: |
|
779 cp = ans; |
|
780 len = INT16SZ; |
|
781 while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) { |
|
782 cp += n; |
|
783 if ((len -= n) == 0) |
|
784 break; |
|
785 } |
|
786 if (n <= 0) { |
|
787 *terrno = errno; |
|
788 Perror(statp, stderr, "read failed", errno); |
|
789 res_nclose(statp); |
|
790 /* |
|
791 * A long running process might get its TCP |
|
792 * connection reset if the remote server was |
|
793 * restarted. Requery the server instead of |
|
794 * trying a new one. When there is only one |
|
795 * server, this means that a query might work |
|
796 * instead of failing. We only allow one reset |
|
797 * per query to prevent looping. |
|
798 */ |
|
799 if (*terrno == ECONNRESET && !connreset) { |
|
800 connreset = 1; |
|
801 res_nclose(statp); |
|
802 goto same_ns; |
|
803 } |
|
804 res_nclose(statp); |
|
805 return (0); |
|
806 } |
|
807 resplen = ns_get16(ans); |
|
808 if (resplen > anssiz) { |
|
809 Dprint(statp->options & RES_DEBUG, |
|
810 (stdout, ";; response truncated\n") |
|
811 ); |
|
812 truncating = 1; |
|
813 len = anssiz; |
|
814 } else |
|
815 len = resplen; |
|
816 if (len < HFIXEDSZ) { |
|
817 /* |
|
818 * Undersized message. |
|
819 */ |
|
820 Dprint(statp->options & RES_DEBUG, |
|
821 (stdout, ";; undersized: %d\n", len)); |
|
822 *terrno = EMSGSIZE; |
|
823 res_nclose(statp); |
|
824 return (0); |
|
825 } |
|
826 cp = ans; |
|
827 while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){ |
|
828 cp += n; |
|
829 len -= n; |
|
830 } |
|
831 if (n <= 0) { |
|
832 *terrno = errno; |
|
833 Perror(statp, stderr, "read(vc)", errno); |
|
834 res_nclose(statp); |
|
835 return (0); |
|
836 } |
|
837 if (truncating) { |
|
838 /* |
|
839 * Flush rest of answer so connection stays in synch. |
|
840 */ |
|
841 anhp->tc = 1; |
|
842 len = resplen - anssiz; |
|
843 while (len != 0) { |
|
844 char junk[PACKETSZ]; |
|
845 |
|
846 n = read(statp->_vcsock, junk, |
|
847 (len > sizeof junk) ? sizeof junk : len); |
|
848 if (n > 0) |
|
849 len -= n; |
|
850 else |
|
851 break; |
|
852 } |
|
853 } |
|
854 /* |
|
855 * If the calling applicating has bailed out of |
|
856 * a previous call and failed to arrange to have |
|
857 * the circuit closed or the server has got |
|
858 * itself confused, then drop the packet and |
|
859 * wait for the correct one. |
|
860 */ |
|
861 if (hp->id != anhp->id) { |
|
862 DprintQ((statp->options & RES_DEBUG) || |
|
863 (statp->pfcode & RES_PRF_REPLY), |
|
864 (stdout, ";; old answer (unexpected):\n"), |
|
865 ans, (resplen > anssiz) ? anssiz: resplen); |
|
866 goto read_len; |
|
867 } |
|
868 |
|
869 /* |
|
870 * All is well, or the error is fatal. Signal that the |
|
871 * next nameserver ought not be tried. |
|
872 */ |
|
873 return (resplen); |
|
874 } |
|
875 |
|
876 static int |
|
877 send_dg(res_state statp, |
|
878 const u_char *buf, int buflen, u_char *ans, int anssiz, |
|
879 int *terrno, int ns, int *v_circuit, int *gotsomewhere) |
|
880 { |
|
881 const HEADER *hp = (const HEADER *)(const void *)buf; |
|
882 HEADER *anhp = (HEADER *)(void *)ans; |
|
883 const struct sockaddr *nsap; |
|
884 int nsaplen; |
|
885 struct timespec now, timeout, finish; |
|
886 fd_set dsmask; |
|
887 struct sockaddr_storage from; |
|
888 socklen_t fromlen; |
|
889 int resplen, seconds, n, s; |
|
890 |
|
891 nsap = get_nsaddr(statp, (size_t)ns); |
|
892 nsaplen = get_salen(nsap); |
|
893 if (EXT(statp).nssocks[ns] == -1) { |
|
894 EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0); |
|
895 if (EXT(statp).nssocks[ns] > highestFD) { |
|
896 res_nclose(statp); |
|
897 errno = ENOTSOCK; |
|
898 } |
|
899 if (EXT(statp).nssocks[ns] < 0) { |
|
900 switch (errno) { |
|
901 case EPROTONOSUPPORT: |
|
902 #ifdef EPFNOSUPPORT |
|
903 case EPFNOSUPPORT: |
|
904 #endif |
|
905 case EAFNOSUPPORT: |
|
906 Perror(statp, stderr, "socket(dg)", errno); |
|
907 return (0); |
|
908 default: |
|
909 *terrno = errno; |
|
910 Perror(statp, stderr, "socket(dg)", errno); |
|
911 return (-1); |
|
912 } |
|
913 } |
|
914 #ifndef CANNOT_CONNECT_DGRAM |
|
915 /* |
|
916 * On a 4.3BSD+ machine (client and server, |
|
917 * actually), sending to a nameserver datagram |
|
918 * port with no nameserver will cause an |
|
919 * ICMP port unreachable message to be returned. |
|
920 * If our datagram socket is "connected" to the |
|
921 * server, we get an ECONNREFUSED error on the next |
|
922 * socket operation, and select returns if the |
|
923 * error message is received. We can thus detect |
|
924 * the absence of a nameserver without timing out. |
|
925 */ |
|
926 if (random_bind(EXT(statp).nssocks[ns], nsap->sa_family) < 0) { |
|
927 Aerror(statp, stderr, "bind(dg)", errno, nsap, |
|
928 nsaplen); |
|
929 res_nclose(statp); |
|
930 return (0); |
|
931 } |
|
932 if (connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) { |
|
933 Aerror(statp, stderr, "connect(dg)", errno, nsap, |
|
934 nsaplen); |
|
935 res_nclose(statp); |
|
936 return (0); |
|
937 } |
|
938 #endif /* !CANNOT_CONNECT_DGRAM */ |
|
939 Dprint(statp->options & RES_DEBUG, |
|
940 (stdout, ";; new DG socket\n")) |
|
941 } |
|
942 s = EXT(statp).nssocks[ns]; |
|
943 #ifndef CANNOT_CONNECT_DGRAM |
|
944 if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) { |
|
945 Perror(statp, stderr, "send", errno); |
|
946 res_nclose(statp); |
|
947 return (0); |
|
948 } |
|
949 #else /* !CANNOT_CONNECT_DGRAM */ |
|
950 if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) |
|
951 { |
|
952 Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); |
|
953 res_nclose(statp); |
|
954 return (0); |
|
955 } |
|
956 #endif /* !CANNOT_CONNECT_DGRAM */ |
|
957 |
|
958 /* |
|
959 * Wait for reply. |
|
960 */ |
|
961 seconds = (statp->retrans << ns); |
|
962 if (ns > 0) |
|
963 seconds /= statp->nscount; |
|
964 if (seconds <= 0) |
|
965 seconds = 1; |
|
966 now = evNowTime(); |
|
967 timeout = evConsTime((long)seconds, 0L); |
|
968 finish = evAddTime(now, timeout); |
|
969 goto nonow; |
|
970 wait: |
|
971 now = evNowTime(); |
|
972 nonow: |
|
973 FD_ZERO(&dsmask); |
|
974 FD_SET(s, &dsmask); |
|
975 if (evCmpTime(finish, now) > 0) |
|
976 timeout = evSubTime(finish, now); |
|
977 else |
|
978 timeout = evConsTime(0L, 0L); |
|
979 n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); |
|
980 if (n == 0) { |
|
981 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); |
|
982 *gotsomewhere = 1; |
|
983 return (0); |
|
984 } |
|
985 if (n < 0) { |
|
986 if (errno == EINTR) |
|
987 goto wait; |
|
988 Perror(statp, stderr, "select", errno); |
|
989 res_nclose(statp); |
|
990 return (0); |
|
991 } |
|
992 errno = 0; |
|
993 fromlen = sizeof(from); |
|
994 resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0, |
|
995 (struct sockaddr *)(void *)&from, &fromlen); |
|
996 if (resplen <= 0) { |
|
997 Perror(statp, stderr, "recvfrom", errno); |
|
998 res_nclose(statp); |
|
999 return (0); |
|
1000 } |
|
1001 *gotsomewhere = 1; |
|
1002 if (resplen < HFIXEDSZ) { |
|
1003 /* |
|
1004 * Undersized message. |
|
1005 */ |
|
1006 Dprint(statp->options & RES_DEBUG, |
|
1007 (stdout, ";; undersized: %d\n", |
|
1008 resplen)); |
|
1009 *terrno = EMSGSIZE; |
|
1010 res_nclose(statp); |
|
1011 return (0); |
|
1012 } |
|
1013 if (hp->id != anhp->id) { |
|
1014 /* |
|
1015 * response from old query, ignore it. |
|
1016 * XXX - potential security hazard could |
|
1017 * be detected here. |
|
1018 */ |
|
1019 DprintQ((statp->options & RES_DEBUG) || |
|
1020 (statp->pfcode & RES_PRF_REPLY), |
|
1021 (stdout, ";; old answer:\n"), |
|
1022 ans, (resplen > anssiz) ? anssiz : resplen); |
|
1023 goto wait; |
|
1024 } |
|
1025 if (!(statp->options & RES_INSECURE1) && |
|
1026 !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) { |
|
1027 /* |
|
1028 * response from wrong server? ignore it. |
|
1029 * XXX - potential security hazard could |
|
1030 * be detected here. |
|
1031 */ |
|
1032 DprintQ((statp->options & RES_DEBUG) || |
|
1033 (statp->pfcode & RES_PRF_REPLY), |
|
1034 (stdout, ";; not our server:\n"), |
|
1035 ans, (resplen > anssiz) ? anssiz : resplen); |
|
1036 goto wait; |
|
1037 } |
|
1038 #ifdef RES_USE_EDNS0 |
|
1039 if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) { |
|
1040 /* |
|
1041 * Do not retry if the server do not understand EDNS0. |
|
1042 * The case has to be captured here, as FORMERR packet do not |
|
1043 * carry query section, hence res_queriesmatch() returns 0. |
|
1044 */ |
|
1045 DprintQ(statp->options & RES_DEBUG, |
|
1046 (stdout, "server rejected query with EDNS0:\n"), |
|
1047 ans, (resplen > anssiz) ? anssiz : resplen); |
|
1048 /* record the error */ |
|
1049 statp->_flags |= RES_F_EDNS0ERR; |
|
1050 res_nclose(statp); |
|
1051 return (0); |
|
1052 } |
|
1053 #endif |
|
1054 if (!(statp->options & RES_INSECURE2) && |
|
1055 !res_queriesmatch(buf, buf + buflen, |
|
1056 ans, ans + anssiz)) { |
|
1057 /* |
|
1058 * response contains wrong query? ignore it. |
|
1059 * XXX - potential security hazard could |
|
1060 * be detected here. |
|
1061 */ |
|
1062 DprintQ((statp->options & RES_DEBUG) || |
|
1063 (statp->pfcode & RES_PRF_REPLY), |
|
1064 (stdout, ";; wrong query name:\n"), |
|
1065 ans, (resplen > anssiz) ? anssiz : resplen); |
|
1066 goto wait; |
|
1067 } |
|
1068 if (anhp->rcode == SERVFAIL || |
|
1069 anhp->rcode == NOTIMP || |
|
1070 anhp->rcode == REFUSED) { |
|
1071 DprintQ(statp->options & RES_DEBUG, |
|
1072 (stdout, "server rejected query:\n"), |
|
1073 ans, (resplen > anssiz) ? anssiz : resplen); |
|
1074 res_nclose(statp); |
|
1075 /* don't retry if called from dig */ |
|
1076 if (!statp->pfcode) |
|
1077 return (0); |
|
1078 } |
|
1079 if (!(statp->options & RES_IGNTC) && anhp->tc) { |
|
1080 /* |
|
1081 * To get the rest of answer, |
|
1082 * use TCP with same server. |
|
1083 */ |
|
1084 Dprint(statp->options & RES_DEBUG, |
|
1085 (stdout, ";; truncated answer\n")); |
|
1086 *v_circuit = 1; |
|
1087 res_nclose(statp); |
|
1088 return (1); |
|
1089 } |
|
1090 /* |
|
1091 * All is well, or the error is fatal. Signal that the |
|
1092 * next nameserver ought not be tried. |
|
1093 */ |
|
1094 return (resplen); |
|
1095 } |
|
1096 |
|
1097 static void |
|
1098 Aerror(const res_state statp, FILE *file, const char *string, int error, |
|
1099 const struct sockaddr *address, int alen) |
|
1100 { |
|
1101 int save = errno; |
|
1102 char hbuf[NI_MAXHOST]; |
|
1103 char sbuf[NI_MAXSERV]; |
|
1104 |
|
1105 alen = alen; |
|
1106 |
|
1107 if ((statp->options & RES_DEBUG) != 0U) { |
|
1108 if (getnameinfo(address, (socklen_t)alen, hbuf, sizeof(hbuf), |
|
1109 sbuf, sizeof(sbuf), niflags)) { |
|
1110 strncpy(hbuf, "?", sizeof(hbuf) - 1); |
|
1111 hbuf[sizeof(hbuf) - 1] = '\0'; |
|
1112 strncpy(sbuf, "?", sizeof(sbuf) - 1); |
|
1113 sbuf[sizeof(sbuf) - 1] = '\0'; |
|
1114 } |
|
1115 fprintf(file, "res_send: %s ([%s].%s): %s\n", |
|
1116 string, hbuf, sbuf, strerror(error)); |
|
1117 } |
|
1118 errno = save; |
|
1119 } |
|
1120 |
|
1121 static void |
|
1122 Perror(const res_state statp, FILE *file, const char *string, int error) { |
|
1123 int save = errno; |
|
1124 |
|
1125 if ((statp->options & RES_DEBUG) != 0U) |
|
1126 fprintf(file, "res_send: %s: %s\n", |
|
1127 string, strerror(error)); |
|
1128 errno = save; |
|
1129 } |
|
1130 |
|
1131 static int |
|
1132 sock_eq(struct sockaddr *a, struct sockaddr *b) { |
|
1133 struct sockaddr_in *a4, *b4; |
|
1134 struct sockaddr_in6 *a6, *b6; |
|
1135 |
|
1136 if (a->sa_family != b->sa_family) |
|
1137 return 0; |
|
1138 switch (a->sa_family) { |
|
1139 case AF_INET: |
|
1140 a4 = (struct sockaddr_in *)(void *)a; |
|
1141 b4 = (struct sockaddr_in *)(void *)b; |
|
1142 return a4->sin_port == b4->sin_port && |
|
1143 a4->sin_addr.s_addr == b4->sin_addr.s_addr; |
|
1144 case AF_INET6: |
|
1145 a6 = (struct sockaddr_in6 *)(void *)a; |
|
1146 b6 = (struct sockaddr_in6 *)(void *)b; |
|
1147 return a6->sin6_port == b6->sin6_port && |
|
1148 #ifdef HAVE_SIN6_SCOPE_ID |
|
1149 a6->sin6_scope_id == b6->sin6_scope_id && |
|
1150 #endif |
|
1151 IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); |
|
1152 default: |
|
1153 return 0; |
|
1154 } |
|
1155 } |
|
1156 |
|
1157 #ifdef NEED_PSELECT |
|
1158 /* XXX needs to move to the porting library. */ |
|
1159 static int |
|
1160 pselect(int nfds, void *rfds, void *wfds, void *efds, |
|
1161 struct timespec *tsp, const sigset_t *sigmask) |
|
1162 { |
|
1163 struct timeval tv, *tvp; |
|
1164 sigset_t sigs; |
|
1165 int n; |
|
1166 |
|
1167 if (tsp) { |
|
1168 tvp = &tv; |
|
1169 tv = evTimeVal(*tsp); |
|
1170 } else |
|
1171 tvp = NULL; |
|
1172 if (sigmask) |
|
1173 sigprocmask(SIG_SETMASK, sigmask, &sigs); |
|
1174 n = select(nfds, rfds, wfds, efds, tvp); |
|
1175 if (sigmask) |
|
1176 sigprocmask(SIG_SETMASK, &sigs, NULL); |
|
1177 if (tsp) |
|
1178 *tsp = evTimeSpec(tv); |
|
1179 return (n); |
|
1180 } |
|
1181 #endif |