Implement second fallback mode for DNS requests.
[glibc.git] / resolv / res_send.c
blob971a4afb6f6e63458a720b7f5bd129a4b883c677
1 /*
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
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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 * SOFTWARE.
51 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
53 * Permission to use, copy, modify, and distribute this software for any
54 * purpose with or without fee is hereby granted, provided that the above
55 * copyright notice and this permission notice appear in all copies.
57 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64 * SOFTWARE.
67 #if defined(LIBC_SCCS) && !defined(lint)
68 static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
69 static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixie Exp $";
70 #endif /* LIBC_SCCS and not lint */
73 * Send query to name server and wait for reply.
76 #include <assert.h>
77 #include <sys/types.h>
78 #include <sys/param.h>
79 #include <sys/time.h>
80 #include <sys/socket.h>
81 #include <sys/uio.h>
82 #include <sys/poll.h>
84 #include <netinet/in.h>
85 #include <arpa/nameser.h>
86 #include <arpa/inet.h>
87 #include <sys/ioctl.h>
89 #include <errno.h>
90 #include <fcntl.h>
91 #include <netdb.h>
92 #include <resolv.h>
93 #include <signal.h>
94 #include <stdio.h>
95 #include <stdlib.h>
96 #include <string.h>
97 #include <unistd.h>
98 #include <kernel-features.h>
100 #if PACKETSZ > 65536
101 #define MAXPACKET PACKETSZ
102 #else
103 #define MAXPACKET 65536
104 #endif
107 #ifndef __ASSUME_SOCK_CLOEXEC
108 static int __have_o_nonblock;
109 #else
110 # define __have_o_nonblock 0
111 #endif
114 /* From ev_streams.c. */
116 static inline void
117 __attribute ((always_inline))
118 evConsIovec(void *buf, size_t cnt, struct iovec *vec) {
119 memset(vec, 0xf5, sizeof (*vec));
120 vec->iov_base = buf;
121 vec->iov_len = cnt;
124 /* From ev_timers.c. */
126 #define BILLION 1000000000
128 static inline void
129 evConsTime(struct timespec *res, time_t sec, long nsec) {
130 res->tv_sec = sec;
131 res->tv_nsec = nsec;
134 static inline void
135 evAddTime(struct timespec *res, const struct timespec *addend1,
136 const struct timespec *addend2) {
137 res->tv_sec = addend1->tv_sec + addend2->tv_sec;
138 res->tv_nsec = addend1->tv_nsec + addend2->tv_nsec;
139 if (res->tv_nsec >= BILLION) {
140 res->tv_sec++;
141 res->tv_nsec -= BILLION;
145 static inline void
146 evSubTime(struct timespec *res, const struct timespec *minuend,
147 const struct timespec *subtrahend) {
148 res->tv_sec = minuend->tv_sec - subtrahend->tv_sec;
149 if (minuend->tv_nsec >= subtrahend->tv_nsec)
150 res->tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec;
151 else {
152 res->tv_nsec = (BILLION
153 - subtrahend->tv_nsec + minuend->tv_nsec);
154 res->tv_sec--;
158 static inline int
159 evCmpTime(struct timespec a, struct timespec b) {
160 long x = a.tv_sec - b.tv_sec;
162 if (x == 0L)
163 x = a.tv_nsec - b.tv_nsec;
164 return (x < 0L ? (-1) : x > 0L ? (1) : (0));
167 static inline void
168 evNowTime(struct timespec *res) {
169 struct timeval now;
171 if (gettimeofday(&now, NULL) < 0)
172 evConsTime(res, 0, 0);
173 else
174 TIMEVAL_TO_TIMESPEC (&now, res);
178 /* Options. Leave them on. */
179 /* #undef DEBUG */
180 #include "res_debug.h"
182 #define EXT(res) ((res)->_u._ext)
184 /* Forward. */
186 static int send_vc(res_state, const u_char *, int,
187 const u_char *, int,
188 u_char **, int *, int *, int, u_char **,
189 u_char **, int *, int *);
190 static int send_dg(res_state, const u_char *, int,
191 const u_char *, int,
192 u_char **, int *, int *, int,
193 int *, int *, u_char **,
194 u_char **, int *, int *);
195 #ifdef DEBUG
196 static void Aerror(const res_state, FILE *, const char *, int,
197 const struct sockaddr *);
198 static void Perror(const res_state, FILE *, const char *, int);
199 #endif
200 static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
202 /* Reachover. */
204 static void convaddr4to6(struct sockaddr_in6 *sa);
206 /* Public. */
208 /* int
209 * res_isourserver(ina)
210 * looks up "ina" in _res.ns_addr_list[]
211 * returns:
212 * 0 : not found
213 * >0 : found
214 * author:
215 * paul vixie, 29may94
218 res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
220 int ns;
222 if (inp->sin6_family == AF_INET) {
223 struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
224 in_port_t port = in4p->sin_port;
225 in_addr_t addr = in4p->sin_addr.s_addr;
227 for (ns = 0; ns < MAXNS; ns++) {
228 const struct sockaddr_in *srv =
229 (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
231 if ((srv != NULL) && (srv->sin_family == AF_INET) &&
232 (srv->sin_port == port) &&
233 (srv->sin_addr.s_addr == INADDR_ANY ||
234 srv->sin_addr.s_addr == addr))
235 return (1);
237 } else if (inp->sin6_family == AF_INET6) {
238 for (ns = 0; ns < MAXNS; ns++) {
239 const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
240 if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
241 (srv->sin6_port == inp->sin6_port) &&
242 !(memcmp(&srv->sin6_addr, &in6addr_any,
243 sizeof (struct in6_addr)) &&
244 memcmp(&srv->sin6_addr, &inp->sin6_addr,
245 sizeof (struct in6_addr))))
246 return (1);
249 return (0);
252 /* int
253 * res_nameinquery(name, type, class, buf, eom)
254 * look for (name,type,class) in the query section of packet (buf,eom)
255 * requires:
256 * buf + HFIXEDSZ <= eom
257 * returns:
258 * -1 : format error
259 * 0 : not found
260 * >0 : found
261 * author:
262 * paul vixie, 29may94
265 res_nameinquery(const char *name, int type, int class,
266 const u_char *buf, const u_char *eom)
268 const u_char *cp = buf + HFIXEDSZ;
269 int qdcount = ntohs(((HEADER*)buf)->qdcount);
271 while (qdcount-- > 0) {
272 char tname[MAXDNAME+1];
273 int n, ttype, tclass;
275 n = dn_expand(buf, eom, cp, tname, sizeof tname);
276 if (n < 0)
277 return (-1);
278 cp += n;
279 if (cp + 2 * INT16SZ > eom)
280 return (-1);
281 NS_GET16(ttype, cp);
282 NS_GET16(tclass, cp);
283 if (ttype == type && tclass == class &&
284 ns_samename(tname, name) == 1)
285 return (1);
287 return (0);
289 libresolv_hidden_def (res_nameinquery)
291 /* int
292 * res_queriesmatch(buf1, eom1, buf2, eom2)
293 * is there a 1:1 mapping of (name,type,class)
294 * in (buf1,eom1) and (buf2,eom2)?
295 * returns:
296 * -1 : format error
297 * 0 : not a 1:1 mapping
298 * >0 : is a 1:1 mapping
299 * author:
300 * paul vixie, 29may94
303 res_queriesmatch(const u_char *buf1, const u_char *eom1,
304 const u_char *buf2, const u_char *eom2)
306 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
307 return (-1);
310 * Only header section present in replies to
311 * dynamic update packets.
313 if ((((HEADER *)buf1)->opcode == ns_o_update) &&
314 (((HEADER *)buf2)->opcode == ns_o_update))
315 return (1);
317 /* Note that we initially do not convert QDCOUNT to the host byte
318 order. We can compare it with the second buffer's QDCOUNT
319 value without doing this. */
320 int qdcount = ((HEADER*)buf1)->qdcount;
321 if (qdcount != ((HEADER*)buf2)->qdcount)
322 return (0);
324 qdcount = htons (qdcount);
325 const u_char *cp = buf1 + HFIXEDSZ;
327 while (qdcount-- > 0) {
328 char tname[MAXDNAME+1];
329 int n, ttype, tclass;
331 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
332 if (n < 0)
333 return (-1);
334 cp += n;
335 if (cp + 2 * INT16SZ > eom1)
336 return (-1);
337 NS_GET16(ttype, cp);
338 NS_GET16(tclass, cp);
339 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
340 return (0);
342 return (1);
344 libresolv_hidden_def (res_queriesmatch)
347 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
348 const u_char *buf2, int buflen2,
349 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
350 int *nansp2, int *resplen2)
352 int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
354 if (statp->nscount == 0) {
355 __set_errno (ESRCH);
356 return (-1);
359 if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
360 __set_errno (EINVAL);
361 return (-1);
364 #ifdef USE_HOOKS
365 if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
366 if (anssiz < MAXPACKET && ansp) {
367 u_char *buf = malloc (MAXPACKET);
368 if (buf == NULL)
369 return (-1);
370 memcpy (buf, ans, HFIXEDSZ);
371 *ansp = buf;
372 ans = buf;
373 anssiz = MAXPACKET;
376 #endif
378 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
379 (stdout, ";; res_send()\n"), buf, buflen);
380 v_circuit = ((statp->options & RES_USEVC)
381 || buflen > PACKETSZ
382 || buflen2 > PACKETSZ);
383 gotsomewhere = 0;
384 terrno = ETIMEDOUT;
387 * If the ns_addr_list in the resolver context has changed, then
388 * invalidate our cached copy and the associated timing data.
390 if (EXT(statp).nsinit) {
391 int needclose = 0;
393 if (EXT(statp).nscount != statp->nscount)
394 needclose++;
395 else
396 for (ns = 0; ns < MAXNS; ns++) {
397 unsigned int map = EXT(statp).nsmap[ns];
398 if (map < MAXNS
399 && !sock_eq((struct sockaddr_in6 *)
400 &statp->nsaddr_list[map],
401 EXT(statp).nsaddrs[ns]))
403 needclose++;
404 break;
407 if (needclose)
408 __res_iclose(statp, false);
412 * Maybe initialize our private copy of the ns_addr_list.
414 if (EXT(statp).nsinit == 0) {
415 unsigned char map[MAXNS];
417 memset (map, MAXNS, sizeof (map));
418 for (n = 0; n < MAXNS; n++) {
419 ns = EXT(statp).nsmap[n];
420 if (ns < statp->nscount)
421 map[ns] = n;
422 else if (ns < MAXNS) {
423 free(EXT(statp).nsaddrs[n]);
424 EXT(statp).nsaddrs[n] = NULL;
425 EXT(statp).nsmap[n] = MAXNS;
428 n = statp->nscount;
429 if (statp->nscount > EXT(statp).nscount)
430 for (n = EXT(statp).nscount, ns = 0;
431 n < statp->nscount; n++) {
432 while (ns < MAXNS
433 && EXT(statp).nsmap[ns] != MAXNS)
434 ns++;
435 if (ns == MAXNS)
436 break;
437 EXT(statp).nsmap[ns] = n;
438 map[n] = ns++;
440 EXT(statp).nscount = n;
441 for (ns = 0; ns < EXT(statp).nscount; ns++) {
442 n = map[ns];
443 if (EXT(statp).nsaddrs[n] == NULL)
444 EXT(statp).nsaddrs[n] =
445 malloc(sizeof (struct sockaddr_in6));
446 if (EXT(statp).nsaddrs[n] != NULL) {
447 memset (mempcpy(EXT(statp).nsaddrs[n],
448 &statp->nsaddr_list[ns],
449 sizeof (struct sockaddr_in)),
450 '\0',
451 sizeof (struct sockaddr_in6)
452 - sizeof (struct sockaddr_in));
453 EXT(statp).nssocks[n] = -1;
454 n++;
457 EXT(statp).nsinit = 1;
461 * Some resolvers want to even out the load on their nameservers.
462 * Note that RES_BLAST overrides RES_ROTATE.
464 if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
465 (statp->options & RES_BLAST) == 0) {
466 struct sockaddr_in6 *ina;
467 unsigned int map;
469 n = 0;
470 while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
471 n++;
472 if (n < MAXNS) {
473 ina = EXT(statp).nsaddrs[n];
474 map = EXT(statp).nsmap[n];
475 for (;;) {
476 ns = n + 1;
477 while (ns < MAXNS
478 && EXT(statp).nsmap[ns] == MAXNS)
479 ns++;
480 if (ns == MAXNS)
481 break;
482 EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
483 EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
484 n = ns;
486 EXT(statp).nsaddrs[n] = ina;
487 EXT(statp).nsmap[n] = map;
492 * Send request, RETRY times, or until successful.
494 for (try = 0; try < statp->retry; try++) {
495 for (ns = 0; ns < MAXNS; ns++)
497 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
499 if (nsap == NULL)
500 goto next_ns;
501 same_ns:
502 #ifdef USE_HOOKS
503 if (__builtin_expect (statp->qhook != NULL, 0)) {
504 int done = 0, loops = 0;
506 do {
507 res_sendhookact act;
509 struct sockaddr_in *nsap4;
510 nsap4 = (struct sockaddr_in *) nsap;
511 act = (*statp->qhook)(&nsap4, &buf, &buflen,
512 ans, anssiz, &resplen);
513 nsap = (struct sockaddr_in6 *) nsap4;
514 switch (act) {
515 case res_goahead:
516 done = 1;
517 break;
518 case res_nextns:
519 __res_iclose(statp, false);
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 return (-1);
533 } while (!done);
535 #endif
537 #ifdef DEBUG
538 char tmpbuf[40];
539 #endif
540 Dprint(statp->options & RES_DEBUG,
541 (stdout, ";; Querying server (# %d) address = %s\n",
542 ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
543 tmpbuf, sizeof (tmpbuf))));
545 if (__builtin_expect (v_circuit, 0)) {
546 /* Use VC; at most one attempt per server. */
547 try = statp->retry;
548 n = send_vc(statp, buf, buflen, buf2, buflen2,
549 &ans, &anssiz, &terrno,
550 ns, ansp, ansp2, nansp2, resplen2);
551 if (n < 0)
552 return (-1);
553 if (n == 0)
554 goto next_ns;
555 } else {
556 /* Use datagrams. */
557 n = send_dg(statp, buf, buflen, buf2, buflen2,
558 &ans, &anssiz, &terrno,
559 ns, &v_circuit, &gotsomewhere, ansp,
560 ansp2, nansp2, resplen2);
561 if (n < 0)
562 return (-1);
563 if (n == 0)
564 goto next_ns;
565 if (v_circuit)
566 // XXX Check whether both requests failed or
567 // XXX whether one has been answered successfully
568 goto same_ns;
571 resplen = n;
573 Dprint((statp->options & RES_DEBUG) ||
574 ((statp->pfcode & RES_PRF_REPLY) &&
575 (statp->pfcode & RES_PRF_HEAD1)),
576 (stdout, ";; got answer:\n"));
578 DprintQ((statp->options & RES_DEBUG) ||
579 (statp->pfcode & RES_PRF_REPLY),
580 (stdout, "%s", ""),
581 ans, (resplen > anssiz) ? anssiz : resplen);
582 if (buf2 != NULL)
583 DprintQ((statp->options & RES_DEBUG) ||
584 (statp->pfcode & RES_PRF_REPLY),
585 (stdout, "%s", ""),
586 *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
589 * If we have temporarily opened a virtual circuit,
590 * or if we haven't been asked to keep a socket open,
591 * close the socket.
593 if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
594 (statp->options & RES_STAYOPEN) == 0) {
595 __res_iclose(statp, false);
597 #ifdef USE_HOOKS
598 if (__builtin_expect (statp->rhook, 0)) {
599 int done = 0, loops = 0;
601 do {
602 res_sendhookact act;
604 act = (*statp->rhook)((struct sockaddr_in *)
605 nsap, buf, buflen,
606 ans, anssiz, &resplen);
607 switch (act) {
608 case res_goahead:
609 case res_done:
610 done = 1;
611 break;
612 case res_nextns:
613 __res_iclose(statp, false);
614 goto next_ns;
615 case res_modified:
616 /* give the hook another try */
617 if (++loops < 42) /*doug adams*/
618 break;
619 /*FALLTHROUGH*/
620 case res_error:
621 /*FALLTHROUGH*/
622 default:
623 return (-1);
625 } while (!done);
628 #endif
629 return (resplen);
630 next_ns: ;
631 } /*foreach ns*/
632 } /*foreach retry*/
633 __res_iclose(statp, false);
634 if (!v_circuit) {
635 if (!gotsomewhere)
636 __set_errno (ECONNREFUSED); /* no nameservers found */
637 else
638 __set_errno (ETIMEDOUT); /* no answer obtained */
639 } else
640 __set_errno (terrno);
641 return (-1);
645 res_nsend(res_state statp,
646 const u_char *buf, int buflen, u_char *ans, int anssiz)
648 return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
649 NULL, NULL, NULL, NULL);
651 libresolv_hidden_def (res_nsend)
653 /* Private */
655 static int
656 send_vc(res_state statp,
657 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
658 u_char **ansp, int *anssizp,
659 int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
660 int *resplen2)
662 const HEADER *hp = (HEADER *) buf;
663 const HEADER *hp2 = (HEADER *) buf2;
664 u_char *ans = *ansp;
665 int orig_anssizp = *anssizp;
666 // XXX REMOVE
667 // int anssiz = *anssizp;
668 HEADER *anhp = (HEADER *) ans;
669 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
670 int truncating, connreset, resplen, n;
671 struct iovec iov[4];
672 u_short len;
673 u_short len2;
674 u_char *cp;
676 if (resplen2 != NULL)
677 *resplen2 = 0;
678 connreset = 0;
679 same_ns:
680 truncating = 0;
682 /* Are we still talking to whom we want to talk to? */
683 if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
684 struct sockaddr_in6 peer;
685 socklen_t size = sizeof peer;
687 if (getpeername(statp->_vcsock,
688 (struct sockaddr *)&peer, &size) < 0 ||
689 !sock_eq(&peer, nsap)) {
690 __res_iclose(statp, false);
691 statp->_flags &= ~RES_F_VC;
695 if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
696 if (statp->_vcsock >= 0)
697 __res_iclose(statp, false);
699 statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
700 if (statp->_vcsock < 0) {
701 *terrno = errno;
702 Perror(statp, stderr, "socket(vc)", errno);
703 return (-1);
705 __set_errno (0);
706 if (connect(statp->_vcsock, (struct sockaddr *)nsap,
707 nsap->sin6_family == AF_INET
708 ? sizeof (struct sockaddr_in)
709 : sizeof (struct sockaddr_in6)) < 0) {
710 *terrno = errno;
711 Aerror(statp, stderr, "connect/vc", errno,
712 (struct sockaddr *) nsap);
713 __res_iclose(statp, false);
714 return (0);
716 statp->_flags |= RES_F_VC;
720 * Send length & message
722 len = htons ((u_short) buflen);
723 evConsIovec(&len, INT16SZ, &iov[0]);
724 evConsIovec((void*)buf, buflen, &iov[1]);
725 int niov = 2;
726 ssize_t explen = INT16SZ + buflen;
727 if (buf2 != NULL) {
728 len2 = htons ((u_short) buflen2);
729 evConsIovec(&len2, INT16SZ, &iov[2]);
730 evConsIovec((void*)buf2, buflen2, &iov[3]);
731 niov = 4;
732 explen += INT16SZ + buflen2;
734 if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
735 *terrno = errno;
736 Perror(statp, stderr, "write failed", errno);
737 __res_iclose(statp, false);
738 return (0);
741 * Receive length & response
743 int recvresp1 = 0;
744 int recvresp2 = buf2 == NULL;
745 uint16_t rlen16;
746 read_len:
747 cp = (u_char *)&rlen16;
748 len = sizeof(rlen16);
749 while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
750 (int)len))) > 0) {
751 cp += n;
752 if ((len -= n) <= 0)
753 break;
755 if (n <= 0) {
756 *terrno = errno;
757 Perror(statp, stderr, "read failed", errno);
758 __res_iclose(statp, false);
760 * A long running process might get its TCP
761 * connection reset if the remote server was
762 * restarted. Requery the server instead of
763 * trying a new one. When there is only one
764 * server, this means that a query might work
765 * instead of failing. We only allow one reset
766 * per query to prevent looping.
768 if (*terrno == ECONNRESET && !connreset) {
769 connreset = 1;
770 goto same_ns;
772 return (0);
774 int rlen = ntohs (rlen16);
776 int *thisanssizp;
777 u_char **thisansp;
778 int *thisresplenp;
779 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
780 thisanssizp = anssizp;
781 thisansp = anscp ?: ansp;
782 assert (anscp != NULL || ansp2 == NULL);
783 thisresplenp = &resplen;
784 } else {
785 if (*anssizp != MAXPACKET) {
786 /* No buffer allocated for the first
787 reply. We can try to use the rest
788 of the user-provided buffer. */
789 #ifdef _STRING_ARCH_unaligned
790 *anssizp2 = orig_anssizp - resplen;
791 *ansp2 = *ansp + resplen;
792 #else
793 int aligned_resplen
794 = ((resplen + __alignof__ (HEADER) - 1)
795 & ~(__alignof__ (HEADER) - 1));
796 *anssizp2 = orig_anssizp - aligned_resplen;
797 *ansp2 = *ansp + aligned_resplen;
798 #endif
799 } else {
800 /* The first reply did not fit into the
801 user-provided buffer. Maybe the second
802 answer will. */
803 *anssizp2 = orig_anssizp;
804 *ansp2 = *ansp;
807 thisanssizp = anssizp2;
808 thisansp = ansp2;
809 thisresplenp = resplen2;
811 anhp = (HEADER *) *thisansp;
813 *thisresplenp = rlen;
814 if (rlen > *thisanssizp) {
815 /* Yes, we test ANSCP here. If we have two buffers
816 both will be allocatable. */
817 if (__builtin_expect (anscp != NULL, 1)) {
818 u_char *newp = malloc (MAXPACKET);
819 if (newp == NULL) {
820 *terrno = ENOMEM;
821 __res_iclose(statp, false);
822 return (0);
824 *thisanssizp = MAXPACKET;
825 *thisansp = newp;
826 anhp = (HEADER *) newp;
827 len = rlen;
828 } else {
829 Dprint(statp->options & RES_DEBUG,
830 (stdout, ";; response truncated\n")
832 truncating = 1;
833 len = *thisanssizp;
835 } else
836 len = rlen;
838 if (__builtin_expect (len < HFIXEDSZ, 0)) {
840 * Undersized message.
842 Dprint(statp->options & RES_DEBUG,
843 (stdout, ";; undersized: %d\n", len));
844 *terrno = EMSGSIZE;
845 __res_iclose(statp, false);
846 return (0);
849 cp = *thisansp;
850 while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
851 cp += n;
852 len -= n;
854 if (__builtin_expect (n <= 0, 0)) {
855 *terrno = errno;
856 Perror(statp, stderr, "read(vc)", errno);
857 __res_iclose(statp, false);
858 return (0);
860 if (__builtin_expect (truncating, 0)) {
862 * Flush rest of answer so connection stays in synch.
864 anhp->tc = 1;
865 len = rlen - *thisanssizp;
866 while (len != 0) {
867 char junk[PACKETSZ];
869 n = read(statp->_vcsock, junk,
870 (len > sizeof junk) ? sizeof junk : len);
871 if (n > 0)
872 len -= n;
873 else
874 break;
878 * If the calling applicating has bailed out of
879 * a previous call and failed to arrange to have
880 * the circuit closed or the server has got
881 * itself confused, then drop the packet and
882 * wait for the correct one.
884 if ((recvresp1 || hp->id != anhp->id)
885 && (recvresp2 || hp2->id != anhp->id)) {
886 DprintQ((statp->options & RES_DEBUG) ||
887 (statp->pfcode & RES_PRF_REPLY),
888 (stdout, ";; old answer (unexpected):\n"),
889 *thisansp,
890 (rlen > *thisanssiz) ? *thisanssiz: rlen);
891 goto read_len;
894 /* Mark which reply we received. */
895 if (recvresp1 == 0 && hp->id == anhp->id)
896 recvresp1 = 1;
897 else
898 recvresp2 = 1;
899 /* Repeat waiting if we have a second answer to arrive. */
900 if ((recvresp1 & recvresp2) == 0)
901 goto read_len;
904 * All is well, or the error is fatal. Signal that the
905 * next nameserver ought not be tried.
907 return resplen;
910 static int
911 reopen (res_state statp, int *terrno, int ns)
913 if (EXT(statp).nssocks[ns] == -1) {
914 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
916 /* only try IPv6 if IPv6 NS and if not failed before */
917 if ((EXT(statp).nscount6 > 0) && !statp->ipv6_unavail) {
918 if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
919 EXT(statp).nssocks[ns] =
920 socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK,
922 #ifndef __ASSUME_SOCK_CLOEXEC
923 if (__have_o_nonblock == 0)
924 __have_o_nonblock
925 = (EXT(statp).nssocks[ns] == -1
926 && errno == EINVAL ? -1 : 1);
927 #endif
929 if (__builtin_expect (__have_o_nonblock < 0, 0))
930 EXT(statp).nssocks[ns] =
931 socket(PF_INET6, SOCK_DGRAM, 0);
932 if (EXT(statp).nssocks[ns] < 0)
933 statp->ipv6_unavail = errno == EAFNOSUPPORT;
934 /* If IPv6 socket and nsap is IPv4, make it
935 IPv4-mapped */
936 else if (nsap->sin6_family == AF_INET)
937 convaddr4to6(nsap);
939 if (EXT(statp).nssocks[ns] < 0) {
940 if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
941 EXT(statp).nssocks[ns]
942 = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK,
944 #ifndef __ASSUME_SOCK_CLOEXEC
945 if (__have_o_nonblock == 0)
946 __have_o_nonblock
947 = (EXT(statp).nssocks[ns] == -1
948 && errno == EINVAL ? -1 : 1);
949 #endif
951 if (__builtin_expect (__have_o_nonblock < 0, 0))
952 EXT(statp).nssocks[ns]
953 = socket(PF_INET, SOCK_DGRAM, 0);
955 if (EXT(statp).nssocks[ns] < 0) {
956 *terrno = errno;
957 Perror(statp, stderr, "socket(dg)", errno);
958 return (-1);
962 * On a 4.3BSD+ machine (client and server,
963 * actually), sending to a nameserver datagram
964 * port with no nameserver will cause an
965 * ICMP port unreachable message to be returned.
966 * If our datagram socket is "connected" to the
967 * server, we get an ECONNREFUSED error on the next
968 * socket operation, and select returns if the
969 * error message is received. We can thus detect
970 * the absence of a nameserver without timing out.
972 if (connect(EXT(statp).nssocks[ns], (struct sockaddr *)nsap,
973 sizeof *nsap) < 0) {
974 Aerror(statp, stderr, "connect(dg)", errno,
975 (struct sockaddr *) nsap);
976 __res_iclose(statp, false);
977 return (0);
979 if (__builtin_expect (__have_o_nonblock < 0, 0)) {
980 /* Make socket non-blocking. */
981 int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
982 if (fl != -1)
983 __fcntl (EXT(statp).nssocks[ns], F_SETFL,
984 fl | O_NONBLOCK);
985 Dprint(statp->options & RES_DEBUG,
986 (stdout, ";; new DG socket\n"))
990 return 1;
993 static int
994 send_dg(res_state statp,
995 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
996 u_char **ansp, int *anssizp,
997 int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
998 u_char **ansp2, int *anssizp2, int *resplen2)
1000 const HEADER *hp = (HEADER *) buf;
1001 const HEADER *hp2 = (HEADER *) buf2;
1002 u_char *ans = *ansp;
1003 int orig_anssizp = *anssizp;
1004 struct timespec now, timeout, finish;
1005 struct pollfd pfd[1];
1006 int ptimeout;
1007 struct sockaddr_in6 from;
1008 int resplen, n;
1011 * Compute time for the total operation.
1013 int seconds = (statp->retrans << ns);
1014 if (ns > 0)
1015 seconds /= statp->nscount;
1016 if (seconds <= 0)
1017 seconds = 1;
1018 bool single_request = (statp->options & RES_SNGLKUP) != 0;
1019 bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
1020 int save_gotsomewhere = *gotsomewhere;
1022 int retval;
1023 retry_reopen:
1024 retval = reopen (statp, terrno, ns);
1025 if (retval <= 0)
1026 return retval;
1027 retry:
1028 evNowTime(&now);
1029 evConsTime(&timeout, seconds, 0);
1030 evAddTime(&finish, &now, &timeout);
1031 int need_recompute = 0;
1032 int nwritten = 0;
1033 int recvresp1 = 0;
1034 int recvresp2 = buf2 == NULL;
1035 pfd[0].fd = EXT(statp).nssocks[ns];
1036 pfd[0].events = POLLOUT;
1037 if (resplen2 != NULL)
1038 *resplen2 = 0;
1039 wait:
1040 if (need_recompute) {
1041 recompute_resend:
1042 evNowTime(&now);
1043 if (evCmpTime(finish, now) <= 0) {
1044 poll_err_out:
1045 Perror(statp, stderr, "poll", errno);
1046 err_out:
1047 __res_iclose(statp, false);
1048 return (0);
1050 evSubTime(&timeout, &finish, &now);
1051 need_recompute = 0;
1053 /* Convert struct timespec in milliseconds. */
1054 ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
1056 n = 0;
1057 if (nwritten == 0)
1058 n = __poll (pfd, 1, 0);
1059 if (__builtin_expect (n == 0, 0)) {
1060 n = __poll (pfd, 1, ptimeout);
1061 need_recompute = 1;
1063 if (n == 0) {
1064 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1065 if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
1067 /* There are quite a few broken name servers out
1068 there which don't handle two outstanding
1069 requests from the same source. There are also
1070 broken firewall settings. If we time out after
1071 having received one answer switch to the mode
1072 where we send the second request only once we
1073 have received the first answer. */
1074 if (!single_request)
1076 statp->options |= RES_SNGLKUP;
1077 single_request = true;
1078 *gotsomewhere = save_gotsomewhere;
1079 goto retry;
1081 else if (!single_request_reopen)
1083 statp->options |= RES_SNGLKUPREOP;
1084 single_request_reopen = true;
1085 *gotsomewhere = save_gotsomewhere;
1086 __res_iclose (statp, false);
1087 goto retry_reopen;
1090 *resplen2 = 1;
1091 return resplen;
1094 *gotsomewhere = 1;
1095 return (0);
1097 if (n < 0) {
1098 if (errno == EINTR)
1099 goto recompute_resend;
1101 goto poll_err_out;
1103 __set_errno (0);
1104 if (pfd[0].revents & POLLOUT) {
1105 ssize_t sr;
1106 if (nwritten != 0)
1107 sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
1108 else
1109 sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
1111 if (sr != buflen) {
1112 if (errno == EINTR || errno == EAGAIN)
1113 goto recompute_resend;
1114 Perror(statp, stderr, "send", errno);
1115 goto err_out;
1117 if (nwritten != 0 || buf2 == NULL
1118 || single_request || single_request_reopen)
1119 pfd[0].events = POLLIN;
1120 else
1121 pfd[0].events = POLLIN | POLLOUT;
1122 ++nwritten;
1123 goto wait;
1124 } else if (pfd[0].revents & POLLIN) {
1125 int *thisanssizp;
1126 u_char **thisansp;
1127 int *thisresplenp;
1129 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
1130 thisanssizp = anssizp;
1131 thisansp = anscp ?: ansp;
1132 assert (anscp != NULL || ansp2 == NULL);
1133 thisresplenp = &resplen;
1134 } else {
1135 if (*anssizp != MAXPACKET) {
1136 /* No buffer allocated for the first
1137 reply. We can try to use the rest
1138 of the user-provided buffer. */
1139 #ifdef _STRING_ARCH_unaligned
1140 *anssizp2 = orig_anssizp - resplen;
1141 *ansp2 = *ansp + resplen;
1142 #else
1143 int aligned_resplen
1144 = ((resplen + __alignof__ (HEADER) - 1)
1145 & ~(__alignof__ (HEADER) - 1));
1146 *anssizp2 = orig_anssizp - aligned_resplen;
1147 *ansp2 = *ansp + aligned_resplen;
1148 #endif
1149 } else {
1150 /* The first reply did not fit into the
1151 user-provided buffer. Maybe the second
1152 answer will. */
1153 *anssizp2 = orig_anssizp;
1154 *ansp2 = *ansp;
1157 thisanssizp = anssizp2;
1158 thisansp = ansp2;
1159 thisresplenp = resplen2;
1162 if (*thisanssizp < MAXPACKET
1163 /* Yes, we test ANSCP here. If we have two buffers
1164 both will be allocatable. */
1165 && anscp
1166 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
1167 || *thisanssizp < *thisresplenp)) {
1168 u_char *newp = malloc (MAXPACKET);
1169 if (newp != NULL) {
1170 *anssizp = MAXPACKET;
1171 *thisansp = ans = newp;
1174 HEADER *anhp = (HEADER *) *thisansp;
1175 socklen_t fromlen = sizeof(struct sockaddr_in6);
1176 assert (sizeof(from) <= fromlen);
1177 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
1178 *thisanssizp, 0,
1179 (struct sockaddr *)&from, &fromlen);
1180 if (__builtin_expect (*thisresplenp <= 0, 0)) {
1181 if (errno == EINTR || errno == EAGAIN) {
1182 need_recompute = 1;
1183 goto wait;
1185 Perror(statp, stderr, "recvfrom", errno);
1186 goto err_out;
1188 *gotsomewhere = 1;
1189 if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
1191 * Undersized message.
1193 Dprint(statp->options & RES_DEBUG,
1194 (stdout, ";; undersized: %d\n",
1195 *thisresplen));
1196 *terrno = EMSGSIZE;
1197 goto err_out;
1199 if ((recvresp1 || hp->id != anhp->id)
1200 && (recvresp2 || hp2->id != anhp->id)) {
1202 * response from old query, ignore it.
1203 * XXX - potential security hazard could
1204 * be detected here.
1206 DprintQ((statp->options & RES_DEBUG) ||
1207 (statp->pfcode & RES_PRF_REPLY),
1208 (stdout, ";; old answer:\n"),
1209 thisansp,
1210 (*thisresplen > *thisanssiz)
1211 ? *thisanssiz : *thisresplen);
1212 goto wait;
1214 if (!(statp->options & RES_INSECURE1) &&
1215 !res_ourserver_p(statp, &from)) {
1217 * response from wrong server? ignore it.
1218 * XXX - potential security hazard could
1219 * be detected here.
1221 DprintQ((statp->options & RES_DEBUG) ||
1222 (statp->pfcode & RES_PRF_REPLY),
1223 (stdout, ";; not our server:\n"),
1224 thisansp,
1225 (*thisresplen > *thisanssiz)
1226 ? *thisanssiz : *thisresplen);
1227 goto wait;
1229 #ifdef RES_USE_EDNS0
1230 if (anhp->rcode == FORMERR
1231 && (statp->options & RES_USE_EDNS0) != 0U) {
1233 * Do not retry if the server does not understand
1234 * EDNS0. The case has to be captured here, as
1235 * FORMERR packet do not carry query section, hence
1236 * res_queriesmatch() returns 0.
1238 DprintQ(statp->options & RES_DEBUG,
1239 (stdout,
1240 "server rejected query with EDNS0:\n"),
1241 thisans,
1242 (*thisresplen > *thisanssiz)
1243 ? *thisanssiz : *thisresplen);
1244 /* record the error */
1245 statp->_flags |= RES_F_EDNS0ERR;
1246 goto err_out;
1248 #endif
1249 if (!(statp->options & RES_INSECURE2)
1250 && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
1251 *thisansp,
1252 *thisansp
1253 + *thisanssizp))
1254 && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
1255 *thisansp,
1256 *thisansp
1257 + *thisanssizp))) {
1259 * response contains wrong query? ignore it.
1260 * XXX - potential security hazard could
1261 * be detected here.
1263 DprintQ((statp->options & RES_DEBUG) ||
1264 (statp->pfcode & RES_PRF_REPLY),
1265 (stdout, ";; wrong query name:\n"),
1266 thisansp,
1267 (*thisresplen > *thisanssiz)
1268 ? *thisanssiz : *thisresplen);
1269 goto wait;
1271 if (anhp->rcode == SERVFAIL ||
1272 anhp->rcode == NOTIMP ||
1273 anhp->rcode == REFUSED) {
1274 DprintQ(statp->options & RES_DEBUG,
1275 (stdout, "server rejected query:\n"),
1276 thisansp,
1277 (*thisresplen > *thisanssiz)
1278 ? *thisanssiz : *thisresplen);
1280 if (recvresp1 || (buf2 != NULL && recvresp2))
1282 *resplen2 = 1;
1283 return resplen;
1285 if (buf2 != NULL)
1287 /* We are waiting for a possible second reply. */
1288 resplen = 1;
1289 if (hp->id == anhp->id)
1290 recvresp1 = 1;
1291 else
1292 recvresp2 = 1;
1294 goto wait;
1297 next_ns:
1298 __res_iclose(statp, false);
1299 /* don't retry if called from dig */
1300 if (!statp->pfcode)
1301 return (0);
1303 if (anhp->rcode == NOERROR && anhp->ancount == 0
1304 && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
1305 DprintQ(statp->options & RES_DEBUG,
1306 (stdout, "referred query:\n"),
1307 thisansp,
1308 (*thisresplen > *thisanssiz)
1309 ? *thisanssiz : *thisresplen);
1310 goto next_ns;
1312 if (!(statp->options & RES_IGNTC) && anhp->tc) {
1314 * To get the rest of answer,
1315 * use TCP with same server.
1317 Dprint(statp->options & RES_DEBUG,
1318 (stdout, ";; truncated answer\n"));
1319 *v_circuit = 1;
1320 __res_iclose(statp, false);
1321 // XXX if we have received one reply we could
1322 // XXX use it and not repeat it over TCP...
1323 return (1);
1325 /* Mark which reply we received. */
1326 if (recvresp1 == 0 && hp->id == anhp->id)
1327 recvresp1 = 1;
1328 else
1329 recvresp2 = 1;
1330 /* Repeat waiting if we have a second answer to arrive. */
1331 if ((recvresp1 & recvresp2) == 0) {
1332 if (single_request || single_request_reopen) {
1333 pfd[0].events = POLLOUT;
1334 if (single_request_reopen) {
1335 __res_iclose (statp, false);
1336 retval = reopen (statp, terrno, ns);
1337 if (retval <= 0)
1338 return retval;
1341 goto wait;
1344 * All is well, or the error is fatal. Signal that the
1345 * next nameserver ought not be tried.
1347 return (resplen);
1348 } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1349 /* Something went wrong. We can stop trying. */
1350 goto err_out;
1352 else {
1353 /* poll should not have returned > 0 in this case. */
1354 abort ();
1358 #ifdef DEBUG
1359 static void
1360 Aerror(const res_state statp, FILE *file, const char *string, int error,
1361 const struct sockaddr *address)
1363 int save = errno;
1365 if ((statp->options & RES_DEBUG) != 0) {
1366 char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
1368 fprintf(file, "res_send: %s ([%s].%u): %s\n",
1369 string,
1370 (address->sa_family == AF_INET
1371 ? inet_ntop(address->sa_family,
1372 &((const struct sockaddr_in *) address)->sin_addr,
1373 tmp, sizeof tmp)
1374 : inet_ntop(address->sa_family,
1375 &((const struct sockaddr_in6 *) address)->sin6_addr,
1376 tmp, sizeof tmp)),
1377 (address->sa_family == AF_INET
1378 ? ntohs(((struct sockaddr_in *) address)->sin_port)
1379 : address->sa_family == AF_INET6
1380 ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
1381 : 0),
1382 strerror(error));
1384 __set_errno (save);
1387 static void
1388 Perror(const res_state statp, FILE *file, const char *string, int error) {
1389 int save = errno;
1391 if ((statp->options & RES_DEBUG) != 0)
1392 fprintf(file, "res_send: %s: %s\n",
1393 string, strerror(error));
1394 __set_errno (save);
1396 #endif
1398 static int
1399 sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
1400 if (a1->sin6_family == a2->sin6_family) {
1401 if (a1->sin6_family == AF_INET)
1402 return ((((struct sockaddr_in *)a1)->sin_port ==
1403 ((struct sockaddr_in *)a2)->sin_port) &&
1404 (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
1405 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1406 else
1407 return ((a1->sin6_port == a2->sin6_port) &&
1408 !memcmp(&a1->sin6_addr, &a2->sin6_addr,
1409 sizeof (struct in6_addr)));
1411 if (a1->sin6_family == AF_INET) {
1412 struct sockaddr_in6 *sap = a1;
1413 a1 = a2;
1414 a2 = sap;
1415 } /* assumes that AF_INET and AF_INET6 are the only possibilities */
1416 return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
1417 IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
1418 (a1->sin6_addr.s6_addr32[3] ==
1419 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1423 * Converts IPv4 family, address and port to
1424 * IPv6 family, IPv4-mapped IPv6 address and port.
1426 static void
1427 convaddr4to6(struct sockaddr_in6 *sa)
1429 struct sockaddr_in *sa4p = (struct sockaddr_in *) sa;
1430 in_port_t port = sa4p->sin_port;
1431 in_addr_t addr = sa4p->sin_addr.s_addr;
1433 sa->sin6_family = AF_INET6;
1434 sa->sin6_port = port;
1435 sa->sin6_addr.s6_addr32[0] = 0;
1436 sa->sin6_addr.s6_addr32[1] = 0;
1437 sa->sin6_addr.s6_addr32[2] = htonl(0xFFFF);
1438 sa->sin6_addr.s6_addr32[3] = addr;