]> git.saurik.com Git - apple/libresolv.git/blob - res_send.c
libresolv-25.tar.gz
[apple/libresolv.git] / res_send.c
1 /*
2 * Copyright (c) 1985, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
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.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36 *
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
43 *
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * SOFTWARE.
52 */
53
54 /*
55 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
56 *
57 * Permission to use, copy, modify, and distribute this software for any
58 * purpose with or without fee is hereby granted, provided that the above
59 * copyright notice and this permission notice appear in all copies.
60 *
61 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
62 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
64 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
68 * SOFTWARE.
69 */
70
71 #if defined(LIBC_SCCS) && !defined(lint)
72 static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
73 static const char rcsid[] = "$Id: res_send.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
74 #endif /* LIBC_SCCS and not lint */
75
76 /*
77 * Send query to name server and wait for reply.
78 */
79
80 #ifndef __APPLE__
81 #include "port_before.h"
82 #include "fd_setsize.h"
83 #endif
84
85 #include <sys/types.h>
86 #include <sys/param.h>
87 #include <sys/time.h>
88 #include <sys/socket.h>
89 #include <sys/uio.h>
90
91 #include <netinet/in.h>
92 #include <arpa/nameser.h>
93 #include <arpa/inet.h>
94
95 #include <errno.h>
96 #include <netdb.h>
97 #include <resolv.h>
98 #include <signal.h>
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <notify.h>
102 #include <pthread.h>
103 #include <string.h>
104 #include <unistd.h>
105 #include <ifaddrs.h>
106 #include <net/if.h>
107 #include <net/if_dl.h>
108 #include "res_private.h"
109
110 #ifndef __APPLE__
111 #include <isc/eventlib.h>
112 #include "port_after.h"
113 #endif
114
115 #ifdef __APPLE__
116 #define ISC_SOCKLEN_T unsigned int
117 #endif
118
119 /* Options. Leave them on. */
120 #define DEBUG
121 #define CANNOT_CONNECT_DGRAM
122 #ifdef __APPLE__
123 #define MULTICAST
124 #endif
125
126 #include "res_debug.h"
127 #include "res_private.h"
128 #include <sys/fcntl.h>
129
130 #define EXT(res) ((res)->_u._ext)
131
132 static const int highestFD = FD_SETSIZE - 1;
133
134 #define MAX_HOOK_RETRIES 42
135
136 /* Forward. */
137
138 static int get_salen __P((const struct sockaddr *));
139 static int send_vc(res_state, const u_char *, int, u_char *, int *, int *, int, struct sockaddr *, int *, int);
140 static int send_dg(res_state, const u_char *, int, u_char *, int *, int *, int, int *, int *, struct sockaddr *, int *, int);
141 static void Aerror(const res_state, FILE *, const char *, int, const struct sockaddr *, int);
142 static void Perror(const res_state, FILE *, const char *, int);
143 static int sock_eq(struct sockaddr *, struct sockaddr *);
144 #ifdef NEED_PSELECT
145 static int pselect(int, void *, void *, void *, struct timespec *, const sigset_t *);
146 #endif
147
148 static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
149 static int interrupt_pipe_enabled = 0;
150 static pthread_key_t interrupt_pipe_key;
151
152 void
153 res_delete_interrupt_token(void *token)
154 {
155 int *interrupt_pipe;
156
157 interrupt_pipe = token;
158 if (interrupt_pipe == NULL) return;
159
160 if (interrupt_pipe[0] >= 0)
161 {
162 close(interrupt_pipe[0]);
163 interrupt_pipe[0] = -1;
164 }
165
166 if (interrupt_pipe[1] >= 0)
167 {
168 close(interrupt_pipe[1]);
169 interrupt_pipe[1] = -1;
170 }
171
172 pthread_setspecific(interrupt_pipe_key, NULL);
173 free(interrupt_pipe);
174 }
175
176 void *
177 res_init_interrupt_token(void)
178 {
179 int *interrupt_pipe;
180
181 interrupt_pipe = (int *)malloc(2 * sizeof(int));
182 if (interrupt_pipe == NULL) return NULL;
183
184 if (pipe(interrupt_pipe) < 0)
185 {
186 /* this shouldn't happen */
187 interrupt_pipe[0] = -1;
188 interrupt_pipe[1] = -1;
189 }
190 else
191 {
192 fcntl(interrupt_pipe[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
193 fcntl(interrupt_pipe[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
194 }
195
196 pthread_setspecific(interrupt_pipe_key, interrupt_pipe);
197
198 return interrupt_pipe;
199 }
200
201 void
202 res_interrupt_requests_enable(void)
203 {
204 interrupt_pipe_enabled = 1;
205 pthread_key_create(&interrupt_pipe_key, NULL);
206 }
207
208 void
209 res_interrupt_requests_disable(void)
210 {
211 interrupt_pipe_enabled = 0;
212 pthread_key_delete(interrupt_pipe_key);
213 }
214
215 void
216 res_interrupt_request(void *token)
217 {
218 int oldwrite;
219 int *interrupt_pipe;
220
221 interrupt_pipe = token;
222
223 if ((interrupt_pipe == NULL) || (interrupt_pipe_enabled == 0)) return;
224
225 oldwrite = interrupt_pipe[1];
226 interrupt_pipe[1] = -1;
227
228 if (oldwrite >= 0) close(oldwrite);
229 }
230
231 #ifdef __APPLE__
232 static struct iovec
233 evConsIovec(void *buf, size_t cnt)
234 {
235 struct iovec ret;
236
237 memset(&ret, 0xf5, sizeof ret);
238 ret.iov_base = buf;
239 ret.iov_len = cnt;
240 return (ret);
241 }
242
243 static struct timespec
244 evConsTime(time_t sec, long nsec)
245 {
246 struct timespec x;
247
248 x.tv_sec = sec;
249 x.tv_nsec = nsec;
250 return (x);
251 }
252
253 static struct timespec
254 evTimeSpec(struct timeval tv)
255 {
256 struct timespec ts;
257
258 ts.tv_sec = tv.tv_sec;
259 ts.tv_nsec = tv.tv_usec * 1000;
260 return (ts);
261 }
262
263 static struct timespec
264 evNowTime()
265 {
266 struct timeval now;
267
268 if (gettimeofday(&now, NULL) < 0) return (evConsTime(0, 0));
269 return (evTimeSpec(now));
270 }
271
272 #ifdef NEED_PSELECT
273 static struct timeval
274 evTimeVal(struct timespec ts)
275 {
276 struct timeval tv;
277
278 tv.tv_sec = ts.tv_sec;
279 tv.tv_usec = ts.tv_nsec / 1000;
280 return (tv);
281 }
282 #endif
283
284 #define BILLION 1000000000
285 static struct timespec
286 evAddTime(struct timespec addend1, struct timespec addend2)
287 {
288 struct timespec x;
289
290 x.tv_sec = addend1.tv_sec + addend2.tv_sec;
291 x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
292 if (x.tv_nsec >= BILLION)
293 {
294 x.tv_sec++;
295 x.tv_nsec -= BILLION;
296 }
297
298 return (x);
299 }
300
301 static struct timespec
302 evSubTime(struct timespec minuend, struct timespec subtrahend)
303 {
304 struct timespec x;
305
306 x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
307 if (minuend.tv_nsec >= subtrahend.tv_nsec)
308 {
309 x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
310 }
311 else
312 {
313 x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
314 x.tv_sec--;
315 }
316
317 return (x);
318 }
319
320 static int
321 evCmpTime(struct timespec a, struct timespec b)
322 {
323 long x = a.tv_sec - b.tv_sec;
324
325 if (x == 0L) x = a.tv_nsec - b.tv_nsec;
326 return (x < 0L ? (-1) : x > 0L ? (1) : (0));
327 }
328
329 #endif /* __APPLE__ */
330
331 /* Public. */
332
333 /* int
334 * res_isourserver(ina)
335 * looks up "ina" in _res.ns_addr_list[]
336 * returns:
337 * 0 : not found
338 * >0 : found
339 * author:
340 * paul vixie, 29may94
341 */
342 int
343 res_ourserver_p(const res_state statp, const struct sockaddr *sa)
344 {
345 const struct sockaddr_in *inp, *srv;
346 const struct sockaddr_in6 *in6p, *srv6;
347 int ns;
348
349 switch (sa->sa_family)
350 {
351 case AF_INET:
352 inp = (const struct sockaddr_in *)sa;
353 for (ns = 0; ns < statp->nscount; ns++)
354 {
355 srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
356 if (srv->sin_family == inp->sin_family &&
357 srv->sin_port == inp->sin_port &&
358 (srv->sin_addr.s_addr == INADDR_ANY ||
359 srv->sin_addr.s_addr == inp->sin_addr.s_addr))
360 return (1);
361 }
362 break;
363 case AF_INET6:
364 if (EXT(statp).ext == NULL) break;
365 in6p = (const struct sockaddr_in6 *)sa;
366 for (ns = 0; ns < statp->nscount; ns++)
367 {
368 srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
369 if (srv6->sin6_family == in6p->sin6_family &&
370 srv6->sin6_port == in6p->sin6_port &&
371 (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
372 IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
373 return (1);
374 }
375 break;
376 default:
377 break;
378 }
379 return (0);
380 }
381
382 /* int
383 * res_nameinquery(name, type, class, buf, eom)
384 * look for (name,type,class) in the query section of packet (buf,eom)
385 * requires:
386 * buf + NS_HFIXEDSZ <= eom
387 * returns:
388 * -1 : format error
389 * 0 : not found
390 * >0 : found
391 * author:
392 * paul vixie, 29may94
393 */
394 int
395 res_nameinquery(const char *name, int type, int class, const u_char *buf, const u_char *eom)
396 {
397 const u_char *cp = buf + NS_HFIXEDSZ;
398 int qdcount = ntohs(((const HEADER*)buf)->qdcount);
399
400 while (qdcount-- > 0)
401 {
402 char tname[NS_MAXDNAME+1];
403 int n, ttype, tclass;
404
405 n = dn_expand(buf, eom, cp, tname, sizeof tname);
406 if (n < 0) return (-1);
407
408 cp += n;
409 if (cp + 2 * NS_INT16SZ > eom) return (-1);
410
411 ttype = ns_get16(cp); cp += NS_INT16SZ;
412 tclass = ns_get16(cp); cp += NS_INT16SZ;
413 if (ttype == type && tclass == class && ns_samename(tname, name) == 1) return (1);
414 }
415
416 return (0);
417 }
418
419 /* int
420 * res_queriesmatch(buf1, eom1, buf2, eom2)
421 * is there a 1:1 mapping of (name,type,class)
422 * in (buf1,eom1) and (buf2,eom2)?
423 * returns:
424 * -1 : format error
425 * 0 : not a 1:1 mapping
426 * >0 : is a 1:1 mapping
427 * author:
428 * paul vixie, 29may94
429 */
430 int
431 res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2, const u_char *eom2)
432 {
433 const u_char *cp = buf1 + NS_HFIXEDSZ;
434 int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
435
436 if (buf1 + NS_HFIXEDSZ > eom1 || buf2 + NS_HFIXEDSZ > eom2)
437 return (-1);
438
439 /*
440 * Only header section present in replies to
441 * dynamic update packets.
442 */
443 if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
444 (((const HEADER *)buf2)->opcode == ns_o_update))
445 return (1);
446
447 if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) return (0);
448
449 while (qdcount-- > 0)
450 {
451 char tname[NS_MAXDNAME+1];
452 int n, ttype, tclass;
453
454 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
455 if (n < 0) return (-1);
456
457 cp += n;
458 if (cp + 2 * NS_INT16SZ > eom1) return (-1);
459
460 ttype = ns_get16(cp); cp += NS_INT16SZ;
461 tclass = ns_get16(cp); cp += NS_INT16SZ;
462 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) return (0);
463 }
464
465 return (1);
466 }
467
468 int
469 dns_res_send(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, struct sockaddr *from, int *fromlen)
470 {
471 int gotsomewhere, terrno, try, v_circuit, resplen, ns;
472 char abuf[NI_MAXHOST];
473 char *notify_name;
474 int notify_token, status, send_status, reply_buf_size;
475 uint64_t exit_requested;
476
477 if (statp->nscount == 0)
478 {
479 errno = ESRCH;
480 return DNS_RES_STATUS_INVALID_RES_STATE;
481 }
482
483 reply_buf_size = *anssiz;
484 if (reply_buf_size < NS_HFIXEDSZ)
485 {
486 errno = EINVAL;
487 return DNS_RES_STATUS_INVALID_ARGUMENT;
488 }
489
490 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), (stdout, ";; res_send()\n"), buf, buflen);
491
492 v_circuit = (statp->options & RES_USEVC) || (buflen > NS_PACKETSZ);
493 gotsomewhere = 0;
494 send_status = 0;
495 terrno = ETIMEDOUT;
496
497 /*
498 * If the ns_addr_list in the resolver context has changed, then
499 * invalidate our cached copy and the associated timing data.
500 */
501 if (EXT(statp).nscount != 0)
502 {
503 int needclose = 0;
504 struct sockaddr_storage peer;
505 ISC_SOCKLEN_T peerlen;
506
507 if (EXT(statp).nscount != statp->nscount)
508 {
509 needclose++;
510 }
511 else
512 {
513 for (ns = 0; ns < statp->nscount; ns++)
514 {
515 if ((statp->nsaddr_list[ns].sin_family) && (EXT(statp).ext != NULL) && (!sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])))
516 {
517 needclose++;
518 break;
519 }
520
521 if (EXT(statp).nssocks[ns] == -1) continue;
522
523 peerlen = sizeof(peer);
524 if (getsockname(EXT(statp).nssocks[ns], (struct sockaddr *)&peer, &peerlen) < 0)
525 {
526 needclose++;
527 break;
528 }
529
530 if (!sock_eq((struct sockaddr *)&peer, get_nsaddr(statp, ns)))
531 {
532 needclose++;
533 break;
534 }
535 }
536 }
537
538 if (needclose)
539 {
540 res_nclose(statp);
541 EXT(statp).nscount = 0;
542 }
543 }
544
545 /*
546 * Maybe initialize our private copy of the ns_addr_list.
547 */
548 if (EXT(statp).nscount == 0)
549 {
550 for (ns = 0; ns < statp->nscount; ns++)
551 {
552 EXT(statp).nstimes[ns] = RES_MAXTIME;
553 EXT(statp).nssocks[ns] = -1;
554 if (!statp->nsaddr_list[ns].sin_family) continue;
555 if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[ns].sin = statp->nsaddr_list[ns];
556 }
557
558 EXT(statp).nscount = statp->nscount;
559 }
560
561 /*
562 * Some resolvers want to even out the load on their nameservers.
563 * Note that RES_BLAST overrides RES_ROTATE.
564 */
565 if (((statp->options & RES_ROTATE) != 0) && ((statp->options & RES_BLAST) == 0))
566 {
567 union res_sockaddr_union inu;
568 struct sockaddr_in ina;
569 int lastns = statp->nscount - 1;
570 int fd;
571 u_int16_t nstime;
572
573 if (EXT(statp).ext != NULL) inu = EXT(statp).ext->nsaddrs[0];
574 ina = statp->nsaddr_list[0];
575 fd = EXT(statp).nssocks[0];
576 nstime = EXT(statp).nstimes[0];
577
578 for (ns = 0; ns < lastns; ns++)
579 {
580 if (EXT(statp).ext != NULL)
581 {
582 EXT(statp).ext->nsaddrs[ns] =EXT(statp).ext->nsaddrs[ns + 1];
583 }
584
585 statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
586 EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
587 EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
588 }
589
590 if (EXT(statp).ext != NULL) EXT(statp).ext->nsaddrs[lastns] = inu;
591 statp->nsaddr_list[lastns] = ina;
592 EXT(statp).nssocks[lastns] = fd;
593 EXT(statp).nstimes[lastns] = nstime;
594 }
595
596 /*
597 * Get notification token
598 * we use a self-notification token to allow a caller
599 * to signal the thread doing this DNS query to quit.
600 */
601 notify_name = NULL;
602 notify_token = -1;
603
604 asprintf(&notify_name, "self.thread.%lu", (unsigned long)pthread_self());
605 if (notify_name != NULL)
606 {
607 status = notify_register_plain(notify_name, &notify_token);
608 free(notify_name);
609 }
610
611 /*
612 * Send request, RETRY times, or until successful.
613 */
614 for (try = 0; try < statp->retry; try++)
615 {
616 for (ns = 0; ns < statp->nscount; ns++)
617 {
618 struct sockaddr *nsap;
619 int nsaplen;
620 nsap = get_nsaddr(statp, ns);
621 nsaplen = get_salen(nsap);
622
623 send_same_ns:
624
625 if (statp->qhook)
626 {
627 int done = 0, loops = 0;
628
629 do
630 {
631 res_sendhookact act;
632
633 act = (*statp->qhook)(&nsap, &buf, &buflen, ans, reply_buf_size, &resplen);
634 switch (act)
635 {
636 case res_goahead:
637 done = 1;
638 break;
639 case res_nextns:
640 res_nclose(statp);
641 goto send_next_ns;
642 case res_done:
643 if (notify_token != -1) notify_cancel(notify_token);
644 return DNS_RES_STATUS_CANCELLED;
645 case res_modified:
646 /* give the hook another try */
647 if (++loops < MAX_HOOK_RETRIES) break;
648 /*FALLTHROUGH*/
649 case res_error:
650 /*FALLTHROUGH*/
651 default:
652 if (notify_token != -1) notify_cancel(notify_token);
653 return DNS_RES_STATUS_CANCELLED;
654 }
655 } while (!done);
656 }
657
658 if (notify_token != -1)
659 {
660 exit_requested = 0;
661 status = notify_get_state(notify_token, &exit_requested);
662 if (exit_requested == ThreadStateExitRequested)
663 {
664 Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
665 res_nclose(statp);
666 notify_cancel(notify_token);
667 return DNS_RES_STATUS_CANCELLED;
668 }
669 }
670
671 Dprint(((statp->options & RES_DEBUG) && getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), NULL, 0, niflags) == 0), (stdout, ";; Querying server (# %d) address = %s\n", ns + 1, abuf));
672
673 send_status = ns_r_noerror;
674
675 if (v_circuit != 0)
676 {
677 /* Use VC; at most one attempt per server. */
678 try = statp->retry;
679
680 *anssiz = reply_buf_size;
681 send_status = send_vc(statp, buf, buflen, ans, anssiz, &terrno, ns, from, fromlen, notify_token);
682 }
683 else
684 {
685 /* Use datagrams. */
686 send_status = send_dg(statp, buf, buflen, ans, anssiz, &terrno, ns, &v_circuit, &gotsomewhere, from, fromlen, notify_token);
687 if (v_circuit != 0) goto send_same_ns;
688 }
689
690 if ((send_status == DNS_RES_STATUS_SYSTEM_ERROR) || (send_status == DNS_RES_STATUS_CANCELLED))
691 {
692 res_nclose(statp);
693 if (notify_token != -1) notify_cancel(notify_token);
694 return send_status;
695 }
696
697 if (send_status != ns_r_noerror) goto send_next_ns;
698
699 Dprint((statp->options & RES_DEBUG) || ((statp->pfcode & RES_PRF_REPLY) && (statp->pfcode & RES_PRF_HEAD1)), (stdout, ";; got answer:\n"));
700 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, "%s", ""), ans, (*anssiz > reply_buf_size) ? reply_buf_size : *anssiz);
701
702 /*
703 * If we have temporarily opened a virtual circuit,
704 * or if we haven't been asked to keep a socket open,
705 * close the socket.
706 */
707 if (((v_circuit != 0) && (statp->options & RES_USEVC) == 0) || (statp->options & RES_STAYOPEN) == 0) res_nclose(statp);
708
709 if (statp->rhook)
710 {
711 int done = 0, loops = 0;
712
713 do
714 {
715 res_sendhookact act;
716
717 act = (*statp->rhook)(nsap, buf, buflen, ans, *anssiz, &resplen);
718 switch (act)
719 {
720 case res_goahead:
721 case res_done:
722 done = 1;
723 break;
724 case res_nextns:
725 res_nclose(statp);
726 goto send_next_ns;
727 case res_modified:
728 /* give the hook another try */
729 if (++loops < MAX_HOOK_RETRIES) break;
730 /*FALLTHROUGH*/
731 case res_error:
732 /*FALLTHROUGH*/
733 default:
734 res_nclose(statp);
735 if (notify_token != -1) notify_cancel(notify_token);
736 return DNS_RES_STATUS_CANCELLED;
737 }
738 } while (!done);
739
740 }
741
742 if (notify_token != -1) notify_cancel(notify_token);
743 return ns_r_noerror;
744
745 send_next_ns: ;
746 } /* foreach ns */
747 } /* foreach retry */
748
749 res_nclose(statp);
750 if (notify_token != -1) notify_cancel(notify_token);
751
752 if (v_circuit == 0)
753 {
754 /* used datagrams */
755 if (gotsomewhere != 0)
756 {
757 errno = ECONNREFUSED;
758 return DNS_RES_STATUS_CONNECTION_REFUSED;
759 }
760
761 errno = ETIMEDOUT;
762 return DNS_RES_STATUS_TIMEOUT;
763 }
764
765 /* used v_circuit */
766 errno = terrno;
767 return send_status;
768 }
769
770 int
771 res_nsend_2(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz, struct sockaddr *from, int *fromlen)
772 {
773 int len, status;
774
775 len = anssiz;
776 status = dns_res_send(statp, buf, buflen, ans, &len, from, fromlen);
777 if (status != ns_r_noerror) len = -1;
778 return len;
779 }
780
781 int
782 res_nsend(res_state statp, const u_char *buf, int buflen, u_char *ans, int anssiz)
783 {
784 struct sockaddr_storage from;
785 int fromlen;
786
787 fromlen = sizeof(struct sockaddr_storage);
788
789 return res_nsend_2(statp, buf, buflen, ans, anssiz, (struct sockaddr *)&from, &fromlen);
790 }
791
792 /* Private */
793
794 static int
795 get_salen(const struct sockaddr *sa)
796 {
797 #ifdef HAVE_SA_LEN
798 /* There are people do not set sa_len. Be forgiving to them. */
799 if (sa->sa_len) return (sa->sa_len);
800 #endif
801
802 if (sa->sa_family == AF_INET) return (sizeof(struct sockaddr_in));
803 else if (sa->sa_family == AF_INET6) return (sizeof(struct sockaddr_in6));
804 else return (0); /* unknown, die on connect */
805 }
806
807 /*
808 * pick appropriate nsaddr_list for use. see res_init() for initialization.
809 */
810 struct sockaddr *
811 get_nsaddr(res_state statp, size_t n)
812 {
813 if ((!statp->nsaddr_list[n].sin_family) && (EXT(statp).ext != NULL))
814 {
815 /*
816 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
817 * than struct sockaddr, and
818 * - user code did not update statp->nsaddr_list[n].
819 */
820 return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
821 }
822 else
823 {
824 /*
825 * - user code updated statp->nsaddr_list[n], or
826 * - statp->nsaddr_list[n] has the same content as
827 * EXT(statp).ext->nsaddrs[n].
828 */
829 return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
830 }
831 }
832
833 static int
834 send_vc(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, int *terrno, int ns, struct sockaddr *from, int *fromlen, int notify_token)
835 {
836 const HEADER *hp = (const HEADER *) buf;
837 HEADER *anhp = (HEADER *) ans;
838 struct sockaddr *nsap;
839 int nsaplen;
840 int truncating, connreset, resplen, n;
841 struct iovec iov[2];
842 u_short len;
843 u_char *cp;
844 void *tmp;
845 int status;
846 uint64_t exit_requested;
847
848 nsap = get_nsaddr(statp, ns);
849 nsaplen = get_salen(nsap);
850
851 connreset = 0;
852
853 vc_same_ns:
854
855 if (notify_token != -1)
856 {
857 exit_requested = 0;
858 status = notify_get_state(notify_token, &exit_requested);
859 if (exit_requested == ThreadStateExitRequested)
860 {
861 Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
862 *terrno = EINTR;
863 return DNS_RES_STATUS_CANCELLED;
864 }
865 }
866
867 truncating = 0;
868
869 /* Are we still talking to whom we want to talk? */
870 if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0)
871 {
872 struct sockaddr_storage peer;
873 ISC_SOCKLEN_T size = sizeof peer;
874
875 if (getpeername(statp->_vcsock, (struct sockaddr *)&peer, &size) < 0 || !sock_eq((struct sockaddr *)&peer, nsap))
876 {
877 res_nclose(statp);
878 statp->_flags &= ~RES_F_VC;
879 }
880 }
881
882 if ((statp->_vcsock < 0) || ((statp->_flags & RES_F_VC) == 0))
883 {
884 if (statp->_vcsock >= 0) res_nclose(statp);
885
886 statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
887 if (statp->_vcsock > highestFD)
888 {
889 res_nclose(statp);
890 errno = ENOTSOCK;
891 }
892
893 if (statp->_vcsock < 0)
894 {
895 *terrno = errno;
896 Perror(statp, stderr, "socket(vc)", errno);
897 return DNS_RES_STATUS_SYSTEM_ERROR;
898 }
899
900 errno = 0;
901 if (connect(statp->_vcsock, nsap, nsaplen) < 0)
902 {
903 *terrno = errno;
904 Aerror(statp, stderr, "connect(vc)", errno, nsap, nsaplen);
905 res_nclose(statp);
906 return DNS_RES_STATUS_CONNECTION_REFUSED;
907 }
908
909 statp->_flags |= RES_F_VC;
910 }
911
912 /*
913 * Send length & message
914 */
915 putshort((u_short)buflen, (u_char*)&len);
916 iov[0] = evConsIovec(&len, NS_INT16SZ);
917 #ifdef __APPLE__
918 tmp = (char *)buf;
919 #else
920 DE_CONST(buf, tmp);
921 #endif
922 iov[1] = evConsIovec(tmp, buflen);
923 if (writev(statp->_vcsock, iov, 2) != (NS_INT16SZ + buflen))
924 {
925 *terrno = errno;
926 Perror(statp, stderr, "write failed", errno);
927 res_nclose(statp);
928 return DNS_RES_STATUS_CONNECTION_FAILED;
929 }
930
931 /*
932 * Receive length & response
933 */
934 read_len:
935
936 if (notify_token != -1)
937 {
938 exit_requested = 0;
939 status = notify_get_state(notify_token, &exit_requested);
940 if (exit_requested == ThreadStateExitRequested)
941 {
942 Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
943 *terrno = EINTR;
944 return DNS_RES_STATUS_CANCELLED;
945 }
946 }
947
948 cp = ans;
949 len = NS_INT16SZ;
950 while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0)
951 {
952 cp += n;
953 if ((len -= n) <= 0) break;
954 }
955
956 if (n <= 0)
957 {
958 *terrno = errno;
959 Perror(statp, stderr, "read failed", errno);
960 res_nclose(statp);
961
962 /*
963 * A long running process might get its TCP
964 * connection reset if the remote server was
965 * restarted. Requery the server instead of
966 * trying a new one. When there is only one
967 * server, this means that a query might work
968 * instead of failing. We only allow one reset
969 * per query to prevent looping.
970 */
971 if (*terrno == ECONNRESET && !connreset)
972 {
973 connreset = 1;
974 res_nclose(statp);
975 goto vc_same_ns;
976 }
977
978 res_nclose(statp);
979 return DNS_RES_STATUS_CONNECTION_FAILED;
980 }
981
982 resplen = ns_get16(ans);
983 if (resplen > *anssiz)
984 {
985 Dprint(statp->options & RES_DEBUG, (stdout, ";; response truncated\n"));
986 truncating = 1;
987 len = *anssiz;
988 }
989 else
990 {
991 len = resplen;
992 }
993
994 if (len < NS_HFIXEDSZ)
995 {
996 /*
997 * Undersized message.
998 */
999 Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", len));
1000 *terrno = EMSGSIZE;
1001 res_nclose(statp);
1002 *anssiz = 0;
1003 return DNS_RES_STATUS_INVALID_REPLY;
1004 }
1005
1006 cp = ans;
1007 while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0)
1008 {
1009 cp += n;
1010 len -= n;
1011 }
1012
1013 if (n <= 0)
1014 {
1015 *terrno = errno;
1016 Perror(statp, stderr, "read(vc)", errno);
1017 res_nclose(statp);
1018 return DNS_RES_STATUS_CONNECTION_FAILED;
1019 }
1020
1021 if (truncating)
1022 {
1023 /*
1024 * Flush rest of answer so connection stays in synch.
1025 */
1026 anhp->tc = 1;
1027 len = resplen - *anssiz;
1028 while (len != 0)
1029 {
1030 char junk[NS_PACKETSZ];
1031
1032 n = read(statp->_vcsock, junk, (len > sizeof junk) ? sizeof junk : len);
1033 if (n > 0) len -= n;
1034 else break;
1035 }
1036 }
1037
1038 /*
1039 * If the calling applicating has bailed out of
1040 * a previous call and failed to arrange to have
1041 * the circuit closed or the server has got
1042 * itself confused, then drop the packet and
1043 * wait for the correct one.
1044 */
1045 if (hp->id != anhp->id)
1046 {
1047 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer (unexpected):\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
1048 goto read_len;
1049 }
1050
1051 /*
1052 * All is well, or the error is fatal. Signal that the
1053 * next nameserver ought not be tried.
1054 */
1055
1056 *fromlen = sizeof(nsap);
1057 memcpy(from, &nsap, *fromlen);
1058 *anssiz = resplen;
1059 return ns_r_noerror;
1060 }
1061
1062 static ssize_t
1063 internal_recvfrom(int s, void *buf, size_t len, struct sockaddr *from, int *fromlen, int *iface)
1064 {
1065 struct sockaddr_dl *sdl;
1066 struct iovec databuffers = { buf, len };
1067 struct msghdr msg;
1068 ssize_t n;
1069 struct cmsghdr *cmp;
1070 char ancillary[1024], ifname[IF_NAMESIZE];
1071 struct in6_pktinfo *ip6_info;
1072 struct sockaddr_in *s4;
1073 struct sockaddr_in6 *s6;
1074
1075 memset(&msg, 0, sizeof(struct msghdr));
1076 msg.msg_name = (caddr_t)from;
1077 msg.msg_namelen = *fromlen;
1078 msg.msg_iov = &databuffers;
1079 msg.msg_iovlen = 1;
1080 msg.msg_control = (caddr_t)&ancillary;
1081 msg.msg_controllen = sizeof(ancillary);
1082
1083 /* Receive the data */
1084 n = recvmsg(s, &msg, 0);
1085 if ((n < 0) || (msg.msg_controllen < sizeof(struct cmsghdr)) || (msg.msg_flags & MSG_CTRUNC))
1086 {
1087 return n;
1088 }
1089
1090 *fromlen = msg.msg_namelen;
1091
1092 s4 = (struct sockaddr_in *)from;
1093 s6 = (struct sockaddr_in6 *)from;
1094
1095 for (cmp = CMSG_FIRSTHDR(&msg); cmp; cmp = CMSG_NXTHDR(&msg, cmp))
1096 {
1097 if ((cmp->cmsg_level == IPPROTO_IP) && (cmp->cmsg_type == IP_RECVIF))
1098 {
1099 sdl = (struct sockaddr_dl *)CMSG_DATA(cmp);
1100 if (sdl->sdl_nlen < IF_NAMESIZE)
1101 {
1102 memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen);
1103 ifname[sdl->sdl_nlen] = 0;
1104 *iface = if_nametoindex(ifname);
1105 }
1106 }
1107 else if ((cmp->cmsg_level == IPPROTO_IPV6) && (cmp->cmsg_type == IPV6_PKTINFO))
1108 {
1109 ip6_info = (struct in6_pktinfo *)CMSG_DATA(cmp);
1110 *iface = ip6_info->ipi6_ifindex;
1111 }
1112 }
1113
1114 return n;
1115 }
1116
1117 static int
1118 send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans, int *anssiz, int *terrno, int ns, int *v_circuit, int *gotsomewhere, struct sockaddr *from, int *fromlen, int notify_token)
1119 {
1120 const HEADER *hp = (const HEADER *) buf;
1121 HEADER *anhp = (HEADER *) ans;
1122 const struct sockaddr *nsap;
1123 int nsaplen, nfds;
1124 struct timespec now, timeout, finish;
1125 fd_set dsmask;
1126 int iface, rif, status;
1127 uint64_t exit_requested;
1128 int *interrupt_pipe;
1129 #ifndef __APPLE__
1130 struct sockaddr_storage from;
1131 ISC_SOCKLEN_T fromlen;
1132 #endif
1133 int resplen, seconds, ntry, n, s;
1134 #ifdef MULTICAST
1135 int multicast;
1136 #endif
1137
1138 interrupt_pipe = NULL;
1139
1140 nsap = get_nsaddr(statp, ns);
1141 nsaplen = get_salen(nsap);
1142 if (EXT(statp).nssocks[ns] == -1)
1143 {
1144 EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
1145 if (EXT(statp).nssocks[ns] > highestFD)
1146 {
1147 res_nclose(statp);
1148 errno = ENOTSOCK;
1149 }
1150
1151 if (EXT(statp).nssocks[ns] < 0)
1152 {
1153 *terrno = errno;
1154 Perror(statp, stderr, "socket(dg)", errno);
1155 return DNS_RES_STATUS_SYSTEM_ERROR;
1156 }
1157
1158 #ifndef CANNOT_CONNECT_DGRAM
1159 /*
1160 * On a 4.3BSD+ machine (client and server,
1161 * actually), sending to a nameserver datagram
1162 * port with no nameserver will cause an
1163 * ICMP port unreachable message to be returned.
1164 * If our datagram socket is "connected" to the
1165 * server, we get an ECONNREFUSED error on the next
1166 * socket operation, and select returns if the
1167 * error message is received. We can thus detect
1168 * the absence of a nameserver without timing out.
1169 */
1170 if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0)
1171 {
1172 Aerror(statp, stderr, "connect(dg)", errno, nsap, nsaplen);
1173 res_nclose(statp);
1174 return DNS_RES_STATUS_CONNECTION_REFUSED;
1175 }
1176
1177 #endif /* !CANNOT_CONNECT_DGRAM */
1178 Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n"))
1179 }
1180
1181 s = EXT(statp).nssocks[ns];
1182 rif = 1;
1183 setsockopt(s, IPPROTO_IP, IP_RECVIF, &rif, sizeof(int));
1184 setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &rif, sizeof(int));
1185
1186 #ifdef MULTICAST
1187 multicast = 0;
1188
1189 if ((nsap->sa_family == AF_INET) && (IN_MULTICAST(ntohl(((struct sockaddr_in *)nsap)->sin_addr.s_addr)))) multicast = AF_INET;
1190 else if ((nsap->sa_family == AF_INET6) && (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)nsap)->sin6_addr))) multicast = AF_INET6;
1191
1192 if (multicast != 0)
1193 {
1194 struct ifaddrs *ifa, *p;
1195 struct sockaddr_in *sin4;
1196 struct sockaddr_in6 *sin6;
1197 int i, ifnum;
1198
1199 if (getifaddrs(&ifa) < 0)
1200 {
1201 Aerror(statp, stderr, "getifaddrs", errno, nsap, nsaplen);
1202 res_nclose(statp);
1203 return DNS_RES_STATUS_SYSTEM_ERROR;
1204 }
1205
1206 for (p = ifa; p != NULL; p = p->ifa_next)
1207 {
1208 if (p->ifa_addr == NULL) continue;
1209 if ((p->ifa_flags & IFF_UP) == 0) continue;
1210 if (p->ifa_addr->sa_family != multicast) continue;
1211 if ((p->ifa_flags & IFF_MULTICAST) == 0) continue;
1212 if ((p->ifa_flags & IFF_POINTOPOINT) != 0)
1213 {
1214 if ((multicast == AF_INET) && (ntohl(((struct sockaddr_in *)nsap)->sin_addr.s_addr) <= INADDR_MAX_LOCAL_GROUP)) continue;
1215 }
1216
1217 sin4 = (struct sockaddr_in *)p->ifa_addr;
1218 sin6 = (struct sockaddr_in6 *)p->ifa_addr;
1219 i = -1;
1220 if (multicast == AF_INET) i = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &sin4->sin_addr, sizeof(sin4->sin_addr));
1221 else if (multicast == AF_INET6)
1222 {
1223 ifnum = if_nametoindex(p->ifa_name);
1224 ((struct sockaddr_in6 *)nsap)->sin6_scope_id = ifnum;
1225 i = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifnum, sizeof(ifnum));
1226 }
1227
1228 if (i < 0)
1229 {
1230 Aerror(statp, stderr, "setsockopt", errno, nsap, nsaplen);
1231 if (multicast == AF_INET6) ((struct sockaddr_in6 *)nsap)->sin6_scope_id = 0;
1232
1233 continue;
1234 }
1235
1236 if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
1237 {
1238 Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
1239 if (multicast == AF_INET6) ((struct sockaddr_in6 *)nsap)->sin6_scope_id = 0;
1240 continue;
1241 }
1242
1243 if (multicast == AF_INET6) ((struct sockaddr_in6 *)nsap)->sin6_scope_id = 0;
1244 }
1245
1246
1247 freeifaddrs(ifa);
1248 }
1249 else
1250 {
1251 #endif /* MULTICAST */
1252
1253 #ifndef CANNOT_CONNECT_DGRAM
1254 if (send(s, (const char*)buf, buflen, 0) != buflen)
1255 {
1256 Perror(statp, stderr, "send", errno);
1257 res_nclose(statp);
1258 return DNS_RES_STATUS_CONNECTION_FAILED;
1259 }
1260
1261 #else /* !CANNOT_CONNECT_DGRAM */
1262 if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
1263 {
1264 Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
1265 res_nclose(statp);
1266 return DNS_RES_STATUS_CONNECTION_FAILED;
1267 }
1268 #endif /* !CANNOT_CONNECT_DGRAM */
1269
1270 #ifdef MULTICAST
1271 }
1272 #endif /* MULTICAST */
1273
1274 /*
1275 * Wait for reply.
1276 */
1277 #ifdef __APPLE__
1278 ntry = statp->nscount * statp->retry;
1279 seconds = statp->retrans / ntry;
1280 if (seconds <= 0) seconds = 1;
1281 timeout.tv_sec = seconds;
1282 timeout.tv_nsec = ((statp->retrans - (seconds * ntry)) * 1000) / ntry;
1283 timeout.tv_nsec *= 1000000;
1284 now = evNowTime();
1285 finish = evAddTime(now, timeout);
1286
1287 if (interrupt_pipe_enabled != 0) interrupt_pipe = pthread_getspecific(interrupt_pipe_key);
1288 #else
1289 seconds = (statp->retrans << ns);
1290 if (ns > 0) seconds /= statp->nscount;
1291 if (seconds <= 0) seconds = 1;
1292 now = evNowTime();
1293 timeout = evConsTime(seconds, 0);
1294 finish = evAddTime(now, timeout);
1295 #endif /* __APPLE__ */
1296 goto nonow;
1297 wait:
1298
1299 now = evNowTime();
1300
1301 nonow:
1302
1303 if (notify_token != -1)
1304 {
1305 exit_requested = 0;
1306 status = notify_get_state(notify_token, &exit_requested);
1307 if (exit_requested == ThreadStateExitRequested)
1308 {
1309 Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
1310 return DNS_RES_STATUS_CANCELLED;
1311 }
1312 }
1313
1314 FD_ZERO(&dsmask);
1315 FD_SET(s, &dsmask);
1316
1317 nfds = s + 1;
1318 if ((interrupt_pipe_enabled != 0) && (interrupt_pipe != NULL))
1319 {
1320 if (interrupt_pipe[0] >= 0)
1321 {
1322 FD_SET(interrupt_pipe[0], &dsmask);
1323 nfds = MAX(s, interrupt_pipe[0]) + 1;
1324 }
1325 }
1326
1327 if (evCmpTime(finish, now) > 0) timeout = evSubTime(finish, now);
1328 else timeout = evConsTime(0, 0);
1329
1330 n = pselect(nfds, &dsmask, NULL, NULL, &timeout, NULL);
1331 if (n == 0)
1332 {
1333 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1334 *gotsomewhere = 1;
1335 return DNS_RES_STATUS_TIMEOUT;
1336 }
1337
1338 if (n < 0)
1339 {
1340 if (errno == EINTR) goto wait;
1341 Perror(statp, stderr, "select", errno);
1342 res_nclose(statp);
1343 return DNS_RES_STATUS_SYSTEM_ERROR;
1344 }
1345
1346 /* socket s and/or interrupt pipe got data */
1347 if ((interrupt_pipe_enabled != 0) && (interrupt_pipe != NULL) && ((interrupt_pipe[0] < 0) || (FD_ISSET(interrupt_pipe[0], &dsmask))))
1348 {
1349 Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
1350 return DNS_RES_STATUS_CANCELLED;
1351 }
1352
1353 errno = 0;
1354 iface = 0;
1355 resplen = internal_recvfrom(s, (char *)ans, *anssiz, from, fromlen, &iface);
1356 if (resplen <= 0)
1357 {
1358 Perror(statp, stderr, "recvfrom", errno);
1359 res_nclose(statp);
1360 return DNS_RES_STATUS_CONNECTION_FAILED;
1361 }
1362
1363 if (nsap->sa_family == AF_INET) memcpy(((struct sockaddr_in *)from)->sin_zero, &iface, 4);
1364 else if (nsap->sa_family == AF_INET6) ((struct sockaddr_in6 *)from)->sin6_scope_id = iface;
1365
1366 *gotsomewhere = 1;
1367 if (resplen < NS_HFIXEDSZ)
1368 {
1369 /*
1370 * Undersized message.
1371 */
1372 Dprint(statp->options & RES_DEBUG, (stdout, ";; undersized: %d\n", resplen));
1373 *terrno = EMSGSIZE;
1374 res_nclose(statp);
1375 return DNS_RES_STATUS_INVALID_REPLY;
1376 }
1377
1378 if (hp->id != anhp->id)
1379 {
1380 /*
1381 * response from old query, ignore it.
1382 * XXX - potential security hazard could
1383 * be detected here.
1384 */
1385 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; old answer:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
1386 goto wait;
1387 }
1388
1389 #ifdef MULTICAST
1390 if (multicast == 0)
1391 {
1392 #endif /* MULTICAST */
1393
1394 if (!(statp->options & RES_INSECURE1) && !res_ourserver_p(statp, from))
1395 {
1396 /*
1397 * response from wrong server? ignore it.
1398 * XXX - potential security hazard could
1399 * be detected here.
1400 */
1401 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; not our server:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
1402 goto wait;
1403 }
1404
1405 #ifdef MULTICAST
1406 }
1407 #endif /* MULTICAST */
1408
1409 #ifdef RES_USE_EDNS0
1410 if (anhp->rcode == ns_r_formerr && (statp->options & RES_USE_EDNS0) != 0)
1411 {
1412 /*
1413 * Do not retry if the server do not understand EDNS0.
1414 * The case has to be captured here, as FORMERR packet do not
1415 * carry query section, hence res_queriesmatch() returns 0.
1416 */
1417 DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query with EDNS0:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
1418 /* record the error */
1419 statp->_flags |= RES_F_EDNS0ERR;
1420 res_nclose(statp);
1421 return DNS_RES_STATUS_CONNECTION_REFUSED;
1422 }
1423 #endif
1424
1425 if (!(statp->options & RES_INSECURE2) && !res_queriesmatch(buf, buf + buflen, ans, ans + *anssiz))
1426 {
1427 /*
1428 * response contains wrong query? ignore it.
1429 * XXX - potential security hazard could
1430 * be detected here.
1431 */
1432 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_REPLY), (stdout, ";; wrong query name:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
1433 res_nclose(statp);
1434 return DNS_RES_STATUS_INVALID_REPLY;
1435 }
1436
1437 if (anhp->rcode == ns_r_servfail || anhp->rcode == ns_r_notimpl || anhp->rcode == ns_r_refused)
1438 {
1439 DprintQ(statp->options & RES_DEBUG, (stdout, "server rejected query:\n"), ans, (resplen > *anssiz) ? *anssiz : resplen);
1440 res_nclose(statp);
1441 /* don't retry if called from dig */
1442 if (!statp->pfcode) return anhp->rcode;
1443 }
1444
1445 if (!(statp->options & RES_IGNTC) && anhp->tc)
1446 {
1447 /*
1448 * To get the rest of answer,
1449 * use TCP with same server.
1450 */
1451 Dprint(statp->options & RES_DEBUG, (stdout, ";; truncated answer\n"));
1452 *v_circuit = 1;
1453 res_nclose(statp);
1454 return ns_r_noerror;
1455 }
1456
1457 /*
1458 * All is well, or the error is fatal. Signal that the
1459 * next nameserver ought not be tried.
1460 */
1461 *anssiz = resplen;
1462 return ns_r_noerror;
1463 }
1464
1465 static void
1466 Aerror(const res_state statp, FILE *file, const char *string, int error, const struct sockaddr *address, int alen)
1467 {
1468 int save = errno;
1469 char hbuf[NI_MAXHOST];
1470 char sbuf[NI_MAXSERV];
1471
1472 alen = alen;
1473
1474 if ((statp->options & RES_DEBUG) != 0)
1475 {
1476 if (getnameinfo(address, alen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), niflags))
1477 {
1478 strncpy(hbuf, "?", sizeof(hbuf) - 1);
1479 hbuf[sizeof(hbuf) - 1] = '\0';
1480 strncpy(sbuf, "?", sizeof(sbuf) - 1);
1481 sbuf[sizeof(sbuf) - 1] = '\0';
1482 }
1483
1484 fprintf(file, "res_send: %s ([%s].%s): %s\n", string, hbuf, sbuf, strerror(error));
1485 }
1486
1487 errno = save;
1488 }
1489
1490 static void
1491 Perror(const res_state statp, FILE *file, const char *string, int error)
1492 {
1493 int save = errno;
1494
1495 if ((statp->options & RES_DEBUG) != 0) fprintf(file, "res_send: %s: %s\n", string, strerror(error));
1496 errno = save;
1497 }
1498
1499 static int
1500 sock_eq(struct sockaddr *a, struct sockaddr *b)
1501 {
1502 struct sockaddr_in *a4, *b4;
1503 struct sockaddr_in6 *a6, *b6;
1504
1505 if (a->sa_family != b->sa_family) return 0;
1506
1507 switch (a->sa_family)
1508 {
1509 case AF_INET:
1510 a4 = (struct sockaddr_in *)a;
1511 b4 = (struct sockaddr_in *)b;
1512 return a4->sin_port == b4->sin_port && a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1513 case AF_INET6:
1514 a6 = (struct sockaddr_in6 *)a;
1515 b6 = (struct sockaddr_in6 *)b;
1516 return a6->sin6_port == b6->sin6_port &&
1517 #ifdef HAVE_SIN6_SCOPE_ID
1518 a6->sin6_scope_id == b6->sin6_scope_id &&
1519 #endif
1520 IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1521 default:
1522 return 0;
1523 }
1524 }
1525
1526 #ifdef NEED_PSELECT
1527 /* XXX needs to move to the porting library. */
1528 static int
1529 pselect(int nfds, void *rfds, void *wfds, void *efds, struct timespec *tsp, const sigset_t *sigmask)
1530 {
1531 struct timeval tv, *tvp = NULL;
1532 sigset_t sigs;
1533 int n;
1534
1535 if (tsp)
1536 {
1537 tvp = &tv;
1538 tv = evTimeVal(*tsp);
1539 }
1540
1541 if (sigmask) sigprocmask(SIG_SETMASK, sigmask, &sigs);
1542 n = select(nfds, rfds, wfds, efds, tvp);
1543 if (sigmask) sigprocmask(SIG_SETMASK, &sigs, NULL);
1544 if (tsp) *tsp = evTimeSpec(tv);
1545 return n;
1546 }
1547 #endif