Home | History | Annotate | Line # | Download | only in resolv
res_send.c revision 1.28
      1 /*	$NetBSD: res_send.c,v 1.28 2013/02/16 13:37:01 christos Exp $	*/
      2 
      3 /*
      4  * Portions Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
      5  * Portions Copyright (C) 1996-2003  Internet Software Consortium.
      6  *
      7  * Permission to use, copy, modify, and/or distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
     12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
     14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
     15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
     16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     17  * PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 /*
     21  * Copyright (c) 1985, 1989, 1993
     22  *    The Regents of the University of California.  All rights reserved.
     23  *
     24  * Redistribution and use in source and binary forms, with or without
     25  * modification, are permitted provided that the following conditions
     26  * are met:
     27  * 1. Redistributions of source code must retain the above copyright
     28  *    notice, this list of conditions and the following disclaimer.
     29  * 2. Redistributions in binary form must reproduce the above copyright
     30  *    notice, this list of conditions and the following disclaimer in the
     31  *    documentation and/or other materials provided with the distribution.
     32  * 3. All advertising materials mentioning features or use of this software
     33  *    must display the following acknowledgement:
     34  * 	This product includes software developed by the University of
     35  * 	California, Berkeley and its contributors.
     36  * 4. Neither the name of the University nor the names of its contributors
     37  *    may be used to endorse or promote products derived from this software
     38  *    without specific prior written permission.
     39  *
     40  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50  * SUCH DAMAGE.
     51  */
     52 
     53 /*
     54  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
     55  *
     56  * Permission to use, copy, modify, and distribute this software for any
     57  * purpose with or without fee is hereby granted, provided that the above
     58  * copyright notice and this permission notice appear in all copies, and that
     59  * the name of Digital Equipment Corporation not be used in advertising or
     60  * publicity pertaining to distribution of the document or software without
     61  * specific, written prior permission.
     62  *
     63  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
     64  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
     65  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
     66  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
     67  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
     68  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
     69  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     70  * SOFTWARE.
     71  */
     72 
     73 /*
     74  * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
     75  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
     76  *
     77  * Permission to use, copy, modify, and distribute this software for any
     78  * purpose with or without fee is hereby granted, provided that the above
     79  * copyright notice and this permission notice appear in all copies.
     80  *
     81  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
     82  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     83  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
     84  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     85  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     86  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     87  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     88  */
     89 
     90 #include <sys/cdefs.h>
     91 #if defined(LIBC_SCCS) && !defined(lint)
     92 #ifdef notdef
     93 static const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
     94 static const char rcsid[] = "Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp";
     95 #else
     96 __RCSID("$NetBSD: res_send.c,v 1.28 2013/02/16 13:37:01 christos Exp $");
     97 #endif
     98 #endif /* LIBC_SCCS and not lint */
     99 
    100 /*! \file
    101  * \brief
    102  * Send query to name server and wait for reply.
    103  */
    104 
    105 #include "namespace.h"
    106 #include "port_before.h"
    107 #ifndef USE_KQUEUE
    108 #include "fd_setsize.h"
    109 #endif /* USE_KQUEUE */
    110 
    111 #include <sys/types.h>
    112 #include <sys/param.h>
    113 #include <sys/time.h>
    114 #include <sys/socket.h>
    115 #include <sys/uio.h>
    116 #ifdef USE_KQUEUE
    117 #include <sys/event.h>
    118 #endif /* USE_KQUEUE */
    119 
    120 #include <netinet/in.h>
    121 #include <arpa/nameser.h>
    122 #include <arpa/inet.h>
    123 
    124 #include <assert.h>
    125 #include <errno.h>
    126 #include <netdb.h>
    127 #include <resolv.h>
    128 #include <signal.h>
    129 #include <stdio.h>
    130 #include <fcntl.h>
    131 #include <stdlib.h>
    132 #include <string.h>
    133 #include <unistd.h>
    134 
    135 #include <isc/eventlib.h>
    136 
    137 #include "port_after.h"
    138 
    139 #if 0
    140 #ifdef __weak_alias
    141 __weak_alias(res_ourserver_p,__res_ourserver_p)
    142 __weak_alias(res_nameinquery,__res_nameinquery)
    143 __weak_alias(res_queriesmatch,__res_queriesmatch)
    144 __weak_alias(res_nsend,__res_nsend)
    145 #endif
    146 #endif
    147 
    148 #ifndef SOCK_NOSIGPIPE
    149 #define SOCK_NOSIGPIPE 0
    150 #endif
    151 #ifndef SOCK_NOCLOEXEC
    152 #define SOCK_NOCLOEXEC 0
    153 #endif
    154 
    155 #ifdef USE_POLL
    156 #ifdef HAVE_STROPTS_H
    157 #include <stropts.h>
    158 #endif
    159 #include <poll.h>
    160 #endif /* USE_POLL */
    161 
    162 /* Options.  Leave them on. */
    163 #ifndef DEBUG
    164 #define DEBUG
    165 #endif
    166 #include "res_debug.h"
    167 #include "res_private.h"
    168 
    169 #define EXT(res) ((res)->_u._ext)
    170 
    171 #if !defined(USE_POLL) && !defined(USE_KQUEUE)
    172 static const int highestFD = FD_SETSIZE - 1;
    173 #endif
    174 
    175 /* Forward. */
    176 
    177 static socklen_t	get_salen(const struct sockaddr *);
    178 static struct sockaddr * get_nsaddr(res_state, size_t);
    179 static int		send_vc(res_state, const void *, size_t,
    180 				u_char *, int, int *, int);
    181 static int		send_dg(res_state,
    182 #ifdef USE_KQUEUE
    183 				int,
    184 #endif
    185 				const void *, size_t,
    186 				u_char *, int, int *, int, int,
    187 				int *, int *);
    188 static void		Aerror(const res_state, FILE *, const char *, int,
    189 			       const struct sockaddr *, socklen_t);
    190 static void		Perror(const res_state, FILE *, const char *, int);
    191 static int		sock_eq(struct sockaddr *, struct sockaddr *);
    192 #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
    193 static int		pselect(int, void *, void *, void *,
    194 				struct timespec *,
    195 				const sigset_t *);
    196 #endif
    197 void res_pquery(const res_state, const u_char *, int, FILE *);
    198 
    199 static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
    200 
    201 /* Public. */
    202 
    203 /*%
    204  *	looks up "ina" in _res.ns_addr_list[]
    205  *
    206  * returns:
    207  *\li	0  : not found
    208  *\li	>0 : found
    209  *
    210  * author:
    211  *\li	paul vixie, 29may94
    212  */
    213 int
    214 res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
    215 	const struct sockaddr_in *inp, *srv;
    216 	const struct sockaddr_in6 *in6p, *srv6;
    217 	int ns;
    218 
    219 	switch (sa->sa_family) {
    220 	case AF_INET:
    221 		inp = (const struct sockaddr_in *)(const void *)sa;
    222 		for (ns = 0;  ns < statp->nscount;  ns++) {
    223 			srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
    224 			if (srv->sin_family == inp->sin_family &&
    225 			    srv->sin_port == inp->sin_port &&
    226 			    (srv->sin_addr.s_addr == INADDR_ANY ||
    227 			     srv->sin_addr.s_addr == inp->sin_addr.s_addr))
    228 				return (1);
    229 		}
    230 		break;
    231 	case AF_INET6:
    232 		if (EXT(statp).ext == NULL)
    233 			break;
    234 		in6p = (const struct sockaddr_in6 *)(const void *)sa;
    235 		for (ns = 0;  ns < statp->nscount;  ns++) {
    236 			srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
    237 			if (srv6->sin6_family == in6p->sin6_family &&
    238 			    srv6->sin6_port == in6p->sin6_port &&
    239 #ifdef HAVE_SIN6_SCOPE_ID
    240 			    (srv6->sin6_scope_id == 0 ||
    241 			     srv6->sin6_scope_id == in6p->sin6_scope_id) &&
    242 #endif
    243 			    (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
    244 			     IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
    245 				return (1);
    246 		}
    247 		break;
    248 	default:
    249 		break;
    250 	}
    251 	return (0);
    252 }
    253 
    254 /*%
    255  *	look for (name,type,class) in the query section of packet (buf,eom)
    256  *
    257  * requires:
    258  *\li	buf + HFIXEDSZ <= eom
    259  *
    260  * returns:
    261  *\li	-1 : format error
    262  *\li	0  : not found
    263  *\li	>0 : found
    264  *
    265  * author:
    266  *\li	paul vixie, 29may94
    267  */
    268 int
    269 res_nameinquery(const char *name, int type, int class,
    270 		const u_char *buf, const u_char *eom)
    271 {
    272 	const u_char *cp = buf + HFIXEDSZ;
    273 	int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
    274 
    275 	while (qdcount-- > 0) {
    276 		char tname[MAXDNAME+1];
    277 		int n, ttype, tclass;
    278 
    279 		n = dn_expand(buf, eom, cp, tname, (int)sizeof tname);
    280 		if (n < 0)
    281 			return (-1);
    282 		cp += n;
    283 		if (cp + 2 * INT16SZ > eom)
    284 			return (-1);
    285 		ttype = ns_get16(cp); cp += INT16SZ;
    286 		tclass = ns_get16(cp); cp += INT16SZ;
    287 		if (ttype == type && tclass == class &&
    288 		    ns_samename(tname, name) == 1)
    289 			return (1);
    290 	}
    291 	return (0);
    292 }
    293 
    294 /*%
    295  *	is there a 1:1 mapping of (name,type,class)
    296  *	in (buf1,eom1) and (buf2,eom2)?
    297  *
    298  * returns:
    299  *\li	-1 : format error
    300  *\li	0  : not a 1:1 mapping
    301  *\li	>0 : is a 1:1 mapping
    302  *
    303  * author:
    304  *\li	paul vixie, 29may94
    305  */
    306 int
    307 res_queriesmatch(const u_char *buf1, const u_char *eom1,
    308 		 const u_char *buf2, const u_char *eom2)
    309 {
    310 	const u_char *cp = buf1 + HFIXEDSZ;
    311 	int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
    312 
    313 	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
    314 		return (-1);
    315 
    316 	/*
    317 	 * Only header section present in replies to
    318 	 * dynamic update packets.
    319 	 */
    320 	if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
    321 	    (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
    322 		return (1);
    323 
    324 	if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
    325 		return (0);
    326 	while (qdcount-- > 0) {
    327 		char tname[MAXDNAME+1];
    328 		int n, ttype, tclass;
    329 
    330 		n = dn_expand(buf1, eom1, cp, tname, (int)sizeof tname);
    331 		if (n < 0)
    332 			return (-1);
    333 		cp += n;
    334 		if (cp + 2 * INT16SZ > eom1)
    335 			return (-1);
    336 		ttype = ns_get16(cp);	cp += INT16SZ;
    337 		tclass = ns_get16(cp); cp += INT16SZ;
    338 		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
    339 			return (0);
    340 	}
    341 	return (1);
    342 }
    343 
    344 int
    345 res_nsend(res_state statp,
    346 	  const u_char *buf, int buflen, u_char *ans, int anssiz)
    347 {
    348 	int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
    349 #ifdef USE_KQUEUE
    350 	int kq;
    351 #endif
    352 	char abuf[NI_MAXHOST];
    353 
    354 	(void)res_check(statp, NULL);
    355 
    356 	/* No name servers or res_init() failure */
    357 	if (statp->nscount == 0 || EXT(statp).ext == NULL) {
    358 		errno = ESRCH;
    359 		return (-1);
    360 	}
    361 	if (anssiz < HFIXEDSZ) {
    362 		errno = EINVAL;
    363 		return (-1);
    364 	}
    365 	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
    366 		(stdout, ";; res_send()\n"), buf, buflen);
    367 	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
    368 	gotsomewhere = 0;
    369 	terrno = ETIMEDOUT;
    370 
    371 #ifdef USE_KQUEUE
    372 	if ((kq = kqueue1(O_CLOEXEC)) == -1) {
    373 		return (-1);
    374 	}
    375 #endif
    376 
    377 	/*
    378 	 * If the ns_addr_list in the resolver context has changed, then
    379 	 * invalidate our cached copy and the associated timing data.
    380 	 */
    381 	if (EXT(statp).nscount != 0) {
    382 		int needclose = 0;
    383 		struct sockaddr_storage peer;
    384 		ISC_SOCKLEN_T peerlen;
    385 
    386 		if (EXT(statp).nscount != statp->nscount)
    387 			needclose++;
    388 		else
    389 			for (ns = 0; ns < statp->nscount; ns++) {
    390 				if (statp->nsaddr_list[ns].sin_family &&
    391 				    !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
    392 					     (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
    393 					needclose++;
    394 					break;
    395 				}
    396 
    397 				if (EXT(statp).nssocks[ns] == -1)
    398 					continue;
    399 				peerlen = sizeof(peer);
    400 				if (getpeername(EXT(statp).nssocks[ns],
    401 				    (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
    402 					needclose++;
    403 					break;
    404 				}
    405 				if (!sock_eq((struct sockaddr *)(void *)&peer,
    406 				    get_nsaddr(statp, (size_t)ns))) {
    407 					needclose++;
    408 					break;
    409 				}
    410 			}
    411 		if (needclose) {
    412 			res_nclose(statp);
    413 			EXT(statp).nscount = 0;
    414 		}
    415 	}
    416 
    417 	/*
    418 	 * Maybe initialize our private copy of the ns_addr_list.
    419 	 */
    420 	if (EXT(statp).nscount == 0) {
    421 		for (ns = 0; ns < statp->nscount; ns++) {
    422 			EXT(statp).nstimes[ns] = RES_MAXTIME;
    423 			EXT(statp).nssocks[ns] = -1;
    424 			if (!statp->nsaddr_list[ns].sin_family)
    425 				continue;
    426 			EXT(statp).ext->nsaddrs[ns].sin =
    427 				 statp->nsaddr_list[ns];
    428 		}
    429 		EXT(statp).nscount = statp->nscount;
    430 	}
    431 
    432 	/*
    433 	 * Some resolvers want to even out the load on their nameservers.
    434 	 * Note that RES_BLAST overrides RES_ROTATE.
    435 	 */
    436 	if ((statp->options & RES_ROTATE) != 0U &&
    437 	    (statp->options & RES_BLAST) == 0U) {
    438 		union res_sockaddr_union inu;
    439 		struct sockaddr_in ina;
    440 		int lastns = statp->nscount - 1;
    441 		int fd;
    442 		u_int16_t nstime;
    443 
    444 		if (EXT(statp).ext != NULL)
    445 			inu = EXT(statp).ext->nsaddrs[0];
    446 		ina = statp->nsaddr_list[0];
    447 		fd = EXT(statp).nssocks[0];
    448 		nstime = EXT(statp).nstimes[0];
    449 		for (ns = 0; ns < lastns; ns++) {
    450 			if (EXT(statp).ext != NULL)
    451 				EXT(statp).ext->nsaddrs[ns] =
    452 					EXT(statp).ext->nsaddrs[ns + 1];
    453 			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
    454 			EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
    455 			EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
    456 		}
    457 		if (EXT(statp).ext != NULL)
    458 			EXT(statp).ext->nsaddrs[lastns] = inu;
    459 		statp->nsaddr_list[lastns] = ina;
    460 		EXT(statp).nssocks[lastns] = fd;
    461 		EXT(statp).nstimes[lastns] = nstime;
    462 	}
    463 
    464 	/*
    465 	 * Send request, RETRY times, or until successful.
    466 	 */
    467 	for (tries = 0; tries < statp->retry; tries++) {
    468 	    for (ns = 0; ns < statp->nscount; ns++) {
    469 		struct sockaddr *nsap;
    470 		socklen_t nsaplen;
    471 		nsap = get_nsaddr(statp, (size_t)ns);
    472 		nsaplen = get_salen(nsap);
    473 		statp->_flags &= ~RES_F_LASTMASK;
    474 		statp->_flags |= (ns << RES_F_LASTSHIFT);
    475  same_ns:
    476 		if (statp->qhook) {
    477 			int done = 0, loops = 0;
    478 
    479 			do {
    480 				res_sendhookact act;
    481 
    482 				act = (*statp->qhook)(&nsap, &buf, &buflen,
    483 						      ans, anssiz, &resplen);
    484 				switch (act) {
    485 				case res_goahead:
    486 					done = 1;
    487 					break;
    488 				case res_nextns:
    489 					res_nclose(statp);
    490 					goto next_ns;
    491 				case res_done:
    492 #ifdef USE_KQUEUE
    493 					close(kq);
    494 #endif
    495 					return (resplen);
    496 				case res_modified:
    497 					/* give the hook another try */
    498 					if (++loops < 42) /*doug adams*/
    499 						break;
    500 					/*FALLTHROUGH*/
    501 				case res_error:
    502 					/*FALLTHROUGH*/
    503 				default:
    504 					goto fail;
    505 				}
    506 			} while (!done);
    507 		}
    508 
    509 		Dprint(((statp->options & RES_DEBUG) &&
    510 			getnameinfo(nsap, nsaplen, abuf,
    511 			    (socklen_t)sizeof(abuf), NULL, 0, niflags) == 0),
    512 		       (stdout, ";; Querying server (# %d) address = %s\n",
    513 			ns + 1, abuf));
    514 
    515 
    516 		if (v_circuit) {
    517 			/* Use VC; at most one attempt per server. */
    518 			tries = statp->retry;
    519 			n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
    520 				    ns);
    521 			if (n < 0)
    522 				goto fail;
    523 			if (n == 0)
    524 				goto next_ns;
    525 			resplen = n;
    526 		} else {
    527 			/* Use datagrams. */
    528 			n = send_dg(statp,
    529 #ifdef USE_KQUEUE
    530 			    kq,
    531 #endif
    532 			    buf, (size_t)buflen, ans, anssiz, &terrno,
    533 			    ns, tries, &v_circuit, &gotsomewhere);
    534 			if (n < 0)
    535 				goto fail;
    536 			if (n == 0)
    537 				goto next_ns;
    538 			if (v_circuit)
    539 				goto same_ns;
    540 			resplen = n;
    541 		}
    542 
    543 		Dprint((statp->options & RES_DEBUG) ||
    544 		       ((statp->pfcode & RES_PRF_REPLY) &&
    545 			(statp->pfcode & RES_PRF_HEAD1)),
    546 		       (stdout, ";; got answer:\n"));
    547 
    548 		DprintQ((statp->options & RES_DEBUG) ||
    549 			(statp->pfcode & RES_PRF_REPLY),
    550 			(stdout, "%s", ""),
    551 			ans, (resplen > anssiz) ? anssiz : resplen);
    552 
    553 		/*
    554 		 * If we have temporarily opened a virtual circuit,
    555 		 * or if we haven't been asked to keep a socket open,
    556 		 * close the socket.
    557 		 */
    558 		if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
    559 		    (statp->options & RES_STAYOPEN) == 0U) {
    560 			res_nclose(statp);
    561 		}
    562 		if (statp->rhook) {
    563 			int done = 0, loops = 0;
    564 
    565 			do {
    566 				res_sendhookact act;
    567 
    568 				act = (*statp->rhook)(nsap, buf, buflen,
    569 						      ans, anssiz, &resplen);
    570 				switch (act) {
    571 				case res_goahead:
    572 				case res_done:
    573 					done = 1;
    574 					break;
    575 				case res_nextns:
    576 					res_nclose(statp);
    577 					goto next_ns;
    578 				case res_modified:
    579 					/* give the hook another try */
    580 					if (++loops < 42) /*doug adams*/
    581 						break;
    582 					/*FALLTHROUGH*/
    583 				case res_error:
    584 					/*FALLTHROUGH*/
    585 				default:
    586 					goto fail;
    587 				}
    588 			} while (!done);
    589 
    590 		}
    591 #ifdef USE_KQUEUE
    592 		close(kq);
    593 #endif
    594 		return (resplen);
    595  next_ns: ;
    596 	   } /*foreach ns*/
    597 	} /*foreach retry*/
    598 	res_nclose(statp);
    599 #ifdef USE_KQUEUE
    600 	close(kq);
    601 #endif
    602 	if (!v_circuit) {
    603 		if (!gotsomewhere)
    604 			errno = ECONNREFUSED;	/*%< no nameservers found */
    605 		else
    606 			errno = ETIMEDOUT;	/*%< no answer obtained */
    607 	} else
    608 		errno = terrno;
    609 	return (-1);
    610  fail:
    611 	res_nclose(statp);
    612 #ifdef USE_KQUEUE
    613 	close(kq);
    614 #endif
    615 	return (-1);
    616 }
    617 
    618 /* Private */
    619 
    620 static socklen_t
    621 get_salen(const struct sockaddr *sa)
    622 {
    623 
    624 #ifdef HAVE_SA_LEN
    625 	/* There are people do not set sa_len.  Be forgiving to them. */
    626 	if (sa->sa_len)
    627 		return (socklen_t)sa->sa_len;
    628 #endif
    629 
    630 	if (sa->sa_family == AF_INET)
    631 		return (socklen_t)sizeof(struct sockaddr_in);
    632 	else if (sa->sa_family == AF_INET6)
    633 		return (socklen_t)sizeof(struct sockaddr_in6);
    634 	else
    635 		return 0;	/*%< unknown, die on connect */
    636 }
    637 
    638 /*%
    639  * pick appropriate nsaddr_list for use.  see res_init() for initialization.
    640  */
    641 static struct sockaddr *
    642 get_nsaddr(res_state statp, size_t n)
    643 {
    644 
    645 	if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
    646 		/*
    647 		 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
    648 		 *   than struct sockaddr, and
    649 		 * - user code did not update statp->nsaddr_list[n].
    650 		 */
    651 		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
    652 	} else {
    653 		/*
    654 		 * - user code updated statp->nsaddr_list[n], or
    655 		 * - statp->nsaddr_list[n] has the same content as
    656 		 *   EXT(statp).ext->nsaddrs[n].
    657 		 */
    658 		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
    659 	}
    660 }
    661 
    662 static int
    663 send_vc(res_state statp,
    664 	const void *buf, size_t buflen, u_char *ans, int anssiz,
    665 	int *terrno, int ns)
    666 {
    667 	const HEADER *hp = (const HEADER *)(const void *)buf;
    668 	HEADER *anhp = (HEADER *)(void *)ans;
    669 	struct sockaddr *nsap;
    670 	socklen_t nsaplen;
    671 	int truncating, connreset, resplen;
    672 	ssize_t n;
    673 	struct iovec iov[2];
    674 	u_short len;
    675 	u_char *cp;
    676 	void *tmp;
    677 #if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
    678 	int on = 1;
    679 #endif
    680 
    681 	nsap = get_nsaddr(statp, (size_t)ns);
    682 	nsaplen = get_salen(nsap);
    683 
    684 	connreset = 0;
    685  same_ns:
    686 	truncating = 0;
    687 
    688 	/* Are we still talking to whom we want to talk to? */
    689 	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
    690 		struct sockaddr_storage peer;
    691 		ISC_SOCKLEN_T size = sizeof peer;
    692 
    693 		if (getpeername(statp->_vcsock,
    694 				(struct sockaddr *)(void *)&peer, &size) < 0 ||
    695 		    !sock_eq((struct sockaddr *)(void *)&peer, nsap)) {
    696 			res_nclose(statp);
    697 			statp->_flags &= ~RES_F_VC;
    698 		}
    699 	}
    700 
    701 	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
    702 		if (statp->_vcsock >= 0)
    703 			res_nclose(statp);
    704 
    705 		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM
    706 			| SOCK_NOSIGPIPE | SOCK_CLOEXEC, 0);
    707 #if SOCK_CLOEXEC == 0
    708 		fcntl(statp->_vcsock, F_SETFD, FD_CLOEXEC);
    709 #endif
    710 #if !defined(USE_POLL) && !defined(USE_KQUEUE)
    711 		if (statp->_vcsock > highestFD) {
    712 			res_nclose(statp);
    713 			errno = ENOTSOCK;
    714 		}
    715 #endif
    716 		if (statp->_vcsock < 0) {
    717 			switch (errno) {
    718 			case EPROTONOSUPPORT:
    719 #ifdef EPFNOSUPPORT
    720 			case EPFNOSUPPORT:
    721 #endif
    722 			case EAFNOSUPPORT:
    723 				Perror(statp, stderr, "socket(vc)", errno);
    724 				return (0);
    725 			default:
    726 				*terrno = errno;
    727 				Perror(statp, stderr, "socket(vc)", errno);
    728 				return (-1);
    729 			}
    730 		}
    731 #if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
    732 		/*
    733 		 * Disable generation of SIGPIPE when writing to a closed
    734 		 * socket.  Write should return -1 and set errno to EPIPE
    735 		 * instead.
    736 		 *
    737 		 * Push on even if setsockopt(SO_NOSIGPIPE) fails.
    738 		 */
    739 		(void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
    740 				 (socklen_t)sizeof(on));
    741 #endif
    742 		errno = 0;
    743 		if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
    744 			*terrno = errno;
    745 			Aerror(statp, stderr, "connect/vc", errno, nsap,
    746 			    nsaplen);
    747 			res_nclose(statp);
    748 			return (0);
    749 		}
    750 		statp->_flags |= RES_F_VC;
    751 	}
    752 
    753 	/*
    754 	 * Send length & message
    755 	 */
    756 	ns_put16((u_short)buflen, (u_char*)(void *)&len);
    757 	iov[0] = evConsIovec(&len, INT16SZ);
    758 	DE_CONST(buf, tmp);
    759 	iov[1] = evConsIovec(tmp, (int)buflen);
    760 	if (writev(statp->_vcsock, iov, 2) != (ssize_t)(INT16SZ + buflen)) {
    761 		*terrno = errno;
    762 		Perror(statp, stderr, "write failed", errno);
    763 		res_nclose(statp);
    764 		return (0);
    765 	}
    766 	/*
    767 	 * Receive length & response
    768 	 */
    769  read_len:
    770 	cp = ans;
    771 	len = INT16SZ;
    772 	while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
    773 		cp += n;
    774 		if ((len -= (u_short)n) == 0)
    775 			break;
    776 	}
    777 	if (n <= 0) {
    778 		*terrno = errno;
    779 		Perror(statp, stderr, "read failed", errno);
    780 		res_nclose(statp);
    781 		/*
    782 		 * A long running process might get its TCP
    783 		 * connection reset if the remote server was
    784 		 * restarted.  Requery the server instead of
    785 		 * trying a new one.  When there is only one
    786 		 * server, this means that a query might work
    787 		 * instead of failing.  We only allow one reset
    788 		 * per query to prevent looping.
    789 		 */
    790 		if (*terrno == ECONNRESET && !connreset) {
    791 			connreset = 1;
    792 			res_nclose(statp);
    793 			goto same_ns;
    794 		}
    795 		res_nclose(statp);
    796 		return (0);
    797 	}
    798 	resplen = ns_get16(ans);
    799 	if (resplen > anssiz) {
    800 		Dprint(statp->options & RES_DEBUG,
    801 		       (stdout, ";; response truncated\n")
    802 		       );
    803 		truncating = 1;
    804 		len = anssiz;
    805 	} else
    806 		len = resplen;
    807 	if (len < HFIXEDSZ) {
    808 		/*
    809 		 * Undersized message.
    810 		 */
    811 		Dprint(statp->options & RES_DEBUG,
    812 		       (stdout, ";; undersized: %d\n", len));
    813 		*terrno = EMSGSIZE;
    814 		res_nclose(statp);
    815 		return (0);
    816 	}
    817 	cp = ans;
    818 	while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
    819 		cp += n;
    820 		len -= (u_short)n;
    821 	}
    822 	if (n <= 0) {
    823 		*terrno = errno;
    824 		Perror(statp, stderr, "read(vc)", errno);
    825 		res_nclose(statp);
    826 		return (0);
    827 	}
    828 	if (truncating) {
    829 		/*
    830 		 * Flush rest of answer so connection stays in synch.
    831 		 */
    832 		anhp->tc = 1;
    833 		len = resplen - anssiz;
    834 		while (len != 0) {
    835 			char junk[PACKETSZ];
    836 
    837 			n = read(statp->_vcsock, junk,
    838 				 (len > sizeof junk) ? sizeof junk : len);
    839 			if (n > 0)
    840 				len -= (u_short)n;
    841 			else
    842 				break;
    843 		}
    844 	}
    845 	/*
    846 	 * If the calling applicating has bailed out of
    847 	 * a previous call and failed to arrange to have
    848 	 * the circuit closed or the server has got
    849 	 * itself confused, then drop the packet and
    850 	 * wait for the correct one.
    851 	 */
    852 	if (hp->id != anhp->id) {
    853 		DprintQ((statp->options & RES_DEBUG) ||
    854 			(statp->pfcode & RES_PRF_REPLY),
    855 			(stdout, ";; old answer (unexpected):\n"),
    856 			ans, (resplen > anssiz) ? anssiz: resplen);
    857 		goto read_len;
    858 	}
    859 
    860 	/*
    861 	 * All is well, or the error is fatal.  Signal that the
    862 	 * next nameserver ought not be tried.
    863 	 */
    864 	return (resplen);
    865 }
    866 
    867 static int
    868 send_dg(res_state statp,
    869 #ifdef USE_KQUEUE
    870 	int kq,
    871 #endif
    872 	const void *buf, size_t buflen, u_char *ans,
    873 	int anssiz, int *terrno, int ns, int tries, int *v_circuit,
    874 	int *gotsomewhere)
    875 {
    876 	const HEADER *hp = (const HEADER *)(const void *)buf;
    877 	HEADER *anhp = (HEADER *)(void *)ans;
    878 	const struct sockaddr *nsap;
    879 	socklen_t nsaplen;
    880 	struct timespec now, timeout, finish;
    881 	struct sockaddr_storage from;
    882 	ISC_SOCKLEN_T fromlen;
    883 	ssize_t resplen;
    884 	int seconds, n, s;
    885 #ifdef USE_KQUEUE
    886 	struct kevent kv;
    887 #else
    888 #ifdef USE_POLL
    889 	int     polltimeout;
    890 	struct pollfd   pollfd;
    891 #else
    892 	fd_set dsmask;
    893 #endif
    894 #endif
    895 
    896 	nsap = get_nsaddr(statp, (size_t)ns);
    897 	nsaplen = get_salen(nsap);
    898 	if (EXT(statp).nssocks[ns] == -1) {
    899 		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM
    900 			| SOCK_CLOEXEC, 0);
    901 #if SOCK_CLOEXEC == 0
    902 		fcntl(EXT(statp)nssocks[ns], F_SETFD, FD_CLOEXEC);
    903 #endif
    904 #if !defined(USE_POLL) && !defined(USE_KQUEUE)
    905 		if (EXT(statp).nssocks[ns] > highestFD) {
    906 			res_nclose(statp);
    907 			errno = ENOTSOCK;
    908 		}
    909 #endif
    910 		if (EXT(statp).nssocks[ns] < 0) {
    911 			switch (errno) {
    912 			case EPROTONOSUPPORT:
    913 #ifdef EPFNOSUPPORT
    914 			case EPFNOSUPPORT:
    915 #endif
    916 			case EAFNOSUPPORT:
    917 				Perror(statp, stderr, "socket(dg)", errno);
    918 				return (0);
    919 			default:
    920 				*terrno = errno;
    921 				Perror(statp, stderr, "socket(dg)", errno);
    922 				return (-1);
    923 			}
    924 		}
    925 #ifndef CANNOT_CONNECT_DGRAM
    926 		/*
    927 		 * On a 4.3BSD+ machine (client and server,
    928 		 * actually), sending to a nameserver datagram
    929 		 * port with no nameserver will cause an
    930 		 * ICMP port unreachable message to be returned.
    931 		 * If our datagram socket is "connected" to the
    932 		 * server, we get an ECONNREFUSED error on the next
    933 		 * socket operation, and select returns if the
    934 		 * error message is received.  We can thus detect
    935 		 * the absence of a nameserver without timing out.
    936 		 *
    937 		 * When the option "insecure1" is specified, we'd
    938 		 * rather expect to see responses from an "unknown"
    939 		 * address.  In order to let the kernel accept such
    940 		 * responses, do not connect the socket here.
    941 		 * XXX: or do we need an explicit option to disable
    942 		 * connecting?
    943  		 */
    944 		if (!(statp->options & RES_INSECURE1) &&
    945 		    connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
    946 			Aerror(statp, stderr, "connect(dg)", errno, nsap,
    947 			    nsaplen);
    948 			res_nclose(statp);
    949 			return (0);
    950 		}
    951 #endif /* !CANNOT_CONNECT_DGRAM */
    952 		Dprint(statp->options & RES_DEBUG,
    953 		       (stdout, ";; new DG socket\n"))
    954 	}
    955 	s = EXT(statp).nssocks[ns];
    956 #ifndef CANNOT_CONNECT_DGRAM
    957 	if (statp->options & RES_INSECURE1) {
    958 		if (sendto(s, buf, buflen, 0, nsap, nsaplen) !=
    959 		    (ssize_t)buflen) {
    960 			Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
    961 			res_nclose(statp);
    962 			return (0);
    963 		}
    964 	} else if (send(s, buf, buflen, 0) != (ssize_t)buflen) {
    965 		Perror(statp, stderr, "send", errno);
    966 		res_nclose(statp);
    967 		return (0);
    968 	}
    969 #else /* !CANNOT_CONNECT_DGRAM */
    970 	if (sendto(s, buf, buflen, 0, nsap, nsaplen) != (ssize_t)buflen)
    971 	{
    972 		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
    973 		res_nclose(statp);
    974 		return (0);
    975 	}
    976 #endif /* !CANNOT_CONNECT_DGRAM */
    977 
    978 	/*
    979 	 * Wait for reply.
    980 	 */
    981 	seconds = (statp->retrans << tries);
    982 	if (ns > 0)
    983 		seconds /= statp->nscount;
    984 	if (seconds <= 0)
    985 		seconds = 1;
    986 	now = evNowTime();
    987 	timeout = evConsTime((time_t)seconds, 0L);
    988 	finish = evAddTime(now, timeout);
    989 	goto nonow;
    990  wait:
    991 	now = evNowTime();
    992  nonow:
    993 #ifndef USE_POLL
    994 	if (evCmpTime(finish, now) > 0)
    995 		timeout = evSubTime(finish, now);
    996 	else
    997 		timeout = evConsTime(0L, 0L);
    998 #ifdef USE_KQUEUE
    999 	EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
   1000 	n = kevent(kq, &kv, 1, &kv, 1, &timeout);
   1001 #else
   1002 	FD_ZERO(&dsmask);
   1003 	FD_SET(s, &dsmask);
   1004 	n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
   1005 #endif
   1006 #else
   1007 	timeout = evSubTime(finish, now);
   1008 	if (timeout.tv_sec < 0)
   1009 		timeout = evConsTime((time_t)0, 0L);
   1010 	polltimeout = 1000*(int)timeout.tv_sec +
   1011 		(int)timeout.tv_nsec/1000000;
   1012 	pollfd.fd = s;
   1013 	pollfd.events = POLLRDNORM;
   1014 	n = poll(&pollfd, 1, polltimeout);
   1015 #endif /* USE_POLL */
   1016 
   1017 	if (n == 0) {
   1018 		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
   1019 		*gotsomewhere = 1;
   1020 		return (0);
   1021 	}
   1022 	if (n < 0) {
   1023 #if defined(USE_POLL)
   1024 		static const char *fun = "poll";
   1025 #elif defined(USE_SELECT)
   1026 		static const char *fun = "select";
   1027 #elif defined(USE_KQUEUE)
   1028 		static const char *fun = "kevent";
   1029 #endif
   1030 		if (errno == EINTR)
   1031 			goto wait;
   1032 		Perror(statp, stderr, fun, errno);
   1033 		res_nclose(statp);
   1034 		return (0);
   1035 	}
   1036 #ifdef USE_KQUEUE
   1037 	if ((int)kv.ident != s)
   1038 		goto wait;
   1039 #endif
   1040 	errno = 0;
   1041 	fromlen = sizeof(from);
   1042 	resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
   1043 			   (struct sockaddr *)(void *)&from, &fromlen);
   1044 	if (resplen <= 0) {
   1045 		Perror(statp, stderr, "recvfrom", errno);
   1046 		res_nclose(statp);
   1047 		return (0);
   1048 	}
   1049 	*gotsomewhere = 1;
   1050 	if (resplen < HFIXEDSZ) {
   1051 		/*
   1052 		 * Undersized message.
   1053 		 */
   1054 		Dprint(statp->options & RES_DEBUG,
   1055 		       (stdout, ";; undersized: %zd\n",
   1056 			resplen));
   1057 		*terrno = EMSGSIZE;
   1058 		res_nclose(statp);
   1059 		return (0);
   1060 	}
   1061 	if (hp->id != anhp->id) {
   1062 		/*
   1063 		 * response from old query, ignore it.
   1064 		 * XXX - potential security hazard could
   1065 		 *	 be detected here.
   1066 		 */
   1067 		DprintQ((statp->options & RES_DEBUG) ||
   1068 			(statp->pfcode & RES_PRF_REPLY),
   1069 			(stdout, ";; old answer:\n"),
   1070 			ans, (resplen > anssiz) ? anssiz : resplen);
   1071 		goto wait;
   1072 	}
   1073 	if (!(statp->options & RES_INSECURE1) &&
   1074 	    !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
   1075 		/*
   1076 		 * response from wrong server? ignore it.
   1077 		 * XXX - potential security hazard could
   1078 		 *	 be detected here.
   1079 		 */
   1080 		DprintQ((statp->options & RES_DEBUG) ||
   1081 			(statp->pfcode & RES_PRF_REPLY),
   1082 			(stdout, ";; not our server:\n"),
   1083 			ans, (resplen > anssiz) ? anssiz : resplen);
   1084 		goto wait;
   1085 	}
   1086 #ifdef RES_USE_EDNS0
   1087 	if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
   1088 		/*
   1089 		 * Do not retry if the server do not understand EDNS0.
   1090 		 * The case has to be captured here, as FORMERR packet do not
   1091 		 * carry query section, hence res_queriesmatch() returns 0.
   1092 		 */
   1093 		DprintQ(statp->options & RES_DEBUG,
   1094 			(stdout, "server rejected query with EDNS0:\n"),
   1095 			ans, (resplen > anssiz) ? anssiz : resplen);
   1096 		/* record the error */
   1097 		statp->_flags |= RES_F_EDNS0ERR;
   1098 		res_nclose(statp);
   1099 		return (0);
   1100 	}
   1101 #endif
   1102 	if (!(statp->options & RES_INSECURE2) &&
   1103 	    !res_queriesmatch(buf, (const u_char *)buf + buflen,
   1104 			      ans, ans + anssiz)) {
   1105 		/*
   1106 		 * response contains wrong query? ignore it.
   1107 		 * XXX - potential security hazard could
   1108 		 *	 be detected here.
   1109 		 */
   1110 		DprintQ((statp->options & RES_DEBUG) ||
   1111 			(statp->pfcode & RES_PRF_REPLY),
   1112 			(stdout, ";; wrong query name:\n"),
   1113 			ans, (int)(resplen > anssiz) ? anssiz : resplen);
   1114 		goto wait;
   1115 	}
   1116 	if (anhp->rcode == SERVFAIL ||
   1117 	    anhp->rcode == NOTIMP ||
   1118 	    anhp->rcode == REFUSED) {
   1119 		DprintQ(statp->options & RES_DEBUG,
   1120 			(stdout, "server rejected query:\n"),
   1121 			ans, (int)(resplen > anssiz) ? anssiz : resplen);
   1122 		res_nclose(statp);
   1123 		/* don't retry if called from dig */
   1124 		if (!statp->pfcode)
   1125 			return (0);
   1126 	}
   1127 	if (!(statp->options & RES_IGNTC) && anhp->tc) {
   1128 		/*
   1129 		 * To get the rest of answer,
   1130 		 * use TCP with same server.
   1131 		 */
   1132 		Dprint(statp->options & RES_DEBUG,
   1133 		       (stdout, ";; truncated answer\n"));
   1134 		*v_circuit = 1;
   1135 		res_nclose(statp);
   1136 		return (1);
   1137 	}
   1138 	/*
   1139 	 * All is well, or the error is fatal.  Signal that the
   1140 	 * next nameserver ought not be tried.
   1141 	 */
   1142 	_DIAGASSERT(__type_fit(int, resplen));
   1143 	return (int)resplen;
   1144 }
   1145 
   1146 static void
   1147 Aerror(const res_state statp, FILE *file, const char *string, int error,
   1148        const struct sockaddr *address, socklen_t alen)
   1149 {
   1150 	int save = errno;
   1151 	char hbuf[NI_MAXHOST];
   1152 	char sbuf[NI_MAXSERV];
   1153 
   1154 	if ((statp->options & RES_DEBUG) != 0U) {
   1155 		if (getnameinfo(address, alen, hbuf,
   1156 		    (socklen_t)sizeof(hbuf), sbuf, (socklen_t)sizeof(sbuf),
   1157 		    niflags)) {
   1158 			strncpy(hbuf, "?", sizeof(hbuf) - 1);
   1159 			hbuf[sizeof(hbuf) - 1] = '\0';
   1160 			strncpy(sbuf, "?", sizeof(sbuf) - 1);
   1161 			sbuf[sizeof(sbuf) - 1] = '\0';
   1162 		}
   1163 		fprintf(file, "res_send: %s ([%s].%s): %s\n",
   1164 			string, hbuf, sbuf, strerror(error));
   1165 	}
   1166 	errno = save;
   1167 }
   1168 
   1169 static void
   1170 Perror(const res_state statp, FILE *file, const char *string, int error) {
   1171 	int save = errno;
   1172 
   1173 	if ((statp->options & RES_DEBUG) != 0U)
   1174 		fprintf(file, "res_send: %s: %s\n",
   1175 			string, strerror(error));
   1176 	errno = save;
   1177 }
   1178 
   1179 static int
   1180 sock_eq(struct sockaddr *a, struct sockaddr *b) {
   1181 	struct sockaddr_in *a4, *b4;
   1182 	struct sockaddr_in6 *a6, *b6;
   1183 
   1184 	if (a->sa_family != b->sa_family)
   1185 		return 0;
   1186 	switch (a->sa_family) {
   1187 	case AF_INET:
   1188 		a4 = (struct sockaddr_in *)(void *)a;
   1189 		b4 = (struct sockaddr_in *)(void *)b;
   1190 		return a4->sin_port == b4->sin_port &&
   1191 		    a4->sin_addr.s_addr == b4->sin_addr.s_addr;
   1192 	case AF_INET6:
   1193 		a6 = (struct sockaddr_in6 *)(void *)a;
   1194 		b6 = (struct sockaddr_in6 *)(void *)b;
   1195 		return a6->sin6_port == b6->sin6_port &&
   1196 #ifdef HAVE_SIN6_SCOPE_ID
   1197 		    a6->sin6_scope_id == b6->sin6_scope_id &&
   1198 #endif
   1199 		    IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
   1200 	default:
   1201 		return 0;
   1202 	}
   1203 }
   1204 
   1205 #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
   1206 /* XXX needs to move to the porting library. */
   1207 static int
   1208 pselect(int nfds, void *rfds, void *wfds, void *efds,
   1209 	struct timespec *tsp, const sigset_t *sigmask)
   1210 {
   1211 	struct timeval tv, *tvp;
   1212 	sigset_t sigs;
   1213 	int n;
   1214 
   1215 	if (tsp) {
   1216 		tvp = &tv;
   1217 		tv = evTimeVal(*tsp);
   1218 	} else
   1219 		tvp = NULL;
   1220 	if (sigmask)
   1221 		sigprocmask(SIG_SETMASK, sigmask, &sigs);
   1222 	n = select(nfds, rfds, wfds, efds, tvp);
   1223 	if (sigmask)
   1224 		sigprocmask(SIG_SETMASK, &sigs, NULL);
   1225 	if (tsp)
   1226 		*tsp = evTimeSpec(tv);
   1227 	return (n);
   1228 }
   1229 #endif
   1230