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