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