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