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