res_send.c revision 260652
1156952Sume/*
2156952Sume * Copyright (c) 1985, 1989, 1993
3156952Sume *    The Regents of the University of California.  All rights reserved.
4156952Sume *
5156952Sume * Redistribution and use in source and binary forms, with or without
6156952Sume * modification, are permitted provided that the following conditions
7156952Sume * are met:
8156952Sume * 1. Redistributions of source code must retain the above copyright
9156952Sume *    notice, this list of conditions and the following disclaimer.
10156952Sume * 2. Redistributions in binary form must reproduce the above copyright
11156952Sume *    notice, this list of conditions and the following disclaimer in the
12156952Sume *    documentation and/or other materials provided with the distribution.
13156952Sume * 4. Neither the name of the University nor the names of its contributors
14156952Sume *    may be used to endorse or promote products derived from this software
15156952Sume *    without specific prior written permission.
16156952Sume *
17156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20156952Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27156952Sume * SUCH DAMAGE.
28156952Sume */
29156952Sume
30156952Sume/*
31156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32156952Sume *
33156952Sume * Permission to use, copy, modify, and distribute this software for any
34156952Sume * purpose with or without fee is hereby granted, provided that the above
35156952Sume * copyright notice and this permission notice appear in all copies, and that
36156952Sume * the name of Digital Equipment Corporation not be used in advertising or
37156952Sume * publicity pertaining to distribution of the document or software without
38156952Sume * specific, written prior permission.
39156952Sume *
40156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42156952Sume * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47156952Sume * SOFTWARE.
48156952Sume */
49156952Sume
50156952Sume/*
51156952Sume * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
52156952Sume * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
53156952Sume *
54156952Sume * Permission to use, copy, modify, and distribute this software for any
55156952Sume * purpose with or without fee is hereby granted, provided that the above
56156952Sume * copyright notice and this permission notice appear in all copies.
57156952Sume *
58156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
59156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60156952Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
61156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
64156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
65156952Sume */
66156952Sume
67156952Sume#if defined(LIBC_SCCS) && !defined(lint)
68156952Sumestatic const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
69186090Sumestatic const char rcsid[] = "$Id: res_send.c,v 1.9.18.10 2008/01/27 02:06:26 marka Exp $";
70156952Sume#endif /* LIBC_SCCS and not lint */
71156956Sume#include <sys/cdefs.h>
72156956Sume__FBSDID("$FreeBSD: head/lib/libc/resolv/res_send.c 260652 2014-01-14 22:05:33Z jilles $");
73156952Sume
74170244Sume/*! \file
75170244Sume * \brief
76156952Sume * Send query to name server and wait for reply.
77156952Sume */
78156952Sume
79156952Sume#include "port_before.h"
80260652Sjilles#if !defined(USE_KQUEUE) && !defined(USE_POLL)
81156952Sume#include "fd_setsize.h"
82156956Sume#endif
83156952Sume
84156956Sume#include "namespace.h"
85156952Sume#include <sys/types.h>
86156952Sume#include <sys/param.h>
87156952Sume#include <sys/time.h>
88156952Sume#include <sys/socket.h>
89156952Sume#include <sys/uio.h>
90156952Sume
91156952Sume#include <netinet/in.h>
92156952Sume#include <arpa/nameser.h>
93156952Sume#include <arpa/inet.h>
94156952Sume
95156952Sume#include <errno.h>
96156952Sume#include <netdb.h>
97156952Sume#include <resolv.h>
98156952Sume#include <signal.h>
99156952Sume#include <stdio.h>
100156952Sume#include <stdlib.h>
101156952Sume#include <string.h>
102156952Sume#include <unistd.h>
103156952Sume
104156952Sume#include <isc/eventlib.h>
105156952Sume
106156952Sume#include "port_after.h"
107156952Sume
108156956Sume#ifdef USE_KQUEUE
109156956Sume#include <sys/event.h>
110156956Sume#else
111156952Sume#ifdef USE_POLL
112156952Sume#ifdef HAVE_STROPTS_H
113156952Sume#include <stropts.h>
114156952Sume#endif
115156952Sume#include <poll.h>
116156952Sume#endif /* USE_POLL */
117156956Sume#endif
118156952Sume
119156956Sume#include "un-namespace.h"
120156956Sume
121156952Sume/* Options.  Leave them on. */
122156952Sume#define DEBUG
123156952Sume#include "res_debug.h"
124156952Sume#include "res_private.h"
125156952Sume
126156952Sume#define EXT(res) ((res)->_u._ext)
127156952Sume
128167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE)
129156952Sumestatic const int highestFD = FD_SETSIZE - 1;
130156952Sume#endif
131156952Sume
132156952Sume/* Forward. */
133156952Sume
134156956Sumestatic int		get_salen(const struct sockaddr *);
135156956Sumestatic struct sockaddr * get_nsaddr(res_state, size_t);
136156952Sumestatic int		send_vc(res_state, const u_char *, int,
137156952Sume				u_char *, int, int *, int);
138156956Sumestatic int		send_dg(res_state,
139156956Sume#ifdef USE_KQUEUE
140156956Sume				int kq,
141156956Sume#endif
142156956Sume				const u_char *, int,
143163661Sume				u_char *, int, int *, int, int,
144156952Sume				int *, int *);
145156952Sumestatic void		Aerror(const res_state, FILE *, const char *, int,
146156952Sume			       const struct sockaddr *, int);
147156952Sumestatic void		Perror(const res_state, FILE *, const char *, int);
148156952Sumestatic int		sock_eq(struct sockaddr *, struct sockaddr *);
149156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
150156952Sumestatic int		pselect(int, void *, void *, void *,
151156952Sume				struct timespec *,
152156952Sume				const sigset_t *);
153156952Sume#endif
154156952Sumevoid res_pquery(const res_state, const u_char *, int, FILE *);
155156952Sume
156156952Sumestatic const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
157156952Sume
158156952Sume/* Public. */
159156952Sume
160170244Sume/*%
161156952Sume *	looks up "ina" in _res.ns_addr_list[]
162170244Sume *
163156952Sume * returns:
164170244Sume *\li	0  : not found
165170244Sume *\li	>0 : found
166170244Sume *
167156952Sume * author:
168170244Sume *\li	paul vixie, 29may94
169156952Sume */
170156952Sumeint
171156952Sumeres_ourserver_p(const res_state statp, const struct sockaddr *sa) {
172156952Sume	const struct sockaddr_in *inp, *srv;
173156952Sume	const struct sockaddr_in6 *in6p, *srv6;
174156952Sume	int ns;
175156952Sume
176156952Sume	switch (sa->sa_family) {
177156952Sume	case AF_INET:
178156952Sume		inp = (const struct sockaddr_in *)sa;
179156952Sume		for (ns = 0;  ns < statp->nscount;  ns++) {
180156952Sume			srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
181156952Sume			if (srv->sin_family == inp->sin_family &&
182156952Sume			    srv->sin_port == inp->sin_port &&
183156952Sume			    (srv->sin_addr.s_addr == INADDR_ANY ||
184156952Sume			     srv->sin_addr.s_addr == inp->sin_addr.s_addr))
185156952Sume				return (1);
186156952Sume		}
187156952Sume		break;
188156952Sume	case AF_INET6:
189156952Sume		if (EXT(statp).ext == NULL)
190156952Sume			break;
191156952Sume		in6p = (const struct sockaddr_in6 *)sa;
192156952Sume		for (ns = 0;  ns < statp->nscount;  ns++) {
193156952Sume			srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
194156952Sume			if (srv6->sin6_family == in6p->sin6_family &&
195156952Sume			    srv6->sin6_port == in6p->sin6_port &&
196156952Sume#ifdef HAVE_SIN6_SCOPE_ID
197156952Sume			    (srv6->sin6_scope_id == 0 ||
198156952Sume			     srv6->sin6_scope_id == in6p->sin6_scope_id) &&
199156952Sume#endif
200156952Sume			    (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
201156952Sume			     IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
202156952Sume				return (1);
203156952Sume		}
204156952Sume		break;
205156952Sume	default:
206156952Sume		break;
207156952Sume	}
208156952Sume	return (0);
209156952Sume}
210156952Sume
211170244Sume/*%
212156952Sume *	look for (name,type,class) in the query section of packet (buf,eom)
213170244Sume *
214156952Sume * requires:
215170244Sume *\li	buf + HFIXEDSZ <= eom
216170244Sume *
217156952Sume * returns:
218170244Sume *\li	-1 : format error
219170244Sume *\li	0  : not found
220170244Sume *\li	>0 : found
221170244Sume *
222156952Sume * author:
223170244Sume *\li	paul vixie, 29may94
224156952Sume */
225156952Sumeint
226156952Sumeres_nameinquery(const char *name, int type, int class,
227156952Sume		const u_char *buf, const u_char *eom)
228156952Sume{
229156952Sume	const u_char *cp = buf + HFIXEDSZ;
230156952Sume	int qdcount = ntohs(((const HEADER*)buf)->qdcount);
231156952Sume
232156952Sume	while (qdcount-- > 0) {
233156952Sume		char tname[MAXDNAME+1];
234156952Sume		int n, ttype, tclass;
235156952Sume
236156952Sume		n = dn_expand(buf, eom, cp, tname, sizeof tname);
237156952Sume		if (n < 0)
238156952Sume			return (-1);
239156952Sume		cp += n;
240156952Sume		if (cp + 2 * INT16SZ > eom)
241156952Sume			return (-1);
242156952Sume		ttype = ns_get16(cp); cp += INT16SZ;
243156952Sume		tclass = ns_get16(cp); cp += INT16SZ;
244156952Sume		if (ttype == type && tclass == class &&
245156952Sume		    ns_samename(tname, name) == 1)
246156952Sume			return (1);
247156952Sume	}
248156952Sume	return (0);
249156952Sume}
250156952Sume
251170244Sume/*%
252156952Sume *	is there a 1:1 mapping of (name,type,class)
253156952Sume *	in (buf1,eom1) and (buf2,eom2)?
254170244Sume *
255156952Sume * returns:
256170244Sume *\li	-1 : format error
257170244Sume *\li	0  : not a 1:1 mapping
258170244Sume *\li	>0 : is a 1:1 mapping
259170244Sume *
260156952Sume * author:
261170244Sume *\li	paul vixie, 29may94
262156952Sume */
263156952Sumeint
264156952Sumeres_queriesmatch(const u_char *buf1, const u_char *eom1,
265156952Sume		 const u_char *buf2, const u_char *eom2)
266156952Sume{
267156952Sume	const u_char *cp = buf1 + HFIXEDSZ;
268156952Sume	int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
269156952Sume
270156952Sume	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
271156952Sume		return (-1);
272156952Sume
273156952Sume	/*
274156952Sume	 * Only header section present in replies to
275156952Sume	 * dynamic update packets.
276156952Sume	 */
277156952Sume	if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
278156952Sume	    (((const HEADER *)buf2)->opcode == ns_o_update))
279156952Sume		return (1);
280156952Sume
281156952Sume	if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
282156952Sume		return (0);
283156952Sume	while (qdcount-- > 0) {
284156952Sume		char tname[MAXDNAME+1];
285156952Sume		int n, ttype, tclass;
286156952Sume
287156952Sume		n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
288156952Sume		if (n < 0)
289156952Sume			return (-1);
290156952Sume		cp += n;
291156952Sume		if (cp + 2 * INT16SZ > eom1)
292156952Sume			return (-1);
293156952Sume		ttype = ns_get16(cp);	cp += INT16SZ;
294156952Sume		tclass = ns_get16(cp); cp += INT16SZ;
295156952Sume		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
296156952Sume			return (0);
297156952Sume	}
298156952Sume	return (1);
299156952Sume}
300156952Sume
301156952Sumeint
302156952Sumeres_nsend(res_state statp,
303156952Sume	  const u_char *buf, int buflen, u_char *ans, int anssiz)
304156952Sume{
305186090Sume	int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
306156956Sume#ifdef USE_KQUEUE
307156956Sume	int kq;
308156956Sume#endif
309156952Sume	char abuf[NI_MAXHOST];
310156952Sume
311165258Sume	/* No name servers or res_init() failure */
312165258Sume	if (statp->nscount == 0 || EXT(statp).ext == NULL) {
313156952Sume		errno = ESRCH;
314156952Sume		return (-1);
315156952Sume	}
316156952Sume	if (anssiz < HFIXEDSZ) {
317156952Sume		errno = EINVAL;
318156952Sume		return (-1);
319156952Sume	}
320156952Sume	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
321156952Sume		(stdout, ";; res_send()\n"), buf, buflen);
322156952Sume	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
323156952Sume	gotsomewhere = 0;
324156952Sume	terrno = ETIMEDOUT;
325156952Sume
326156956Sume#ifdef USE_KQUEUE
327156956Sume	if ((kq = kqueue()) < 0) {
328156956Sume		Perror(statp, stderr, "kqueue", errno);
329156956Sume		return (-1);
330156956Sume	}
331156956Sume#endif
332156956Sume
333156952Sume	/*
334156952Sume	 * If the ns_addr_list in the resolver context has changed, then
335156952Sume	 * invalidate our cached copy and the associated timing data.
336156952Sume	 */
337156952Sume	if (EXT(statp).nscount != 0) {
338156952Sume		int needclose = 0;
339156952Sume		struct sockaddr_storage peer;
340156952Sume		ISC_SOCKLEN_T peerlen;
341156952Sume
342156952Sume		if (EXT(statp).nscount != statp->nscount)
343156952Sume			needclose++;
344156952Sume		else
345156952Sume			for (ns = 0; ns < statp->nscount; ns++) {
346156952Sume				if (statp->nsaddr_list[ns].sin_family &&
347156952Sume				    !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
348156952Sume					     (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
349156952Sume					needclose++;
350156952Sume					break;
351156952Sume				}
352156952Sume
353156952Sume				if (EXT(statp).nssocks[ns] == -1)
354156952Sume					continue;
355156952Sume				peerlen = sizeof(peer);
356156956Sume				if (_getsockname(EXT(statp).nssocks[ns],
357156952Sume				    (struct sockaddr *)&peer, &peerlen) < 0) {
358156952Sume					needclose++;
359156952Sume					break;
360156952Sume				}
361156952Sume				if (!sock_eq((struct sockaddr *)&peer,
362156952Sume				    get_nsaddr(statp, ns))) {
363156952Sume					needclose++;
364156952Sume					break;
365156952Sume				}
366156952Sume			}
367156952Sume		if (needclose) {
368156952Sume			res_nclose(statp);
369156952Sume			EXT(statp).nscount = 0;
370156952Sume		}
371156952Sume	}
372156952Sume
373156952Sume	/*
374156952Sume	 * Maybe initialize our private copy of the ns_addr_list.
375156952Sume	 */
376156952Sume	if (EXT(statp).nscount == 0) {
377156952Sume		for (ns = 0; ns < statp->nscount; ns++) {
378156952Sume			EXT(statp).nstimes[ns] = RES_MAXTIME;
379156952Sume			EXT(statp).nssocks[ns] = -1;
380156952Sume			if (!statp->nsaddr_list[ns].sin_family)
381156952Sume				continue;
382156952Sume			EXT(statp).ext->nsaddrs[ns].sin =
383156952Sume				 statp->nsaddr_list[ns];
384156952Sume		}
385156952Sume		EXT(statp).nscount = statp->nscount;
386156952Sume	}
387156952Sume
388156952Sume	/*
389156952Sume	 * Some resolvers want to even out the load on their nameservers.
390156952Sume	 * Note that RES_BLAST overrides RES_ROTATE.
391156952Sume	 */
392156952Sume	if ((statp->options & RES_ROTATE) != 0U &&
393156952Sume	    (statp->options & RES_BLAST) == 0U) {
394156952Sume		union res_sockaddr_union inu;
395156952Sume		struct sockaddr_in ina;
396156952Sume		int lastns = statp->nscount - 1;
397156952Sume		int fd;
398156952Sume		u_int16_t nstime;
399156952Sume
400156952Sume		if (EXT(statp).ext != NULL)
401156952Sume			inu = EXT(statp).ext->nsaddrs[0];
402156952Sume		ina = statp->nsaddr_list[0];
403156952Sume		fd = EXT(statp).nssocks[0];
404156952Sume		nstime = EXT(statp).nstimes[0];
405156952Sume		for (ns = 0; ns < lastns; ns++) {
406156952Sume			if (EXT(statp).ext != NULL)
407156952Sume                                EXT(statp).ext->nsaddrs[ns] =
408156952Sume					EXT(statp).ext->nsaddrs[ns + 1];
409156952Sume			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
410156952Sume			EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
411156952Sume			EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
412156952Sume		}
413156952Sume		if (EXT(statp).ext != NULL)
414156952Sume			EXT(statp).ext->nsaddrs[lastns] = inu;
415156952Sume		statp->nsaddr_list[lastns] = ina;
416156952Sume		EXT(statp).nssocks[lastns] = fd;
417156952Sume		EXT(statp).nstimes[lastns] = nstime;
418156952Sume	}
419156952Sume
420156952Sume	/*
421156952Sume	 * Send request, RETRY times, or until successful.
422156952Sume	 */
423186090Sume	for (tries = 0; tries < statp->retry; tries++) {
424156952Sume	    for (ns = 0; ns < statp->nscount; ns++) {
425156952Sume		struct sockaddr *nsap;
426156952Sume		int nsaplen;
427156952Sume		nsap = get_nsaddr(statp, ns);
428156952Sume		nsaplen = get_salen(nsap);
429156952Sume		statp->_flags &= ~RES_F_LASTMASK;
430156952Sume		statp->_flags |= (ns << RES_F_LASTSHIFT);
431156952Sume same_ns:
432156952Sume		if (statp->qhook) {
433156952Sume			int done = 0, loops = 0;
434156952Sume
435156952Sume			do {
436156952Sume				res_sendhookact act;
437156952Sume
438156952Sume				act = (*statp->qhook)(&nsap, &buf, &buflen,
439156952Sume						      ans, anssiz, &resplen);
440156952Sume				switch (act) {
441156952Sume				case res_goahead:
442156952Sume					done = 1;
443156952Sume					break;
444156952Sume				case res_nextns:
445156952Sume					res_nclose(statp);
446156952Sume					goto next_ns;
447156952Sume				case res_done:
448156956Sume#ifdef USE_KQUEUE
449156956Sume					_close(kq);
450156956Sume#endif
451156952Sume					return (resplen);
452156952Sume				case res_modified:
453156952Sume					/* give the hook another try */
454156952Sume					if (++loops < 42) /*doug adams*/
455156952Sume						break;
456156952Sume					/*FALLTHROUGH*/
457156952Sume				case res_error:
458156952Sume					/*FALLTHROUGH*/
459156952Sume				default:
460156952Sume					goto fail;
461156952Sume				}
462156952Sume			} while (!done);
463156952Sume		}
464156952Sume
465156952Sume		Dprint(((statp->options & RES_DEBUG) &&
466156952Sume			getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
467156952Sume				    NULL, 0, niflags) == 0),
468156952Sume		       (stdout, ";; Querying server (# %d) address = %s\n",
469156952Sume			ns + 1, abuf));
470156952Sume
471156952Sume
472156952Sume		if (v_circuit) {
473156952Sume			/* Use VC; at most one attempt per server. */
474186090Sume			tries = statp->retry;
475156952Sume			n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
476156952Sume				    ns);
477156952Sume			if (n < 0)
478156952Sume				goto fail;
479156952Sume			if (n == 0)
480156952Sume				goto next_ns;
481156952Sume			resplen = n;
482156952Sume		} else {
483156952Sume			/* Use datagrams. */
484156956Sume			n = send_dg(statp,
485156956Sume#ifdef USE_KQUEUE
486156956Sume				    kq,
487156956Sume#endif
488156956Sume				    buf, buflen, ans, anssiz, &terrno,
489186090Sume				    ns, tries, &v_circuit, &gotsomewhere);
490156952Sume			if (n < 0)
491156952Sume				goto fail;
492156952Sume			if (n == 0)
493156952Sume				goto next_ns;
494156952Sume			if (v_circuit)
495156952Sume				goto same_ns;
496156952Sume			resplen = n;
497156952Sume		}
498156952Sume
499156952Sume		Dprint((statp->options & RES_DEBUG) ||
500156952Sume		       ((statp->pfcode & RES_PRF_REPLY) &&
501156952Sume			(statp->pfcode & RES_PRF_HEAD1)),
502156952Sume		       (stdout, ";; got answer:\n"));
503156952Sume
504156952Sume		DprintQ((statp->options & RES_DEBUG) ||
505156952Sume			(statp->pfcode & RES_PRF_REPLY),
506156952Sume			(stdout, "%s", ""),
507156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
508156952Sume
509156952Sume		/*
510156952Sume		 * If we have temporarily opened a virtual circuit,
511156952Sume		 * or if we haven't been asked to keep a socket open,
512156952Sume		 * close the socket.
513156952Sume		 */
514156952Sume		if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
515156952Sume		    (statp->options & RES_STAYOPEN) == 0U) {
516156952Sume			res_nclose(statp);
517156952Sume		}
518156952Sume		if (statp->rhook) {
519156952Sume			int done = 0, loops = 0;
520156952Sume
521156952Sume			do {
522156952Sume				res_sendhookact act;
523156952Sume
524156952Sume				act = (*statp->rhook)(nsap, buf, buflen,
525156952Sume						      ans, anssiz, &resplen);
526156952Sume				switch (act) {
527156952Sume				case res_goahead:
528156952Sume				case res_done:
529156952Sume					done = 1;
530156952Sume					break;
531156952Sume				case res_nextns:
532156952Sume					res_nclose(statp);
533156952Sume					goto next_ns;
534156952Sume				case res_modified:
535156952Sume					/* give the hook another try */
536156952Sume					if (++loops < 42) /*doug adams*/
537156952Sume						break;
538156952Sume					/*FALLTHROUGH*/
539156952Sume				case res_error:
540156952Sume					/*FALLTHROUGH*/
541156952Sume				default:
542156952Sume					goto fail;
543156952Sume				}
544156952Sume			} while (!done);
545156952Sume
546156952Sume		}
547156956Sume#ifdef USE_KQUEUE
548156956Sume		_close(kq);
549156956Sume#endif
550156952Sume		return (resplen);
551156952Sume next_ns: ;
552156952Sume	   } /*foreach ns*/
553156952Sume	} /*foreach retry*/
554156952Sume	res_nclose(statp);
555156956Sume#ifdef USE_KQUEUE
556156956Sume	_close(kq);
557156956Sume#endif
558156952Sume	if (!v_circuit) {
559156952Sume		if (!gotsomewhere)
560170244Sume			errno = ECONNREFUSED;	/*%< no nameservers found */
561156952Sume		else
562170244Sume			errno = ETIMEDOUT;	/*%< no answer obtained */
563156952Sume	} else
564156952Sume		errno = terrno;
565156952Sume	return (-1);
566156952Sume fail:
567156952Sume	res_nclose(statp);
568156956Sume#ifdef USE_KQUEUE
569156956Sume	_close(kq);
570156956Sume#endif
571156952Sume	return (-1);
572156952Sume}
573156952Sume
574156952Sume/* Private */
575156952Sume
576156952Sumestatic int
577156952Sumeget_salen(sa)
578156952Sume	const struct sockaddr *sa;
579156952Sume{
580156952Sume
581156952Sume#ifdef HAVE_SA_LEN
582156952Sume	/* There are people do not set sa_len.  Be forgiving to them. */
583156952Sume	if (sa->sa_len)
584156952Sume		return (sa->sa_len);
585156952Sume#endif
586156952Sume
587156952Sume	if (sa->sa_family == AF_INET)
588156952Sume		return (sizeof(struct sockaddr_in));
589156952Sume	else if (sa->sa_family == AF_INET6)
590156952Sume		return (sizeof(struct sockaddr_in6));
591156952Sume	else
592170244Sume		return (0);	/*%< unknown, die on connect */
593156952Sume}
594156952Sume
595170244Sume/*%
596156952Sume * pick appropriate nsaddr_list for use.  see res_init() for initialization.
597156952Sume */
598156952Sumestatic struct sockaddr *
599156952Sumeget_nsaddr(statp, n)
600156952Sume	res_state statp;
601156952Sume	size_t n;
602156952Sume{
603156952Sume
604156952Sume	if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
605156952Sume		/*
606156952Sume		 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
607156952Sume		 *   than struct sockaddr, and
608156952Sume		 * - user code did not update statp->nsaddr_list[n].
609156952Sume		 */
610156952Sume		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
611156952Sume	} else {
612156952Sume		/*
613156952Sume		 * - user code updated statp->nsaddr_list[n], or
614156952Sume		 * - statp->nsaddr_list[n] has the same content as
615156952Sume		 *   EXT(statp).ext->nsaddrs[n].
616156952Sume		 */
617156952Sume		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
618156952Sume	}
619156952Sume}
620156952Sume
621156952Sumestatic int
622156952Sumesend_vc(res_state statp,
623156952Sume	const u_char *buf, int buflen, u_char *ans, int anssiz,
624156952Sume	int *terrno, int ns)
625156952Sume{
626156952Sume	const HEADER *hp = (const HEADER *) buf;
627156952Sume	HEADER *anhp = (HEADER *) ans;
628156952Sume	struct sockaddr *nsap;
629156952Sume	int nsaplen;
630156952Sume	int truncating, connreset, resplen, n;
631156952Sume	struct iovec iov[2];
632156952Sume	u_short len;
633156952Sume	u_char *cp;
634156952Sume	void *tmp;
635186090Sume#ifdef SO_NOSIGPIPE
636186090Sume	int on = 1;
637186090Sume#endif
638156952Sume
639156952Sume	nsap = get_nsaddr(statp, ns);
640156952Sume	nsaplen = get_salen(nsap);
641156952Sume
642156952Sume	connreset = 0;
643156952Sume same_ns:
644156952Sume	truncating = 0;
645156952Sume
646156952Sume	/* Are we still talking to whom we want to talk to? */
647156952Sume	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
648156952Sume		struct sockaddr_storage peer;
649156952Sume		ISC_SOCKLEN_T size = sizeof peer;
650156952Sume
651156956Sume		if (_getpeername(statp->_vcsock,
652156952Sume				(struct sockaddr *)&peer, &size) < 0 ||
653156952Sume		    !sock_eq((struct sockaddr *)&peer, nsap)) {
654156952Sume			res_nclose(statp);
655156952Sume			statp->_flags &= ~RES_F_VC;
656156952Sume		}
657156952Sume	}
658156952Sume
659156952Sume	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
660156952Sume		if (statp->_vcsock >= 0)
661156952Sume			res_nclose(statp);
662156952Sume
663255336Sjilles		statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM |
664255336Sjilles		    SOCK_CLOEXEC, 0);
665167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE)
666156952Sume		if (statp->_vcsock > highestFD) {
667156952Sume			res_nclose(statp);
668156952Sume			errno = ENOTSOCK;
669156952Sume		}
670167246Sjhb#endif
671156952Sume		if (statp->_vcsock < 0) {
672156952Sume			switch (errno) {
673156952Sume			case EPROTONOSUPPORT:
674156952Sume#ifdef EPFNOSUPPORT
675156952Sume			case EPFNOSUPPORT:
676156952Sume#endif
677156952Sume			case EAFNOSUPPORT:
678156952Sume				Perror(statp, stderr, "socket(vc)", errno);
679156952Sume				return (0);
680156952Sume			default:
681156952Sume				*terrno = errno;
682156952Sume				Perror(statp, stderr, "socket(vc)", errno);
683156952Sume				return (-1);
684156952Sume			}
685156952Sume		}
686186090Sume#ifdef SO_NOSIGPIPE
687186090Sume		/*
688186090Sume		 * Disable generation of SIGPIPE when writing to a closed
689186090Sume		 * socket.  Write should return -1 and set errno to EPIPE
690186090Sume		 * instead.
691186090Sume		 *
692186090Sume		 * Push on even if setsockopt(SO_NOSIGPIPE) fails.
693186090Sume		 */
694186090Sume		(void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
695186090Sume			         sizeof(on));
696186090Sume#endif
697156952Sume		errno = 0;
698156956Sume		if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
699156952Sume			*terrno = errno;
700156952Sume			Aerror(statp, stderr, "connect/vc", errno, nsap,
701156952Sume			    nsaplen);
702156952Sume			res_nclose(statp);
703156952Sume			return (0);
704156952Sume		}
705156952Sume		statp->_flags |= RES_F_VC;
706156952Sume	}
707156952Sume
708156952Sume	/*
709156952Sume	 * Send length & message
710156952Sume	 */
711156952Sume	ns_put16((u_short)buflen, (u_char*)&len);
712156952Sume	iov[0] = evConsIovec(&len, INT16SZ);
713156952Sume	DE_CONST(buf, tmp);
714156952Sume	iov[1] = evConsIovec(tmp, buflen);
715156956Sume	if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
716156952Sume		*terrno = errno;
717156952Sume		Perror(statp, stderr, "write failed", errno);
718156952Sume		res_nclose(statp);
719156952Sume		return (0);
720156952Sume	}
721156952Sume	/*
722156952Sume	 * Receive length & response
723156952Sume	 */
724156952Sume read_len:
725156952Sume	cp = ans;
726156952Sume	len = INT16SZ;
727156956Sume	while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
728156952Sume		cp += n;
729156952Sume		if ((len -= n) == 0)
730156952Sume			break;
731156952Sume	}
732156952Sume	if (n <= 0) {
733156952Sume		*terrno = errno;
734156952Sume		Perror(statp, stderr, "read failed", errno);
735156952Sume		res_nclose(statp);
736156952Sume		/*
737156952Sume		 * A long running process might get its TCP
738156952Sume		 * connection reset if the remote server was
739156952Sume		 * restarted.  Requery the server instead of
740156952Sume		 * trying a new one.  When there is only one
741156952Sume		 * server, this means that a query might work
742156952Sume		 * instead of failing.  We only allow one reset
743156952Sume		 * per query to prevent looping.
744156952Sume		 */
745156952Sume		if (*terrno == ECONNRESET && !connreset) {
746156952Sume			connreset = 1;
747156952Sume			res_nclose(statp);
748156952Sume			goto same_ns;
749156952Sume		}
750156952Sume		res_nclose(statp);
751156952Sume		return (0);
752156952Sume	}
753156952Sume	resplen = ns_get16(ans);
754156952Sume	if (resplen > anssiz) {
755156952Sume		Dprint(statp->options & RES_DEBUG,
756156952Sume		       (stdout, ";; response truncated\n")
757156952Sume		       );
758156952Sume		truncating = 1;
759156952Sume		len = anssiz;
760156952Sume	} else
761156952Sume		len = resplen;
762156952Sume	if (len < HFIXEDSZ) {
763156952Sume		/*
764156952Sume		 * Undersized message.
765156952Sume		 */
766156952Sume		Dprint(statp->options & RES_DEBUG,
767156952Sume		       (stdout, ";; undersized: %d\n", len));
768156952Sume		*terrno = EMSGSIZE;
769156952Sume		res_nclose(statp);
770156952Sume		return (0);
771156952Sume	}
772156952Sume	cp = ans;
773156956Sume	while (len != 0 &&
774156956Sume	    (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
775156952Sume		cp += n;
776156952Sume		len -= n;
777156952Sume	}
778156952Sume	if (n <= 0) {
779156952Sume		*terrno = errno;
780156952Sume		Perror(statp, stderr, "read(vc)", errno);
781156952Sume		res_nclose(statp);
782156952Sume		return (0);
783156952Sume	}
784156952Sume	if (truncating) {
785156952Sume		/*
786156952Sume		 * Flush rest of answer so connection stays in synch.
787156952Sume		 */
788156952Sume		anhp->tc = 1;
789156952Sume		len = resplen - anssiz;
790156952Sume		while (len != 0) {
791156952Sume			char junk[PACKETSZ];
792156952Sume
793156956Sume			n = _read(statp->_vcsock, junk,
794156956Sume			    (len > sizeof junk) ? sizeof junk : len);
795156952Sume			if (n > 0)
796156952Sume				len -= n;
797156952Sume			else
798156952Sume				break;
799156952Sume		}
800156952Sume	}
801156952Sume	/*
802156952Sume	 * If the calling applicating has bailed out of
803156952Sume	 * a previous call and failed to arrange to have
804156952Sume	 * the circuit closed or the server has got
805156952Sume	 * itself confused, then drop the packet and
806156952Sume	 * wait for the correct one.
807156952Sume	 */
808156952Sume	if (hp->id != anhp->id) {
809156952Sume		DprintQ((statp->options & RES_DEBUG) ||
810156952Sume			(statp->pfcode & RES_PRF_REPLY),
811156952Sume			(stdout, ";; old answer (unexpected):\n"),
812156952Sume			ans, (resplen > anssiz) ? anssiz: resplen);
813156952Sume		goto read_len;
814156952Sume	}
815156952Sume
816156952Sume	/*
817156952Sume	 * All is well, or the error is fatal.  Signal that the
818156952Sume	 * next nameserver ought not be tried.
819156952Sume	 */
820156952Sume	return (resplen);
821156952Sume}
822156952Sume
823156952Sumestatic int
824156952Sumesend_dg(res_state statp,
825156956Sume#ifdef USE_KQUEUE
826156956Sume	int kq,
827156956Sume#endif
828163661Sume	const u_char *buf, int buflen, u_char *ans,
829186090Sume	int anssiz, int *terrno, int ns, int tries, int *v_circuit,
830163661Sume	int *gotsomewhere)
831156952Sume{
832156952Sume	const HEADER *hp = (const HEADER *) buf;
833156952Sume	HEADER *anhp = (HEADER *) ans;
834156952Sume	const struct sockaddr *nsap;
835156952Sume	int nsaplen;
836156952Sume	struct timespec now, timeout, finish;
837156952Sume	struct sockaddr_storage from;
838156952Sume	ISC_SOCKLEN_T fromlen;
839156952Sume	int resplen, seconds, n, s;
840156956Sume#ifdef USE_KQUEUE
841156956Sume	struct kevent kv;
842156956Sume#else
843156952Sume#ifdef USE_POLL
844156952Sume	int     polltimeout;
845156952Sume	struct pollfd   pollfd;
846156952Sume#else
847156952Sume	fd_set dsmask;
848156952Sume#endif
849156956Sume#endif
850156952Sume
851156952Sume	nsap = get_nsaddr(statp, ns);
852156952Sume	nsaplen = get_salen(nsap);
853156952Sume	if (EXT(statp).nssocks[ns] == -1) {
854156956Sume		EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
855255336Sjilles		    SOCK_DGRAM | SOCK_CLOEXEC, 0);
856167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE)
857156952Sume		if (EXT(statp).nssocks[ns] > highestFD) {
858156952Sume			res_nclose(statp);
859156952Sume			errno = ENOTSOCK;
860156952Sume		}
861167246Sjhb#endif
862156952Sume		if (EXT(statp).nssocks[ns] < 0) {
863156952Sume			switch (errno) {
864156952Sume			case EPROTONOSUPPORT:
865156952Sume#ifdef EPFNOSUPPORT
866156952Sume			case EPFNOSUPPORT:
867156952Sume#endif
868156952Sume			case EAFNOSUPPORT:
869156952Sume				Perror(statp, stderr, "socket(dg)", errno);
870156952Sume				return (0);
871156952Sume			default:
872156952Sume				*terrno = errno;
873156952Sume				Perror(statp, stderr, "socket(dg)", errno);
874156952Sume				return (-1);
875156952Sume			}
876156952Sume		}
877156952Sume#ifndef CANNOT_CONNECT_DGRAM
878156952Sume		/*
879156952Sume		 * On a 4.3BSD+ machine (client and server,
880156952Sume		 * actually), sending to a nameserver datagram
881156952Sume		 * port with no nameserver will cause an
882156952Sume		 * ICMP port unreachable message to be returned.
883156952Sume		 * If our datagram socket is "connected" to the
884156952Sume		 * server, we get an ECONNREFUSED error on the next
885156952Sume		 * socket operation, and select returns if the
886156952Sume		 * error message is received.  We can thus detect
887156952Sume		 * the absence of a nameserver without timing out.
888156956Sume		 *
889156956Sume		 * When the option "insecure1" is specified, we'd
890156956Sume		 * rather expect to see responses from an "unknown"
891156956Sume		 * address.  In order to let the kernel accept such
892156956Sume		 * responses, do not connect the socket here.
893156956Sume		 * XXX: or do we need an explicit option to disable
894156956Sume		 * connecting?
895156952Sume		 */
896156956Sume		if (!(statp->options & RES_INSECURE1) &&
897156956Sume		    _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
898156952Sume			Aerror(statp, stderr, "connect(dg)", errno, nsap,
899156952Sume			    nsaplen);
900156952Sume			res_nclose(statp);
901156952Sume			return (0);
902156952Sume		}
903156952Sume#endif /* !CANNOT_CONNECT_DGRAM */
904156952Sume		Dprint(statp->options & RES_DEBUG,
905156952Sume		       (stdout, ";; new DG socket\n"))
906156952Sume	}
907156952Sume	s = EXT(statp).nssocks[ns];
908156952Sume#ifndef CANNOT_CONNECT_DGRAM
909156956Sume	if (statp->options & RES_INSECURE1) {
910156956Sume		if (_sendto(s,
911156956Sume		    (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
912156956Sume			Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
913156956Sume			res_nclose(statp);
914156956Sume			return (0);
915156956Sume		}
916156956Sume	} else if (send(s, (const char*)buf, buflen, 0) != buflen) {
917156952Sume		Perror(statp, stderr, "send", errno);
918156952Sume		res_nclose(statp);
919156952Sume		return (0);
920156952Sume	}
921156952Sume#else /* !CANNOT_CONNECT_DGRAM */
922156956Sume	if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
923156952Sume	{
924156952Sume		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
925156952Sume		res_nclose(statp);
926156952Sume		return (0);
927156952Sume	}
928156952Sume#endif /* !CANNOT_CONNECT_DGRAM */
929156952Sume
930156952Sume	/*
931156952Sume	 * Wait for reply.
932156952Sume	 */
933186090Sume	seconds = (statp->retrans << tries);
934156952Sume	if (ns > 0)
935156952Sume		seconds /= statp->nscount;
936156952Sume	if (seconds <= 0)
937156952Sume		seconds = 1;
938156952Sume	now = evNowTime();
939156952Sume	timeout = evConsTime(seconds, 0);
940156952Sume	finish = evAddTime(now, timeout);
941156952Sume	goto nonow;
942156952Sume wait:
943156952Sume	now = evNowTime();
944156952Sume nonow:
945156952Sume#ifndef USE_POLL
946156952Sume	if (evCmpTime(finish, now) > 0)
947156952Sume		timeout = evSubTime(finish, now);
948156952Sume	else
949156952Sume		timeout = evConsTime(0, 0);
950156956Sume#ifdef USE_KQUEUE
951156956Sume	EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
952156956Sume	n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
953156956Sume#else
954156956Sume	FD_ZERO(&dsmask);
955156956Sume	FD_SET(s, &dsmask);
956156952Sume	n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
957156956Sume#endif
958156952Sume#else
959156952Sume	timeout = evSubTime(finish, now);
960156952Sume	if (timeout.tv_sec < 0)
961156952Sume		timeout = evConsTime(0, 0);
962156952Sume	polltimeout = 1000*timeout.tv_sec +
963156952Sume		timeout.tv_nsec/1000000;
964156952Sume	pollfd.fd = s;
965156952Sume	pollfd.events = POLLRDNORM;
966260652Sjilles	n = _poll(&pollfd, 1, polltimeout);
967156952Sume#endif /* USE_POLL */
968156952Sume
969156952Sume	if (n == 0) {
970156952Sume		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
971156952Sume		*gotsomewhere = 1;
972156952Sume		return (0);
973156952Sume	}
974156952Sume	if (n < 0) {
975156952Sume		if (errno == EINTR)
976156952Sume			goto wait;
977156956Sume#ifdef USE_KQUEUE
978156956Sume		Perror(statp, stderr, "kevent", errno);
979156956Sume#else
980156952Sume#ifndef USE_POLL
981156952Sume		Perror(statp, stderr, "select", errno);
982156952Sume#else
983156952Sume		Perror(statp, stderr, "poll", errno);
984156952Sume#endif /* USE_POLL */
985156956Sume#endif
986156952Sume		res_nclose(statp);
987156952Sume		return (0);
988156952Sume	}
989160967Sume#ifdef USE_KQUEUE
990160967Sume	if (kv.ident != s)
991160967Sume		goto wait;
992160967Sume#endif
993156952Sume	errno = 0;
994156952Sume	fromlen = sizeof(from);
995156956Sume	resplen = _recvfrom(s, (char*)ans, anssiz,0,
996156952Sume			   (struct sockaddr *)&from, &fromlen);
997156952Sume	if (resplen <= 0) {
998156952Sume		Perror(statp, stderr, "recvfrom", errno);
999156952Sume		res_nclose(statp);
1000156952Sume		return (0);
1001156952Sume	}
1002156952Sume	*gotsomewhere = 1;
1003156952Sume	if (resplen < HFIXEDSZ) {
1004156952Sume		/*
1005156952Sume		 * Undersized message.
1006156952Sume		 */
1007156952Sume		Dprint(statp->options & RES_DEBUG,
1008156952Sume		       (stdout, ";; undersized: %d\n",
1009156952Sume			resplen));
1010156952Sume		*terrno = EMSGSIZE;
1011156952Sume		res_nclose(statp);
1012156952Sume		return (0);
1013156952Sume	}
1014156952Sume	if (hp->id != anhp->id) {
1015156952Sume		/*
1016156952Sume		 * response from old query, ignore it.
1017156952Sume		 * XXX - potential security hazard could
1018156952Sume		 *	 be detected here.
1019156952Sume		 */
1020156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1021156952Sume			(statp->pfcode & RES_PRF_REPLY),
1022156952Sume			(stdout, ";; old answer:\n"),
1023156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1024156952Sume		goto wait;
1025156952Sume	}
1026156952Sume	if (!(statp->options & RES_INSECURE1) &&
1027156952Sume	    !res_ourserver_p(statp, (struct sockaddr *)&from)) {
1028156952Sume		/*
1029156952Sume		 * response from wrong server? ignore it.
1030156952Sume		 * XXX - potential security hazard could
1031156952Sume		 *	 be detected here.
1032156952Sume		 */
1033156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1034156952Sume			(statp->pfcode & RES_PRF_REPLY),
1035156952Sume			(stdout, ";; not our server:\n"),
1036156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1037156952Sume		goto wait;
1038156952Sume	}
1039156952Sume#ifdef RES_USE_EDNS0
1040156952Sume	if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1041156952Sume		/*
1042156952Sume		 * Do not retry if the server do not understand EDNS0.
1043156952Sume		 * The case has to be captured here, as FORMERR packet do not
1044156952Sume		 * carry query section, hence res_queriesmatch() returns 0.
1045156952Sume		 */
1046156952Sume		DprintQ(statp->options & RES_DEBUG,
1047156952Sume			(stdout, "server rejected query with EDNS0:\n"),
1048156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1049156952Sume		/* record the error */
1050156952Sume		statp->_flags |= RES_F_EDNS0ERR;
1051156952Sume		res_nclose(statp);
1052156952Sume		return (0);
1053156952Sume	}
1054156952Sume#endif
1055156952Sume	if (!(statp->options & RES_INSECURE2) &&
1056156952Sume	    !res_queriesmatch(buf, buf + buflen,
1057156952Sume			      ans, ans + anssiz)) {
1058156952Sume		/*
1059156952Sume		 * response contains wrong query? ignore it.
1060156952Sume		 * XXX - potential security hazard could
1061156952Sume		 *	 be detected here.
1062156952Sume		 */
1063156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1064156952Sume			(statp->pfcode & RES_PRF_REPLY),
1065156952Sume			(stdout, ";; wrong query name:\n"),
1066156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1067156952Sume		goto wait;
1068156952Sume	}
1069156952Sume	if (anhp->rcode == SERVFAIL ||
1070156952Sume	    anhp->rcode == NOTIMP ||
1071156952Sume	    anhp->rcode == REFUSED) {
1072156952Sume		DprintQ(statp->options & RES_DEBUG,
1073156952Sume			(stdout, "server rejected query:\n"),
1074156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1075156952Sume		res_nclose(statp);
1076156952Sume		/* don't retry if called from dig */
1077156952Sume		if (!statp->pfcode)
1078156952Sume			return (0);
1079156952Sume	}
1080156952Sume	if (!(statp->options & RES_IGNTC) && anhp->tc) {
1081156952Sume		/*
1082156952Sume		 * To get the rest of answer,
1083156952Sume		 * use TCP with same server.
1084156952Sume		 */
1085156952Sume		Dprint(statp->options & RES_DEBUG,
1086156952Sume		       (stdout, ";; truncated answer\n"));
1087156952Sume		*v_circuit = 1;
1088156952Sume		res_nclose(statp);
1089156952Sume		return (1);
1090156952Sume	}
1091156952Sume	/*
1092156952Sume	 * All is well, or the error is fatal.  Signal that the
1093156952Sume	 * next nameserver ought not be tried.
1094156952Sume	 */
1095156952Sume	return (resplen);
1096156952Sume}
1097156952Sume
1098156952Sumestatic void
1099156952SumeAerror(const res_state statp, FILE *file, const char *string, int error,
1100156952Sume       const struct sockaddr *address, int alen)
1101156952Sume{
1102156952Sume	int save = errno;
1103156952Sume	char hbuf[NI_MAXHOST];
1104156952Sume	char sbuf[NI_MAXSERV];
1105156952Sume
1106156952Sume	if ((statp->options & RES_DEBUG) != 0U) {
1107156952Sume		if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
1108156952Sume		    sbuf, sizeof(sbuf), niflags)) {
1109156952Sume			strncpy(hbuf, "?", sizeof(hbuf) - 1);
1110156952Sume			hbuf[sizeof(hbuf) - 1] = '\0';
1111156952Sume			strncpy(sbuf, "?", sizeof(sbuf) - 1);
1112156952Sume			sbuf[sizeof(sbuf) - 1] = '\0';
1113156952Sume		}
1114156952Sume		fprintf(file, "res_send: %s ([%s].%s): %s\n",
1115156952Sume			string, hbuf, sbuf, strerror(error));
1116156952Sume	}
1117156952Sume	errno = save;
1118156952Sume}
1119156952Sume
1120156952Sumestatic void
1121156952SumePerror(const res_state statp, FILE *file, const char *string, int error) {
1122156952Sume	int save = errno;
1123156952Sume
1124156952Sume	if ((statp->options & RES_DEBUG) != 0U)
1125156952Sume		fprintf(file, "res_send: %s: %s\n",
1126156952Sume			string, strerror(error));
1127156952Sume	errno = save;
1128156952Sume}
1129156952Sume
1130156952Sumestatic int
1131156952Sumesock_eq(struct sockaddr *a, struct sockaddr *b) {
1132156952Sume	struct sockaddr_in *a4, *b4;
1133156952Sume	struct sockaddr_in6 *a6, *b6;
1134156952Sume
1135156952Sume	if (a->sa_family != b->sa_family)
1136156952Sume		return 0;
1137156952Sume	switch (a->sa_family) {
1138156952Sume	case AF_INET:
1139156952Sume		a4 = (struct sockaddr_in *)a;
1140156952Sume		b4 = (struct sockaddr_in *)b;
1141156952Sume		return a4->sin_port == b4->sin_port &&
1142156952Sume		    a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1143156952Sume	case AF_INET6:
1144156952Sume		a6 = (struct sockaddr_in6 *)a;
1145156952Sume		b6 = (struct sockaddr_in6 *)b;
1146156952Sume		return a6->sin6_port == b6->sin6_port &&
1147156952Sume#ifdef HAVE_SIN6_SCOPE_ID
1148156952Sume		    a6->sin6_scope_id == b6->sin6_scope_id &&
1149156952Sume#endif
1150156952Sume		    IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1151156952Sume	default:
1152156952Sume		return 0;
1153156952Sume	}
1154156952Sume}
1155156952Sume
1156156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
1157156952Sume/* XXX needs to move to the porting library. */
1158156952Sumestatic int
1159156952Sumepselect(int nfds, void *rfds, void *wfds, void *efds,
1160156952Sume	struct timespec *tsp, const sigset_t *sigmask)
1161156952Sume{
1162156952Sume	struct timeval tv, *tvp;
1163156952Sume	sigset_t sigs;
1164156952Sume	int n;
1165156952Sume
1166156952Sume	if (tsp) {
1167156952Sume		tvp = &tv;
1168156952Sume		tv = evTimeVal(*tsp);
1169156952Sume	} else
1170156952Sume		tvp = NULL;
1171156952Sume	if (sigmask)
1172156952Sume		sigprocmask(SIG_SETMASK, sigmask, &sigs);
1173156952Sume	n = select(nfds, rfds, wfds, efds, tvp);
1174156952Sume	if (sigmask)
1175156952Sume		sigprocmask(SIG_SETMASK, &sigs, NULL);
1176156952Sume	if (tsp)
1177156952Sume		*tsp = evTimeSpec(tv);
1178156952Sume	return (n);
1179156952Sume}
1180156952Sume#endif
1181