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