Simplify x86 strcmp-sse4 unwind info.
[glibc.git] / resolv / res_send.c
blob28a47e42b8ef03726db2e087faa45e67a9ad5726
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 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
495 if (nsap == NULL)
496 goto next_ns;
497 same_ns:
498 #ifdef USE_HOOKS
499 if (__builtin_expect (statp->qhook != NULL, 0)) {
500 int done = 0, loops = 0;
502 do {
503 res_sendhookact act;
505 struct sockaddr_in *nsap4;
506 nsap4 = (struct sockaddr_in *) nsap;
507 act = (*statp->qhook)(&nsap4, &buf, &buflen,
508 ans, anssiz, &resplen);
509 nsap = (struct sockaddr_in6 *) nsap4;
510 switch (act) {
511 case res_goahead:
512 done = 1;
513 break;
514 case res_nextns:
515 __res_iclose(statp, false);
516 goto next_ns;
517 case res_done:
518 return (resplen);
519 case res_modified:
520 /* give the hook another try */
521 if (++loops < 42) /*doug adams*/
522 break;
523 /*FALLTHROUGH*/
524 case res_error:
525 /*FALLTHROUGH*/
526 default:
527 return (-1);
529 } while (!done);
531 #endif
533 #ifdef DEBUG
534 char tmpbuf[40];
535 #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);
585 * If we have temporarily opened a virtual circuit,
586 * or if we haven't been asked to keep a socket open,
587 * close the socket.
589 if ((v_circuit && (statp->options & RES_USEVC) == 0) ||
590 (statp->options & RES_STAYOPEN) == 0) {
591 __res_iclose(statp, false);
593 #ifdef USE_HOOKS
594 if (__builtin_expect (statp->rhook, 0)) {
595 int done = 0, loops = 0;
597 do {
598 res_sendhookact act;
600 act = (*statp->rhook)((struct sockaddr_in *)
601 nsap, buf, buflen,
602 ans, anssiz, &resplen);
603 switch (act) {
604 case res_goahead:
605 case res_done:
606 done = 1;
607 break;
608 case res_nextns:
609 __res_iclose(statp, false);
610 goto next_ns;
611 case res_modified:
612 /* give the hook another try */
613 if (++loops < 42) /*doug adams*/
614 break;
615 /*FALLTHROUGH*/
616 case res_error:
617 /*FALLTHROUGH*/
618 default:
619 return (-1);
621 } while (!done);
624 #endif
625 return (resplen);
626 next_ns: ;
627 } /*foreach ns*/
628 } /*foreach retry*/
629 __res_iclose(statp, false);
630 if (!v_circuit) {
631 if (!gotsomewhere)
632 __set_errno (ECONNREFUSED); /* no nameservers found */
633 else
634 __set_errno (ETIMEDOUT); /* no answer obtained */
635 } else
636 __set_errno (terrno);
637 return (-1);
641 res_nsend(res_state statp,
642 const u_char *buf, int buflen, u_char *ans, int anssiz)
644 return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
645 NULL, NULL, NULL, NULL);
647 libresolv_hidden_def (res_nsend)
649 /* Private */
651 static int
652 send_vc(res_state statp,
653 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
654 u_char **ansp, int *anssizp,
655 int *terrno, int ns, u_char **anscp, u_char **ansp2, int *anssizp2,
656 int *resplen2)
658 const HEADER *hp = (HEADER *) buf;
659 const HEADER *hp2 = (HEADER *) buf2;
660 u_char *ans = *ansp;
661 int orig_anssizp = *anssizp;
662 // XXX REMOVE
663 // int anssiz = *anssizp;
664 HEADER *anhp = (HEADER *) ans;
665 struct sockaddr_in6 *nsap = EXT(statp).nsaddrs[ns];
666 int truncating, connreset, resplen, n;
667 struct iovec iov[4];
668 u_short len;
669 u_short len2;
670 u_char *cp;
672 if (resplen2 != NULL)
673 *resplen2 = 0;
674 connreset = 0;
675 same_ns:
676 truncating = 0;
678 /* Are we still talking to whom we want to talk to? */
679 if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
680 struct sockaddr_in6 peer;
681 socklen_t size = sizeof peer;
683 if (getpeername(statp->_vcsock,
684 (struct sockaddr *)&peer, &size) < 0 ||
685 !sock_eq(&peer, nsap)) {
686 __res_iclose(statp, false);
687 statp->_flags &= ~RES_F_VC;
691 if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
692 if (statp->_vcsock >= 0)
693 __res_iclose(statp, false);
695 statp->_vcsock = socket(nsap->sin6_family, SOCK_STREAM, 0);
696 if (statp->_vcsock < 0) {
697 *terrno = errno;
698 Perror(statp, stderr, "socket(vc)", errno);
699 return (-1);
701 __set_errno (0);
702 if (connect(statp->_vcsock, (struct sockaddr *)nsap,
703 nsap->sin6_family == AF_INET
704 ? sizeof (struct sockaddr_in)
705 : sizeof (struct sockaddr_in6)) < 0) {
706 *terrno = errno;
707 Aerror(statp, stderr, "connect/vc", errno,
708 (struct sockaddr *) nsap);
709 __res_iclose(statp, false);
710 return (0);
712 statp->_flags |= RES_F_VC;
716 * Send length & message
718 len = htons ((u_short) buflen);
719 evConsIovec(&len, INT16SZ, &iov[0]);
720 evConsIovec((void*)buf, buflen, &iov[1]);
721 int niov = 2;
722 ssize_t explen = INT16SZ + buflen;
723 if (buf2 != NULL) {
724 len2 = htons ((u_short) buflen2);
725 evConsIovec(&len2, INT16SZ, &iov[2]);
726 evConsIovec((void*)buf2, buflen2, &iov[3]);
727 niov = 4;
728 explen += INT16SZ + buflen2;
730 if (TEMP_FAILURE_RETRY (writev(statp->_vcsock, iov, niov)) != explen) {
731 *terrno = errno;
732 Perror(statp, stderr, "write failed", errno);
733 __res_iclose(statp, false);
734 return (0);
737 * Receive length & response
739 int recvresp1 = 0;
740 int recvresp2 = buf2 == NULL;
741 uint16_t rlen16;
742 read_len:
743 cp = (u_char *)&rlen16;
744 len = sizeof(rlen16);
745 while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
746 (int)len))) > 0) {
747 cp += n;
748 if ((len -= n) <= 0)
749 break;
751 if (n <= 0) {
752 *terrno = errno;
753 Perror(statp, stderr, "read failed", errno);
754 __res_iclose(statp, false);
756 * A long running process might get its TCP
757 * connection reset if the remote server was
758 * restarted. Requery the server instead of
759 * trying a new one. When there is only one
760 * server, this means that a query might work
761 * instead of failing. We only allow one reset
762 * per query to prevent looping.
764 if (*terrno == ECONNRESET && !connreset) {
765 connreset = 1;
766 goto same_ns;
768 return (0);
770 int rlen = ntohs (rlen16);
772 int *thisanssizp;
773 u_char **thisansp;
774 int *thisresplenp;
775 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
776 thisanssizp = anssizp;
777 thisansp = anscp ?: ansp;
778 assert (anscp != NULL || ansp2 == NULL);
779 thisresplenp = &resplen;
780 } else {
781 if (*anssizp != MAXPACKET) {
782 /* No buffer allocated for the first
783 reply. We can try to use the rest
784 of the user-provided buffer. */
785 #ifdef _STRING_ARCH_unaligned
786 *anssizp2 = orig_anssizp - resplen;
787 *ansp2 = *ansp + resplen;
788 #else
789 int aligned_resplen
790 = ((resplen + __alignof__ (HEADER) - 1)
791 & ~(__alignof__ (HEADER) - 1));
792 *anssizp2 = orig_anssizp - aligned_resplen;
793 *ansp2 = *ansp + aligned_resplen;
794 #endif
795 } else {
796 /* The first reply did not fit into the
797 user-provided buffer. Maybe the second
798 answer will. */
799 *anssizp2 = orig_anssizp;
800 *ansp2 = *ansp;
803 thisanssizp = anssizp2;
804 thisansp = ansp2;
805 thisresplenp = resplen2;
807 anhp = (HEADER *) *thisansp;
809 *thisresplenp = rlen;
810 if (rlen > *thisanssizp) {
811 /* Yes, we test ANSCP here. If we have two buffers
812 both will be allocatable. */
813 if (__builtin_expect (anscp != NULL, 1)) {
814 u_char *newp = malloc (MAXPACKET);
815 if (newp == NULL) {
816 *terrno = ENOMEM;
817 __res_iclose(statp, false);
818 return (0);
820 *thisanssizp = MAXPACKET;
821 *thisansp = newp;
822 anhp = (HEADER *) newp;
823 len = rlen;
824 } else {
825 Dprint(statp->options & RES_DEBUG,
826 (stdout, ";; response truncated\n")
828 truncating = 1;
829 len = *thisanssizp;
831 } else
832 len = rlen;
834 if (__builtin_expect (len < HFIXEDSZ, 0)) {
836 * Undersized message.
838 Dprint(statp->options & RES_DEBUG,
839 (stdout, ";; undersized: %d\n", len));
840 *terrno = EMSGSIZE;
841 __res_iclose(statp, false);
842 return (0);
845 cp = *thisansp;
846 while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
847 cp += n;
848 len -= n;
850 if (__builtin_expect (n <= 0, 0)) {
851 *terrno = errno;
852 Perror(statp, stderr, "read(vc)", errno);
853 __res_iclose(statp, false);
854 return (0);
856 if (__builtin_expect (truncating, 0)) {
858 * Flush rest of answer so connection stays in synch.
860 anhp->tc = 1;
861 len = rlen - *thisanssizp;
862 while (len != 0) {
863 char junk[PACKETSZ];
865 n = read(statp->_vcsock, junk,
866 (len > sizeof junk) ? sizeof junk : len);
867 if (n > 0)
868 len -= n;
869 else
870 break;
874 * If the calling applicating has bailed out of
875 * a previous call and failed to arrange to have
876 * the circuit closed or the server has got
877 * itself confused, then drop the packet and
878 * wait for the correct one.
880 if ((recvresp1 || hp->id != anhp->id)
881 && (recvresp2 || hp2->id != anhp->id)) {
882 DprintQ((statp->options & RES_DEBUG) ||
883 (statp->pfcode & RES_PRF_REPLY),
884 (stdout, ";; old answer (unexpected):\n"),
885 *thisansp,
886 (rlen > *thisanssiz) ? *thisanssiz: rlen);
887 goto read_len;
890 /* Mark which reply we received. */
891 if (recvresp1 == 0 && hp->id == anhp->id)
892 recvresp1 = 1;
893 else
894 recvresp2 = 1;
895 /* Repeat waiting if we have a second answer to arrive. */
896 if ((recvresp1 & recvresp2) == 0)
897 goto read_len;
900 * All is well, or the error is fatal. Signal that the
901 * next nameserver ought not be tried.
903 return resplen;
906 static int
907 reopen (res_state statp, int *terrno, int ns)
909 if (EXT(statp).nssocks[ns] == -1) {
910 struct sockaddr *nsap
911 = (struct sockaddr *) EXT(statp).nsaddrs[ns];
912 socklen_t slen;
914 /* only try IPv6 if IPv6 NS and if not failed before */
915 if (nsap->sa_family == AF_INET6 && !statp->ipv6_unavail) {
916 if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
917 EXT(statp).nssocks[ns] =
918 socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK,
920 #ifndef __ASSUME_SOCK_CLOEXEC
921 if (__have_o_nonblock == 0)
922 __have_o_nonblock
923 = (EXT(statp).nssocks[ns] == -1
924 && errno == EINVAL ? -1 : 1);
925 #endif
927 if (__builtin_expect (__have_o_nonblock < 0, 0))
928 EXT(statp).nssocks[ns] =
929 socket(PF_INET6, SOCK_DGRAM, 0);
930 if (EXT(statp).nssocks[ns] < 0)
931 statp->ipv6_unavail = errno == EAFNOSUPPORT;
932 slen = sizeof (struct sockaddr_in6);
933 } else if (nsap->sa_family == AF_INET) {
934 if (__builtin_expect (__have_o_nonblock >= 0, 1)) {
935 EXT(statp).nssocks[ns]
936 = socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK,
938 #ifndef __ASSUME_SOCK_CLOEXEC
939 if (__have_o_nonblock == 0)
940 __have_o_nonblock
941 = (EXT(statp).nssocks[ns] == -1
942 && errno == EINVAL ? -1 : 1);
943 #endif
945 if (__builtin_expect (__have_o_nonblock < 0, 0))
946 EXT(statp).nssocks[ns]
947 = socket(PF_INET, SOCK_DGRAM, 0);
948 slen = sizeof (struct sockaddr_in);
950 if (EXT(statp).nssocks[ns] < 0) {
951 *terrno = errno;
952 Perror(statp, stderr, "socket(dg)", errno);
953 return (-1);
957 * On a 4.3BSD+ machine (client and server,
958 * actually), sending to a nameserver datagram
959 * port with no nameserver will cause an
960 * ICMP port unreachable message to be returned.
961 * If our datagram socket is "connected" to the
962 * server, we get an ECONNREFUSED error on the next
963 * socket operation, and select returns if the
964 * error message is received. We can thus detect
965 * the absence of a nameserver without timing out.
967 if (connect(EXT(statp).nssocks[ns], nsap, slen) < 0) {
968 Aerror(statp, stderr, "connect(dg)", errno, nsap);
969 __res_iclose(statp, false);
970 return (0);
972 if (__builtin_expect (__have_o_nonblock < 0, 0)) {
973 /* Make socket non-blocking. */
974 int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL);
975 if (fl != -1)
976 __fcntl (EXT(statp).nssocks[ns], F_SETFL,
977 fl | O_NONBLOCK);
978 Dprint(statp->options & RES_DEBUG,
979 (stdout, ";; new DG socket\n"))
983 return 1;
986 static int
987 send_dg(res_state statp,
988 const u_char *buf, int buflen, const u_char *buf2, int buflen2,
989 u_char **ansp, int *anssizp,
990 int *terrno, int ns, int *v_circuit, int *gotsomewhere, u_char **anscp,
991 u_char **ansp2, int *anssizp2, int *resplen2)
993 const HEADER *hp = (HEADER *) buf;
994 const HEADER *hp2 = (HEADER *) buf2;
995 u_char *ans = *ansp;
996 int orig_anssizp = *anssizp;
997 struct timespec now, timeout, finish;
998 struct pollfd pfd[1];
999 int ptimeout;
1000 struct sockaddr_in6 from;
1001 int resplen = 0;
1002 int n;
1005 * Compute time for the total operation.
1007 int seconds = (statp->retrans << ns);
1008 if (ns > 0)
1009 seconds /= statp->nscount;
1010 if (seconds <= 0)
1011 seconds = 1;
1012 bool single_request = (statp->options & RES_SNGLKUP) != 0;
1013 bool single_request_reopen = (statp->options & RES_SNGLKUPREOP) != 0;
1014 int save_gotsomewhere = *gotsomewhere;
1016 int retval;
1017 retry_reopen:
1018 retval = reopen (statp, terrno, ns);
1019 if (retval <= 0)
1020 return retval;
1021 retry:
1022 evNowTime(&now);
1023 evConsTime(&timeout, seconds, 0);
1024 evAddTime(&finish, &now, &timeout);
1025 int need_recompute = 0;
1026 int nwritten = 0;
1027 int recvresp1 = 0;
1028 int recvresp2 = buf2 == NULL;
1029 pfd[0].fd = EXT(statp).nssocks[ns];
1030 pfd[0].events = POLLOUT;
1031 if (resplen2 != NULL)
1032 *resplen2 = 0;
1033 wait:
1034 if (need_recompute) {
1035 recompute_resend:
1036 evNowTime(&now);
1037 if (evCmpTime(finish, now) <= 0) {
1038 poll_err_out:
1039 Perror(statp, stderr, "poll", errno);
1040 err_out:
1041 __res_iclose(statp, false);
1042 return (0);
1044 evSubTime(&timeout, &finish, &now);
1045 need_recompute = 0;
1047 /* Convert struct timespec in milliseconds. */
1048 ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000;
1050 n = 0;
1051 if (nwritten == 0)
1052 n = __poll (pfd, 1, 0);
1053 if (__builtin_expect (n == 0, 0)) {
1054 n = __poll (pfd, 1, ptimeout);
1055 need_recompute = 1;
1057 if (n == 0) {
1058 Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1059 if (resplen > 1 && (recvresp1 || (buf2 != NULL && recvresp2)))
1061 /* There are quite a few broken name servers out
1062 there which don't handle two outstanding
1063 requests from the same source. There are also
1064 broken firewall settings. If we time out after
1065 having received one answer switch to the mode
1066 where we send the second request only once we
1067 have received the first answer. */
1068 if (!single_request)
1070 statp->options |= RES_SNGLKUP;
1071 single_request = true;
1072 *gotsomewhere = save_gotsomewhere;
1073 goto retry;
1075 else if (!single_request_reopen)
1077 statp->options |= RES_SNGLKUPREOP;
1078 single_request_reopen = true;
1079 *gotsomewhere = save_gotsomewhere;
1080 __res_iclose (statp, false);
1081 goto retry_reopen;
1084 *resplen2 = 1;
1085 return resplen;
1088 *gotsomewhere = 1;
1089 return (0);
1091 if (n < 0) {
1092 if (errno == EINTR)
1093 goto recompute_resend;
1095 goto poll_err_out;
1097 __set_errno (0);
1098 if (pfd[0].revents & POLLOUT) {
1099 ssize_t sr;
1100 if (nwritten != 0)
1101 sr = send (pfd[0].fd, buf2, buflen2, MSG_NOSIGNAL);
1102 else
1103 sr = send (pfd[0].fd, buf, buflen, MSG_NOSIGNAL);
1105 if (sr != buflen) {
1106 if (errno == EINTR || errno == EAGAIN)
1107 goto recompute_resend;
1108 Perror(statp, stderr, "send", errno);
1109 goto err_out;
1111 if (nwritten != 0 || buf2 == NULL
1112 || single_request || single_request_reopen)
1113 pfd[0].events = POLLIN;
1114 else
1115 pfd[0].events = POLLIN | POLLOUT;
1116 ++nwritten;
1117 goto wait;
1118 } else if (pfd[0].revents & POLLIN) {
1119 int *thisanssizp;
1120 u_char **thisansp;
1121 int *thisresplenp;
1123 if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) {
1124 thisanssizp = anssizp;
1125 thisansp = anscp ?: ansp;
1126 assert (anscp != NULL || ansp2 == NULL);
1127 thisresplenp = &resplen;
1128 } else {
1129 if (*anssizp != MAXPACKET) {
1130 /* No buffer allocated for the first
1131 reply. We can try to use the rest
1132 of the user-provided buffer. */
1133 #ifdef _STRING_ARCH_unaligned
1134 *anssizp2 = orig_anssizp - resplen;
1135 *ansp2 = *ansp + resplen;
1136 #else
1137 int aligned_resplen
1138 = ((resplen + __alignof__ (HEADER) - 1)
1139 & ~(__alignof__ (HEADER) - 1));
1140 *anssizp2 = orig_anssizp - aligned_resplen;
1141 *ansp2 = *ansp + aligned_resplen;
1142 #endif
1143 } else {
1144 /* The first reply did not fit into the
1145 user-provided buffer. Maybe the second
1146 answer will. */
1147 *anssizp2 = orig_anssizp;
1148 *ansp2 = *ansp;
1151 thisanssizp = anssizp2;
1152 thisansp = ansp2;
1153 thisresplenp = resplen2;
1156 if (*thisanssizp < MAXPACKET
1157 /* Yes, we test ANSCP here. If we have two buffers
1158 both will be allocatable. */
1159 && anscp
1160 && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0
1161 || *thisanssizp < *thisresplenp)) {
1162 u_char *newp = malloc (MAXPACKET);
1163 if (newp != NULL) {
1164 *anssizp = MAXPACKET;
1165 *thisansp = ans = newp;
1168 HEADER *anhp = (HEADER *) *thisansp;
1169 socklen_t fromlen = sizeof(struct sockaddr_in6);
1170 assert (sizeof(from) <= fromlen);
1171 *thisresplenp = recvfrom(pfd[0].fd, (char*)*thisansp,
1172 *thisanssizp, 0,
1173 (struct sockaddr *)&from, &fromlen);
1174 if (__builtin_expect (*thisresplenp <= 0, 0)) {
1175 if (errno == EINTR || errno == EAGAIN) {
1176 need_recompute = 1;
1177 goto wait;
1179 Perror(statp, stderr, "recvfrom", errno);
1180 goto err_out;
1182 *gotsomewhere = 1;
1183 if (__builtin_expect (*thisresplenp < HFIXEDSZ, 0)) {
1185 * Undersized message.
1187 Dprint(statp->options & RES_DEBUG,
1188 (stdout, ";; undersized: %d\n",
1189 *thisresplen));
1190 *terrno = EMSGSIZE;
1191 goto err_out;
1193 if ((recvresp1 || hp->id != anhp->id)
1194 && (recvresp2 || hp2->id != anhp->id)) {
1196 * response from old query, ignore it.
1197 * XXX - potential security hazard could
1198 * be detected here.
1200 DprintQ((statp->options & RES_DEBUG) ||
1201 (statp->pfcode & RES_PRF_REPLY),
1202 (stdout, ";; old answer:\n"),
1203 thisansp,
1204 (*thisresplen > *thisanssiz)
1205 ? *thisanssiz : *thisresplen);
1206 goto wait;
1208 if (!(statp->options & RES_INSECURE1) &&
1209 !res_ourserver_p(statp, &from)) {
1211 * response from wrong server? ignore it.
1212 * XXX - potential security hazard could
1213 * be detected here.
1215 DprintQ((statp->options & RES_DEBUG) ||
1216 (statp->pfcode & RES_PRF_REPLY),
1217 (stdout, ";; not our server:\n"),
1218 thisansp,
1219 (*thisresplen > *thisanssiz)
1220 ? *thisanssiz : *thisresplen);
1221 goto wait;
1223 #ifdef RES_USE_EDNS0
1224 if (anhp->rcode == FORMERR
1225 && (statp->options & RES_USE_EDNS0) != 0U) {
1227 * Do not retry if the server does not understand
1228 * EDNS0. The case has to be captured here, as
1229 * FORMERR packet do not carry query section, hence
1230 * res_queriesmatch() returns 0.
1232 DprintQ(statp->options & RES_DEBUG,
1233 (stdout,
1234 "server rejected query with EDNS0:\n"),
1235 thisans,
1236 (*thisresplen > *thisanssiz)
1237 ? *thisanssiz : *thisresplen);
1238 /* record the error */
1239 statp->_flags |= RES_F_EDNS0ERR;
1240 goto err_out;
1242 #endif
1243 if (!(statp->options & RES_INSECURE2)
1244 && (recvresp1 || !res_queriesmatch(buf, buf + buflen,
1245 *thisansp,
1246 *thisansp
1247 + *thisanssizp))
1248 && (recvresp2 || !res_queriesmatch(buf2, buf2 + buflen2,
1249 *thisansp,
1250 *thisansp
1251 + *thisanssizp))) {
1253 * response contains wrong query? ignore it.
1254 * XXX - potential security hazard could
1255 * be detected here.
1257 DprintQ((statp->options & RES_DEBUG) ||
1258 (statp->pfcode & RES_PRF_REPLY),
1259 (stdout, ";; wrong query name:\n"),
1260 thisansp,
1261 (*thisresplen > *thisanssiz)
1262 ? *thisanssiz : *thisresplen);
1263 goto wait;
1265 if (anhp->rcode == SERVFAIL ||
1266 anhp->rcode == NOTIMP ||
1267 anhp->rcode == REFUSED) {
1268 DprintQ(statp->options & RES_DEBUG,
1269 (stdout, "server rejected query:\n"),
1270 thisansp,
1271 (*thisresplen > *thisanssiz)
1272 ? *thisanssiz : *thisresplen);
1274 if (recvresp1 || (buf2 != NULL && recvresp2))
1275 return resplen;
1276 if (buf2 != NULL)
1278 /* We are waiting for a possible second reply. */
1279 if (hp->id == anhp->id)
1280 recvresp1 = 1;
1281 else
1282 recvresp2 = 1;
1284 goto wait;
1287 next_ns:
1288 __res_iclose(statp, false);
1289 /* don't retry if called from dig */
1290 if (!statp->pfcode)
1291 return (0);
1293 if (anhp->rcode == NOERROR && anhp->ancount == 0
1294 && anhp->aa == 0 && anhp->ra == 0 && anhp->arcount == 0) {
1295 DprintQ(statp->options & RES_DEBUG,
1296 (stdout, "referred query:\n"),
1297 thisansp,
1298 (*thisresplen > *thisanssiz)
1299 ? *thisanssiz : *thisresplen);
1300 goto next_ns;
1302 if (!(statp->options & RES_IGNTC) && anhp->tc) {
1304 * To get the rest of answer,
1305 * use TCP with same server.
1307 Dprint(statp->options & RES_DEBUG,
1308 (stdout, ";; truncated answer\n"));
1309 *v_circuit = 1;
1310 __res_iclose(statp, false);
1311 // XXX if we have received one reply we could
1312 // XXX use it and not repeat it over TCP...
1313 return (1);
1315 /* Mark which reply we received. */
1316 if (recvresp1 == 0 && hp->id == anhp->id)
1317 recvresp1 = 1;
1318 else
1319 recvresp2 = 1;
1320 /* Repeat waiting if we have a second answer to arrive. */
1321 if ((recvresp1 & recvresp2) == 0) {
1322 if (single_request || single_request_reopen) {
1323 pfd[0].events = POLLOUT;
1324 if (single_request_reopen) {
1325 __res_iclose (statp, false);
1326 retval = reopen (statp, terrno, ns);
1327 if (retval <= 0)
1328 return retval;
1331 goto wait;
1334 * All is well, or the error is fatal. Signal that the
1335 * next nameserver ought not be tried.
1337 return (resplen);
1338 } else if (pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
1339 /* Something went wrong. We can stop trying. */
1340 goto err_out;
1342 else {
1343 /* poll should not have returned > 0 in this case. */
1344 abort ();
1348 #ifdef DEBUG
1349 static void
1350 Aerror(const res_state statp, FILE *file, const char *string, int error,
1351 const struct sockaddr *address)
1353 int save = errno;
1355 if ((statp->options & RES_DEBUG) != 0) {
1356 char tmp[sizeof "xxxx.xxxx.xxxx.255.255.255.255"];
1358 fprintf(file, "res_send: %s ([%s].%u): %s\n",
1359 string,
1360 (address->sa_family == AF_INET
1361 ? inet_ntop(address->sa_family,
1362 &((const struct sockaddr_in *) address)->sin_addr,
1363 tmp, sizeof tmp)
1364 : inet_ntop(address->sa_family,
1365 &((const struct sockaddr_in6 *) address)->sin6_addr,
1366 tmp, sizeof tmp)),
1367 (address->sa_family == AF_INET
1368 ? ntohs(((struct sockaddr_in *) address)->sin_port)
1369 : address->sa_family == AF_INET6
1370 ? ntohs(((struct sockaddr_in6 *) address)->sin6_port)
1371 : 0),
1372 strerror(error));
1374 __set_errno (save);
1377 static void
1378 Perror(const res_state statp, FILE *file, const char *string, int error) {
1379 int save = errno;
1381 if ((statp->options & RES_DEBUG) != 0)
1382 fprintf(file, "res_send: %s: %s\n",
1383 string, strerror(error));
1384 __set_errno (save);
1386 #endif
1388 static int
1389 sock_eq(struct sockaddr_in6 *a1, struct sockaddr_in6 *a2) {
1390 if (a1->sin6_family == a2->sin6_family) {
1391 if (a1->sin6_family == AF_INET)
1392 return ((((struct sockaddr_in *)a1)->sin_port ==
1393 ((struct sockaddr_in *)a2)->sin_port) &&
1394 (((struct sockaddr_in *)a1)->sin_addr.s_addr ==
1395 ((struct sockaddr_in *)a2)->sin_addr.s_addr));
1396 else
1397 return ((a1->sin6_port == a2->sin6_port) &&
1398 !memcmp(&a1->sin6_addr, &a2->sin6_addr,
1399 sizeof (struct in6_addr)));
1401 if (a1->sin6_family == AF_INET) {
1402 struct sockaddr_in6 *sap = a1;
1403 a1 = a2;
1404 a2 = sap;
1405 } /* assumes that AF_INET and AF_INET6 are the only possibilities */
1406 return ((a1->sin6_port == ((struct sockaddr_in *)a2)->sin_port) &&
1407 IN6_IS_ADDR_V4MAPPED(&a1->sin6_addr) &&
1408 (a1->sin6_addr.s6_addr32[3] ==
1409 ((struct sockaddr_in *)a2)->sin_addr.s_addr));