Don't underestimate length of DST substitution
[glibc.git] / resolv / res_send.c
blobb0966ae0369c565849a7ae08f9caf246ee427772
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 /* Public. */
204 /* int
205 * res_isourserver(ina)
206 * looks up "ina" in _res.ns_addr_list[]
207 * returns:
208 * 0 : not found
209 * >0 : found
210 * author:
211 * paul vixie, 29may94
214 res_ourserver_p(const res_state statp, const struct sockaddr_in6 *inp)
216 int ns;
218 if (inp->sin6_family == AF_INET) {
219 struct sockaddr_in *in4p = (struct sockaddr_in *) inp;
220 in_port_t port = in4p->sin_port;
221 in_addr_t addr = in4p->sin_addr.s_addr;
223 for (ns = 0; ns < MAXNS; ns++) {
224 const struct sockaddr_in *srv =
225 (struct sockaddr_in *)EXT(statp).nsaddrs[ns];
227 if ((srv != NULL) && (srv->sin_family == AF_INET) &&
228 (srv->sin_port == port) &&
229 (srv->sin_addr.s_addr == INADDR_ANY ||
230 srv->sin_addr.s_addr == addr))
231 return (1);
233 } else if (inp->sin6_family == AF_INET6) {
234 for (ns = 0; ns < MAXNS; ns++) {
235 const struct sockaddr_in6 *srv = EXT(statp).nsaddrs[ns];
236 if ((srv != NULL) && (srv->sin6_family == AF_INET6) &&
237 (srv->sin6_port == inp->sin6_port) &&
238 !(memcmp(&srv->sin6_addr, &in6addr_any,
239 sizeof (struct in6_addr)) &&
240 memcmp(&srv->sin6_addr, &inp->sin6_addr,
241 sizeof (struct in6_addr))))
242 return (1);
245 return (0);
248 /* int
249 * res_nameinquery(name, type, class, buf, eom)
250 * look for (name,type,class) in the query section of packet (buf,eom)
251 * requires:
252 * buf + HFIXEDSZ <= eom
253 * returns:
254 * -1 : format error
255 * 0 : not found
256 * >0 : found
257 * author:
258 * paul vixie, 29may94
261 res_nameinquery(const char *name, int type, int class,
262 const u_char *buf, const u_char *eom)
264 const u_char *cp = buf + HFIXEDSZ;
265 int qdcount = ntohs(((HEADER*)buf)->qdcount);
267 while (qdcount-- > 0) {
268 char tname[MAXDNAME+1];
269 int n, ttype, tclass;
271 n = dn_expand(buf, eom, cp, tname, sizeof tname);
272 if (n < 0)
273 return (-1);
274 cp += n;
275 if (cp + 2 * INT16SZ > eom)
276 return (-1);
277 NS_GET16(ttype, cp);
278 NS_GET16(tclass, cp);
279 if (ttype == type && tclass == class &&
280 ns_samename(tname, name) == 1)
281 return (1);
283 return (0);
285 libresolv_hidden_def (res_nameinquery)
287 /* int
288 * res_queriesmatch(buf1, eom1, buf2, eom2)
289 * is there a 1:1 mapping of (name,type,class)
290 * in (buf1,eom1) and (buf2,eom2)?
291 * returns:
292 * -1 : format error
293 * 0 : not a 1:1 mapping
294 * >0 : is a 1:1 mapping
295 * author:
296 * paul vixie, 29may94
299 res_queriesmatch(const u_char *buf1, const u_char *eom1,
300 const u_char *buf2, const u_char *eom2)
302 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
303 return (-1);
306 * Only header section present in replies to
307 * dynamic update packets.
309 if ((((HEADER *)buf1)->opcode == ns_o_update) &&
310 (((HEADER *)buf2)->opcode == ns_o_update))
311 return (1);
313 /* Note that we initially do not convert QDCOUNT to the host byte
314 order. We can compare it with the second buffer's QDCOUNT
315 value without doing this. */
316 int qdcount = ((HEADER*)buf1)->qdcount;
317 if (qdcount != ((HEADER*)buf2)->qdcount)
318 return (0);
320 qdcount = htons (qdcount);
321 const u_char *cp = buf1 + HFIXEDSZ;
323 while (qdcount-- > 0) {
324 char tname[MAXDNAME+1];
325 int n, ttype, tclass;
327 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
328 if (n < 0)
329 return (-1);
330 cp += n;
331 if (cp + 2 * INT16SZ > eom1)
332 return (-1);
333 NS_GET16(ttype, cp);
334 NS_GET16(tclass, cp);
335 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
336 return (0);
338 return (1);
340 libresolv_hidden_def (res_queriesmatch)
343 __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
344 const u_char *buf2, int buflen2,
345 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
346 int *nansp2, int *resplen2)
348 int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
350 if (statp->nscount == 0) {
351 __set_errno (ESRCH);
352 return (-1);
355 if (anssiz < (buf2 == NULL ? 1 : 2) * HFIXEDSZ) {
356 __set_errno (EINVAL);
357 return (-1);
360 #ifdef USE_HOOKS
361 if (__builtin_expect (statp->qhook || statp->rhook, 0)) {
362 if (anssiz < MAXPACKET && ansp) {
363 u_char *buf = malloc (MAXPACKET);
364 if (buf == NULL)
365 return (-1);
366 memcpy (buf, ans, HFIXEDSZ);
367 *ansp = buf;
368 ans = buf;
369 anssiz = MAXPACKET;
372 #endif
374 DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
375 (stdout, ";; res_send()\n"), buf, buflen);
376 v_circuit = ((statp->options & RES_USEVC)
377 || buflen > PACKETSZ
378 || buflen2 > PACKETSZ);
379 gotsomewhere = 0;
380 terrno = ETIMEDOUT;
383 * If the ns_addr_list in the resolver context has changed, then
384 * invalidate our cached copy and the associated timing data.
386 if (EXT(statp).nsinit) {
387 int needclose = 0;
389 if (EXT(statp).nscount != statp->nscount)
390 needclose++;
391 else
392 for (ns = 0; ns < MAXNS; ns++) {
393 unsigned int map = EXT(statp).nsmap[ns];
394 if (map < MAXNS
395 && !sock_eq((struct sockaddr_in6 *)
396 &statp->nsaddr_list[map],
397 EXT(statp).nsaddrs[ns]))
399 needclose++;
400 break;
403 if (needclose)
404 __res_iclose(statp, false);
408 * Maybe initialize our private copy of the ns_addr_list.
410 if (EXT(statp).nsinit == 0) {
411 unsigned char map[MAXNS];
413 memset (map, MAXNS, sizeof (map));
414 for (n = 0; n < MAXNS; n++) {
415 ns = EXT(statp).nsmap[n];
416 if (ns < statp->nscount)
417 map[ns] = n;
418 else if (ns < MAXNS) {
419 free(EXT(statp).nsaddrs[n]);
420 EXT(statp).nsaddrs[n] = NULL;
421 EXT(statp).nsmap[n] = MAXNS;
424 n = statp->nscount;
425 if (statp->nscount > EXT(statp).nscount)
426 for (n = EXT(statp).nscount, ns = 0;
427 n < statp->nscount; n++) {
428 while (ns < MAXNS
429 && EXT(statp).nsmap[ns] != MAXNS)
430 ns++;
431 if (ns == MAXNS)
432 break;
433 EXT(statp).nsmap[ns] = n;
434 map[n] = ns++;
436 EXT(statp).nscount = n;
437 for (ns = 0; ns < EXT(statp).nscount; ns++) {
438 n = map[ns];
439 if (EXT(statp).nsaddrs[n] == NULL)
440 EXT(statp).nsaddrs[n] =
441 malloc(sizeof (struct sockaddr_in6));
442 if (EXT(statp).nsaddrs[n] != NULL) {
443 memset (mempcpy(EXT(statp).nsaddrs[n],
444 &statp->nsaddr_list[n],
445 sizeof (struct sockaddr_in)),
446 '\0',
447 sizeof (struct sockaddr_in6)
448 - sizeof (struct sockaddr_in));
449 EXT(statp).nssocks[n] = -1;
450 n++;
453 EXT(statp).nsinit = 1;
457 * Some resolvers want to even out the load on their nameservers.
458 * Note that RES_BLAST overrides RES_ROTATE.
460 if (__builtin_expect ((statp->options & RES_ROTATE) != 0, 0) &&
461 (statp->options & RES_BLAST) == 0) {
462 struct sockaddr_in6 *ina;
463 unsigned int map;
465 n = 0;
466 while (n < MAXNS && EXT(statp).nsmap[n] == MAXNS)
467 n++;
468 if (n < MAXNS) {
469 ina = EXT(statp).nsaddrs[n];
470 map = EXT(statp).nsmap[n];
471 for (;;) {
472 ns = n + 1;
473 while (ns < MAXNS
474 && EXT(statp).nsmap[ns] == MAXNS)
475 ns++;
476 if (ns == MAXNS)
477 break;
478 EXT(statp).nsaddrs[n] = EXT(statp).nsaddrs[ns];
479 EXT(statp).nsmap[n] = EXT(statp).nsmap[ns];
480 n = ns;
482 EXT(statp).nsaddrs[n] = ina;
483 EXT(statp).nsmap[n] = map;
488 * Send request, RETRY times, or until successful.
490 for (try = 0; try < statp->retry; try++) {
491 for (ns = 0; ns < MAXNS; ns++)
493 #ifdef DEBUG
494 char tmpbuf[40];
495 #endif
496 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
498 if (nsap == NULL)
499 goto next_ns;
500 same_ns:
501 #ifdef USE_HOOKS
502 if (__builtin_expect (statp->qhook != NULL, 0)) {
503 int done = 0, loops = 0;
505 do {
506 res_sendhookact act;
508 struct sockaddr_in *nsap4;
509 nsap4 = (struct sockaddr_in *) nsap;
510 act = (*statp->qhook)(&nsap4, &buf, &buflen,
511 ans, anssiz, &resplen);
512 nsap = (struct sockaddr_in6 *) nsap4;
513 switch (act) {
514 case res_goahead:
515 done = 1;
516 break;
517 case res_nextns:
518 __res_iclose(statp, false);
519 goto next_ns;
520 case res_done:
521 return (resplen);
522 case res_modified:
523 /* give the hook another try */
524 if (++loops < 42) /*doug adams*/
525 break;
526 /*FALLTHROUGH*/
527 case res_error:
528 /*FALLTHROUGH*/
529 default:
530 return (-1);
532 } while (!done);
534 #endif
536 Dprint(statp->options & RES_DEBUG,
537 (stdout, ";; Querying server (# %d) address = %s\n",
538 ns + 1, inet_ntop(AF_INET6, &nsap->sin6_addr,
539 tmpbuf, sizeof (tmpbuf))));
541 if (__builtin_expect (v_circuit, 0)) {
542 /* Use VC; at most one attempt per server. */
543 try = statp->retry;
544 n = send_vc(statp, buf, buflen, buf2, buflen2,
545 &ans, &anssiz, &terrno,
546 ns, ansp, ansp2, nansp2, resplen2);
547 if (n < 0)
548 return (-1);
549 if (n == 0)
550 goto next_ns;
551 } else {
552 /* Use datagrams. */
553 n = send_dg(statp, buf, buflen, buf2, buflen2,
554 &ans, &anssiz, &terrno,
555 ns, &v_circuit, &gotsomewhere, ansp,
556 ansp2, nansp2, resplen2);
557 if (n < 0)
558 return (-1);
559 if (n == 0)
560 goto next_ns;
561 if (v_circuit)
562 // XXX Check whether both requests failed or
563 // XXX whether one has been answered successfully
564 goto same_ns;
567 resplen = n;
569 Dprint((statp->options & RES_DEBUG) ||
570 ((statp->pfcode & RES_PRF_REPLY) &&
571 (statp->pfcode & RES_PRF_HEAD1)),
572 (stdout, ";; got answer:\n"));
574 DprintQ((statp->options & RES_DEBUG) ||
575 (statp->pfcode & RES_PRF_REPLY),
576 (stdout, "%s", ""),
577 ans, (resplen > anssiz) ? anssiz : resplen);
578 if (buf2 != NULL) {
579 DprintQ((statp->options & RES_DEBUG) ||
580 (statp->pfcode & RES_PRF_REPLY),
581 (stdout, "%s", ""),
582 *ansp2, (*resplen2 > *nansp2) ? *nansp2 : *resplen2);
586 * If we have temporarily opened a virtual circuit,
587 * or if we haven't been asked to keep a socket open,
588 * close the socket.
590 if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
591 (statp->options & RES_STAYOPEN) == 0) {
592 __res_iclose(statp, false);
594 #ifdef USE_HOOKS
595 if (__builtin_expect (statp->rhook, 0)) {
596 int done = 0, loops = 0;
598 do {
599 res_sendhookact act;
601 act = (*statp->rhook)((struct sockaddr_in *)
602 nsap, buf, buflen,
603 ans, anssiz, &resplen);
604 switch (act) {
605 case res_goahead:
606 case res_done:
607 done = 1;
608 break;
609 case res_nextns:
610 __res_iclose(statp, false);
611 goto next_ns;
612 case res_modified:
613 /* give the hook another try */
614 if (++loops < 42) /*doug adams*/
615 break;
616 /*FALLTHROUGH*/
617 case res_error:
618 /*FALLTHROUGH*/
619 default:
620 return (-1);
622 } while (!done);
625 #endif
626 return (resplen);
627 next_ns: ;
628 } /*foreach ns*/
629 } /*foreach retry*/
630 __res_iclose(statp, false);
631 if (!v_circuit) {
632 if (!gotsomewhere)
633 __set_errno (ECONNREFUSED); /* no nameservers found */
634 else
635 __set_errno (ETIMEDOUT); /* no answer obtained */
636 } else
637 __set_errno (terrno);
638 return (-1);
642 res_nsend(res_state statp,
643 const u_char *buf, int buflen, u_char *ans, int anssiz)
645 return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
646 NULL, NULL, NULL, NULL);
648 libresolv_hidden_def (res_nsend)
650 /* Private */
652 static int
653 send_vc(res_state statp,
654 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
655 u_char **ansp, int *anssizp,
656 int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
657 int *resplen2)
659 const HEADER *hp = (HEADER *) buf;
660 const HEADER *hp2 = (HEADER *) buf2;
661 u_char *ans = *ansp;
662 int orig_anssizp = *anssizp;
663 // XXX REMOVE
664 // int anssiz = *anssizp;
665 HEADER *anhp = (HEADER *) ans;
666 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
667 int truncating, connreset, resplen, n;
668 struct iovec iov[4];
669 u_short len;
670 u_short len2;
671 u_char *cp;
673 if (resplen2 != NULL)
674 *resplen2 = 0;
675 connreset = 0;
676 same_ns:
677 truncating = 0;
679 /* Are we still talking to whom we want to talk to? */
680 if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
681 struct sockaddr_in6 peer;
682 socklen_t size = sizeof peer;
684 if (getpeername(statp->_vcsock,
685 (struct sockaddr *)&peer, &size) < 0 ||
686 !sock_eq(&peer, nsap)) {
687 __res_iclose(statp, false);
688 statp->_flags &= ~RES_F_VC;
692 if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
693 if (statp->_vcsock >= 0)
694 __res_iclose(statp, false);
696 statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
697 if (statp->_vcsock < 0) {
698 *terrno = errno;
699 Perror(statp, stderr, "socket(vc)", errno);
700 return (-1);
702 __set_errno (0);
703 if (connect(statp->_vcsock, (struct sockaddr *)nsap,
704 nsap->sin6_family == AF_INET
705 ? sizeof (struct sockaddr_in)
706 : sizeof (struct sockaddr_in6)) < 0) {
707 *terrno = errno;
708 Aerror(statp, stderr, "connect/vc", errno,
709 (struct sockaddr *) nsap);
710 __res_iclose(statp, false);
711 return (0);
713 statp->_flags |= RES_F_VC;
717 * Send length & message
719 len = htons ((u_short) buflen);
720 evConsIovec(&len, INT16SZ, &iov[0]);
721 evConsIovec((void*)buf, buflen, &iov[1]);
722 int niov = 2;
723 ssize_t explen = INT16SZ + buflen;
724 if (buf2 != NULL) {
725 len2 = htons ((u_short) buflen2);
726 evConsIovec(&len2, INT16SZ, &iov[2]);
727 evConsIovec((void*)buf2, buflen2, &iov[3]);
728 niov = 4;
729 explen += INT16SZ + buflen2;
731 if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
732 *terrno = errno;
733 Perror(statp, stderr, "write failed", errno);
734 __res_iclose(statp, false);
735 return (0);
738 * Receive length & response
740 int recvresp1 = 0;
741 int recvresp2 = buf2 == NULL;
742 uint16_t rlen16;
743 read_len:
744 cp = (u_char *)&rlen16;
745 len = sizeof(rlen16);
746 while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
747 (int)len))) > 0) {
748 cp += n;
749 if ((len -= n) <= 0)
750 break;
752 if (n <= 0) {
753 *terrno = errno;
754 Perror(statp, stderr, "read failed", errno);
755 __res_iclose(statp, false);
757 * A long running process might get its TCP
758 * connection reset if the remote server was
759 * restarted. Requery the server instead of
760 * trying a new one. When there is only one
761 * server, this means that a query might work
762 * instead of failing. We only allow one reset
763 * per query to prevent looping.
765 if (*terrno == ECONNRESET && !connreset) {
766 connreset = 1;
767 goto same_ns;
769 return (0);
771 int rlen = ntohs (rlen16);
773 int *thisanssizp;
774 u_char **thisansp;
775 int *thisresplenp;
776 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
777 thisanssizp = anssizp;
778 thisansp = anscp ?: ansp;
779 assert (anscp != NULL || ansp2 == NULL);
780 thisresplenp = &resplen;
781 } else {
782 if (*anssizp != MAXPACKET) {
783 /* No buffer allocated for the first
784 reply. We can try to use the rest
785 of the user-provided buffer. */
786 #ifdef _STRING_ARCH_unaligned
787 *anssizp2 = orig_anssizp - resplen;
788 *ansp2 = *ansp + resplen;
789 #else
790 int aligned_resplen
791 = ((resplen + __alignof__ (HEADER) - 1)
792 & ~(__alignof__ (HEADER) - 1));
793 *anssizp2 = orig_anssizp - aligned_resplen;
794 *ansp2 = *ansp + aligned_resplen;
795 #endif
796 } else {
797 /* The first reply did not fit into the
798 user-provided buffer. Maybe the second
799 answer will. */
800 *anssizp2 = orig_anssizp;
801 *ansp2 = *ansp;
804 thisanssizp = anssizp2;
805 thisansp = ansp2;
806 thisresplenp = resplen2;
808 anhp = (HEADER *) *thisansp;
810 *thisresplenp = rlen;
811 if (rlen > *thisanssizp) {
812 /* Yes, we test ANSCP here. If we have two buffers
813 both will be allocatable. */
814 if (__builtin_expect (anscp != NULL, 1)) {
815 u_char *newp = malloc (MAXPACKET);
816 if (newp == NULL) {
817 *terrno = ENOMEM;
818 __res_iclose(statp, false);
819 return (0);
821 *thisanssizp = MAXPACKET;
822 *thisansp = newp;
823 anhp = (HEADER *) newp;
824 len = rlen;
825 } else {
826 Dprint(statp->options & RES_DEBUG,
827 (stdout, ";; response truncated\n")
829 truncating = 1;
830 len = *thisanssizp;
832 } else
833 len = rlen;
835 if (__builtin_expect (len < HFIXEDSZ, 0)) {
837 * Undersized message.
839 Dprint(statp->options & RES_DEBUG,
840 (stdout, ";; undersized: %d\n", len));
841 *terrno = EMSGSIZE;
842 __res_iclose(statp, false);
843 return (0);
846 cp = *thisansp;
847 while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
848 cp += n;
849 len -= n;
851 if (__builtin_expect (n <= 0, 0)) {
852 *terrno = errno;
853 Perror(statp, stderr, "read(vc)", errno);
854 __res_iclose(statp, false);
855 return (0);
857 if (__builtin_expect (truncating, 0)) {
859 * Flush rest of answer so connection stays in synch.
861 anhp->tc = 1;
862 len = rlen - *thisanssizp;
863 while (len != 0) {
864 char junk[PACKETSZ];
866 n = read(statp->_vcsock, junk,
867 (len > sizeof junk) ? sizeof junk : len);
868 if (n > 0)
869 len -= n;
870 else
871 break;
875 * If the calling applicating has bailed out of
876 * a previous call and failed to arrange to have
877 * the circuit closed or the server has got
878 * itself confused, then drop the packet and
879 * wait for the correct one.
881 if ((recvresp1 || hp->id != anhp->id)
882 && (recvresp2 || hp2->id != anhp->id)) {
883 DprintQ((statp->options & RES_DEBUG) ||
884 (statp->pfcode & RES_PRF_REPLY),
885 (stdout, ";; old answer (unexpected):\n"),
886 *thisansp,
887 (rlen > *thisanssizp) ? *thisanssizp: rlen);
888 goto read_len;
891 /* Mark which reply we received. */
892 if (recvresp1 == 0 && hp->id == anhp->id)
893 recvresp1 = 1;
894 else
895 recvresp2 = 1;
896 /* Repeat waiting if we have a second answer to arrive. */
897 if ((recvresp1 & recvresp2) == 0)
898 goto read_len;
901 * All is well, or the error is fatal. Signal that the
902 * next nameserver ought not be tried.
904 return resplen;
907 static int
908 reopen (res_state statp, int *terrno, int ns)
910 if (EXT(statp).nssocks[ns] == -1) {
911 struct sockaddr *nsap
912 = (struct sockaddr *) EXT(statp).nsaddrs[ns];
913 socklen_t slen;
915 /* only try IPv6 if IPv6 NS and if not failed before */
916 if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) {
917 if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
918 EXT(statp).nssocks[ns] =
919 socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK,
921 #ifndef __ASSUME_SOCK_CLOEXEC
922 if (__have_o_nonblock == 0)
923 __have_o_nonblock
924 = (EXT(statp).nssocks[ns] == -1
925 && errno == EINVAL ? -1 : 1);
926 #endif
928 if (__builtin_expect (__have_o_nonblock < 0, 0))
929 EXT(statp).nssocks[ns] =
930 socket(PF_INET6, SOCK_DGRAM, 0);
931 if (EXT(statp).nssocks[ns] < 0)
932 statp->ipv6_unavail = errno == EAFNOSUPPORT;
933 slen = sizeof (struct sockaddr_in6);
934 } else if (nsap->sa_family == AF_INET) {
935 if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
936 EXT(statp).nssocks[ns]
937 = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK,
939 #ifndef __ASSUME_SOCK_CLOEXEC
940 if (__have_o_nonblock == 0)
941 __have_o_nonblock
942 = (EXT(statp).nssocks[ns] == -1
943 && errno == EINVAL ? -1 : 1);
944 #endif
946 if (__builtin_expect (__have_o_nonblock < 0, 0))
947 EXT(statp).nssocks[ns]
948 = socket(PF_INET, SOCK_DGRAM, 0);
949 slen = sizeof (struct sockaddr_in);
951 if (EXT(statp).nssocks[ns] < 0) {
952 *terrno = errno;
953 Perror(statp, stderr, "socket(dg)", errno);
954 return (-1);
958 * On a 4.3BSD+ machine (client and server,
959 * actually), sending to a nameserver datagram
960 * port with no nameserver will cause an
961 * ICMP port unreachable message to be returned.
962 * If our datagram socket is "connected" to the
963 * server, we get an ECONNREFUSED error on the next
964 * socket operation, and select returns if the
965 * error message is received. We can thus detect
966 * the absence of a nameserver without timing out.
968 if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) {
969 Aerror(statp, stderr, "connect(dg)", errno, nsap);
970 __res_iclose(statp, false);
971 return (0);
973 if (__builtin_expect (__have_o_nonblock < 0, 0)) {
974 /* Make socket non-blocking. */
975 int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
976 if (fl != -1)
977 __fcntl (EXT(statp).nssocks[ns], F_SETFL,
978 fl | O_NONBLOCK);
979 Dprint(statp->options & RES_DEBUG,
980 (stdout, ";; new DG socket\n"))
984 return 1;
987 static int
988 send_dg(res_state statp,
989 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
990 u_char **ansp, int *anssizp,
991 int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
992 u_char **ansp2, int *anssizp2, int *resplen2)
994 const HEADER *hp = (HEADER *) buf;
995 const HEADER *hp2 = (HEADER *) buf2;
996 u_char *ans = *ansp;
997 int orig_anssizp = *anssizp;
998 struct timespec now, timeout, finish;
999 struct pollfd pfd[1];
1000 int ptimeout;
1001 struct sockaddr_in6 from;
1002 int resplen = 0;
1003 int n;
1006 * Compute time for the total operation.
1008 int seconds = (statp->retrans << ns);
1009 if (ns > 0)
1010 seconds /= statp->nscount;
1011 if (seconds <= 0)
1012 seconds = 1;
1013 bool single_request = (statp->options & RES_SNGLKUP) != 0;
1014 bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
1015 int save_gotsomewhere = *gotsomewhere;
1017 int retval;
1018 retry_reopen:
1019 retval = reopen (statp, terrno, ns);
1020 if (retval <= 0)
1021 return retval;
1022 retry:
1023 evNowTime(&now);
1024 evConsTime(&timeout, seconds, 0);
1025 evAddTime(&finish, &now, &timeout);
1026 int need_recompute = 0;
1027 int nwritten = 0;
1028 int recvresp1 = 0;
1029 int recvresp2 = buf2 == NULL;
1030 pfd[0].fd = EXT(statp).nssocks[ns];
1031 pfd[0].events = POLLOUT;
1032 if (resplen2 != NULL)
1033 *resplen2 = 0;
1034 wait:
1035 if (need_recompute) {
1036 recompute_resend:
1037 evNowTime(&now);
1038 if (evCmpTime(finish, now) <= 0) {
1039 poll_err_out:
1040 Perror(statp, stderr, "poll", errno);
1041 err_out:
1042 __res_iclose(statp, false);
1043 return (0);
1045 evSubTime(&timeout, &finish, &now);
1046 need_recompute = 0;
1048 /* Convert struct timespec in milliseconds. */
1049 ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
1051 n = 0;
1052 if (nwritten == 0)
1053 n = __poll (pfd, 1, 0);
1054 if (__builtin_expect (n == 0, 0)) {
1055 n = __poll (pfd, 1, ptimeout);
1056 need_recompute = 1;
1058 if (n == 0) {
1059 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1060 if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
1062 /* There are quite a few broken name servers out
1063 there which don't handle two outstanding
1064 requests from the same source. There are also
1065 broken firewall settings. If we time out after
1066 having received one answer switch to the mode
1067 where we send the second request only once we
1068 have received the first answer. */
1069 if (!single_request)
1071 statp->options |= RES_SNGLKUP;
1072 single_request = true;
1073 *gotsomewhere = save_gotsomewhere;
1074 goto retry;
1076 else if (!single_request_reopen)
1078 statp->options |= RES_SNGLKUPREOP;
1079 single_request_reopen = true;
1080 *gotsomewhere = save_gotsomewhere;
1081 __res_iclose (statp, false);
1082 goto retry_reopen;
1085 *resplen2 = 1;
1086 return resplen;
1089 *gotsomewhere = 1;
1090 return (0);
1092 if (n < 0) {
1093 if (errno == EINTR)
1094 goto recompute_resend;
1096 goto poll_err_out;
1098 __set_errno (0);
1099 if (pfd[0].revents & POLLOUT) {
1100 ssize_t sr;
1101 if (nwritten != 0)
1102 sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
1103 else
1104 sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
1106 if (sr != buflen) {
1107 if (errno == EINTR || errno == EAGAIN)
1108 goto recompute_resend;
1109 Perror(statp, stderr, "send", errno);
1110 goto err_out;
1112 if (nwritten != 0 || buf2 == NULL
1113 || single_request || single_request_reopen)
1114 pfd[0].events = POLLIN;
1115 else
1116 pfd[0].events = POLLIN | POLLOUT;
1117 ++nwritten;
1118 goto wait;
1119 } else if (pfd[0].revents & POLLIN) {
1120 int *thisanssizp;
1121 u_char **thisansp;
1122 int *thisresplenp;
1124 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
1125 thisanssizp = anssizp;
1126 thisansp = anscp ?: ansp;
1127 assert (anscp != NULL || ansp2 == NULL);
1128 thisresplenp = &resplen;
1129 } else {
1130 if (*anssizp != MAXPACKET) {
1131 /* No buffer allocated for the first
1132 reply. We can try to use the rest
1133 of the user-provided buffer. */
1134 #ifdef _STRING_ARCH_unaligned
1135 *anssizp2 = orig_anssizp - resplen;
1136 *ansp2 = *ansp + resplen;
1137 #else
1138 int aligned_resplen
1139 = ((resplen + __alignof__ (HEADER) - 1)
1140 & ~(__alignof__ (HEADER) - 1));
1141 *anssizp2 = orig_anssizp - aligned_resplen;
1142 *ansp2 = *ansp + aligned_resplen;
1143 #endif
1144 } else {
1145 /* The first reply did not fit into the
1146 user-provided buffer. Maybe the second
1147 answer will. */
1148 *anssizp2 = orig_anssizp;
1149 *ansp2 = *ansp;
1152 thisanssizp = anssizp2;
1153 thisansp = ansp2;
1154 thisresplenp = resplen2;
1157 if (*thisanssizp < MAXPACKET
1158 /* Yes, we test ANSCP here. If we have two buffers
1159 both will be allocatable. */
1160 && anscp
1161 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
1162 || *thisanssizp < *thisresplenp)) {
1163 u_char *newp = malloc (MAXPACKET);
1164 if (newp != NULL) {
1165 *anssizp = MAXPACKET;
1166 *thisansp = ans = newp;
1169 HEADER *anhp = (HEADER *) *thisansp;
1170 socklen_t fromlen = sizeof(struct sockaddr_in6);
1171 assert (sizeof(from) <= fromlen);
1172 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
1173 *thisanssizp, 0,
1174 (struct sockaddr *)&from, &fromlen);
1175 if (__builtin_expect (*thisresplenp <= 0, 0)) {
1176 if (errno == EINTR || errno == EAGAIN) {
1177 need_recompute = 1;
1178 goto wait;
1180 Perror(statp, stderr, "recvfrom", errno);
1181 goto err_out;
1183 *gotsomewhere = 1;
1184 if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
1186 * Undersized message.
1188 Dprint(statp->options & RES_DEBUG,
1189 (stdout, ";; undersized: %d\n",
1190 *thisresplenp));
1191 *terrno = EMSGSIZE;
1192 goto err_out;
1194 if ((recvresp1 || hp->id != anhp->id)
1195 && (recvresp2 || hp2->id != anhp->id)) {
1197 * response from old query, ignore it.
1198 * XXX - potential security hazard could
1199 * be detected here.
1201 DprintQ((statp->options & RES_DEBUG) ||
1202 (statp->pfcode & RES_PRF_REPLY),
1203 (stdout, ";; old answer:\n"),
1204 thisansp,
1205 (*thisresplenp > *thisanssizp)
1206 ? *thisanssizp : *thisresplenp);
1207 goto wait;
1209 if (!(statp->options & RES_INSECURE1) &&
1210 !res_ourserver_p(statp, &from)) {
1212 * response from wrong server? ignore it.
1213 * XXX - potential security hazard could
1214 * be detected here.
1216 DprintQ((statp->options & RES_DEBUG) ||
1217 (statp->pfcode & RES_PRF_REPLY),
1218 (stdout, ";; not our server:\n"),
1219 thisansp,
1220 (*thisresplenp > *thisanssizp)
1221 ? *thisanssizp : *thisresplenp);
1222 goto wait;
1224 #ifdef RES_USE_EDNS0
1225 if (anhp->rcode == FORMERR
1226 && (statp->options & RES_USE_EDNS0) != 0U) {
1228 * Do not retry if the server does not understand
1229 * EDNS0. The case has to be captured here, as
1230 * FORMERR packet do not carry query section, hence
1231 * res_queriesmatch() returns 0.
1233 DprintQ(statp->options & RES_DEBUG,
1234 (stdout,
1235 "server rejected query with EDNS0:\n"),
1236 thisansp,
1237 (*thisresplenp > *thisanssizp)
1238 ? *thisanssizp : *thisresplenp);
1239 /* record the error */
1240 statp->_flags |= RES_F_EDNS0ERR;
1241 goto err_out;
1243 #endif
1244 if (!(statp->options & RES_INSECURE2)
1245 && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
1246 *thisansp,
1247 *thisansp
1248 + *thisanssizp))
1249 && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
1250 *thisansp,
1251 *thisansp
1252 + *thisanssizp))) {
1254 * response contains wrong query? ignore it.
1255 * XXX - potential security hazard could
1256 * be detected here.
1258 DprintQ((statp->options & RES_DEBUG) ||
1259 (statp->pfcode & RES_PRF_REPLY),
1260 (stdout, ";; wrong query name:\n"),
1261 thisansp,
1262 (*thisresplenp > *thisanssizp)
1263 ? *thisanssizp : *thisresplenp);
1264 goto wait;
1266 if (anhp->rcode == SERVFAIL ||
1267 anhp->rcode == NOTIMP ||
1268 anhp->rcode == REFUSED) {
1269 DprintQ(statp->options & RES_DEBUG,
1270 (stdout, "server rejected query:\n"),
1271 thisansp,
1272 (*thisresplenp > *thisanssizp)
1273 ? *thisanssizp : *thisresplenp);
1275 if (recvresp1 || (buf2 != NULL && recvresp2))
1276 return resplen;
1277 if (buf2 != NULL)
1279 /* We are waiting for a possible second reply. */
1280 if (hp->id == anhp->id)
1281 recvresp1 = 1;
1282 else
1283 recvresp2 = 1;
1285 goto wait;
1288 next_ns:
1289 __res_iclose(statp, false);
1290 /* don't retry if called from dig */
1291 if (!statp->pfcode)
1292 return (0);
1294 if (anhp->rcode == NOERROR && anhp->ancount == 0
1295 && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
1296 DprintQ(statp->options & RES_DEBUG,
1297 (stdout, "referred query:\n"),
1298 thisansp,
1299 (*thisresplenp > *thisanssizp)
1300 ? *thisanssizp : *thisresplenp);
1301 goto next_ns;
1303 if (!(statp->options & RES_IGNTC) && anhp->tc) {
1305 * To get the rest of answer,
1306 * use TCP with same server.
1308 Dprint(statp->options & RES_DEBUG,
1309 (stdout, ";; truncated answer\n"));
1310 *v_circuit = 1;
1311 __res_iclose(statp, false);
1312 // XXX if we have received one reply we could
1313 // XXX use it and not repeat it over TCP...
1314 return (1);
1316 /* Mark which reply we received. */
1317 if (recvresp1 == 0 && hp->id == anhp->id)
1318 recvresp1 = 1;
1319 else
1320 recvresp2 = 1;
1321 /* Repeat waiting if we have a second answer to arrive. */
1322 if ((recvresp1 & recvresp2) == 0) {
1323 if (single_request || single_request_reopen) {
1324 pfd[0].events = POLLOUT;
1325 if (single_request_reopen) {
1326 __res_iclose (statp, false);
1327 retval = reopen (statp, terrno, ns);
1328 if (retval <= 0)
1329 return retval;
1332 goto wait;
1335 * All is well, or the error is fatal. Signal that the
1336 * next nameserver ought not be tried.
1338 return (resplen);
1339 } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1340 /* Something went wrong. We can stop trying. */
1341 goto err_out;
1343 else {
1344 /* poll should not have returned > 0 in this case. */
1345 abort ();
1349 #ifdef DEBUG
1350 static void
1351 Aerror(const res_state statp, FILE *file, const char *string, int error,
1352 const struct sockaddr *address)
1354 int save = errno;
1356 if ((statp->options & RES_DEBUG) != 0) {
1357 char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
1359 fprintf(file, "res_send: %s ([%s].%u): %s\n",
1360 string,
1361 (address->sa_family == AF_INET
1362 ? inet_ntop(address->sa_family,
1363 &((const struct sockaddr_in *) address)->sin_addr,
1364 tmp, sizeof tmp)
1365 : inet_ntop(address->sa_family,
1366 &((const struct sockaddr_in6 *) address)->sin6_addr,
1367 tmp, sizeof tmp)),
1368 (address->sa_family == AF_INET
1369 ? ntohs(((struct sockaddr_in *) address)->sin_port)
1370 : address->sa_family == AF_INET6
1371 ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
1372 : 0),
1373 strerror(error));
1375 __set_errno (save);
1378 static void
1379 Perror(const res_state statp, FILE *file, const char *string, int error) {
1380 int save = errno;
1382 if ((statp->options & RES_DEBUG) != 0)
1383 fprintf(file, "res_send: %s: %s\n",
1384 string, strerror(error));
1385 __set_errno (save);
1387 #endif
1389 static int
1390 sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
1391 if (a1->sin6_family == a2->sin6_family) {
1392 if (a1->sin6_family == AF_INET)
1393 return ((((struct sockaddr_in *)a1)->sin_port ==
1394 ((struct sockaddr_in *)a2)->sin_port) &&
1395 (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
1396 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1397 else
1398 return ((a1->sin6_port == a2->sin6_port) &&
1399 !memcmp(&a1->sin6_addr, &a2->sin6_addr,
1400 sizeof (struct in6_addr)));
1402 if (a1->sin6_family == AF_INET) {
1403 struct sockaddr_in6 *sap = a1;
1404 a1 = a2;
1405 a2 = sap;
1406 } /* assumes that AF_INET and AF_INET6 are the only possibilities */
1407 return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
1408 IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
1409 (a1->sin6_addr.s6_addr32[3] ==
1410 ((struct sockaddr_in *)a2)->sin_addr.s_addr));