2 * Copyright (c) 1985, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
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.
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
55 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
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.
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
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 */
77 * Send query to name server and wait for reply.
81 #include "port_before.h"
82 #include "fd_setsize.h"
85 #include <sys/types.h>
86 #include <sys/param.h>
88 #include <sys/socket.h>
91 #include <netinet/in.h>
92 #include <arpa/nameser.h>
93 #include <arpa/inet.h>
107 #include <net/if_dl.h>
108 #include "res_private.h"
111 #include <isc/eventlib.h>
112 #include "port_after.h"
116 #define ISC_SOCKLEN_T unsigned int
119 /* Options. Leave them on. */
121 #define CANNOT_CONNECT_DGRAM
126 #include "res_debug.h"
127 #include "res_private.h"
128 #include <sys/fcntl.h>
130 #define EXT(res) ((res)->_u._ext)
132 static const int highestFD
= FD_SETSIZE
- 1;
134 #define MAX_HOOK_RETRIES 42
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
*);
145 static int pselect(int, void *, void *, void *, struct timespec
*, const sigset_t
*);
148 static const int niflags
= NI_NUMERICHOST
| NI_NUMERICSERV
;
149 static int interrupt_pipe_enabled
= 0;
150 static pthread_key_t interrupt_pipe_key
;
153 res_delete_interrupt_token(void *token
)
157 interrupt_pipe
= token
;
158 if (interrupt_pipe
== NULL
) return;
160 if (interrupt_pipe
[0] >= 0)
162 close(interrupt_pipe
[0]);
163 interrupt_pipe
[0] = -1;
166 if (interrupt_pipe
[1] >= 0)
168 close(interrupt_pipe
[1]);
169 interrupt_pipe
[1] = -1;
172 pthread_setspecific(interrupt_pipe_key
, NULL
);
173 free(interrupt_pipe
);
177 res_init_interrupt_token(void)
181 interrupt_pipe
= (int *)malloc(2 * sizeof(int));
182 if (interrupt_pipe
== NULL
) return NULL
;
184 if (pipe(interrupt_pipe
) < 0)
186 /* this shouldn't happen */
187 interrupt_pipe
[0] = -1;
188 interrupt_pipe
[1] = -1;
192 fcntl(interrupt_pipe
[0], F_SETFD
, FD_CLOEXEC
| O_NONBLOCK
);
193 fcntl(interrupt_pipe
[1], F_SETFD
, FD_CLOEXEC
| O_NONBLOCK
);
196 pthread_setspecific(interrupt_pipe_key
, interrupt_pipe
);
198 return interrupt_pipe
;
202 res_interrupt_requests_enable(void)
204 interrupt_pipe_enabled
= 1;
205 pthread_key_create(&interrupt_pipe_key
, NULL
);
209 res_interrupt_requests_disable(void)
211 interrupt_pipe_enabled
= 0;
212 pthread_key_delete(interrupt_pipe_key
);
216 res_interrupt_request(void *token
)
221 interrupt_pipe
= token
;
223 if ((interrupt_pipe
== NULL
) || (interrupt_pipe_enabled
== 0)) return;
225 oldwrite
= interrupt_pipe
[1];
226 interrupt_pipe
[1] = -1;
228 if (oldwrite
>= 0) close(oldwrite
);
233 evConsIovec(void *buf
, size_t cnt
)
237 memset(&ret
, 0xf5, sizeof ret
);
243 static struct timespec
244 evConsTime(time_t sec
, long nsec
)
253 static struct timespec
254 evTimeSpec(struct timeval tv
)
258 ts
.tv_sec
= tv
.tv_sec
;
259 ts
.tv_nsec
= tv
.tv_usec
* 1000;
263 static struct timespec
268 if (gettimeofday(&now
, NULL
) < 0) return (evConsTime(0, 0));
269 return (evTimeSpec(now
));
273 static struct timeval
274 evTimeVal(struct timespec ts
)
278 tv
.tv_sec
= ts
.tv_sec
;
279 tv
.tv_usec
= ts
.tv_nsec
/ 1000;
284 #define BILLION 1000000000
285 static struct timespec
286 evAddTime(struct timespec addend1
, struct timespec addend2
)
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
)
295 x
.tv_nsec
-= BILLION
;
301 static struct timespec
302 evSubTime(struct timespec minuend
, struct timespec subtrahend
)
306 x
.tv_sec
= minuend
.tv_sec
- subtrahend
.tv_sec
;
307 if (minuend
.tv_nsec
>= subtrahend
.tv_nsec
)
309 x
.tv_nsec
= minuend
.tv_nsec
- subtrahend
.tv_nsec
;
313 x
.tv_nsec
= BILLION
- subtrahend
.tv_nsec
+ minuend
.tv_nsec
;
321 evCmpTime(struct timespec a
, struct timespec b
)
323 long x
= a
.tv_sec
- b
.tv_sec
;
325 if (x
== 0L) x
= a
.tv_nsec
- b
.tv_nsec
;
326 return (x
< 0L ? (-1) : x
> 0L ? (1) : (0));
329 #endif /* __APPLE__ */
334 * res_isourserver(ina)
335 * looks up "ina" in _res.ns_addr_list[]
340 * paul vixie, 29may94
343 res_ourserver_p(const res_state statp
, const struct sockaddr
*sa
)
345 const struct sockaddr_in
*inp
, *srv
;
346 const struct sockaddr_in6
*in6p
, *srv6
;
349 switch (sa
->sa_family
)
352 inp
= (const struct sockaddr_in
*)sa
;
353 for (ns
= 0; ns
< statp
->nscount
; ns
++)
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
))
364 if (EXT(statp
).ext
== NULL
) break;
365 in6p
= (const struct sockaddr_in6
*)sa
;
366 for (ns
= 0; ns
< statp
->nscount
; ns
++)
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
)))
383 * res_nameinquery(name, type, class, buf, eom)
384 * look for (name,type,class) in the query section of packet (buf,eom)
386 * buf + NS_HFIXEDSZ <= eom
392 * paul vixie, 29may94
395 res_nameinquery(const char *name
, int type
, int class, const u_char
*buf
, const u_char
*eom
)
397 const u_char
*cp
= buf
+ NS_HFIXEDSZ
;
398 int qdcount
= ntohs(((const HEADER
*)buf
)->qdcount
);
400 while (qdcount
-- > 0)
402 char tname
[NS_MAXDNAME
+1];
403 int n
, ttype
, tclass
;
405 n
= dn_expand(buf
, eom
, cp
, tname
, sizeof tname
);
406 if (n
< 0) return (-1);
409 if (cp
+ 2 * NS_INT16SZ
> eom
) return (-1);
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);
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)?
425 * 0 : not a 1:1 mapping
426 * >0 : is a 1:1 mapping
428 * paul vixie, 29may94
431 res_queriesmatch(const u_char
*buf1
, const u_char
*eom1
, const u_char
*buf2
, const u_char
*eom2
)
433 const u_char
*cp
= buf1
+ NS_HFIXEDSZ
;
434 int qdcount
= ntohs(((const HEADER
*)buf1
)->qdcount
);
436 if (buf1
+ NS_HFIXEDSZ
> eom1
|| buf2
+ NS_HFIXEDSZ
> eom2
)
440 * Only header section present in replies to
441 * dynamic update packets.
443 if ((((const HEADER
*)buf1
)->opcode
== ns_o_update
) &&
444 (((const HEADER
*)buf2
)->opcode
== ns_o_update
))
447 if (qdcount
!= ntohs(((const HEADER
*)buf2
)->qdcount
)) return (0);
449 while (qdcount
-- > 0)
451 char tname
[NS_MAXDNAME
+1];
452 int n
, ttype
, tclass
;
454 n
= dn_expand(buf1
, eom1
, cp
, tname
, sizeof tname
);
455 if (n
< 0) return (-1);
458 if (cp
+ 2 * NS_INT16SZ
> eom1
) return (-1);
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);
469 dns_res_send(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int *anssiz
, struct sockaddr
*from
, int *fromlen
)
471 int gotsomewhere
, terrno
, try, v_circuit
, resplen
, ns
;
472 char abuf
[NI_MAXHOST
];
474 int notify_token
, status
, send_status
, reply_buf_size
;
475 uint64_t exit_requested
;
477 if (statp
->nscount
== 0)
480 return DNS_RES_STATUS_INVALID_RES_STATE
;
483 reply_buf_size
= *anssiz
;
484 if (reply_buf_size
< NS_HFIXEDSZ
)
487 return DNS_RES_STATUS_INVALID_ARGUMENT
;
490 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_QUERY
), (stdout
, ";; res_send()\n"), buf
, buflen
);
492 v_circuit
= (statp
->options
& RES_USEVC
) || (buflen
> NS_PACKETSZ
);
498 * If the ns_addr_list in the resolver context has changed, then
499 * invalidate our cached copy and the associated timing data.
501 if (EXT(statp
).nscount
!= 0)
504 struct sockaddr_storage peer
;
505 ISC_SOCKLEN_T peerlen
;
507 if (EXT(statp
).nscount
!= statp
->nscount
)
513 for (ns
= 0; ns
< statp
->nscount
; ns
++)
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
])))
521 if (EXT(statp
).nssocks
[ns
] == -1) continue;
523 peerlen
= sizeof(peer
);
524 if (getsockname(EXT(statp
).nssocks
[ns
], (struct sockaddr
*)&peer
, &peerlen
) < 0)
530 if (!sock_eq((struct sockaddr
*)&peer
, get_nsaddr(statp
, ns
)))
541 EXT(statp
).nscount
= 0;
546 * Maybe initialize our private copy of the ns_addr_list.
548 if (EXT(statp
).nscount
== 0)
550 for (ns
= 0; ns
< statp
->nscount
; ns
++)
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
];
558 EXT(statp
).nscount
= statp
->nscount
;
562 * Some resolvers want to even out the load on their nameservers.
563 * Note that RES_BLAST overrides RES_ROTATE.
565 if (((statp
->options
& RES_ROTATE
) != 0) && ((statp
->options
& RES_BLAST
) == 0))
567 union res_sockaddr_union inu
;
568 struct sockaddr_in ina
;
569 int lastns
= statp
->nscount
- 1;
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];
578 for (ns
= 0; ns
< lastns
; ns
++)
580 if (EXT(statp
).ext
!= NULL
)
582 EXT(statp
).ext
->nsaddrs
[ns
] =EXT(statp
).ext
->nsaddrs
[ns
+ 1];
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];
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
;
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.
604 asprintf(¬ify_name
, "self.thread.%lu", (unsigned long)pthread_self());
605 if (notify_name
!= NULL
)
607 status
= notify_register_plain(notify_name
, ¬ify_token
);
612 * Send request, RETRY times, or until successful.
614 for (try = 0; try < statp
->retry
; try++)
616 for (ns
= 0; ns
< statp
->nscount
; ns
++)
618 struct sockaddr
*nsap
;
620 nsap
= get_nsaddr(statp
, ns
);
621 nsaplen
= get_salen(nsap
);
627 int done
= 0, loops
= 0;
633 act
= (*statp
->qhook
)(&nsap
, &buf
, &buflen
, ans
, reply_buf_size
, &resplen
);
643 if (notify_token
!= -1) notify_cancel(notify_token
);
644 return DNS_RES_STATUS_CANCELLED
;
646 /* give the hook another try */
647 if (++loops
< MAX_HOOK_RETRIES
) break;
652 if (notify_token
!= -1) notify_cancel(notify_token
);
653 return DNS_RES_STATUS_CANCELLED
;
658 if (notify_token
!= -1)
661 status
= notify_get_state(notify_token
, &exit_requested
);
662 if (exit_requested
== ThreadStateExitRequested
)
664 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
666 notify_cancel(notify_token
);
667 return DNS_RES_STATUS_CANCELLED
;
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
));
673 send_status
= ns_r_noerror
;
677 /* Use VC; at most one attempt per server. */
680 *anssiz
= reply_buf_size
;
681 send_status
= send_vc(statp
, buf
, buflen
, ans
, anssiz
, &terrno
, ns
, from
, fromlen
, notify_token
);
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
;
690 if ((send_status
== DNS_RES_STATUS_SYSTEM_ERROR
) || (send_status
== DNS_RES_STATUS_CANCELLED
))
693 if (notify_token
!= -1) notify_cancel(notify_token
);
697 if (send_status
!= ns_r_noerror
) goto send_next_ns
;
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
);
703 * If we have temporarily opened a virtual circuit,
704 * or if we haven't been asked to keep a socket open,
707 if (((v_circuit
!= 0) && (statp
->options
& RES_USEVC
) == 0) || (statp
->options
& RES_STAYOPEN
) == 0) res_nclose(statp
);
711 int done
= 0, loops
= 0;
717 act
= (*statp
->rhook
)(nsap
, buf
, buflen
, ans
, *anssiz
, &resplen
);
728 /* give the hook another try */
729 if (++loops
< MAX_HOOK_RETRIES
) break;
735 if (notify_token
!= -1) notify_cancel(notify_token
);
736 return DNS_RES_STATUS_CANCELLED
;
742 if (notify_token
!= -1) notify_cancel(notify_token
);
747 } /* foreach retry */
750 if (notify_token
!= -1) notify_cancel(notify_token
);
755 if (gotsomewhere
!= 0)
757 errno
= ECONNREFUSED
;
758 return DNS_RES_STATUS_CONNECTION_REFUSED
;
762 return DNS_RES_STATUS_TIMEOUT
;
771 res_nsend_2(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int anssiz
, struct sockaddr
*from
, int *fromlen
)
776 status
= dns_res_send(statp
, buf
, buflen
, ans
, &len
, from
, fromlen
);
777 if (status
!= ns_r_noerror
) len
= -1;
782 res_nsend(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int anssiz
)
784 struct sockaddr_storage from
;
787 fromlen
= sizeof(struct sockaddr_storage
);
789 return res_nsend_2(statp
, buf
, buflen
, ans
, anssiz
, (struct sockaddr
*)&from
, &fromlen
);
795 get_salen(const struct sockaddr
*sa
)
798 /* There are people do not set sa_len. Be forgiving to them. */
799 if (sa
->sa_len
) return (sa
->sa_len
);
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 */
808 * pick appropriate nsaddr_list for use. see res_init() for initialization.
811 get_nsaddr(res_state statp
, size_t n
)
813 if ((!statp
->nsaddr_list
[n
].sin_family
) && (EXT(statp
).ext
!= NULL
))
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].
820 return (struct sockaddr
*)(void *)&EXT(statp
).ext
->nsaddrs
[n
];
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].
829 return (struct sockaddr
*)(void *)&statp
->nsaddr_list
[n
];
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
)
836 const HEADER
*hp
= (const HEADER
*) buf
;
837 HEADER
*anhp
= (HEADER
*) ans
;
838 struct sockaddr
*nsap
;
840 int truncating
, connreset
, resplen
, n
;
846 uint64_t exit_requested
;
848 nsap
= get_nsaddr(statp
, ns
);
849 nsaplen
= get_salen(nsap
);
855 if (notify_token
!= -1)
858 status
= notify_get_state(notify_token
, &exit_requested
);
859 if (exit_requested
== ThreadStateExitRequested
)
861 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
863 return DNS_RES_STATUS_CANCELLED
;
869 /* Are we still talking to whom we want to talk? */
870 if (statp
->_vcsock
>= 0 && (statp
->_flags
& RES_F_VC
) != 0)
872 struct sockaddr_storage peer
;
873 ISC_SOCKLEN_T size
= sizeof peer
;
875 if (getpeername(statp
->_vcsock
, (struct sockaddr
*)&peer
, &size
) < 0 || !sock_eq((struct sockaddr
*)&peer
, nsap
))
878 statp
->_flags
&= ~RES_F_VC
;
882 if ((statp
->_vcsock
< 0) || ((statp
->_flags
& RES_F_VC
) == 0))
884 if (statp
->_vcsock
>= 0) res_nclose(statp
);
886 statp
->_vcsock
= socket(nsap
->sa_family
, SOCK_STREAM
, 0);
887 if (statp
->_vcsock
> highestFD
)
893 if (statp
->_vcsock
< 0)
896 Perror(statp
, stderr
, "socket(vc)", errno
);
897 return DNS_RES_STATUS_SYSTEM_ERROR
;
901 if (connect(statp
->_vcsock
, nsap
, nsaplen
) < 0)
904 Aerror(statp
, stderr
, "connect(vc)", errno
, nsap
, nsaplen
);
906 return DNS_RES_STATUS_CONNECTION_REFUSED
;
909 statp
->_flags
|= RES_F_VC
;
913 * Send length & message
915 putshort((u_short
)buflen
, (u_char
*)&len
);
916 iov
[0] = evConsIovec(&len
, NS_INT16SZ
);
922 iov
[1] = evConsIovec(tmp
, buflen
);
923 if (writev(statp
->_vcsock
, iov
, 2) != (NS_INT16SZ
+ buflen
))
926 Perror(statp
, stderr
, "write failed", errno
);
928 return DNS_RES_STATUS_CONNECTION_FAILED
;
932 * Receive length & response
936 if (notify_token
!= -1)
939 status
= notify_get_state(notify_token
, &exit_requested
);
940 if (exit_requested
== ThreadStateExitRequested
)
942 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
944 return DNS_RES_STATUS_CANCELLED
;
950 while ((n
= read(statp
->_vcsock
, (char *)cp
, (int)len
)) > 0)
953 if ((len
-= n
) <= 0) break;
959 Perror(statp
, stderr
, "read failed", errno
);
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.
971 if (*terrno
== ECONNRESET
&& !connreset
)
979 return DNS_RES_STATUS_CONNECTION_FAILED
;
982 resplen
= ns_get16(ans
);
983 if (resplen
> *anssiz
)
985 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; response truncated\n"));
994 if (len
< NS_HFIXEDSZ
)
997 * Undersized message.
999 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; undersized: %d\n", len
));
1003 return DNS_RES_STATUS_INVALID_REPLY
;
1007 while (len
!= 0 && (n
= read(statp
->_vcsock
, (char *)cp
, (int)len
)) > 0)
1016 Perror(statp
, stderr
, "read(vc)", errno
);
1018 return DNS_RES_STATUS_CONNECTION_FAILED
;
1024 * Flush rest of answer so connection stays in synch.
1027 len
= resplen
- *anssiz
;
1030 char junk
[NS_PACKETSZ
];
1032 n
= read(statp
->_vcsock
, junk
, (len
> sizeof junk
) ? sizeof junk
: len
);
1033 if (n
> 0) len
-= n
;
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.
1045 if (hp
->id
!= anhp
->id
)
1047 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; old answer (unexpected):\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1052 * All is well, or the error is fatal. Signal that the
1053 * next nameserver ought not be tried.
1056 *fromlen
= sizeof(nsap
);
1057 memcpy(from
, &nsap
, *fromlen
);
1059 return ns_r_noerror
;
1063 internal_recvfrom(int s
, void *buf
, size_t len
, struct sockaddr
*from
, int *fromlen
, int *iface
)
1065 struct sockaddr_dl
*sdl
;
1066 struct iovec databuffers
= { buf
, len
};
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
;
1075 memset(&msg
, 0, sizeof(struct msghdr
));
1076 msg
.msg_name
= (caddr_t
)from
;
1077 msg
.msg_namelen
= *fromlen
;
1078 msg
.msg_iov
= &databuffers
;
1080 msg
.msg_control
= (caddr_t
)&ancillary
;
1081 msg
.msg_controllen
= sizeof(ancillary
);
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
))
1090 *fromlen
= msg
.msg_namelen
;
1092 s4
= (struct sockaddr_in
*)from
;
1093 s6
= (struct sockaddr_in6
*)from
;
1095 for (cmp
= CMSG_FIRSTHDR(&msg
); cmp
; cmp
= CMSG_NXTHDR(&msg
, cmp
))
1097 if ((cmp
->cmsg_level
== IPPROTO_IP
) && (cmp
->cmsg_type
== IP_RECVIF
))
1099 sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmp
);
1100 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1102 memcpy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1103 ifname
[sdl
->sdl_nlen
] = 0;
1104 *iface
= if_nametoindex(ifname
);
1107 else if ((cmp
->cmsg_level
== IPPROTO_IPV6
) && (cmp
->cmsg_type
== IPV6_PKTINFO
))
1109 ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmp
);
1110 *iface
= ip6_info
->ipi6_ifindex
;
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
)
1120 const HEADER
*hp
= (const HEADER
*) buf
;
1121 HEADER
*anhp
= (HEADER
*) ans
;
1122 const struct sockaddr
*nsap
;
1124 struct timespec now
, timeout
, finish
;
1126 int iface
, rif
, status
;
1127 uint64_t exit_requested
;
1128 int *interrupt_pipe
;
1130 struct sockaddr_storage from
;
1131 ISC_SOCKLEN_T fromlen
;
1133 int resplen
, seconds
, ntry
, n
, s
;
1138 interrupt_pipe
= NULL
;
1140 nsap
= get_nsaddr(statp
, ns
);
1141 nsaplen
= get_salen(nsap
);
1142 if (EXT(statp
).nssocks
[ns
] == -1)
1144 EXT(statp
).nssocks
[ns
] = socket(nsap
->sa_family
, SOCK_DGRAM
, 0);
1145 if (EXT(statp
).nssocks
[ns
] > highestFD
)
1151 if (EXT(statp
).nssocks
[ns
] < 0)
1154 Perror(statp
, stderr
, "socket(dg)", errno
);
1155 return DNS_RES_STATUS_SYSTEM_ERROR
;
1158 #ifndef CANNOT_CONNECT_DGRAM
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.
1170 if (connect(EXT(statp
).nssocks
[ns
], nsap
, nsaplen
) < 0)
1172 Aerror(statp
, stderr
, "connect(dg)", errno
, nsap
, nsaplen
);
1174 return DNS_RES_STATUS_CONNECTION_REFUSED
;
1177 #endif /* !CANNOT_CONNECT_DGRAM */
1178 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; new DG socket\n"))
1181 s
= EXT(statp
).nssocks
[ns
];
1183 setsockopt(s
, IPPROTO_IP
, IP_RECVIF
, &rif
, sizeof(int));
1184 setsockopt(s
, IPPROTO_IPV6
, IPV6_PKTINFO
, &rif
, sizeof(int));
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
;
1194 struct ifaddrs
*ifa
, *p
;
1195 struct sockaddr_in
*sin4
;
1196 struct sockaddr_in6
*sin6
;
1199 if (getifaddrs(&ifa
) < 0)
1201 Aerror(statp
, stderr
, "getifaddrs", errno
, nsap
, nsaplen
);
1203 return DNS_RES_STATUS_SYSTEM_ERROR
;
1206 for (p
= ifa
; p
!= NULL
; p
= p
->ifa_next
)
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)
1214 if ((multicast
== AF_INET
) && (ntohl(((struct sockaddr_in
*)nsap
)->sin_addr
.s_addr
) <= INADDR_MAX_LOCAL_GROUP
)) continue;
1217 sin4
= (struct sockaddr_in
*)p
->ifa_addr
;
1218 sin6
= (struct sockaddr_in6
*)p
->ifa_addr
;
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
)
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
));
1230 Aerror(statp
, stderr
, "setsockopt", errno
, nsap
, nsaplen
);
1231 if (multicast
== AF_INET6
) ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= 0;
1236 if (sendto(s
, (const char*)buf
, buflen
, 0, nsap
, nsaplen
) != buflen
)
1238 Aerror(statp
, stderr
, "sendto", errno
, nsap
, nsaplen
);
1239 if (multicast
== AF_INET6
) ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= 0;
1243 if (multicast
== AF_INET6
) ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= 0;
1251 #endif /* MULTICAST */
1253 #ifndef CANNOT_CONNECT_DGRAM
1254 if (send(s
, (const char*)buf
, buflen
, 0) != buflen
)
1256 Perror(statp
, stderr
, "send", errno
);
1258 return DNS_RES_STATUS_CONNECTION_FAILED
;
1261 #else /* !CANNOT_CONNECT_DGRAM */
1262 if (sendto(s
, (const char*)buf
, buflen
, 0, nsap
, nsaplen
) != buflen
)
1264 Aerror(statp
, stderr
, "sendto", errno
, nsap
, nsaplen
);
1266 return DNS_RES_STATUS_CONNECTION_FAILED
;
1268 #endif /* !CANNOT_CONNECT_DGRAM */
1272 #endif /* MULTICAST */
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;
1285 finish
= evAddTime(now
, timeout
);
1287 if (interrupt_pipe_enabled
!= 0) interrupt_pipe
= pthread_getspecific(interrupt_pipe_key
);
1289 seconds
= (statp
->retrans
<< ns
);
1290 if (ns
> 0) seconds
/= statp
->nscount
;
1291 if (seconds
<= 0) seconds
= 1;
1293 timeout
= evConsTime(seconds
, 0);
1294 finish
= evAddTime(now
, timeout
);
1295 #endif /* __APPLE__ */
1303 if (notify_token
!= -1)
1306 status
= notify_get_state(notify_token
, &exit_requested
);
1307 if (exit_requested
== ThreadStateExitRequested
)
1309 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
1310 return DNS_RES_STATUS_CANCELLED
;
1318 if ((interrupt_pipe_enabled
!= 0) && (interrupt_pipe
!= NULL
))
1320 if (interrupt_pipe
[0] >= 0)
1322 FD_SET(interrupt_pipe
[0], &dsmask
);
1323 nfds
= MAX(s
, interrupt_pipe
[0]) + 1;
1327 if (evCmpTime(finish
, now
) > 0) timeout
= evSubTime(finish
, now
);
1328 else timeout
= evConsTime(0, 0);
1330 n
= pselect(nfds
, &dsmask
, NULL
, NULL
, &timeout
, NULL
);
1333 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; timeout\n"));
1335 return DNS_RES_STATUS_TIMEOUT
;
1340 if (errno
== EINTR
) goto wait
;
1341 Perror(statp
, stderr
, "select", errno
);
1343 return DNS_RES_STATUS_SYSTEM_ERROR
;
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
))))
1349 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
1350 return DNS_RES_STATUS_CANCELLED
;
1355 resplen
= internal_recvfrom(s
, (char *)ans
, *anssiz
, from
, fromlen
, &iface
);
1358 Perror(statp
, stderr
, "recvfrom", errno
);
1360 return DNS_RES_STATUS_CONNECTION_FAILED
;
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
;
1367 if (resplen
< NS_HFIXEDSZ
)
1370 * Undersized message.
1372 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; undersized: %d\n", resplen
));
1375 return DNS_RES_STATUS_INVALID_REPLY
;
1378 if (hp
->id
!= anhp
->id
)
1381 * response from old query, ignore it.
1382 * XXX - potential security hazard could
1385 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; old answer:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1392 #endif /* MULTICAST */
1394 if (!(statp
->options
& RES_INSECURE1
) && !res_ourserver_p(statp
, from
))
1397 * response from wrong server? ignore it.
1398 * XXX - potential security hazard could
1401 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; not our server:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1407 #endif /* MULTICAST */
1409 #ifdef RES_USE_EDNS0
1410 if (anhp
->rcode
== ns_r_formerr
&& (statp
->options
& RES_USE_EDNS0
) != 0)
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.
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
;
1421 return DNS_RES_STATUS_CONNECTION_REFUSED
;
1425 if (!(statp
->options
& RES_INSECURE2
) && !res_queriesmatch(buf
, buf
+ buflen
, ans
, ans
+ *anssiz
))
1428 * response contains wrong query? ignore it.
1429 * XXX - potential security hazard could
1432 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; wrong query name:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1434 return DNS_RES_STATUS_INVALID_REPLY
;
1437 if (anhp
->rcode
== ns_r_servfail
|| anhp
->rcode
== ns_r_notimpl
|| anhp
->rcode
== ns_r_refused
)
1439 DprintQ(statp
->options
& RES_DEBUG
, (stdout
, "server rejected query:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1441 /* don't retry if called from dig */
1442 if (!statp
->pfcode
) return anhp
->rcode
;
1445 if (!(statp
->options
& RES_IGNTC
) && anhp
->tc
)
1448 * To get the rest of answer,
1449 * use TCP with same server.
1451 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; truncated answer\n"));
1454 return ns_r_noerror
;
1458 * All is well, or the error is fatal. Signal that the
1459 * next nameserver ought not be tried.
1462 return ns_r_noerror
;
1466 Aerror(const res_state statp
, FILE *file
, const char *string
, int error
, const struct sockaddr
*address
, int alen
)
1469 char hbuf
[NI_MAXHOST
];
1470 char sbuf
[NI_MAXSERV
];
1474 if ((statp
->options
& RES_DEBUG
) != 0)
1476 if (getnameinfo(address
, alen
, hbuf
, sizeof(hbuf
), sbuf
, sizeof(sbuf
), niflags
))
1478 strncpy(hbuf
, "?", sizeof(hbuf
) - 1);
1479 hbuf
[sizeof(hbuf
) - 1] = '\0';
1480 strncpy(sbuf
, "?", sizeof(sbuf
) - 1);
1481 sbuf
[sizeof(sbuf
) - 1] = '\0';
1484 fprintf(file
, "res_send: %s ([%s].%s): %s\n", string
, hbuf
, sbuf
, strerror(error
));
1491 Perror(const res_state statp
, FILE *file
, const char *string
, int error
)
1495 if ((statp
->options
& RES_DEBUG
) != 0) fprintf(file
, "res_send: %s: %s\n", string
, strerror(error
));
1500 sock_eq(struct sockaddr
*a
, struct sockaddr
*b
)
1502 struct sockaddr_in
*a4
, *b4
;
1503 struct sockaddr_in6
*a6
, *b6
;
1505 if (a
->sa_family
!= b
->sa_family
) return 0;
1507 switch (a
->sa_family
)
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
;
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
&&
1520 IN6_ARE_ADDR_EQUAL(&a6
->sin6_addr
, &b6
->sin6_addr
);
1527 /* XXX needs to move to the porting library. */
1529 pselect(int nfds
, void *rfds
, void *wfds
, void *efds
, struct timespec
*tsp
, const sigset_t
*sigmask
)
1531 struct timeval tv
, *tvp
= NULL
;
1538 tv
= evTimeVal(*tsp
);
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
);