1331722Seadler/*
2269867Sume * Portions Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
3269867Sume * Portions Copyright (C) 1996-2003  Internet Software Consortium.
4269867Sume *
5269867Sume * Permission to use, copy, modify, and/or distribute this software for any
6269867Sume * purpose with or without fee is hereby granted, provided that the above
7269867Sume * copyright notice and this permission notice appear in all copies.
8269867Sume *
9269867Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10269867Sume * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11269867Sume * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12269867Sume * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13269867Sume * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14269867Sume * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15269867Sume * PERFORMANCE OF THIS SOFTWARE.
16269867Sume */
17269867Sume
18269867Sume/*
19156952Sume * Copyright (c) 1985, 1989, 1993
20156952Sume *    The Regents of the University of California.  All rights reserved.
21269867Sume *
22156952Sume * Redistribution and use in source and binary forms, with or without
23156952Sume * modification, are permitted provided that the following conditions
24156952Sume * are met:
25156952Sume * 1. Redistributions of source code must retain the above copyright
26156952Sume *    notice, this list of conditions and the following disclaimer.
27156952Sume * 2. Redistributions in binary form must reproduce the above copyright
28156952Sume *    notice, this list of conditions and the following disclaimer in the
29156952Sume *    documentation and/or other materials provided with the distribution.
30156952Sume * 4. Neither the name of the University nor the names of its contributors
31156952Sume *    may be used to endorse or promote products derived from this software
32156952Sume *    without specific prior written permission.
33269867Sume *
34156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37156952Sume * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44156952Sume * SUCH DAMAGE.
45156952Sume */
46156952Sume
47156952Sume/*
48156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation.
49269867Sume *
50156952Sume * Permission to use, copy, modify, and distribute this software for any
51156952Sume * purpose with or without fee is hereby granted, provided that the above
52156952Sume * copyright notice and this permission notice appear in all copies, and that
53156952Sume * the name of Digital Equipment Corporation not be used in advertising or
54156952Sume * publicity pertaining to distribution of the document or software without
55156952Sume * specific, written prior permission.
56269867Sume *
57156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
58156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
59156952Sume * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
60156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64156952Sume * SOFTWARE.
65156952Sume */
66156952Sume
67156952Sume#if defined(LIBC_SCCS) && !defined(lint)
68156952Sumestatic const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
69269867Sumestatic const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $";
70156952Sume#endif /* LIBC_SCCS and not lint */
71156956Sume#include <sys/cdefs.h>
72156956Sume__FBSDID("$FreeBSD$");
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/param.h>
86156952Sume#include <sys/time.h>
87156952Sume#include <sys/socket.h>
88156952Sume#include <sys/uio.h>
89156952Sume
90156952Sume#include <netinet/in.h>
91156952Sume#include <arpa/nameser.h>
92156952Sume#include <arpa/inet.h>
93156952Sume
94156952Sume#include <errno.h>
95156952Sume#include <netdb.h>
96156952Sume#include <resolv.h>
97156952Sume#include <signal.h>
98156952Sume#include <stdio.h>
99156952Sume#include <stdlib.h>
100156952Sume#include <string.h>
101156952Sume#include <unistd.h>
102156952Sume
103156952Sume#include <isc/eventlib.h>
104156952Sume
105156952Sume#include "port_after.h"
106156952Sume
107156956Sume#ifdef USE_KQUEUE
108156956Sume#include <sys/event.h>
109156956Sume#else
110156952Sume#ifdef USE_POLL
111156952Sume#ifdef HAVE_STROPTS_H
112156952Sume#include <stropts.h>
113156952Sume#endif
114156952Sume#include <poll.h>
115156952Sume#endif /* USE_POLL */
116156956Sume#endif
117156952Sume
118156956Sume#include "un-namespace.h"
119156956Sume
120156952Sume/* Options.  Leave them on. */
121292250Sngie#ifndef	DEBUG
122292250Sngie#define	DEBUG
123292250Sngie#endif
124156952Sume#include "res_debug.h"
125156952Sume#include "res_private.h"
126156952Sume
127156952Sume#define EXT(res) ((res)->_u._ext)
128156952Sume
129167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE)
130156952Sumestatic const int highestFD = FD_SETSIZE - 1;
131156952Sume#endif
132156952Sume
133156952Sume/* Forward. */
134156952Sume
135156956Sumestatic int		get_salen(const struct sockaddr *);
136156956Sumestatic struct sockaddr * get_nsaddr(res_state, size_t);
137156952Sumestatic int		send_vc(res_state, const u_char *, int,
138156952Sume				u_char *, int, int *, int);
139156956Sumestatic int		send_dg(res_state,
140156956Sume#ifdef USE_KQUEUE
141156956Sume				int kq,
142156956Sume#endif
143156956Sume				const u_char *, int,
144163661Sume				u_char *, int, int *, int, int,
145156952Sume				int *, int *);
146156952Sumestatic void		Aerror(const res_state, FILE *, const char *, int,
147156952Sume			       const struct sockaddr *, int);
148156952Sumestatic void		Perror(const res_state, FILE *, const char *, int);
149156952Sumestatic int		sock_eq(struct sockaddr *, struct sockaddr *);
150156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
151156952Sumestatic int		pselect(int, void *, void *, void *,
152156952Sume				struct timespec *,
153156952Sume				const sigset_t *);
154156952Sume#endif
155156952Sumevoid res_pquery(const res_state, const u_char *, int, FILE *);
156156952Sume
157156952Sumestatic const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
158156952Sume
159156952Sume/* Public. */
160156952Sume
161170244Sume/*%
162156952Sume *	looks up "ina" in _res.ns_addr_list[]
163170244Sume *
164156952Sume * returns:
165170244Sume *\li	0  : not found
166170244Sume *\li	>0 : found
167170244Sume *
168156952Sume * author:
169170244Sume *\li	paul vixie, 29may94
170156952Sume */
171156952Sumeint
172156952Sumeres_ourserver_p(const res_state statp, const struct sockaddr *sa) {
173156952Sume	const struct sockaddr_in *inp, *srv;
174156952Sume	const struct sockaddr_in6 *in6p, *srv6;
175156952Sume	int ns;
176156952Sume
177156952Sume	switch (sa->sa_family) {
178156952Sume	case AF_INET:
179156952Sume		inp = (const struct sockaddr_in *)sa;
180156952Sume		for (ns = 0;  ns < statp->nscount;  ns++) {
181156952Sume			srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
182156952Sume			if (srv->sin_family == inp->sin_family &&
183156952Sume			    srv->sin_port == inp->sin_port &&
184156952Sume			    (srv->sin_addr.s_addr == INADDR_ANY ||
185156952Sume			     srv->sin_addr.s_addr == inp->sin_addr.s_addr))
186156952Sume				return (1);
187156952Sume		}
188156952Sume		break;
189156952Sume	case AF_INET6:
190156952Sume		if (EXT(statp).ext == NULL)
191156952Sume			break;
192156952Sume		in6p = (const struct sockaddr_in6 *)sa;
193156952Sume		for (ns = 0;  ns < statp->nscount;  ns++) {
194156952Sume			srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
195156952Sume			if (srv6->sin6_family == in6p->sin6_family &&
196156952Sume			    srv6->sin6_port == in6p->sin6_port &&
197156952Sume#ifdef HAVE_SIN6_SCOPE_ID
198156952Sume			    (srv6->sin6_scope_id == 0 ||
199156952Sume			     srv6->sin6_scope_id == in6p->sin6_scope_id) &&
200156952Sume#endif
201156952Sume			    (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
202156952Sume			     IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
203156952Sume				return (1);
204156952Sume		}
205156952Sume		break;
206156952Sume	default:
207156952Sume		break;
208156952Sume	}
209156952Sume	return (0);
210156952Sume}
211156952Sume
212170244Sume/*%
213156952Sume *	look for (name,type,class) in the query section of packet (buf,eom)
214170244Sume *
215156952Sume * requires:
216170244Sume *\li	buf + HFIXEDSZ <= eom
217170244Sume *
218156952Sume * returns:
219170244Sume *\li	-1 : format error
220170244Sume *\li	0  : not found
221170244Sume *\li	>0 : found
222170244Sume *
223156952Sume * author:
224170244Sume *\li	paul vixie, 29may94
225156952Sume */
226156952Sumeint
227156952Sumeres_nameinquery(const char *name, int type, int class,
228156952Sume		const u_char *buf, const u_char *eom)
229156952Sume{
230156952Sume	const u_char *cp = buf + HFIXEDSZ;
231156952Sume	int qdcount = ntohs(((const HEADER*)buf)->qdcount);
232156952Sume
233156952Sume	while (qdcount-- > 0) {
234156952Sume		char tname[MAXDNAME+1];
235156952Sume		int n, ttype, tclass;
236156952Sume
237156952Sume		n = dn_expand(buf, eom, cp, tname, sizeof tname);
238156952Sume		if (n < 0)
239156952Sume			return (-1);
240156952Sume		cp += n;
241156952Sume		if (cp + 2 * INT16SZ > eom)
242156952Sume			return (-1);
243156952Sume		ttype = ns_get16(cp); cp += INT16SZ;
244156952Sume		tclass = ns_get16(cp); cp += INT16SZ;
245156952Sume		if (ttype == type && tclass == class &&
246156952Sume		    ns_samename(tname, name) == 1)
247156952Sume			return (1);
248156952Sume	}
249156952Sume	return (0);
250156952Sume}
251156952Sume
252170244Sume/*%
253156952Sume *	is there a 1:1 mapping of (name,type,class)
254156952Sume *	in (buf1,eom1) and (buf2,eom2)?
255170244Sume *
256156952Sume * returns:
257170244Sume *\li	-1 : format error
258170244Sume *\li	0  : not a 1:1 mapping
259170244Sume *\li	>0 : is a 1:1 mapping
260170244Sume *
261156952Sume * author:
262170244Sume *\li	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{
306186090Sume	int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
307156956Sume#ifdef USE_KQUEUE
308156956Sume	int kq;
309156956Sume#endif
310156952Sume	char abuf[NI_MAXHOST];
311156952Sume
312165258Sume	/* No name servers or res_init() failure */
313165258Sume	if (statp->nscount == 0 || EXT(statp).ext == NULL) {
314156952Sume		errno = ESRCH;
315156952Sume		return (-1);
316156952Sume	}
317156952Sume	if (anssiz < HFIXEDSZ) {
318156952Sume		errno = EINVAL;
319156952Sume		return (-1);
320156952Sume	}
321156952Sume	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
322156952Sume		(stdout, ";; res_send()\n"), buf, buflen);
323156952Sume	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
324156952Sume	gotsomewhere = 0;
325156952Sume	terrno = ETIMEDOUT;
326156952Sume
327156956Sume#ifdef USE_KQUEUE
328156956Sume	if ((kq = kqueue()) < 0) {
329156956Sume		Perror(statp, stderr, "kqueue", errno);
330156956Sume		return (-1);
331156956Sume	}
332156956Sume#endif
333156956Sume
334156952Sume	/*
335156952Sume	 * If the ns_addr_list in the resolver context has changed, then
336156952Sume	 * invalidate our cached copy and the associated timing data.
337156952Sume	 */
338156952Sume	if (EXT(statp).nscount != 0) {
339156952Sume		int needclose = 0;
340156952Sume		struct sockaddr_storage peer;
341156952Sume		ISC_SOCKLEN_T peerlen;
342156952Sume
343156952Sume		if (EXT(statp).nscount != statp->nscount)
344156952Sume			needclose++;
345156952Sume		else
346156952Sume			for (ns = 0; ns < statp->nscount; ns++) {
347156952Sume				if (statp->nsaddr_list[ns].sin_family &&
348156952Sume				    !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
349156952Sume					     (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
350156952Sume					needclose++;
351156952Sume					break;
352156952Sume				}
353156952Sume
354156952Sume				if (EXT(statp).nssocks[ns] == -1)
355156952Sume					continue;
356156952Sume				peerlen = sizeof(peer);
357269867Sume				if (_getpeername(EXT(statp).nssocks[ns],
358156952Sume				    (struct sockaddr *)&peer, &peerlen) < 0) {
359156952Sume					needclose++;
360156952Sume					break;
361156952Sume				}
362156952Sume				if (!sock_eq((struct sockaddr *)&peer,
363156952Sume				    get_nsaddr(statp, ns))) {
364156952Sume					needclose++;
365156952Sume					break;
366156952Sume				}
367156952Sume			}
368156952Sume		if (needclose) {
369156952Sume			res_nclose(statp);
370156952Sume			EXT(statp).nscount = 0;
371156952Sume		}
372156952Sume	}
373156952Sume
374156952Sume	/*
375156952Sume	 * Maybe initialize our private copy of the ns_addr_list.
376156952Sume	 */
377156952Sume	if (EXT(statp).nscount == 0) {
378156952Sume		for (ns = 0; ns < statp->nscount; ns++) {
379156952Sume			EXT(statp).nstimes[ns] = RES_MAXTIME;
380156952Sume			EXT(statp).nssocks[ns] = -1;
381156952Sume			if (!statp->nsaddr_list[ns].sin_family)
382156952Sume				continue;
383156952Sume			EXT(statp).ext->nsaddrs[ns].sin =
384156952Sume				 statp->nsaddr_list[ns];
385156952Sume		}
386156952Sume		EXT(statp).nscount = statp->nscount;
387156952Sume	}
388156952Sume
389156952Sume	/*
390156952Sume	 * Some resolvers want to even out the load on their nameservers.
391156952Sume	 * Note that RES_BLAST overrides RES_ROTATE.
392156952Sume	 */
393156952Sume	if ((statp->options & RES_ROTATE) != 0U &&
394156952Sume	    (statp->options & RES_BLAST) == 0U) {
395156952Sume		union res_sockaddr_union inu;
396156952Sume		struct sockaddr_in ina;
397156952Sume		int lastns = statp->nscount - 1;
398156952Sume		int fd;
399156952Sume		u_int16_t nstime;
400156952Sume
401156952Sume		if (EXT(statp).ext != NULL)
402156952Sume			inu = EXT(statp).ext->nsaddrs[0];
403156952Sume		ina = statp->nsaddr_list[0];
404156952Sume		fd = EXT(statp).nssocks[0];
405156952Sume		nstime = EXT(statp).nstimes[0];
406156952Sume		for (ns = 0; ns < lastns; ns++) {
407156952Sume			if (EXT(statp).ext != NULL)
408269867Sume				EXT(statp).ext->nsaddrs[ns] =
409156952Sume					EXT(statp).ext->nsaddrs[ns + 1];
410156952Sume			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
411156952Sume			EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
412156952Sume			EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
413156952Sume		}
414156952Sume		if (EXT(statp).ext != NULL)
415156952Sume			EXT(statp).ext->nsaddrs[lastns] = inu;
416156952Sume		statp->nsaddr_list[lastns] = ina;
417156952Sume		EXT(statp).nssocks[lastns] = fd;
418156952Sume		EXT(statp).nstimes[lastns] = nstime;
419156952Sume	}
420156952Sume
421156952Sume	/*
422156952Sume	 * Send request, RETRY times, or until successful.
423156952Sume	 */
424186090Sume	for (tries = 0; tries < statp->retry; tries++) {
425156952Sume	    for (ns = 0; ns < statp->nscount; ns++) {
426156952Sume		struct sockaddr *nsap;
427156952Sume		int nsaplen;
428156952Sume		nsap = get_nsaddr(statp, ns);
429156952Sume		nsaplen = get_salen(nsap);
430156952Sume		statp->_flags &= ~RES_F_LASTMASK;
431156952Sume		statp->_flags |= (ns << RES_F_LASTSHIFT);
432156952Sume same_ns:
433156952Sume		if (statp->qhook) {
434156952Sume			int done = 0, loops = 0;
435156952Sume
436156952Sume			do {
437156952Sume				res_sendhookact act;
438156952Sume
439156952Sume				act = (*statp->qhook)(&nsap, &buf, &buflen,
440156952Sume						      ans, anssiz, &resplen);
441156952Sume				switch (act) {
442156952Sume				case res_goahead:
443156952Sume					done = 1;
444156952Sume					break;
445156952Sume				case res_nextns:
446156952Sume					res_nclose(statp);
447156952Sume					goto next_ns;
448156952Sume				case res_done:
449156956Sume#ifdef USE_KQUEUE
450156956Sume					_close(kq);
451156956Sume#endif
452156952Sume					return (resplen);
453156952Sume				case res_modified:
454156952Sume					/* give the hook another try */
455156952Sume					if (++loops < 42) /*doug adams*/
456156952Sume						break;
457156952Sume					/*FALLTHROUGH*/
458156952Sume				case res_error:
459156952Sume					/*FALLTHROUGH*/
460156952Sume				default:
461156952Sume					goto fail;
462156952Sume				}
463156952Sume			} while (!done);
464156952Sume		}
465156952Sume
466156952Sume		Dprint(((statp->options & RES_DEBUG) &&
467156952Sume			getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
468156952Sume				    NULL, 0, niflags) == 0),
469156952Sume		       (stdout, ";; Querying server (# %d) address = %s\n",
470156952Sume			ns + 1, abuf));
471156952Sume
472156952Sume
473156952Sume		if (v_circuit) {
474156952Sume			/* Use VC; at most one attempt per server. */
475186090Sume			tries = statp->retry;
476156952Sume			n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
477156952Sume				    ns);
478156952Sume			if (n < 0)
479156952Sume				goto fail;
480156952Sume			if (n == 0)
481156952Sume				goto next_ns;
482156952Sume			resplen = n;
483156952Sume		} else {
484156952Sume			/* Use datagrams. */
485156956Sume			n = send_dg(statp,
486156956Sume#ifdef USE_KQUEUE
487156956Sume				    kq,
488156956Sume#endif
489156956Sume				    buf, buflen, ans, anssiz, &terrno,
490186090Sume				    ns, tries, &v_circuit, &gotsomewhere);
491156952Sume			if (n < 0)
492156952Sume				goto fail;
493156952Sume			if (n == 0)
494156952Sume				goto next_ns;
495156952Sume			if (v_circuit)
496156952Sume				goto same_ns;
497156952Sume			resplen = n;
498156952Sume		}
499156952Sume
500156952Sume		Dprint((statp->options & RES_DEBUG) ||
501156952Sume		       ((statp->pfcode & RES_PRF_REPLY) &&
502156952Sume			(statp->pfcode & RES_PRF_HEAD1)),
503156952Sume		       (stdout, ";; got answer:\n"));
504156952Sume
505156952Sume		DprintQ((statp->options & RES_DEBUG) ||
506156952Sume			(statp->pfcode & RES_PRF_REPLY),
507156952Sume			(stdout, "%s", ""),
508156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
509156952Sume
510156952Sume		/*
511156952Sume		 * If we have temporarily opened a virtual circuit,
512156952Sume		 * or if we haven't been asked to keep a socket open,
513156952Sume		 * close the socket.
514156952Sume		 */
515156952Sume		if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
516156952Sume		    (statp->options & RES_STAYOPEN) == 0U) {
517156952Sume			res_nclose(statp);
518156952Sume		}
519156952Sume		if (statp->rhook) {
520156952Sume			int done = 0, loops = 0;
521156952Sume
522156952Sume			do {
523156952Sume				res_sendhookact act;
524156952Sume
525156952Sume				act = (*statp->rhook)(nsap, buf, buflen,
526156952Sume						      ans, anssiz, &resplen);
527156952Sume				switch (act) {
528156952Sume				case res_goahead:
529156952Sume				case res_done:
530156952Sume					done = 1;
531156952Sume					break;
532156952Sume				case res_nextns:
533156952Sume					res_nclose(statp);
534156952Sume					goto next_ns;
535156952Sume				case res_modified:
536156952Sume					/* give the hook another try */
537156952Sume					if (++loops < 42) /*doug adams*/
538156952Sume						break;
539156952Sume					/*FALLTHROUGH*/
540156952Sume				case res_error:
541156952Sume					/*FALLTHROUGH*/
542156952Sume				default:
543156952Sume					goto fail;
544156952Sume				}
545156952Sume			} while (!done);
546156952Sume
547156952Sume		}
548156956Sume#ifdef USE_KQUEUE
549156956Sume		_close(kq);
550156956Sume#endif
551156952Sume		return (resplen);
552156952Sume next_ns: ;
553156952Sume	   } /*foreach ns*/
554156952Sume	} /*foreach retry*/
555156952Sume	res_nclose(statp);
556156956Sume#ifdef USE_KQUEUE
557156956Sume	_close(kq);
558156956Sume#endif
559156952Sume	if (!v_circuit) {
560156952Sume		if (!gotsomewhere)
561170244Sume			errno = ECONNREFUSED;	/*%< no nameservers found */
562156952Sume		else
563170244Sume			errno = ETIMEDOUT;	/*%< no answer obtained */
564156952Sume	} else
565156952Sume		errno = terrno;
566156952Sume	return (-1);
567156952Sume fail:
568156952Sume	res_nclose(statp);
569156956Sume#ifdef USE_KQUEUE
570156956Sume	_close(kq);
571156956Sume#endif
572156952Sume	return (-1);
573156952Sume}
574156952Sume
575156952Sume/* Private */
576156952Sume
577156952Sumestatic int
578288114Srodrigcget_salen(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 *
599288114Srodrigcget_nsaddr(res_state statp, size_t n)
600156952Sume{
601156952Sume
602156952Sume	if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
603156952Sume		/*
604156952Sume		 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
605156952Sume		 *   than struct sockaddr, and
606156952Sume		 * - user code did not update statp->nsaddr_list[n].
607156952Sume		 */
608156952Sume		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
609156952Sume	} else {
610156952Sume		/*
611156952Sume		 * - user code updated statp->nsaddr_list[n], or
612156952Sume		 * - statp->nsaddr_list[n] has the same content as
613156952Sume		 *   EXT(statp).ext->nsaddrs[n].
614156952Sume		 */
615156952Sume		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
616156952Sume	}
617156952Sume}
618156952Sume
619156952Sumestatic int
620156952Sumesend_vc(res_state statp,
621156952Sume	const u_char *buf, int buflen, u_char *ans, int anssiz,
622156952Sume	int *terrno, int ns)
623156952Sume{
624156952Sume	const HEADER *hp = (const HEADER *) buf;
625156952Sume	HEADER *anhp = (HEADER *) ans;
626156952Sume	struct sockaddr *nsap;
627156952Sume	int nsaplen;
628156952Sume	int truncating, connreset, resplen, n;
629156952Sume	struct iovec iov[2];
630156952Sume	u_short len;
631156952Sume	u_char *cp;
632156952Sume	void *tmp;
633186090Sume#ifdef SO_NOSIGPIPE
634186090Sume	int on = 1;
635186090Sume#endif
636156952Sume
637156952Sume	nsap = get_nsaddr(statp, ns);
638156952Sume	nsaplen = get_salen(nsap);
639156952Sume
640156952Sume	connreset = 0;
641156952Sume same_ns:
642156952Sume	truncating = 0;
643156952Sume
644156952Sume	/* Are we still talking to whom we want to talk to? */
645156952Sume	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
646156952Sume		struct sockaddr_storage peer;
647156952Sume		ISC_SOCKLEN_T size = sizeof peer;
648156952Sume
649156956Sume		if (_getpeername(statp->_vcsock,
650156952Sume				(struct sockaddr *)&peer, &size) < 0 ||
651156952Sume		    !sock_eq((struct sockaddr *)&peer, nsap)) {
652156952Sume			res_nclose(statp);
653156952Sume			statp->_flags &= ~RES_F_VC;
654156952Sume		}
655156952Sume	}
656156952Sume
657156952Sume	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
658156952Sume		if (statp->_vcsock >= 0)
659156952Sume			res_nclose(statp);
660156952Sume
661255336Sjilles		statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM |
662255336Sjilles		    SOCK_CLOEXEC, 0);
663167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE)
664156952Sume		if (statp->_vcsock > highestFD) {
665156952Sume			res_nclose(statp);
666156952Sume			errno = ENOTSOCK;
667156952Sume		}
668167246Sjhb#endif
669156952Sume		if (statp->_vcsock < 0) {
670156952Sume			switch (errno) {
671156952Sume			case EPROTONOSUPPORT:
672156952Sume#ifdef EPFNOSUPPORT
673156952Sume			case EPFNOSUPPORT:
674156952Sume#endif
675156952Sume			case EAFNOSUPPORT:
676156952Sume				Perror(statp, stderr, "socket(vc)", errno);
677156952Sume				return (0);
678156952Sume			default:
679156952Sume				*terrno = errno;
680156952Sume				Perror(statp, stderr, "socket(vc)", errno);
681156952Sume				return (-1);
682156952Sume			}
683156952Sume		}
684186090Sume#ifdef SO_NOSIGPIPE
685186090Sume		/*
686186090Sume		 * Disable generation of SIGPIPE when writing to a closed
687186090Sume		 * socket.  Write should return -1 and set errno to EPIPE
688269867Sume		 * instead.
689186090Sume		 *
690186090Sume		 * Push on even if setsockopt(SO_NOSIGPIPE) fails.
691186090Sume		 */
692186090Sume		(void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
693269867Sume				 sizeof(on));
694186090Sume#endif
695156952Sume		errno = 0;
696156956Sume		if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
697156952Sume			*terrno = errno;
698156952Sume			Aerror(statp, stderr, "connect/vc", errno, nsap,
699156952Sume			    nsaplen);
700156952Sume			res_nclose(statp);
701156952Sume			return (0);
702156952Sume		}
703156952Sume		statp->_flags |= RES_F_VC;
704156952Sume	}
705156952Sume
706156952Sume	/*
707156952Sume	 * Send length & message
708156952Sume	 */
709156952Sume	ns_put16((u_short)buflen, (u_char*)&len);
710156952Sume	iov[0] = evConsIovec(&len, INT16SZ);
711156952Sume	DE_CONST(buf, tmp);
712156952Sume	iov[1] = evConsIovec(tmp, buflen);
713156956Sume	if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
714156952Sume		*terrno = errno;
715156952Sume		Perror(statp, stderr, "write failed", errno);
716156952Sume		res_nclose(statp);
717156952Sume		return (0);
718156952Sume	}
719156952Sume	/*
720156952Sume	 * Receive length & response
721156952Sume	 */
722156952Sume read_len:
723156952Sume	cp = ans;
724156952Sume	len = INT16SZ;
725156956Sume	while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
726156952Sume		cp += n;
727156952Sume		if ((len -= n) == 0)
728156952Sume			break;
729156952Sume	}
730156952Sume	if (n <= 0) {
731156952Sume		*terrno = errno;
732156952Sume		Perror(statp, stderr, "read failed", errno);
733156952Sume		res_nclose(statp);
734156952Sume		/*
735156952Sume		 * A long running process might get its TCP
736156952Sume		 * connection reset if the remote server was
737156952Sume		 * restarted.  Requery the server instead of
738156952Sume		 * trying a new one.  When there is only one
739156952Sume		 * server, this means that a query might work
740156952Sume		 * instead of failing.  We only allow one reset
741156952Sume		 * per query to prevent looping.
742156952Sume		 */
743156952Sume		if (*terrno == ECONNRESET && !connreset) {
744156952Sume			connreset = 1;
745156952Sume			res_nclose(statp);
746156952Sume			goto same_ns;
747156952Sume		}
748156952Sume		res_nclose(statp);
749156952Sume		return (0);
750156952Sume	}
751156952Sume	resplen = ns_get16(ans);
752156952Sume	if (resplen > anssiz) {
753156952Sume		Dprint(statp->options & RES_DEBUG,
754156952Sume		       (stdout, ";; response truncated\n")
755156952Sume		       );
756156952Sume		truncating = 1;
757156952Sume		len = anssiz;
758156952Sume	} else
759156952Sume		len = resplen;
760156952Sume	if (len < HFIXEDSZ) {
761156952Sume		/*
762156952Sume		 * Undersized message.
763156952Sume		 */
764156952Sume		Dprint(statp->options & RES_DEBUG,
765156952Sume		       (stdout, ";; undersized: %d\n", len));
766156952Sume		*terrno = EMSGSIZE;
767156952Sume		res_nclose(statp);
768156952Sume		return (0);
769156952Sume	}
770156952Sume	cp = ans;
771156956Sume	while (len != 0 &&
772156956Sume	    (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
773156952Sume		cp += n;
774156952Sume		len -= n;
775156952Sume	}
776156952Sume	if (n <= 0) {
777156952Sume		*terrno = errno;
778156952Sume		Perror(statp, stderr, "read(vc)", errno);
779156952Sume		res_nclose(statp);
780156952Sume		return (0);
781156952Sume	}
782156952Sume	if (truncating) {
783156952Sume		/*
784156952Sume		 * Flush rest of answer so connection stays in synch.
785156952Sume		 */
786156952Sume		anhp->tc = 1;
787156952Sume		len = resplen - anssiz;
788156952Sume		while (len != 0) {
789156952Sume			char junk[PACKETSZ];
790156952Sume
791156956Sume			n = _read(statp->_vcsock, junk,
792156956Sume			    (len > sizeof junk) ? sizeof junk : len);
793156952Sume			if (n > 0)
794156952Sume				len -= n;
795156952Sume			else
796156952Sume				break;
797156952Sume		}
798156952Sume	}
799156952Sume	/*
800156952Sume	 * If the calling applicating has bailed out of
801156952Sume	 * a previous call and failed to arrange to have
802156952Sume	 * the circuit closed or the server has got
803156952Sume	 * itself confused, then drop the packet and
804156952Sume	 * wait for the correct one.
805156952Sume	 */
806156952Sume	if (hp->id != anhp->id) {
807156952Sume		DprintQ((statp->options & RES_DEBUG) ||
808156952Sume			(statp->pfcode & RES_PRF_REPLY),
809156952Sume			(stdout, ";; old answer (unexpected):\n"),
810156952Sume			ans, (resplen > anssiz) ? anssiz: resplen);
811156952Sume		goto read_len;
812156952Sume	}
813156952Sume
814156952Sume	/*
815156952Sume	 * All is well, or the error is fatal.  Signal that the
816156952Sume	 * next nameserver ought not be tried.
817156952Sume	 */
818156952Sume	return (resplen);
819156952Sume}
820156952Sume
821156952Sumestatic int
822156952Sumesend_dg(res_state statp,
823156956Sume#ifdef USE_KQUEUE
824156956Sume	int kq,
825156956Sume#endif
826163661Sume	const u_char *buf, int buflen, u_char *ans,
827186090Sume	int anssiz, int *terrno, int ns, int tries, int *v_circuit,
828163661Sume	int *gotsomewhere)
829156952Sume{
830156952Sume	const HEADER *hp = (const HEADER *) buf;
831156952Sume	HEADER *anhp = (HEADER *) ans;
832156952Sume	const struct sockaddr *nsap;
833156952Sume	int nsaplen;
834156952Sume	struct timespec now, timeout, finish;
835156952Sume	struct sockaddr_storage from;
836156952Sume	ISC_SOCKLEN_T fromlen;
837156952Sume	int resplen, seconds, n, s;
838156956Sume#ifdef USE_KQUEUE
839156956Sume	struct kevent kv;
840156956Sume#else
841156952Sume#ifdef USE_POLL
842156952Sume	int     polltimeout;
843156952Sume	struct pollfd   pollfd;
844156952Sume#else
845156952Sume	fd_set dsmask;
846156952Sume#endif
847156956Sume#endif
848156952Sume
849156952Sume	nsap = get_nsaddr(statp, ns);
850156952Sume	nsaplen = get_salen(nsap);
851156952Sume	if (EXT(statp).nssocks[ns] == -1) {
852156956Sume		EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
853255336Sjilles		    SOCK_DGRAM | SOCK_CLOEXEC, 0);
854167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE)
855156952Sume		if (EXT(statp).nssocks[ns] > highestFD) {
856156952Sume			res_nclose(statp);
857156952Sume			errno = ENOTSOCK;
858156952Sume		}
859167246Sjhb#endif
860156952Sume		if (EXT(statp).nssocks[ns] < 0) {
861156952Sume			switch (errno) {
862156952Sume			case EPROTONOSUPPORT:
863156952Sume#ifdef EPFNOSUPPORT
864156952Sume			case EPFNOSUPPORT:
865156952Sume#endif
866156952Sume			case EAFNOSUPPORT:
867156952Sume				Perror(statp, stderr, "socket(dg)", errno);
868156952Sume				return (0);
869156952Sume			default:
870156952Sume				*terrno = errno;
871156952Sume				Perror(statp, stderr, "socket(dg)", errno);
872156952Sume				return (-1);
873156952Sume			}
874156952Sume		}
875156952Sume#ifndef CANNOT_CONNECT_DGRAM
876156952Sume		/*
877156952Sume		 * On a 4.3BSD+ machine (client and server,
878156952Sume		 * actually), sending to a nameserver datagram
879156952Sume		 * port with no nameserver will cause an
880156952Sume		 * ICMP port unreachable message to be returned.
881156952Sume		 * If our datagram socket is "connected" to the
882156952Sume		 * server, we get an ECONNREFUSED error on the next
883156952Sume		 * socket operation, and select returns if the
884156952Sume		 * error message is received.  We can thus detect
885156952Sume		 * the absence of a nameserver without timing out.
886156956Sume		 *
887156956Sume		 * When the option "insecure1" is specified, we'd
888156956Sume		 * rather expect to see responses from an "unknown"
889156956Sume		 * address.  In order to let the kernel accept such
890156956Sume		 * responses, do not connect the socket here.
891156956Sume		 * XXX: or do we need an explicit option to disable
892156956Sume		 * connecting?
893156952Sume		 */
894156956Sume		if (!(statp->options & RES_INSECURE1) &&
895156956Sume		    _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
896156952Sume			Aerror(statp, stderr, "connect(dg)", errno, nsap,
897156952Sume			    nsaplen);
898156952Sume			res_nclose(statp);
899156952Sume			return (0);
900156952Sume		}
901156952Sume#endif /* !CANNOT_CONNECT_DGRAM */
902156952Sume		Dprint(statp->options & RES_DEBUG,
903156952Sume		       (stdout, ";; new DG socket\n"))
904156952Sume	}
905156952Sume	s = EXT(statp).nssocks[ns];
906156952Sume#ifndef CANNOT_CONNECT_DGRAM
907156956Sume	if (statp->options & RES_INSECURE1) {
908156956Sume		if (_sendto(s,
909156956Sume		    (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
910156956Sume			Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
911156956Sume			res_nclose(statp);
912156956Sume			return (0);
913156956Sume		}
914156956Sume	} else if (send(s, (const char*)buf, buflen, 0) != buflen) {
915156952Sume		Perror(statp, stderr, "send", errno);
916156952Sume		res_nclose(statp);
917156952Sume		return (0);
918156952Sume	}
919156952Sume#else /* !CANNOT_CONNECT_DGRAM */
920156956Sume	if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
921156952Sume	{
922156952Sume		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
923156952Sume		res_nclose(statp);
924156952Sume		return (0);
925156952Sume	}
926156952Sume#endif /* !CANNOT_CONNECT_DGRAM */
927156952Sume
928156952Sume	/*
929156952Sume	 * Wait for reply.
930156952Sume	 */
931186090Sume	seconds = (statp->retrans << tries);
932156952Sume	if (ns > 0)
933156952Sume		seconds /= statp->nscount;
934156952Sume	if (seconds <= 0)
935156952Sume		seconds = 1;
936156952Sume	now = evNowTime();
937156952Sume	timeout = evConsTime(seconds, 0);
938156952Sume	finish = evAddTime(now, timeout);
939156952Sume	goto nonow;
940156952Sume wait:
941156952Sume	now = evNowTime();
942156952Sume nonow:
943156952Sume#ifndef USE_POLL
944156952Sume	if (evCmpTime(finish, now) > 0)
945156952Sume		timeout = evSubTime(finish, now);
946156952Sume	else
947156952Sume		timeout = evConsTime(0, 0);
948156956Sume#ifdef USE_KQUEUE
949156956Sume	EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
950156956Sume	n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
951156956Sume#else
952156956Sume	FD_ZERO(&dsmask);
953156956Sume	FD_SET(s, &dsmask);
954156952Sume	n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
955156956Sume#endif
956156952Sume#else
957156952Sume	timeout = evSubTime(finish, now);
958156952Sume	if (timeout.tv_sec < 0)
959156952Sume		timeout = evConsTime(0, 0);
960156952Sume	polltimeout = 1000*timeout.tv_sec +
961156952Sume		timeout.tv_nsec/1000000;
962156952Sume	pollfd.fd = s;
963156952Sume	pollfd.events = POLLRDNORM;
964260652Sjilles	n = _poll(&pollfd, 1, polltimeout);
965156952Sume#endif /* USE_POLL */
966156952Sume
967156952Sume	if (n == 0) {
968156952Sume		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
969156952Sume		*gotsomewhere = 1;
970156952Sume		return (0);
971156952Sume	}
972156952Sume	if (n < 0) {
973156952Sume		if (errno == EINTR)
974156952Sume			goto wait;
975156956Sume#ifdef USE_KQUEUE
976156956Sume		Perror(statp, stderr, "kevent", errno);
977156956Sume#else
978156952Sume#ifndef USE_POLL
979156952Sume		Perror(statp, stderr, "select", errno);
980156952Sume#else
981156952Sume		Perror(statp, stderr, "poll", errno);
982156952Sume#endif /* USE_POLL */
983156956Sume#endif
984156952Sume		res_nclose(statp);
985156952Sume		return (0);
986156952Sume	}
987160967Sume#ifdef USE_KQUEUE
988160967Sume	if (kv.ident != s)
989160967Sume		goto wait;
990160967Sume#endif
991156952Sume	errno = 0;
992156952Sume	fromlen = sizeof(from);
993156956Sume	resplen = _recvfrom(s, (char*)ans, anssiz,0,
994156952Sume			   (struct sockaddr *)&from, &fromlen);
995156952Sume	if (resplen <= 0) {
996156952Sume		Perror(statp, stderr, "recvfrom", errno);
997156952Sume		res_nclose(statp);
998156952Sume		return (0);
999156952Sume	}
1000156952Sume	*gotsomewhere = 1;
1001156952Sume	if (resplen < HFIXEDSZ) {
1002156952Sume		/*
1003156952Sume		 * Undersized message.
1004156952Sume		 */
1005156952Sume		Dprint(statp->options & RES_DEBUG,
1006156952Sume		       (stdout, ";; undersized: %d\n",
1007156952Sume			resplen));
1008156952Sume		*terrno = EMSGSIZE;
1009156952Sume		res_nclose(statp);
1010156952Sume		return (0);
1011156952Sume	}
1012156952Sume	if (hp->id != anhp->id) {
1013156952Sume		/*
1014156952Sume		 * response from old query, ignore it.
1015156952Sume		 * XXX - potential security hazard could
1016156952Sume		 *	 be detected here.
1017156952Sume		 */
1018156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1019156952Sume			(statp->pfcode & RES_PRF_REPLY),
1020156952Sume			(stdout, ";; old answer:\n"),
1021156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1022156952Sume		goto wait;
1023156952Sume	}
1024156952Sume	if (!(statp->options & RES_INSECURE1) &&
1025156952Sume	    !res_ourserver_p(statp, (struct sockaddr *)&from)) {
1026156952Sume		/*
1027156952Sume		 * response from wrong server? ignore it.
1028156952Sume		 * XXX - potential security hazard could
1029156952Sume		 *	 be detected here.
1030156952Sume		 */
1031156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1032156952Sume			(statp->pfcode & RES_PRF_REPLY),
1033156952Sume			(stdout, ";; not our server:\n"),
1034156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1035156952Sume		goto wait;
1036156952Sume	}
1037156952Sume#ifdef RES_USE_EDNS0
1038156952Sume	if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1039156952Sume		/*
1040156952Sume		 * Do not retry if the server do not understand EDNS0.
1041156952Sume		 * The case has to be captured here, as FORMERR packet do not
1042156952Sume		 * carry query section, hence res_queriesmatch() returns 0.
1043156952Sume		 */
1044156952Sume		DprintQ(statp->options & RES_DEBUG,
1045156952Sume			(stdout, "server rejected query with EDNS0:\n"),
1046156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1047156952Sume		/* record the error */
1048156952Sume		statp->_flags |= RES_F_EDNS0ERR;
1049156952Sume		res_nclose(statp);
1050156952Sume		return (0);
1051156952Sume	}
1052156952Sume#endif
1053156952Sume	if (!(statp->options & RES_INSECURE2) &&
1054156952Sume	    !res_queriesmatch(buf, buf + buflen,
1055156952Sume			      ans, ans + anssiz)) {
1056156952Sume		/*
1057156952Sume		 * response contains wrong query? ignore it.
1058156952Sume		 * XXX - potential security hazard could
1059156952Sume		 *	 be detected here.
1060156952Sume		 */
1061156952Sume		DprintQ((statp->options & RES_DEBUG) ||
1062156952Sume			(statp->pfcode & RES_PRF_REPLY),
1063156952Sume			(stdout, ";; wrong query name:\n"),
1064156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1065156952Sume		goto wait;
1066156952Sume	}
1067156952Sume	if (anhp->rcode == SERVFAIL ||
1068156952Sume	    anhp->rcode == NOTIMP ||
1069156952Sume	    anhp->rcode == REFUSED) {
1070156952Sume		DprintQ(statp->options & RES_DEBUG,
1071156952Sume			(stdout, "server rejected query:\n"),
1072156952Sume			ans, (resplen > anssiz) ? anssiz : resplen);
1073156952Sume		res_nclose(statp);
1074156952Sume		/* don't retry if called from dig */
1075156952Sume		if (!statp->pfcode)
1076156952Sume			return (0);
1077156952Sume	}
1078156952Sume	if (!(statp->options & RES_IGNTC) && anhp->tc) {
1079156952Sume		/*
1080156952Sume		 * To get the rest of answer,
1081156952Sume		 * use TCP with same server.
1082156952Sume		 */
1083156952Sume		Dprint(statp->options & RES_DEBUG,
1084156952Sume		       (stdout, ";; truncated answer\n"));
1085156952Sume		*v_circuit = 1;
1086156952Sume		res_nclose(statp);
1087156952Sume		return (1);
1088156952Sume	}
1089156952Sume	/*
1090156952Sume	 * All is well, or the error is fatal.  Signal that the
1091156952Sume	 * next nameserver ought not be tried.
1092156952Sume	 */
1093156952Sume	return (resplen);
1094156952Sume}
1095156952Sume
1096156952Sumestatic void
1097156952SumeAerror(const res_state statp, FILE *file, const char *string, int error,
1098156952Sume       const struct sockaddr *address, int alen)
1099156952Sume{
1100156952Sume	int save = errno;
1101156952Sume	char hbuf[NI_MAXHOST];
1102156952Sume	char sbuf[NI_MAXSERV];
1103156952Sume
1104156952Sume	if ((statp->options & RES_DEBUG) != 0U) {
1105156952Sume		if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
1106156952Sume		    sbuf, sizeof(sbuf), niflags)) {
1107156952Sume			strncpy(hbuf, "?", sizeof(hbuf) - 1);
1108156952Sume			hbuf[sizeof(hbuf) - 1] = '\0';
1109156952Sume			strncpy(sbuf, "?", sizeof(sbuf) - 1);
1110156952Sume			sbuf[sizeof(sbuf) - 1] = '\0';
1111156952Sume		}
1112156952Sume		fprintf(file, "res_send: %s ([%s].%s): %s\n",
1113156952Sume			string, hbuf, sbuf, strerror(error));
1114156952Sume	}
1115156952Sume	errno = save;
1116156952Sume}
1117156952Sume
1118156952Sumestatic void
1119156952SumePerror(const res_state statp, FILE *file, const char *string, int error) {
1120156952Sume	int save = errno;
1121156952Sume
1122156952Sume	if ((statp->options & RES_DEBUG) != 0U)
1123156952Sume		fprintf(file, "res_send: %s: %s\n",
1124156952Sume			string, strerror(error));
1125156952Sume	errno = save;
1126156952Sume}
1127156952Sume
1128156952Sumestatic int
1129156952Sumesock_eq(struct sockaddr *a, struct sockaddr *b) {
1130156952Sume	struct sockaddr_in *a4, *b4;
1131156952Sume	struct sockaddr_in6 *a6, *b6;
1132156952Sume
1133156952Sume	if (a->sa_family != b->sa_family)
1134156952Sume		return 0;
1135156952Sume	switch (a->sa_family) {
1136156952Sume	case AF_INET:
1137156952Sume		a4 = (struct sockaddr_in *)a;
1138156952Sume		b4 = (struct sockaddr_in *)b;
1139156952Sume		return a4->sin_port == b4->sin_port &&
1140156952Sume		    a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1141156952Sume	case AF_INET6:
1142156952Sume		a6 = (struct sockaddr_in6 *)a;
1143156952Sume		b6 = (struct sockaddr_in6 *)b;
1144156952Sume		return a6->sin6_port == b6->sin6_port &&
1145156952Sume#ifdef HAVE_SIN6_SCOPE_ID
1146156952Sume		    a6->sin6_scope_id == b6->sin6_scope_id &&
1147156952Sume#endif
1148156952Sume		    IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1149156952Sume	default:
1150156952Sume		return 0;
1151156952Sume	}
1152156952Sume}
1153156952Sume
1154156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
1155156952Sume/* XXX needs to move to the porting library. */
1156156952Sumestatic int
1157156952Sumepselect(int nfds, void *rfds, void *wfds, void *efds,
1158156952Sume	struct timespec *tsp, const sigset_t *sigmask)
1159156952Sume{
1160156952Sume	struct timeval tv, *tvp;
1161156952Sume	sigset_t sigs;
1162156952Sume	int n;
1163156952Sume
1164156952Sume	if (tsp) {
1165156952Sume		tvp = &tv;
1166156952Sume		tv = evTimeVal(*tsp);
1167156952Sume	} else
1168156952Sume		tvp = NULL;
1169156952Sume	if (sigmask)
1170156952Sume		sigprocmask(SIG_SETMASK, sigmask, &sigs);
1171156952Sume	n = select(nfds, rfds, wfds, efds, tvp);
1172156952Sume	if (sigmask)
1173156952Sume		sigprocmask(SIG_SETMASK, &sigs, NULL);
1174156952Sume	if (tsp)
1175156952Sume		*tsp = evTimeSpec(tv);
1176156952Sume	return (n);
1177156952Sume}
1178156952Sume#endif
1179