res_send.c revision 165258
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 * 3. All advertising materials mentioning features or use of this software
14156952Sume *    must display the following acknowledgement:
15156952Sume * 	This product includes software developed by the University of
16156952Sume * 	California, Berkeley and its contributors.
17156952Sume * 4. Neither the name of the University nor the names of its contributors
18156952Sume *    may be used to endorse or promote products derived from this software
19156952Sume *    without specific prior written permission.
20156952Sume *
21156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24156952Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31156952Sume * SUCH DAMAGE.
32156952Sume */
33156952Sume
34156952Sume/*
35156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36156952Sume *
37156952Sume * Permission to use, copy, modify, and distribute this software for any
38156952Sume * purpose with or without fee is hereby granted, provided that the above
39156952Sume * copyright notice and this permission notice appear in all copies, and that
40156952Sume * the name of Digital Equipment Corporation not be used in advertising or
41156952Sume * publicity pertaining to distribution of the document or software without
42156952Sume * specific, written prior permission.
43156952Sume *
44156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46156952Sume * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
47156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51156952Sume * SOFTWARE.
52156952Sume */
53156952Sume
54156952Sume/*
55156952Sume * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
56156952Sume * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
57156952Sume *
58156952Sume * Permission to use, copy, modify, and distribute this software for any
59156952Sume * purpose with or without fee is hereby granted, provided that the above
60156952Sume * copyright notice and this permission notice appear in all copies.
61156952Sume *
62156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
63156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
64156952Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
65156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
66156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
67156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
68156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
69156952Sume */
70156952Sume
71156952Sume#if defined(LIBC_SCCS) && !defined(lint)
72156952Sumestatic const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
73165258Sumestatic const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.9 2006/10/16 23:00:50 marka Exp $";
74156952Sume#endif /* LIBC_SCCS and not lint */
75156956Sume#include <sys/cdefs.h>
76156956Sume__FBSDID("$FreeBSD: head/lib/libc/resolv/res_send.c 165258 2006-12-15 20:59:55Z ume $");
77156952Sume
78156952Sume/*
79156952Sume * Send query to name server and wait for reply.
80156952Sume */
81156952Sume
82156952Sume#include "port_before.h"
83156956Sume#ifndef USE_KQUEUE
84156952Sume#include "fd_setsize.h"
85156956Sume#endif
86156952Sume
87156956Sume#include "namespace.h"
88156952Sume#include <sys/types.h>
89156952Sume#include <sys/param.h>
90156952Sume#include <sys/time.h>
91156952Sume#include <sys/socket.h>
92156952Sume#include <sys/uio.h>
93156952Sume
94156952Sume#include <netinet/in.h>
95156952Sume#include <arpa/nameser.h>
96156952Sume#include <arpa/inet.h>
97156952Sume
98156952Sume#include <errno.h>
99156952Sume#include <netdb.h>
100156952Sume#include <resolv.h>
101156952Sume#include <signal.h>
102156952Sume#include <stdio.h>
103156952Sume#include <stdlib.h>
104156952Sume#include <string.h>
105156952Sume#include <unistd.h>
106156952Sume
107156952Sume#include <isc/eventlib.h>
108156952Sume
109156952Sume#include "port_after.h"
110156952Sume
111156956Sume#ifdef USE_KQUEUE
112156956Sume#include <sys/event.h>
113156956Sume#else
114156952Sume#ifdef USE_POLL
115156952Sume#ifdef HAVE_STROPTS_H
116156952Sume#include <stropts.h>
117156952Sume#endif
118156952Sume#include <poll.h>
119156952Sume#endif /* USE_POLL */
120156956Sume#endif
121156952Sume
122156956Sume#include "un-namespace.h"
123156956Sume
124156952Sume/* Options.  Leave them on. */
125156952Sume#define DEBUG
126156952Sume#include "res_debug.h"
127156952Sume#include "res_private.h"
128156952Sume
129156952Sume#define EXT(res) ((res)->_u._ext)
130156952Sume
131156952Sume#ifndef USE_POLL
132156952Sumestatic const int highestFD = FD_SETSIZE - 1;
133156952Sume#else
134156952Sumestatic int highestFD = 0;
135156952Sume#endif
136156952Sume
137156952Sume/* Forward. */
138156952Sume
139156956Sumestatic int		get_salen(const struct sockaddr *);
140156956Sumestatic struct sockaddr * get_nsaddr(res_state, size_t);
141156952Sumestatic int		send_vc(res_state, const u_char *, int,
142156952Sume				u_char *, int, int *, int);
143156956Sumestatic int		send_dg(res_state,
144156956Sume#ifdef USE_KQUEUE
145156956Sume				int kq,
146156956Sume#endif
147156956Sume				const u_char *, int,
148163661Sume				u_char *, int, int *, int, int,
149156952Sume				int *, int *);
150156952Sumestatic void		Aerror(const res_state, FILE *, const char *, int,
151156952Sume			       const struct sockaddr *, int);
152156952Sumestatic void		Perror(const res_state, FILE *, const char *, int);
153156952Sumestatic int		sock_eq(struct sockaddr *, struct sockaddr *);
154156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
155156952Sumestatic int		pselect(int, void *, void *, void *,
156156952Sume				struct timespec *,
157156952Sume				const sigset_t *);
158156952Sume#endif
159156952Sumevoid res_pquery(const res_state, const u_char *, int, FILE *);
160156952Sume
161156952Sumestatic const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
162156952Sume
163156952Sume/* Public. */
164156952Sume
165156952Sume/* int
166156952Sume * res_isourserver(ina)
167156952Sume *	looks up "ina" in _res.ns_addr_list[]
168156952Sume * returns:
169156952Sume *	0  : not found
170156952Sume *	>0 : found
171156952Sume * author:
172156952Sume *	paul vixie, 29may94
173156952Sume */
174156952Sumeint
175156952Sumeres_ourserver_p(const res_state statp, const struct sockaddr *sa) {
176156952Sume	const struct sockaddr_in *inp, *srv;
177156952Sume	const struct sockaddr_in6 *in6p, *srv6;
178156952Sume	int ns;
179156952Sume
180156952Sume	switch (sa->sa_family) {
181156952Sume	case AF_INET:
182156952Sume		inp = (const struct sockaddr_in *)sa;
183156952Sume		for (ns = 0;  ns < statp->nscount;  ns++) {
184156952Sume			srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
185156952Sume			if (srv->sin_family == inp->sin_family &&
186156952Sume			    srv->sin_port == inp->sin_port &&
187156952Sume			    (srv->sin_addr.s_addr == INADDR_ANY ||
188156952Sume			     srv->sin_addr.s_addr == inp->sin_addr.s_addr))
189156952Sume				return (1);
190156952Sume		}
191156952Sume		break;
192156952Sume	case AF_INET6:
193156952Sume		if (EXT(statp).ext == NULL)
194156952Sume			break;
195156952Sume		in6p = (const struct sockaddr_in6 *)sa;
196156952Sume		for (ns = 0;  ns < statp->nscount;  ns++) {
197156952Sume			srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
198156952Sume			if (srv6->sin6_family == in6p->sin6_family &&
199156952Sume			    srv6->sin6_port == in6p->sin6_port &&
200156952Sume#ifdef HAVE_SIN6_SCOPE_ID
201156952Sume			    (srv6->sin6_scope_id == 0 ||
202156952Sume			     srv6->sin6_scope_id == in6p->sin6_scope_id) &&
203156952Sume#endif
204156952Sume			    (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
205156952Sume			     IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
206156952Sume				return (1);
207156952Sume		}
208156952Sume		break;
209156952Sume	default:
210156952Sume		break;
211156952Sume	}
212156952Sume	return (0);
213156952Sume}
214156952Sume
215156952Sume/* int
216156952Sume * res_nameinquery(name, type, class, buf, eom)
217156952Sume *	look for (name,type,class) in the query section of packet (buf,eom)
218156952Sume * requires:
219156952Sume *	buf + HFIXEDSZ <= eom
220156952Sume * returns:
221156952Sume *	-1 : format error
222156952Sume *	0  : not found
223156952Sume *	>0 : found
224156952Sume * author:
225156952Sume *	paul vixie, 29may94
226156952Sume */
227156952Sumeint
228156952Sumeres_nameinquery(const char *name, int type, int class,
229156952Sume		const u_char *buf, const u_char *eom)
230156952Sume{
231156952Sume	const u_char *cp = buf + HFIXEDSZ;
232156952Sume	int qdcount = ntohs(((const HEADER*)buf)->qdcount);
233156952Sume
234156952Sume	while (qdcount-- > 0) {
235156952Sume		char tname[MAXDNAME+1];
236156952Sume		int n, ttype, tclass;
237156952Sume
238156952Sume		n = dn_expand(buf, eom, cp, tname, sizeof tname);
239156952Sume		if (n < 0)
240156952Sume			return (-1);
241156952Sume		cp += n;
242156952Sume		if (cp + 2 * INT16SZ > eom)
243156952Sume			return (-1);
244156952Sume		ttype = ns_get16(cp); cp += INT16SZ;
245156952Sume		tclass = ns_get16(cp); cp += INT16SZ;
246156952Sume		if (ttype == type && tclass == class &&
247156952Sume		    ns_samename(tname, name) == 1)
248156952Sume			return (1);
249156952Sume	}
250156952Sume	return (0);
251156952Sume}
252156952Sume
253156952Sume/* int
254156952Sume * res_queriesmatch(buf1, eom1, buf2, eom2)
255156952Sume *	is there a 1:1 mapping of (name,type,class)
256156952Sume *	in (buf1,eom1) and (buf2,eom2)?
257156952Sume * returns:
258156952Sume *	-1 : format error
259156952Sume *	0  : not a 1:1 mapping
260156952Sume *	>0 : is a 1:1 mapping
261156952Sume * author:
262156952Sume *	paul vixie, 29may94
263156952Sume */
264156952Sumeint
265156952Sumeres_queriesmatch(const u_char *buf1, const u_char *eom1,
266156952Sume		 const u_char *buf2, const u_char *eom2)
267156952Sume{
268156952Sume	const u_char *cp = buf1 + HFIXEDSZ;
269156952Sume	int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
270156952Sume
271156952Sume	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
272156952Sume		return (-1);
273156952Sume
274156952Sume	/*
275156952Sume	 * Only header section present in replies to
276156952Sume	 * dynamic update packets.
277156952Sume	 */
278156952Sume	if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
279156952Sume	    (((const HEADER *)buf2)->opcode == ns_o_update))
280156952Sume		return (1);
281156952Sume
282156952Sume	if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
283156952Sume		return (0);
284156952Sume	while (qdcount-- > 0) {
285156952Sume		char tname[MAXDNAME+1];
286156952Sume		int n, ttype, tclass;
287156952Sume
288156952Sume		n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
289156952Sume		if (n < 0)
290156952Sume			return (-1);
291156952Sume		cp += n;
292156952Sume		if (cp + 2 * INT16SZ > eom1)
293156952Sume			return (-1);
294156952Sume		ttype = ns_get16(cp);	cp += INT16SZ;
295156952Sume		tclass = ns_get16(cp); cp += INT16SZ;
296156952Sume		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
297156952Sume			return (0);
298156952Sume	}
299156952Sume	return (1);
300156952Sume}
301156952Sume
302156952Sumeint
303156952Sumeres_nsend(res_state statp,
304156952Sume	  const u_char *buf, int buflen, u_char *ans, int anssiz)
305156952Sume{
306156952Sume	int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
307156956Sume#ifdef USE_KQUEUE
308156956Sume	int kq;
309156956Sume#endif
310156952Sume	char abuf[NI_MAXHOST];
311156952Sume
312156952Sume#ifdef USE_POLL
313156952Sume	highestFD = sysconf(_SC_OPEN_MAX) - 1;
314156952Sume#endif
315156952Sume
316165258Sume	/* No name servers or res_init() failure */
317165258Sume	if (statp->nscount == 0 || EXT(statp).ext == NULL) {
318156952Sume		errno = ESRCH;
319156952Sume		return (-1);
320156952Sume	}
321156952Sume	if (anssiz < HFIXEDSZ) {
322156952Sume		errno = EINVAL;
323156952Sume		return (-1);
324156952Sume	}
325156952Sume	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
326156952Sume		(stdout, ";; res_send()\n"), buf, buflen);
327156952Sume	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
328156952Sume	gotsomewhere = 0;
329156952Sume	terrno = ETIMEDOUT;
330156952Sume
331156956Sume#ifdef USE_KQUEUE
332156956Sume	if ((kq = kqueue()) < 0) {
333156956Sume		Perror(statp, stderr, "kqueue", errno);
334156956Sume		return (-1);
335156956Sume	}
336156956Sume#endif
337156956Sume
338156952Sume	/*
339156952Sume	 * If the ns_addr_list in the resolver context has changed, then
340156952Sume	 * invalidate our cached copy and the associated timing data.
341156952Sume	 */
342156952Sume	if (EXT(statp).nscount != 0) {
343156952Sume		int needclose = 0;
344156952Sume		struct sockaddr_storage peer;
345156952Sume		ISC_SOCKLEN_T peerlen;
346156952Sume
347156952Sume		if (EXT(statp).nscount != statp->nscount)
348156952Sume			needclose++;
349156952Sume		else
350156952Sume			for (ns = 0; ns < statp->nscount; ns++) {
351156952Sume				if (statp->nsaddr_list[ns].sin_family &&
352156952Sume				    !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
353156952Sume					     (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
354156952Sume					needclose++;
355156952Sume					break;
356156952Sume				}
357156952Sume
358156952Sume				if (EXT(statp).nssocks[ns] == -1)
359156952Sume					continue;
360156952Sume				peerlen = sizeof(peer);
361156956Sume				if (_getsockname(EXT(statp).nssocks[ns],
362156952Sume				    (struct sockaddr *)&peer, &peerlen) < 0) {
363156952Sume					needclose++;
364156952Sume					break;
365156952Sume				}
366156952Sume				if (!sock_eq((struct sockaddr *)&peer,
367156952Sume				    get_nsaddr(statp, ns))) {
368156952Sume					needclose++;
369156952Sume					break;
370156952Sume				}
371156952Sume			}
372156952Sume		if (needclose) {
373156952Sume			res_nclose(statp);
374156952Sume			EXT(statp).nscount = 0;
375156952Sume		}
376156952Sume	}
377156952Sume
378156952Sume	/*
379156952Sume	 * Maybe initialize our private copy of the ns_addr_list.
380156952Sume	 */
381156952Sume	if (EXT(statp).nscount == 0) {
382156952Sume		for (ns = 0; ns < statp->nscount; ns++) {
383156952Sume			EXT(statp).nstimes[ns] = RES_MAXTIME;
384156952Sume			EXT(statp).nssocks[ns] = -1;
385156952Sume			if (!statp->nsaddr_list[ns].sin_family)
386156952Sume				continue;
387156952Sume			EXT(statp).ext->nsaddrs[ns].sin =
388156952Sume				 statp->nsaddr_list[ns];
389156952Sume		}
390156952Sume		EXT(statp).nscount = statp->nscount;
391156952Sume	}
392156952Sume
393156952Sume	/*
394156952Sume	 * Some resolvers want to even out the load on their nameservers.
395156952Sume	 * Note that RES_BLAST overrides RES_ROTATE.
396156952Sume	 */
397156952Sume	if ((statp->options & RES_ROTATE) != 0U &&
398156952Sume	    (statp->options & RES_BLAST) == 0U) {
399156952Sume		union res_sockaddr_union inu;
400156952Sume		struct sockaddr_in ina;
401156952Sume		int lastns = statp->nscount - 1;
402156952Sume		int fd;
403156952Sume		u_int16_t nstime;
404156952Sume
405156952Sume		if (EXT(statp).ext != NULL)
406156952Sume			inu = EXT(statp).ext->nsaddrs[0];
407156952Sume		ina = statp->nsaddr_list[0];
408156952Sume		fd = EXT(statp).nssocks[0];
409156952Sume		nstime = EXT(statp).nstimes[0];
410156952Sume		for (ns = 0; ns < lastns; ns++) {
411156952Sume			if (EXT(statp).ext != NULL)
412156952Sume                                EXT(statp).ext->nsaddrs[ns] =
413156952Sume					EXT(statp).ext->nsaddrs[ns + 1];
414156952Sume			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
415156952Sume			EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
416156952Sume			EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
417156952Sume		}
418156952Sume		if (EXT(statp).ext != NULL)
419156952Sume			EXT(statp).ext->nsaddrs[lastns] = inu;
420156952Sume		statp->nsaddr_list[lastns] = ina;
421156952Sume		EXT(statp).nssocks[lastns] = fd;
422156952Sume		EXT(statp).nstimes[lastns] = nstime;
423156952Sume	}
424156952Sume
425156952Sume	/*
426156952Sume	 * Send request, RETRY times, or until successful.
427156952Sume	 */
428156952Sume	for (try = 0; try < statp->retry; try++) {
429156952Sume	    for (ns = 0; ns < statp->nscount; ns++) {
430156952Sume		struct sockaddr *nsap;
431156952Sume		int nsaplen;
432156952Sume		nsap = get_nsaddr(statp, ns);
433156952Sume		nsaplen = get_salen(nsap);
434156952Sume		statp->_flags &= ~RES_F_LASTMASK;
435156952Sume		statp->_flags |= (ns << RES_F_LASTSHIFT);
436156952Sume same_ns:
437156952Sume		if (statp->qhook) {
438156952Sume			int done = 0, loops = 0;
439156952Sume
440156952Sume			do {
441156952Sume				res_sendhookact act;
442156952Sume
443156952Sume				act = (*statp->qhook)(&nsap, &buf, &buflen,
444156952Sume						      ans, anssiz, &resplen);
445156952Sume				switch (act) {
446156952Sume				case res_goahead:
447156952Sume					done = 1;
448156952Sume					break;
449156952Sume				case res_nextns:
450156952Sume					res_nclose(statp);
451156952Sume					goto next_ns;
452156952Sume				case res_done:
453156956Sume#ifdef USE_KQUEUE
454156956Sume					_close(kq);
455156956Sume#endif
456156952Sume					return (resplen);
457156952Sume				case res_modified:
458156952Sume					/* give the hook another try */
459156952Sume					if (++loops < 42) /*doug adams*/
460156952Sume						break;
461156952Sume					/*FALLTHROUGH*/
462156952Sume				case res_error:
463156952Sume					/*FALLTHROUGH*/
464156952Sume				default:
465156952Sume					goto fail;
466156952Sume				}
467156952Sume			} while (!done);
468156952Sume		}
469156952Sume
470156952Sume		Dprint(((statp->options & RES_DEBUG) &&
471156952Sume			getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
472156952Sume				    NULL, 0, niflags) == 0),
473156952Sume		       (stdout, ";; Querying server (# %d) address = %s\n",
474156952Sume			ns + 1, abuf));
475156952Sume
476156952Sume
477156952Sume		if (v_circuit) {
478156952Sume			/* Use VC; at most one attempt per server. */
479156952Sume			try = statp->retry;
480156952Sume			n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
481156952Sume				    ns);
482156952Sume			if (n < 0)
483156952Sume				goto fail;
484156952Sume			if (n == 0)
485156952Sume				goto next_ns;
486156952Sume			resplen = n;
487156952Sume		} else {
488156952Sume			/* Use datagrams. */
489156956Sume			n = send_dg(statp,
490156956Sume#ifdef USE_KQUEUE
491156956Sume				    kq,
492156956Sume#endif
493156956Sume				    buf, buflen, ans, anssiz, &terrno,
494163661Sume				    ns, try, &v_circuit, &gotsomewhere);
495156952Sume			if (n < 0)
496156952Sume				goto fail;
497156952Sume			if (n == 0)
498156952Sume				goto next_ns;
499156952Sume			if (v_circuit)
500156952Sume				goto same_ns;
501156952Sume			resplen = n;
502156952Sume		}
503156952Sume
504156952Sume		Dprint((statp->options & RES_DEBUG) ||
505156952Sume		       ((statp->pfcode & RES_PRF_REPLY) &&
506156952Sume			(statp->pfcode & RES_PRF_HEAD1)),
507156952Sume		       (stdout, ";; got answer:\n"));
508156952Sume
509156952Sume		DprintQ((statp->options & RES_DEBUG) ||
510156952Sume			(statp->pfcode & RES_PRF_REPLY),
511156952Sume			(stdout, "%s", ""),
512156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
513156952Sume
514156952Sume		/*
515156952Sume		 * If we have temporarily opened a virtual circuit,
516156952Sume		 * or if we haven't been asked to keep a socket open,
517156952Sume		 * close the socket.
518156952Sume		 */
519156952Sume		if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
520156952Sume		    (statp->options & RES_STAYOPEN) == 0U) {
521156952Sume			res_nclose(statp);
522156952Sume		}
523156952Sume		if (statp->rhook) {
524156952Sume			int done = 0, loops = 0;
525156952Sume
526156952Sume			do {
527156952Sume				res_sendhookact act;
528156952Sume
529156952Sume				act = (*statp->rhook)(nsap, buf, buflen,
530156952Sume						      ans, anssiz, &resplen);
531156952Sume				switch (act) {
532156952Sume				case res_goahead:
533156952Sume				case res_done:
534156952Sume					done = 1;
535156952Sume					break;
536156952Sume				case res_nextns:
537156952Sume					res_nclose(statp);
538156952Sume					goto next_ns;
539156952Sume				case res_modified:
540156952Sume					/* give the hook another try */
541156952Sume					if (++loops < 42) /*doug adams*/
542156952Sume						break;
543156952Sume					/*FALLTHROUGH*/
544156952Sume				case res_error:
545156952Sume					/*FALLTHROUGH*/
546156952Sume				default:
547156952Sume					goto fail;
548156952Sume				}
549156952Sume			} while (!done);
550156952Sume
551156952Sume		}
552156956Sume#ifdef USE_KQUEUE
553156956Sume		_close(kq);
554156956Sume#endif
555156952Sume		return (resplen);
556156952Sume next_ns: ;
557156952Sume	   } /*foreach ns*/
558156952Sume	} /*foreach retry*/
559156952Sume	res_nclose(statp);
560156956Sume#ifdef USE_KQUEUE
561156956Sume	_close(kq);
562156956Sume#endif
563156952Sume	if (!v_circuit) {
564156952Sume		if (!gotsomewhere)
565156952Sume			errno = ECONNREFUSED;	/* no nameservers found */
566156952Sume		else
567156952Sume			errno = ETIMEDOUT;	/* no answer obtained */
568156952Sume	} else
569156952Sume		errno = terrno;
570156952Sume	return (-1);
571156952Sume fail:
572156952Sume	res_nclose(statp);
573156956Sume#ifdef USE_KQUEUE
574156956Sume	_close(kq);
575156956Sume#endif
576156952Sume	return (-1);
577156952Sume}
578156952Sume
579156952Sume/* Private */
580156952Sume
581156952Sumestatic int
582156952Sumeget_salen(sa)
583156952Sume	const struct sockaddr *sa;
584156952Sume{
585156952Sume
586156952Sume#ifdef HAVE_SA_LEN
587156952Sume	/* There are people do not set sa_len.  Be forgiving to them. */
588156952Sume	if (sa->sa_len)
589156952Sume		return (sa->sa_len);
590156952Sume#endif
591156952Sume
592156952Sume	if (sa->sa_family == AF_INET)
593156952Sume		return (sizeof(struct sockaddr_in));
594156952Sume	else if (sa->sa_family == AF_INET6)
595156952Sume		return (sizeof(struct sockaddr_in6));
596156952Sume	else
597156952Sume		return (0);	/* unknown, die on connect */
598156952Sume}
599156952Sume
600156952Sume/*
601156952Sume * pick appropriate nsaddr_list for use.  see res_init() for initialization.
602156952Sume */
603156952Sumestatic struct sockaddr *
604156952Sumeget_nsaddr(statp, n)
605156952Sume	res_state statp;
606156952Sume	size_t n;
607156952Sume{
608156952Sume
609156952Sume	if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
610156952Sume		/*
611156952Sume		 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
612156952Sume		 *   than struct sockaddr, and
613156952Sume		 * - user code did not update statp->nsaddr_list[n].
614156952Sume		 */
615156952Sume		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
616156952Sume	} else {
617156952Sume		/*
618156952Sume		 * - user code updated statp->nsaddr_list[n], or
619156952Sume		 * - statp->nsaddr_list[n] has the same content as
620156952Sume		 *   EXT(statp).ext->nsaddrs[n].
621156952Sume		 */
622156952Sume		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
623156952Sume	}
624156952Sume}
625156952Sume
626156952Sumestatic int
627156952Sumesend_vc(res_state statp,
628156952Sume	const u_char *buf, int buflen, u_char *ans, int anssiz,
629156952Sume	int *terrno, int ns)
630156952Sume{
631156952Sume	const HEADER *hp = (const HEADER *) buf;
632156952Sume	HEADER *anhp = (HEADER *) ans;
633156952Sume	struct sockaddr *nsap;
634156952Sume	int nsaplen;
635156952Sume	int truncating, connreset, resplen, n;
636156952Sume	struct iovec iov[2];
637156952Sume	u_short len;
638156952Sume	u_char *cp;
639156952Sume	void *tmp;
640156952Sume
641156952Sume	nsap = get_nsaddr(statp, ns);
642156952Sume	nsaplen = get_salen(nsap);
643156952Sume
644156952Sume	connreset = 0;
645156952Sume same_ns:
646156952Sume	truncating = 0;
647156952Sume
648156952Sume	/* Are we still talking to whom we want to talk to? */
649156952Sume	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
650156952Sume		struct sockaddr_storage peer;
651156952Sume		ISC_SOCKLEN_T size = sizeof peer;
652156952Sume
653156956Sume		if (_getpeername(statp->_vcsock,
654156952Sume				(struct sockaddr *)&peer, &size) < 0 ||
655156952Sume		    !sock_eq((struct sockaddr *)&peer, nsap)) {
656156952Sume			res_nclose(statp);
657156952Sume			statp->_flags &= ~RES_F_VC;
658156952Sume		}
659156952Sume	}
660156952Sume
661156952Sume	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
662156952Sume		if (statp->_vcsock >= 0)
663156952Sume			res_nclose(statp);
664156952Sume
665156956Sume		statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0);
666156952Sume		if (statp->_vcsock > highestFD) {
667156952Sume			res_nclose(statp);
668156952Sume			errno = ENOTSOCK;
669156952Sume		}
670156952Sume		if (statp->_vcsock < 0) {
671156952Sume			switch (errno) {
672156952Sume			case EPROTONOSUPPORT:
673156952Sume#ifdef EPFNOSUPPORT
674156952Sume			case EPFNOSUPPORT:
675156952Sume#endif
676156952Sume			case EAFNOSUPPORT:
677156952Sume				Perror(statp, stderr, "socket(vc)", errno);
678156952Sume				return (0);
679156952Sume			default:
680156952Sume				*terrno = errno;
681156952Sume				Perror(statp, stderr, "socket(vc)", errno);
682156952Sume				return (-1);
683156952Sume			}
684156952Sume		}
685156952Sume		errno = 0;
686156956Sume		if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
687156952Sume			*terrno = errno;
688156952Sume			Aerror(statp, stderr, "connect/vc", errno, nsap,
689156952Sume			    nsaplen);
690156952Sume			res_nclose(statp);
691156952Sume			return (0);
692156952Sume		}
693156952Sume		statp->_flags |= RES_F_VC;
694156952Sume	}
695156952Sume
696156952Sume	/*
697156952Sume	 * Send length & message
698156952Sume	 */
699156952Sume	ns_put16((u_short)buflen, (u_char*)&len);
700156952Sume	iov[0] = evConsIovec(&len, INT16SZ);
701156952Sume	DE_CONST(buf, tmp);
702156952Sume	iov[1] = evConsIovec(tmp, buflen);
703156956Sume	if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
704156952Sume		*terrno = errno;
705156952Sume		Perror(statp, stderr, "write failed", errno);
706156952Sume		res_nclose(statp);
707156952Sume		return (0);
708156952Sume	}
709156952Sume	/*
710156952Sume	 * Receive length & response
711156952Sume	 */
712156952Sume read_len:
713156952Sume	cp = ans;
714156952Sume	len = INT16SZ;
715156956Sume	while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
716156952Sume		cp += n;
717156952Sume		if ((len -= n) == 0)
718156952Sume			break;
719156952Sume	}
720156952Sume	if (n <= 0) {
721156952Sume		*terrno = errno;
722156952Sume		Perror(statp, stderr, "read failed", errno);
723156952Sume		res_nclose(statp);
724156952Sume		/*
725156952Sume		 * A long running process might get its TCP
726156952Sume		 * connection reset if the remote server was
727156952Sume		 * restarted.  Requery the server instead of
728156952Sume		 * trying a new one.  When there is only one
729156952Sume		 * server, this means that a query might work
730156952Sume		 * instead of failing.  We only allow one reset
731156952Sume		 * per query to prevent looping.
732156952Sume		 */
733156952Sume		if (*terrno == ECONNRESET && !connreset) {
734156952Sume			connreset = 1;
735156952Sume			res_nclose(statp);
736156952Sume			goto same_ns;
737156952Sume		}
738156952Sume		res_nclose(statp);
739156952Sume		return (0);
740156952Sume	}
741156952Sume	resplen = ns_get16(ans);
742156952Sume	if (resplen > anssiz) {
743156952Sume		Dprint(statp->options & RES_DEBUG,
744156952Sume		       (stdout, ";; response truncated\n")
745156952Sume		       );
746156952Sume		truncating = 1;
747156952Sume		len = anssiz;
748156952Sume	} else
749156952Sume		len = resplen;
750156952Sume	if (len < HFIXEDSZ) {
751156952Sume		/*
752156952Sume		 * Undersized message.
753156952Sume		 */
754156952Sume		Dprint(statp->options & RES_DEBUG,
755156952Sume		       (stdout, ";; undersized: %d\n", len));
756156952Sume		*terrno = EMSGSIZE;
757156952Sume		res_nclose(statp);
758156952Sume		return (0);
759156952Sume	}
760156952Sume	cp = ans;
761156956Sume	while (len != 0 &&
762156956Sume	    (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
763156952Sume		cp += n;
764156952Sume		len -= n;
765156952Sume	}
766156952Sume	if (n <= 0) {
767156952Sume		*terrno = errno;
768156952Sume		Perror(statp, stderr, "read(vc)", errno);
769156952Sume		res_nclose(statp);
770156952Sume		return (0);
771156952Sume	}
772156952Sume	if (truncating) {
773156952Sume		/*
774156952Sume		 * Flush rest of answer so connection stays in synch.
775156952Sume		 */
776156952Sume		anhp->tc = 1;
777156952Sume		len = resplen - anssiz;
778156952Sume		while (len != 0) {
779156952Sume			char junk[PACKETSZ];
780156952Sume
781156956Sume			n = _read(statp->_vcsock, junk,
782156956Sume			    (len > sizeof junk) ? sizeof junk : len);
783156952Sume			if (n > 0)
784156952Sume				len -= n;
785156952Sume			else
786156952Sume				break;
787156952Sume		}
788156952Sume	}
789156952Sume	/*
790156952Sume	 * If the calling applicating has bailed out of
791156952Sume	 * a previous call and failed to arrange to have
792156952Sume	 * the circuit closed or the server has got
793156952Sume	 * itself confused, then drop the packet and
794156952Sume	 * wait for the correct one.
795156952Sume	 */
796156952Sume	if (hp->id != anhp->id) {
797156952Sume		DprintQ((statp->options & RES_DEBUG) ||
798156952Sume			(statp->pfcode & RES_PRF_REPLY),
799156952Sume			(stdout, ";; old answer (unexpected):\n"),
800156952Sume			ans, (resplen > anssiz) ? anssiz: resplen);
801156952Sume		goto read_len;
802156952Sume	}
803156952Sume
804156952Sume	/*
805156952Sume	 * All is well, or the error is fatal.  Signal that the
806156952Sume	 * next nameserver ought not be tried.
807156952Sume	 */
808156952Sume	return (resplen);
809156952Sume}
810156952Sume
811156952Sumestatic int
812156952Sumesend_dg(res_state statp,
813156956Sume#ifdef USE_KQUEUE
814156956Sume	int kq,
815156956Sume#endif
816163661Sume	const u_char *buf, int buflen, u_char *ans,
817163661Sume	int anssiz, int *terrno, int ns, int try, int *v_circuit,
818163661Sume	int *gotsomewhere)
819156952Sume{
820156952Sume	const HEADER *hp = (const HEADER *) buf;
821156952Sume	HEADER *anhp = (HEADER *) ans;
822156952Sume	const struct sockaddr *nsap;
823156952Sume	int nsaplen;
824156952Sume	struct timespec now, timeout, finish;
825156952Sume	struct sockaddr_storage from;
826156952Sume	ISC_SOCKLEN_T fromlen;
827156952Sume	int resplen, seconds, n, s;
828156956Sume#ifdef USE_KQUEUE
829156956Sume	struct kevent kv;
830156956Sume#else
831156952Sume#ifdef USE_POLL
832156952Sume	int     polltimeout;
833156952Sume	struct pollfd   pollfd;
834156952Sume#else
835156952Sume	fd_set dsmask;
836156952Sume#endif
837156956Sume#endif
838156952Sume
839156952Sume	nsap = get_nsaddr(statp, ns);
840156952Sume	nsaplen = get_salen(nsap);
841156952Sume	if (EXT(statp).nssocks[ns] == -1) {
842156956Sume		EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
843156956Sume		    SOCK_DGRAM, 0);
844156952Sume		if (EXT(statp).nssocks[ns] > highestFD) {
845156952Sume			res_nclose(statp);
846156952Sume			errno = ENOTSOCK;
847156952Sume		}
848156952Sume		if (EXT(statp).nssocks[ns] < 0) {
849156952Sume			switch (errno) {
850156952Sume			case EPROTONOSUPPORT:
851156952Sume#ifdef EPFNOSUPPORT
852156952Sume			case EPFNOSUPPORT:
853156952Sume#endif
854156952Sume			case EAFNOSUPPORT:
855156952Sume				Perror(statp, stderr, "socket(dg)", errno);
856156952Sume				return (0);
857156952Sume			default:
858156952Sume				*terrno = errno;
859156952Sume				Perror(statp, stderr, "socket(dg)", errno);
860156952Sume				return (-1);
861156952Sume			}
862156952Sume		}
863156952Sume#ifndef CANNOT_CONNECT_DGRAM
864156952Sume		/*
865156952Sume		 * On a 4.3BSD+ machine (client and server,
866156952Sume		 * actually), sending to a nameserver datagram
867156952Sume		 * port with no nameserver will cause an
868156952Sume		 * ICMP port unreachable message to be returned.
869156952Sume		 * If our datagram socket is "connected" to the
870156952Sume		 * server, we get an ECONNREFUSED error on the next
871156952Sume		 * socket operation, and select returns if the
872156952Sume		 * error message is received.  We can thus detect
873156952Sume		 * the absence of a nameserver without timing out.
874156956Sume		 *
875156956Sume		 * When the option "insecure1" is specified, we'd
876156956Sume		 * rather expect to see responses from an "unknown"
877156956Sume		 * address.  In order to let the kernel accept such
878156956Sume		 * responses, do not connect the socket here.
879156956Sume		 * XXX: or do we need an explicit option to disable
880156956Sume		 * connecting?
881156952Sume		 */
882156956Sume		if (!(statp->options & RES_INSECURE1) &&
883156956Sume		    _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
884156952Sume			Aerror(statp, stderr, "connect(dg)", errno, nsap,
885156952Sume			    nsaplen);
886156952Sume			res_nclose(statp);
887156952Sume			return (0);
888156952Sume		}
889156952Sume#endif /* !CANNOT_CONNECT_DGRAM */
890156952Sume		Dprint(statp->options & RES_DEBUG,
891156952Sume		       (stdout, ";; new DG socket\n"))
892156952Sume	}
893156952Sume	s = EXT(statp).nssocks[ns];
894156952Sume#ifndef CANNOT_CONNECT_DGRAM
895156956Sume	if (statp->options & RES_INSECURE1) {
896156956Sume		if (_sendto(s,
897156956Sume		    (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
898156956Sume			Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
899156956Sume			res_nclose(statp);
900156956Sume			return (0);
901156956Sume		}
902156956Sume	} else if (send(s, (const char*)buf, buflen, 0) != buflen) {
903156952Sume		Perror(statp, stderr, "send", errno);
904156952Sume		res_nclose(statp);
905156952Sume		return (0);
906156952Sume	}
907156952Sume#else /* !CANNOT_CONNECT_DGRAM */
908156956Sume	if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
909156952Sume	{
910156952Sume		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
911156952Sume		res_nclose(statp);
912156952Sume		return (0);
913156952Sume	}
914156952Sume#endif /* !CANNOT_CONNECT_DGRAM */
915156952Sume
916156952Sume	/*
917156952Sume	 * Wait for reply.
918156952Sume	 */
919163661Sume	seconds = (statp->retrans << try);
920156952Sume	if (ns > 0)
921156952Sume		seconds /= statp->nscount;
922156952Sume	if (seconds <= 0)
923156952Sume		seconds = 1;
924156952Sume	now = evNowTime();
925156952Sume	timeout = evConsTime(seconds, 0);
926156952Sume	finish = evAddTime(now, timeout);
927156952Sume	goto nonow;
928156952Sume wait:
929156952Sume	now = evNowTime();
930156952Sume nonow:
931156952Sume#ifndef USE_POLL
932156952Sume	if (evCmpTime(finish, now) > 0)
933156952Sume		timeout = evSubTime(finish, now);
934156952Sume	else
935156952Sume		timeout = evConsTime(0, 0);
936156956Sume#ifdef USE_KQUEUE
937156956Sume	EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
938156956Sume	n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
939156956Sume#else
940156956Sume	FD_ZERO(&dsmask);
941156956Sume	FD_SET(s, &dsmask);
942156952Sume	n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
943156956Sume#endif
944156952Sume#else
945156952Sume	timeout = evSubTime(finish, now);
946156952Sume	if (timeout.tv_sec < 0)
947156952Sume		timeout = evConsTime(0, 0);
948156952Sume	polltimeout = 1000*timeout.tv_sec +
949156952Sume		timeout.tv_nsec/1000000;
950156952Sume	pollfd.fd = s;
951156952Sume	pollfd.events = POLLRDNORM;
952156952Sume	n = poll(&pollfd, 1, polltimeout);
953156952Sume#endif /* USE_POLL */
954156952Sume
955156952Sume	if (n == 0) {
956156952Sume		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
957156952Sume		*gotsomewhere = 1;
958156952Sume		return (0);
959156952Sume	}
960156952Sume	if (n < 0) {
961156952Sume		if (errno == EINTR)
962156952Sume			goto wait;
963156956Sume#ifdef USE_KQUEUE
964156956Sume		Perror(statp, stderr, "kevent", errno);
965156956Sume#else
966156952Sume#ifndef USE_POLL
967156952Sume		Perror(statp, stderr, "select", errno);
968156952Sume#else
969156952Sume		Perror(statp, stderr, "poll", errno);
970156952Sume#endif /* USE_POLL */
971156956Sume#endif
972156952Sume		res_nclose(statp);
973156952Sume		return (0);
974156952Sume	}
975160967Sume#ifdef USE_KQUEUE
976160967Sume	if (kv.ident != s)
977160967Sume		goto wait;
978160967Sume#endif
979156952Sume	errno = 0;
980156952Sume	fromlen = sizeof(from);
981156956Sume	resplen = _recvfrom(s, (char*)ans, anssiz,0,
982156952Sume			   (struct sockaddr *)&from, &fromlen);
983156952Sume	if (resplen <= 0) {
984156952Sume		Perror(statp, stderr, "recvfrom", errno);
985156952Sume		res_nclose(statp);
986156952Sume		return (0);
987156952Sume	}
988156952Sume	*gotsomewhere = 1;
989156952Sume	if (resplen < HFIXEDSZ) {
990156952Sume		/*
991156952Sume		 * Undersized message.
992156952Sume		 */
993156952Sume		Dprint(statp->options & RES_DEBUG,
994156952Sume		       (stdout, ";; undersized: %d\n",
995156952Sume			resplen));
996156952Sume		*terrno = EMSGSIZE;
997156952Sume		res_nclose(statp);
998156952Sume		return (0);
999156952Sume	}
1000156952Sume	if (hp->id != anhp->id) {
1001156952Sume		/*
1002156952Sume		 * response from old query, ignore it.
1003156952Sume		 * XXX - potential security hazard could
1004156952Sume		 *	 be detected here.
1005156952Sume		 */
1006156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1007156952Sume			(statp->pfcode & RES_PRF_REPLY),
1008156952Sume			(stdout, ";; old answer:\n"),
1009156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1010156952Sume		goto wait;
1011156952Sume	}
1012156952Sume	if (!(statp->options & RES_INSECURE1) &&
1013156952Sume	    !res_ourserver_p(statp, (struct sockaddr *)&from)) {
1014156952Sume		/*
1015156952Sume		 * response from wrong server? ignore it.
1016156952Sume		 * XXX - potential security hazard could
1017156952Sume		 *	 be detected here.
1018156952Sume		 */
1019156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1020156952Sume			(statp->pfcode & RES_PRF_REPLY),
1021156952Sume			(stdout, ";; not our server:\n"),
1022156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1023156952Sume		goto wait;
1024156952Sume	}
1025156952Sume#ifdef RES_USE_EDNS0
1026156952Sume	if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1027156952Sume		/*
1028156952Sume		 * Do not retry if the server do not understand EDNS0.
1029156952Sume		 * The case has to be captured here, as FORMERR packet do not
1030156952Sume		 * carry query section, hence res_queriesmatch() returns 0.
1031156952Sume		 */
1032156952Sume		DprintQ(statp->options & RES_DEBUG,
1033156952Sume			(stdout, "server rejected query with EDNS0:\n"),
1034156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1035156952Sume		/* record the error */
1036156952Sume		statp->_flags |= RES_F_EDNS0ERR;
1037156952Sume		res_nclose(statp);
1038156952Sume		return (0);
1039156952Sume	}
1040156952Sume#endif
1041156952Sume	if (!(statp->options & RES_INSECURE2) &&
1042156952Sume	    !res_queriesmatch(buf, buf + buflen,
1043156952Sume			      ans, ans + anssiz)) {
1044156952Sume		/*
1045156952Sume		 * response contains wrong query? ignore it.
1046156952Sume		 * XXX - potential security hazard could
1047156952Sume		 *	 be detected here.
1048156952Sume		 */
1049156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1050156952Sume			(statp->pfcode & RES_PRF_REPLY),
1051156952Sume			(stdout, ";; wrong query name:\n"),
1052156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1053156952Sume		goto wait;
1054156952Sume	}
1055156952Sume	if (anhp->rcode == SERVFAIL ||
1056156952Sume	    anhp->rcode == NOTIMP ||
1057156952Sume	    anhp->rcode == REFUSED) {
1058156952Sume		DprintQ(statp->options & RES_DEBUG,
1059156952Sume			(stdout, "server rejected query:\n"),
1060156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1061156952Sume		res_nclose(statp);
1062156952Sume		/* don't retry if called from dig */
1063156952Sume		if (!statp->pfcode)
1064156952Sume			return (0);
1065156952Sume	}
1066156952Sume	if (!(statp->options & RES_IGNTC) && anhp->tc) {
1067156952Sume		/*
1068156952Sume		 * To get the rest of answer,
1069156952Sume		 * use TCP with same server.
1070156952Sume		 */
1071156952Sume		Dprint(statp->options & RES_DEBUG,
1072156952Sume		       (stdout, ";; truncated answer\n"));
1073156952Sume		*v_circuit = 1;
1074156952Sume		res_nclose(statp);
1075156952Sume		return (1);
1076156952Sume	}
1077156952Sume	/*
1078156952Sume	 * All is well, or the error is fatal.  Signal that the
1079156952Sume	 * next nameserver ought not be tried.
1080156952Sume	 */
1081156952Sume	return (resplen);
1082156952Sume}
1083156952Sume
1084156952Sumestatic void
1085156952SumeAerror(const res_state statp, FILE *file, const char *string, int error,
1086156952Sume       const struct sockaddr *address, int alen)
1087156952Sume{
1088156952Sume	int save = errno;
1089156952Sume	char hbuf[NI_MAXHOST];
1090156952Sume	char sbuf[NI_MAXSERV];
1091156952Sume
1092156952Sume	alen = alen;
1093156952Sume
1094156952Sume	if ((statp->options & RES_DEBUG) != 0U) {
1095156952Sume		if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
1096156952Sume		    sbuf, sizeof(sbuf), niflags)) {
1097156952Sume			strncpy(hbuf, "?", sizeof(hbuf) - 1);
1098156952Sume			hbuf[sizeof(hbuf) - 1] = '\0';
1099156952Sume			strncpy(sbuf, "?", sizeof(sbuf) - 1);
1100156952Sume			sbuf[sizeof(sbuf) - 1] = '\0';
1101156952Sume		}
1102156952Sume		fprintf(file, "res_send: %s ([%s].%s): %s\n",
1103156952Sume			string, hbuf, sbuf, strerror(error));
1104156952Sume	}
1105156952Sume	errno = save;
1106156952Sume}
1107156952Sume
1108156952Sumestatic void
1109156952SumePerror(const res_state statp, FILE *file, const char *string, int error) {
1110156952Sume	int save = errno;
1111156952Sume
1112156952Sume	if ((statp->options & RES_DEBUG) != 0U)
1113156952Sume		fprintf(file, "res_send: %s: %s\n",
1114156952Sume			string, strerror(error));
1115156952Sume	errno = save;
1116156952Sume}
1117156952Sume
1118156952Sumestatic int
1119156952Sumesock_eq(struct sockaddr *a, struct sockaddr *b) {
1120156952Sume	struct sockaddr_in *a4, *b4;
1121156952Sume	struct sockaddr_in6 *a6, *b6;
1122156952Sume
1123156952Sume	if (a->sa_family != b->sa_family)
1124156952Sume		return 0;
1125156952Sume	switch (a->sa_family) {
1126156952Sume	case AF_INET:
1127156952Sume		a4 = (struct sockaddr_in *)a;
1128156952Sume		b4 = (struct sockaddr_in *)b;
1129156952Sume		return a4->sin_port == b4->sin_port &&
1130156952Sume		    a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1131156952Sume	case AF_INET6:
1132156952Sume		a6 = (struct sockaddr_in6 *)a;
1133156952Sume		b6 = (struct sockaddr_in6 *)b;
1134156952Sume		return a6->sin6_port == b6->sin6_port &&
1135156952Sume#ifdef HAVE_SIN6_SCOPE_ID
1136156952Sume		    a6->sin6_scope_id == b6->sin6_scope_id &&
1137156952Sume#endif
1138156952Sume		    IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1139156952Sume	default:
1140156952Sume		return 0;
1141156952Sume	}
1142156952Sume}
1143156952Sume
1144156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
1145156952Sume/* XXX needs to move to the porting library. */
1146156952Sumestatic int
1147156952Sumepselect(int nfds, void *rfds, void *wfds, void *efds,
1148156952Sume	struct timespec *tsp, const sigset_t *sigmask)
1149156952Sume{
1150156952Sume	struct timeval tv, *tvp;
1151156952Sume	sigset_t sigs;
1152156952Sume	int n;
1153156952Sume
1154156952Sume	if (tsp) {
1155156952Sume		tvp = &tv;
1156156952Sume		tv = evTimeVal(*tsp);
1157156952Sume	} else
1158156952Sume		tvp = NULL;
1159156952Sume	if (sigmask)
1160156952Sume		sigprocmask(SIG_SETMASK, sigmask, &sigs);
1161156952Sume	n = select(nfds, rfds, wfds, efds, tvp);
1162156952Sume	if (sigmask)
1163156952Sume		sigprocmask(SIG_SETMASK, &sigs, NULL);
1164156952Sume	if (tsp)
1165156952Sume		*tsp = evTimeSpec(tv);
1166156952Sume	return (n);
1167156952Sume}
1168156952Sume#endif
1169