1/*
2 * Copyright (c) 1985, 1989, 1993
3 *    The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32 *
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 * SOFTWARE.
48 */
49
50/*
51 * Portions Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
52 * Portions Copyright (c) 1996-2003 by Internet Software Consortium
53 *
54 * Permission to use, copy, modify, and distribute this software for any
55 * purpose with or without fee is hereby granted, provided that the above
56 * copyright notice and this permission notice appear in all copies.
57 *
58 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
59 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
60 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
61 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
62 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
63 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
64 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
65 *
66 *   Internet Systems Consortium, Inc.
67 *   950 Charter Street
68 *   Redwood City, CA 94063
69 *   <info@isc.org>
70 *   http://www.isc.org/
71 */
72
73#if defined(LIBC_SCCS) && !defined(lint)
74static const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
75static const char rcsid[] = "$Id: res_send.c,v 1.5 2007/05/27 16:27:57 tls Exp $";
76#endif /* LIBC_SCCS and not lint */
77
78/*
79 * Send query to name server and wait for reply.
80 */
81
82#include <sys/types.h>
83#include <sys/param.h>
84#include <sys/time.h>
85#include <sys/socket.h>
86#include <sys/uio.h>
87
88#include <netinet/in.h>
89#include <arpa/inet.h>
90
91#include <errno.h>
92#include <netdb.h>
93#include <signal.h>
94#include <stdio.h>
95#include <stdlib.h>
96#include <string.h>
97#include <unistd.h>
98
99/* Rename the I/O functions in case we're tracing. */
100#define send		trace_mr_send
101#define recvfrom	trace_mr_recvfrom
102
103#ifdef _FORTIFY_SOURCE
104#undef read		/* FORTIFY_SOURCE gets this at trace_mr_read anyway */
105#endif
106
107#define read		trace_mr_read
108#define connect		trace_mr_connect
109#define socket		trace_mr_socket
110#define bind		trace_mr_bind
111#define close		trace_mr_close
112#define select		trace_mr_select
113#define time		trace_mr_time
114
115#include "minires/minires.h"
116#include "omapip/trace_mr.h"
117#include "arpa/nameser.h"
118
119#define	CHECK_SRVR_ADDR
120
121static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2);
122void res_pquery(const res_state, const u_char *, int, FILE *);
123
124/* int
125 * res_isourserver(ina)
126 *	looks up "ina" in _res.ns_addr_list[]
127 * returns:
128 *	0  : not found
129 *	>0 : found
130 * author:
131 *	paul vixie, 29may94
132 */
133int
134res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) {
135	struct sockaddr_in ina;
136	int ns;
137
138	ina = *inp;
139	for (ns = 0;  ns < statp->nscount;  ns++) {
140		const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
141
142		if (srv->sin_family == ina.sin_family &&
143		    srv->sin_port == ina.sin_port &&
144		    (srv->sin_addr.s_addr == INADDR_ANY ||
145		     srv->sin_addr.s_addr == ina.sin_addr.s_addr))
146			return (1);
147	}
148	return (0);
149}
150
151/* int
152 * res_nameinquery(name, type, class, buf, eom)
153 *	look for (name,type,class) in the query section of packet (buf,eom)
154 * requires:
155 *	buf + HFIXEDSZ <= eom
156 * returns:
157 *	-1 : format error
158 *	0  : not found
159 *	>0 : found
160 * author:
161 *	paul vixie, 29may94
162 */
163int
164res_nameinquery(const char *name, int type, int class,
165		const u_char *buf, const u_char *eom)
166{
167	const u_char *cp = buf + HFIXEDSZ;
168	int qdcount = ntohs(((const HEADER *)buf)->qdcount);
169
170	while (qdcount-- > 0) {
171		char tname[MAXDNAME+1];
172		int n, ttype, tclass;
173
174		n = dn_expand(buf, eom, cp, tname, sizeof tname);
175		if (n < 0)
176			return (-1);
177		cp += n;
178		if (cp + 2 * INT16SZ > eom)
179			return (-1);
180		ttype = getUShort(cp); cp += INT16SZ;
181		tclass = getUShort(cp); cp += INT16SZ;
182		if (ttype == type && tclass == class &&
183		    ns_samename(tname, name) == 1)
184			return (1);
185	}
186	return (0);
187}
188
189/* int
190 * res_queriesmatch(buf1, eom1, buf2, eom2)
191 *	is there a 1:1 mapping of (name,type,class)
192 *	in (buf1,eom1) and (buf2,eom2)?
193 * returns:
194 *	-1 : format error
195 *	0  : not a 1:1 mapping
196 *	>0 : is a 1:1 mapping
197 * author:
198 *	paul vixie, 29may94
199 */
200int
201res_queriesmatch(const u_char *buf1, const u_char *eom1,
202		 const u_char *buf2, const u_char *eom2)
203{
204	const u_char *cp = buf1 + HFIXEDSZ;
205	int qdcount = ntohs(((const HEADER *)buf1)->qdcount);
206
207	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
208		return (-1);
209
210	/*
211	 * Only header section present in replies to
212	 * dynamic update packets.
213	 */
214	if ( (((const HEADER *)buf1)->opcode == ns_o_update) &&
215	     (((const HEADER *)buf2)->opcode == ns_o_update) )
216		return (1);
217
218	if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
219		return (0);
220	while (qdcount-- > 0) {
221		char tname[MAXDNAME+1];
222		int n, ttype, tclass;
223
224		n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
225		if (n < 0)
226			return (-1);
227		cp += n;
228		if (cp + 2 * INT16SZ > eom1)
229			return (-1);
230		ttype = getUShort(cp);	cp += INT16SZ;
231		tclass = getUShort(cp); cp += INT16SZ;
232		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
233			return (0);
234	}
235	return (1);
236}
237
238isc_result_t
239res_nsend(res_state statp,
240	  double *buf, unsigned buflen,
241	  double *ans, unsigned anssiz, unsigned *ansret)
242{
243	HEADER *hp = (HEADER *) buf;
244	HEADER *anhp = (HEADER *) ans;
245	int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
246	u_int badns;	/* XXX NSMAX can't exceed #/bits in this variable */
247	static int highestFD = FD_SETSIZE - 1;
248
249	if (anssiz < HFIXEDSZ) {
250		return ISC_R_INVALIDARG;
251	}
252	DprintQ((statp->options & RES_DEBUG) ||
253		(statp->pfcode & RES_PRF_QUERY),
254		(stdout, ";; res_send()\n"), buf, buflen);
255	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
256	gotsomewhere = 0;
257	connreset = 0;
258	terrno = ISC_R_TIMEDOUT;
259	badns = 0;
260
261	/*
262	 * Some callers want to even out the load on their resolver list.
263	 */
264	if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) {
265		struct sockaddr_in ina;
266		int lastns = statp->nscount - 1;
267
268		ina = statp->nsaddr_list[0];
269		for (ns = 0; ns < lastns; ns++)
270			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
271		statp->nsaddr_list[lastns] = ina;
272	}
273
274#if defined (TRACING)
275	trace_mr_statp_setup (statp);
276#endif
277
278	/*
279	 * Send request, RETRY times, or until successful
280	 */
281	for (try = 0; try < statp->retry; try++) {
282	    for (ns = 0; ns < statp->nscount; ns++) {
283		struct sockaddr_in *nsap = &statp->nsaddr_list[ns];
284 same_ns:
285		if (badns & (1 << ns)) {
286			res_nclose(statp);
287			goto next_ns;
288		}
289
290		if (statp->qhook) {
291			int done = 0, loops = 0;
292
293			do {
294				res_sendhookact act;
295
296				act = (*statp->qhook)(&nsap, &buf, &buflen,
297						      ans, anssiz, &resplen);
298				switch (act) {
299				case res_goahead:
300					done = 1;
301					break;
302				case res_nextns:
303					res_nclose(statp);
304					goto next_ns;
305				case res_done:
306					return (resplen);
307				case res_modified:
308					/* give the hook another try */
309					if (++loops < 42) /*doug adams*/
310						break;
311					/*FALLTHROUGH*/
312				case res_error:
313					/*FALLTHROUGH*/
314				default:
315					return ISC_R_UNEXPECTED;
316				}
317			} while (!done);
318		}
319
320		Dprint(statp->options & RES_DEBUG,
321		       (stdout, ";; Querying server (# %d) address = %s\n",
322			ns + 1, inet_ntoa(nsap->sin_addr)));
323
324		if (v_circuit) {
325			int truncated;
326			struct iovec iov[2];
327			u_short len;
328			u_char *cp;
329
330			/* Use VC; at most one attempt per server. */
331			try = statp->retry;
332			truncated = 0;
333
334			/* Are we still talking to whom we want to talk to? */
335			if (statp->_sock >= 0 &&
336			    (statp->_flags & RES_F_VC) != 0) {
337				struct sockaddr_in peer;
338				SOCKLEN_T size = sizeof(peer);
339
340				if (getpeername(statp->_sock,
341						(struct sockaddr *)&peer,
342						&size) < 0) {
343					res_nclose(statp);
344					statp->_flags &= ~RES_F_VC;
345				} else if (!cmpsock(&peer, nsap)) {
346					res_nclose(statp);
347					statp->_flags &= ~RES_F_VC;
348				}
349			}
350
351			if (statp->_sock < 0 ||
352			    (statp->_flags & RES_F_VC) == 0) {
353				if (statp->_sock >= 0)
354					res_nclose(statp);
355
356				statp->_sock = socket(PF_INET,
357						       SOCK_STREAM, 0);
358				if (statp->_sock < 0 ||
359				    statp->_sock > highestFD) {
360					terrno = uerr2isc (errno);
361					Perror(statp, stderr,
362					       "socket(vc)", errno);
363					return (-1);
364				}
365				errno = 0;
366				if (connect(statp->_sock,
367					    (struct sockaddr *)nsap,
368					    sizeof *nsap) < 0) {
369					terrno = uerr2isc (errno);
370					Aerror(statp, stderr, "connect/vc",
371					       errno, *nsap);
372					badns |= (1 << ns);
373					res_nclose(statp);
374					goto next_ns;
375				}
376				statp->_flags |= RES_F_VC;
377			}
378			/*
379			 * Send length & message
380			 */
381			putUShort((u_char*)&len, buflen);
382			iov[0].iov_base = (caddr_t)&len;
383			iov[0].iov_len = INT16SZ;
384			iov[1].iov_base = (const caddr_t)buf;
385			iov[1].iov_len = buflen;
386			if (writev(statp->_sock, iov, 2) !=
387			    (INT16SZ + buflen)) {
388				terrno = uerr2isc (errno);
389				Perror(statp, stderr, "write failed", errno);
390				badns |= (1 << ns);
391				res_nclose(statp);
392				goto next_ns;
393			}
394			/*
395			 * Receive length & response
396			 */
397 read_len:
398			cp = (u_char *)ans;
399			len = INT16SZ;
400			while ((n = read(statp->_sock,
401					 (char *)cp, (unsigned)len)) > 0) {
402				cp += n;
403				if ((len -= n) <= 0)
404					break;
405			}
406			if (n <= 0) {
407				terrno = uerr2isc (errno);
408				Perror(statp, stderr, "read failed", errno);
409				res_nclose(statp);
410				/*
411				 * A long running process might get its TCP
412				 * connection reset if the remote server was
413				 * restarted.  Requery the server instead of
414				 * trying a new one.  When there is only one
415				 * server, this means that a query might work
416				 * instead of failing.  We only allow one reset
417				 * per query to prevent looping.
418				 */
419				if (terrno == ISC_R_CONNREFUSED &&
420				    !connreset) {
421					connreset = 1;
422					res_nclose(statp);
423					goto same_ns;
424				}
425				res_nclose(statp);
426				goto next_ns;
427			}
428			resplen = getUShort ((unsigned char *)ans);
429			if (resplen > anssiz) {
430				Dprint(statp->options & RES_DEBUG,
431				       (stdout, ";; response truncated\n")
432				       );
433				truncated = 1;
434				len = anssiz;
435			} else
436				len = resplen;
437			if (len < HFIXEDSZ) {
438				/*
439				 * Undersized message.
440				 */
441				Dprint(statp->options & RES_DEBUG,
442				       (stdout, ";; undersized: %d\n", len));
443				terrno = ISC_R_NOSPACE;
444				badns |= (1 << ns);
445				res_nclose(statp);
446				goto next_ns;
447			}
448			cp = (u_char *)ans;
449			while (len != 0 &&
450			       (n = read(statp->_sock,
451					 (char *)cp, (unsigned)len))
452			       > 0) {
453				cp += n;
454				len -= n;
455			}
456			if (n <= 0) {
457				terrno = uerr2isc (errno);
458				Perror(statp, stderr, "read(vc)", errno);
459				res_nclose(statp);
460				goto next_ns;
461			}
462			if (truncated) {
463				/*
464				 * Flush rest of answer
465				 * so connection stays in synch.
466				 */
467				anhp->tc = 1;
468				len = resplen - anssiz;
469				while (len != 0) {
470					char junk[PACKETSZ];
471
472					n = (len > sizeof(junk)
473					     ? sizeof(junk)
474					     : len);
475					n = read(statp->_sock,
476						 junk, (unsigned)n);
477					if (n > 0)
478						len -= n;
479					else
480						break;
481				}
482			}
483			/*
484			 * The calling applicating has bailed out of
485			 * a previous call and failed to arrange to have
486			 * the circuit closed or the server has got
487			 * itself confused. Anyway drop the packet and
488			 * wait for the correct one.
489			 */
490			if (hp->id != anhp->id) {
491				DprintQ((statp->options & RES_DEBUG) ||
492					(statp->pfcode & RES_PRF_REPLY),
493					(stdout,
494					 ";; old answer (unexpected):\n"),
495					ans, (resplen>anssiz)?anssiz:resplen);
496				goto read_len;
497			}
498		} else {
499			/*
500			 * Use datagrams.
501			 */
502			int start, timeout, finish;
503			fd_set dsmask;
504			struct sockaddr_in from;
505			SOCKLEN_T fromlen;
506			int seconds;
507
508			if (statp->_sock < 0 ||
509			    (statp->_flags & RES_F_VC) != 0) {
510				if ((statp->_flags & RES_F_VC) != 0)
511					res_nclose(statp);
512				statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);
513				if (statp->_sock < 0 ||
514				    statp->_sock > highestFD) {
515#ifndef CAN_RECONNECT
516 bad_dg_sock:
517#endif
518					terrno = uerr2isc (errno);
519					Perror(statp, stderr,
520					       "socket(dg)", errno);
521					return terrno;
522				}
523				statp->_flags &= ~RES_F_CONN;
524			}
525#ifndef CANNOT_CONNECT_DGRAM
526			/*
527			 * On a 4.3BSD+ machine (client and server,
528			 * actually), sending to a nameserver datagram
529			 * port with no nameserver will cause an
530			 * ICMP port unreachable message to be returned.
531			 * If our datagram socket is "connected" to the
532			 * server, we get an ECONNREFUSED error on the next
533			 * socket operation, and select returns if the
534			 * error message is received.  We can thus detect
535			 * the absence of a nameserver without timing out.
536			 * If we have sent queries to at least two servers,
537			 * however, we don't want to remain connected,
538			 * as we wish to receive answers from the first
539			 * server to respond.
540			 */
541			if (statp->nscount == 1 || (try == 0 && ns == 0)) {
542				/*
543				 * Connect only if we are sure we won't
544				 * receive a response from another server.
545				 */
546				if ((statp->_flags & RES_F_CONN) == 0) {
547					if (connect(statp->_sock,
548						    (struct sockaddr *)nsap,
549						    sizeof *nsap) < 0) {
550						Aerror(statp, stderr,
551						       "connect(dg)",
552						       errno, *nsap);
553						badns |= (1 << ns);
554						res_nclose(statp);
555						goto next_ns;
556					}
557					statp->_flags |= RES_F_CONN;
558				}
559                              if (send(statp->_sock,
560				       (const char*)buf, (unsigned)buflen, 0)
561				  != buflen) {
562					Perror(statp, stderr, "send", errno);
563					badns |= (1 << ns);
564					res_nclose(statp);
565					goto next_ns;
566				}
567			} else {
568				/*
569				 * Disconnect if we want to listen
570				 * for responses from more than one server.
571				 */
572				if ((statp->_flags & RES_F_CONN) != 0) {
573#ifdef CAN_RECONNECT
574					struct sockaddr_in no_addr;
575
576					no_addr.sin_family = AF_INET;
577					no_addr.sin_addr.s_addr = INADDR_ANY;
578					no_addr.sin_port = 0;
579					(void) connect(statp->_sock,
580						       (struct sockaddr *)
581						        &no_addr,
582						       sizeof no_addr);
583#else
584					struct sockaddr_in local_addr;
585					SOCKLEN_T len;
586					int result, s1;
587
588					len = sizeof(local_addr);
589					s1 = socket(PF_INET, SOCK_DGRAM, 0);
590					result = getsockname(statp->_sock,
591						(struct sockaddr *)&local_addr,
592							     &len);
593					if (s1 < 0)
594						goto bad_dg_sock;
595					(void) dup2(s1, statp->_sock);
596					(void) close(s1);
597					if (result == 0) {
598						/*
599						 * Attempt to rebind to old
600						 * port.  Note connected socket
601						 * has an sin_addr set.
602						 */
603						local_addr.sin_addr.s_addr =
604							htonl(0);
605						(void)bind(statp->_sock,
606							   (struct sockaddr *)
607							   &local_addr,
608							   (unsigned)len);
609					}
610					Dprint(statp->options & RES_DEBUG,
611					       (stdout, ";; new DG socket\n"));
612#endif /* CAN_RECONNECT */
613					statp->_flags &= ~RES_F_CONN;
614					errno = 0;
615				}
616#endif /* !CANNOT_CONNECT_DGRAM */
617				if (sendto(statp->_sock,
618					   (const char *)buf, buflen, 0,
619					   (struct sockaddr *)nsap,
620					   sizeof *nsap)
621				    != buflen) {
622					Aerror(statp, stderr, "sendto", errno, *nsap);
623					badns |= (1 << ns);
624					res_nclose(statp);
625					goto next_ns;
626				}
627#ifndef CANNOT_CONNECT_DGRAM
628			}
629#endif /* !CANNOT_CONNECT_DGRAM */
630
631			if (statp->_sock < 0 || statp->_sock > highestFD) {
632				Perror(statp, stderr,
633				       "fd out-of-bounds", EMFILE);
634				res_nclose(statp);
635				goto next_ns;
636			}
637
638			/*
639			 * Wait for reply
640			 */
641			seconds = (statp->retrans << try);
642			if (try > 0)
643				seconds /= statp->nscount;
644			if (seconds <= 0)
645				seconds = 1;
646			start = cur_time;
647			timeout = seconds;
648			finish = start + timeout;
649 wait:
650			FD_ZERO(&dsmask);
651			FD_SET(statp->_sock, &dsmask);
652			{
653				struct timeval t;
654				t.tv_sec = timeout;
655				t.tv_usec = 0;
656				n = select(statp->_sock + 1,
657					   &dsmask, NULL, NULL, &t);
658			}
659			if (n == 0) {
660				Dprint(statp->options & RES_DEBUG,
661				       (stdout, ";; timeout\n"));
662				gotsomewhere = 1;
663				goto next_ns;
664			}
665			if (n < 0) {
666				if (errno == EINTR) {
667					if (finish >= cur_time) {
668						timeout = finish - cur_time;
669						goto wait;
670					}
671				}
672				Perror(statp, stderr, "select", errno);
673				res_nclose(statp);
674				goto next_ns;
675			}
676			errno = 0;
677			fromlen = sizeof(struct sockaddr_in);
678			resplen = recvfrom(statp->_sock,
679					   (char *)ans, anssiz, 0,
680					   (struct sockaddr *)&from, &fromlen);
681			if (resplen <= 0) {
682				Perror(statp, stderr, "recvfrom", errno);
683				res_nclose(statp);
684				goto next_ns;
685			}
686			gotsomewhere = 1;
687			if (resplen < HFIXEDSZ) {
688				/*
689				 * Undersized message.
690				 */
691				Dprint(statp->options & RES_DEBUG,
692				       (stdout, ";; undersized: %d\n",
693					resplen));
694				terrno = ISC_R_NOSPACE;
695				badns |= (1 << ns);
696				res_nclose(statp);
697				goto next_ns;
698			}
699			if (hp->id != anhp->id) {
700				/*
701				 * response from old query, ignore it.
702				 * XXX - potential security hazard could
703				 *	 be detected here.
704				 */
705				DprintQ((statp->options & RES_DEBUG) ||
706					(statp->pfcode & RES_PRF_REPLY),
707					(stdout, ";; old answer:\n"),
708					ans, (resplen>anssiz)?anssiz:resplen);
709				goto wait;
710			}
711#ifdef CHECK_SRVR_ADDR
712			if (!(statp->options & RES_INSECURE1) &&
713			    !res_ourserver_p(statp, &from)) {
714				/*
715				 * response from wrong server? ignore it.
716				 * XXX - potential security hazard could
717				 *	 be detected here.
718				 */
719				DprintQ((statp->options & RES_DEBUG) ||
720					(statp->pfcode & RES_PRF_REPLY),
721					(stdout, ";; not our server:\n"),
722					ans, (resplen>anssiz)?anssiz:resplen);
723				goto wait;
724			}
725#endif
726			if (!(statp->options & RES_INSECURE2) &&
727			    !res_queriesmatch((u_char *)buf,
728					      ((u_char *)buf) + buflen,
729					      (u_char *)ans,
730					      ((u_char *)ans) + anssiz)) {
731				/*
732				 * response contains wrong query? ignore it.
733				 * XXX - potential security hazard could
734				 *	 be detected here.
735				 */
736				DprintQ((statp->options & RES_DEBUG) ||
737					(statp->pfcode & RES_PRF_REPLY),
738					(stdout, ";; wrong query name:\n"),
739					ans, (resplen>anssiz)?anssiz:resplen);
740				goto wait;
741			}
742			if (anhp->rcode == SERVFAIL ||
743			    anhp->rcode == NOTIMP ||
744			    anhp->rcode == REFUSED) {
745				DprintQ(statp->options & RES_DEBUG,
746					(stdout, "server rejected query:\n"),
747					ans, (resplen>anssiz)?anssiz:resplen);
748				badns |= (1 << ns);
749				res_nclose(statp);
750				/* don't retry if called from dig */
751				if (!statp->pfcode)
752					goto next_ns;
753			}
754			if (!(statp->options & RES_IGNTC) && anhp->tc) {
755				/*
756				 * get rest of answer;
757				 * use TCP with same server.
758				 */
759				Dprint(statp->options & RES_DEBUG,
760				       (stdout, ";; truncated answer\n"));
761				v_circuit = 1;
762				res_nclose(statp);
763				goto same_ns;
764			}
765		} /*if vc/dg*/
766		Dprint((statp->options & RES_DEBUG) ||
767		       ((statp->pfcode & RES_PRF_REPLY) &&
768			(statp->pfcode & RES_PRF_HEAD1)),
769		       (stdout, ";; got answer:\n"));
770		DprintQ((statp->options & RES_DEBUG) ||
771			(statp->pfcode & RES_PRF_REPLY),
772			(stdout, ""),
773			ans, (resplen>anssiz)?anssiz:resplen);
774		/*
775		 * If using virtual circuits, we assume that the first server
776		 * is preferred over the rest (i.e. it is on the local
777		 * machine) and only keep that one open.
778		 * If we have temporarily opened a virtual circuit,
779		 * or if we haven't been asked to keep a socket open,
780		 * close the socket.
781		 */
782		if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||
783		    !(statp->options & RES_STAYOPEN)) {
784			res_nclose(statp);
785		}
786		if (statp->rhook) {
787			int done = 0, loops = 0;
788
789			do {
790				res_sendhookact act;
791
792				act = (*statp->rhook)(nsap, buf, buflen,
793						      ans, anssiz, &resplen);
794				switch (act) {
795				case res_goahead:
796				case res_done:
797					done = 1;
798					break;
799				case res_nextns:
800					res_nclose(statp);
801					goto next_ns;
802				case res_modified:
803					/* give the hook another try */
804					if (++loops < 42) /*doug adams*/
805						break;
806					/*FALLTHROUGH*/
807				case res_error:
808					/*FALLTHROUGH*/
809				default:
810					return ISC_R_UNEXPECTED;
811				}
812			} while (!done);
813
814		}
815		*ansret = resplen;
816		return ISC_R_SUCCESS;
817 next_ns: ;
818	   } /*foreach ns*/
819	} /*foreach retry*/
820	res_nclose(statp);
821	if (!v_circuit) {
822		if (!gotsomewhere)
823			terrno = ISC_R_CONNREFUSED;  /* no nameservers found */
824		else
825			errno = ISC_R_TIMEDOUT;	/* no answer obtained */
826	}
827	return terrno;
828}
829
830/*
831 * This routine is for closing the socket if a virtual circuit is used and
832 * the program wants to close it.  This provides support for endhostent()
833 * which expects to close the socket.
834 *
835 * This routine is not expected to be user visible.
836 */
837void
838res_nclose(res_state statp) {
839	if (statp->_sock >= 0) {
840		(void) close(statp->_sock);
841		statp->_sock = -1;
842		statp->_flags &= ~(RES_F_VC | RES_F_CONN);
843	}
844}
845
846/* Private */
847static int
848cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {
849	return ((a1->sin_family == a2->sin_family) &&
850		(a1->sin_port == a2->sin_port) &&
851		(a1->sin_addr.s_addr == a2->sin_addr.s_addr));
852}
853
854#ifdef NEED_PSELECT
855/* XXX needs to move to the porting library. */
856static int
857pselect(int nfds, void *rfds, void *wfds, void *efds,
858	struct timespec *tsp,
859	const sigset_t *sigmask)
860{
861	struct timeval tv, *tvp;
862	sigset_t sigs;
863	int n;
864
865	if (tsp) {
866		tvp = &tv;
867		tv = evTimeVal(*tsp);
868	} else
869		tvp = NULL;
870	if (sigmask)
871		sigprocmask(SIG_SETMASK, sigmask, &sigs);
872	n = select(nfds, rfds, wfds, efds, tvp);
873	if (sigmask)
874		sigprocmask(SIG_SETMASK, &sigs, NULL);
875	if (tsp)
876		*tsp = evTimeSpec(tv);
877	return (n);
878}
879#endif
880