summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/res_send.c
diff options
context:
space:
mode:
authoreric <>2013-11-12 20:37:16 +0000
committereric <>2013-11-12 20:37:16 +0000
commiteb56a6b4b449d7d65f54812c03a2562929966616 (patch)
tree24970078f56a3204649b6aa7d8775779cafb68db /src/lib/libc/net/res_send.c
parent8ef84bdff61bb5b6cd20dcdccc675cee0f3a17bc (diff)
downloadopenbsd-eb56a6b4b449d7d65f54812c03a2562929966616.tar.gz
openbsd-eb56a6b4b449d7d65f54812c03a2562929966616.tar.bz2
openbsd-eb56a6b4b449d7d65f54812c03a2562929966616.zip
remove dead files
ok deraadt@
Diffstat (limited to 'src/lib/libc/net/res_send.c')
-rw-r--r--src/lib/libc/net/res_send.c853
1 files changed, 0 insertions, 853 deletions
diff --git a/src/lib/libc/net/res_send.c b/src/lib/libc/net/res_send.c
deleted file mode 100644
index 09b1385892..0000000000
--- a/src/lib/libc/net/res_send.c
+++ /dev/null
@@ -1,853 +0,0 @@
1/* $OpenBSD: res_send.c,v 1.21 2008/05/11 05:03:03 brad 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 /* change this to "0"
59 * if you talk to a lot
60 * of multi-homed SunOS
61 * ("broken") name servers.
62 */
63#define CHECK_SRVR_ADDR 1 /* XXX - should be in options.h */
64
65/*
66 * Send query to name server and wait for reply.
67 */
68
69#include <sys/types.h>
70#include <sys/param.h>
71#include <sys/time.h>
72#include <sys/socket.h>
73#include <sys/uio.h>
74#include <netinet/in.h>
75#include <arpa/nameser.h>
76#include <arpa/inet.h>
77
78#include <errno.h>
79#include <netdb.h>
80#include <poll.h>
81#include <resolv.h>
82#include <stdio.h>
83#include <stdlib.h>
84#include <string.h>
85#include <unistd.h>
86
87#include "thread_private.h"
88
89static int s = -1; /* socket used for communications */
90static int connected = 0; /* is the socket connected */
91static int vc = 0; /* is the socket a virtual ciruit? */
92static int af = 0; /* address family of socket */
93
94#define CAN_RECONNECT 1
95
96#ifndef DEBUG
97# define Dprint(cond, args) /*empty*/
98# define DprintQ(cond, args, query, size) /*empty*/
99# define Aerror(file, string, error, address) /*empty*/
100# define Perror(file, string, error) /*empty*/
101#else
102# define Dprint(cond, args) if (cond) {fprintf args;} else {}
103# define DprintQ(cond, args, query, size) if (cond) {\
104 fprintf args;\
105 __fp_nquery(query, size, stdout);\
106 } else {}
107static char abuf[NI_MAXHOST];
108static char pbuf[NI_MAXSERV];
109static void Aerror(FILE *, char *, int, struct sockaddr *);
110static void Perror(FILE *, char *, int);
111
112 static void
113 Aerror(FILE *file, char *string, int error, struct sockaddr *address)
114 {
115 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
116 int save = errno;
117
118 if (_resp->options & RES_DEBUG) {
119 if (getnameinfo(address, address->sa_len, abuf, sizeof(abuf),
120 pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
121 strlcpy(abuf, "?", sizeof(abuf));
122 strlcpy(pbuf, "?", sizeof(pbuf));
123 }
124 fprintf(file, "res_send: %s ([%s].%s): %s\n",
125 string, abuf, pbuf, strerror(error));
126 }
127 errno = save;
128 }
129 static void
130 Perror(FILE *file, char *string, int error)
131 {
132 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
133 int save = errno;
134
135 if (_resp->options & RES_DEBUG) {
136 fprintf(file, "res_send: %s: %s\n",
137 string, strerror(error));
138 }
139 errno = save;
140 }
141#endif
142
143static res_send_qhook Qhook = NULL;
144static res_send_rhook Rhook = NULL;
145
146void
147res_send_setqhook(res_send_qhook hook)
148{
149
150 Qhook = hook;
151}
152
153void
154res_send_setrhook(res_send_rhook hook)
155{
156
157 Rhook = hook;
158}
159
160#ifdef INET6
161static struct sockaddr * get_nsaddr(size_t);
162
163/*
164 * pick appropriate nsaddr_list for use. see res_init() for initialization.
165 */
166static struct sockaddr *
167get_nsaddr(size_t n)
168{
169 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
170 struct __res_state_ext *_res_extp = _THREAD_PRIVATE(_res_ext, _res_ext,
171 &_res_ext);
172
173 if (!_resp->nsaddr_list[n].sin_family) {
174 /*
175 * - _res_extp->nsaddr_list[n] holds an address that is larger
176 * than struct sockaddr, and
177 * - user code did not update _resp->nsaddr_list[n].
178 */
179 return (struct sockaddr *)&_res_extp->nsaddr_list[n];
180 } else {
181 /*
182 * - user code updated _res.nsaddr_list[n], or
183 * - _resp->nsaddr_list[n] has the same content as
184 * _res_extp->nsaddr_list[n].
185 */
186 return (struct sockaddr *)&_resp->nsaddr_list[n];
187 }
188}
189#else
190#define get_nsaddr(n) ((struct sockaddr *)&_resp->nsaddr_list[(n)])
191#endif
192
193/* int
194 * res_isourserver(ina)
195 * looks up "ina" in _resp->ns_addr_list[]
196 * returns:
197 * 0 : not found
198 * >0 : found
199 * author:
200 * paul vixie, 29may94
201 */
202int
203res_isourserver(const struct sockaddr_in *inp)
204{
205 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
206#ifdef INET6
207 const struct sockaddr_in6 *in6p = (const struct sockaddr_in6 *)inp;
208 const struct sockaddr_in6 *srv6;
209#endif
210 const struct sockaddr_in *srv;
211 int ns, ret;
212
213 ret = 0;
214 switch (inp->sin_family) {
215#ifdef INET6
216 case AF_INET6:
217 for (ns = 0; ns < _resp->nscount; ns++) {
218 srv6 = (struct sockaddr_in6 *)get_nsaddr(ns);
219 if (srv6->sin6_family == in6p->sin6_family &&
220 srv6->sin6_port == in6p->sin6_port &&
221 srv6->sin6_scope_id == in6p->sin6_scope_id &&
222 (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
223 IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr,
224 &in6p->sin6_addr))) {
225 ret++;
226 break;
227 }
228 }
229 break;
230#endif
231 case AF_INET:
232 for (ns = 0; ns < _resp->nscount; ns++) {
233 srv = (struct sockaddr_in *)get_nsaddr(ns);
234 if (srv->sin_family == inp->sin_family &&
235 srv->sin_port == inp->sin_port &&
236 (srv->sin_addr.s_addr == INADDR_ANY ||
237 srv->sin_addr.s_addr == inp->sin_addr.s_addr)) {
238 ret++;
239 break;
240 }
241 }
242 break;
243 }
244 return (ret);
245}
246
247/* int
248 * res_nameinquery(name, type, class, buf, eom)
249 * look for (name,type,class) in the query section of packet (buf,eom)
250 * returns:
251 * -1 : format error
252 * 0 : not found
253 * >0 : found
254 * author:
255 * paul vixie, 29may94
256 */
257int
258res_nameinquery(const char *name, int type, int class, const u_char *buf,
259 const u_char *eom)
260{
261 const u_char *cp = buf + HFIXEDSZ;
262 int qdcount = ntohs(((HEADER*)buf)->qdcount);
263
264 while (qdcount-- > 0) {
265 char tname[MAXDNAME+1];
266 int n, ttype, tclass;
267
268 n = dn_expand(buf, eom, cp, tname, sizeof tname);
269 if (n < 0)
270 return (-1);
271 cp += n;
272 ttype = _getshort(cp); cp += INT16SZ;
273 tclass = _getshort(cp); cp += INT16SZ;
274 if (ttype == type &&
275 tclass == class &&
276 strcasecmp(tname, name) == 0)
277 return (1);
278 }
279 return (0);
280}
281
282/* int
283 * res_queriesmatch(buf1, eom1, buf2, eom2)
284 * is there a 1:1 mapping of (name,type,class)
285 * in (buf1,eom1) and (buf2,eom2)?
286 * returns:
287 * -1 : format error
288 * 0 : not a 1:1 mapping
289 * >0 : is a 1:1 mapping
290 * author:
291 * paul vixie, 29may94
292 */
293int
294res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2,
295 const u_char *eom2)
296{
297 const u_char *cp = buf1 + HFIXEDSZ;
298 int qdcount = ntohs(((HEADER*)buf1)->qdcount);
299
300 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
301 return (0);
302 while (qdcount-- > 0) {
303 char tname[MAXDNAME+1];
304 int n, ttype, tclass;
305
306 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
307 if (n < 0)
308 return (-1);
309 cp += n;
310 ttype = _getshort(cp); cp += INT16SZ;
311 tclass = _getshort(cp); cp += INT16SZ;
312 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
313 return (0);
314 }
315 return (1);
316}
317
318int
319res_send(const u_char *buf, int buflen, u_char *ans, int anssiz)
320{
321 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
322 HEADER *hp = (HEADER *) buf;
323 HEADER *anhp = (HEADER *) ans;
324 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
325 int n;
326 u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
327
328 if (_res_init(0) == -1) {
329 /* errno should have been set by res_init() in this case. */
330 return (-1);
331 }
332 DprintQ((_resp->options & RES_DEBUG) || (_resp->pfcode & RES_PRF_QUERY),
333 (stdout, ";; res_send()\n"), buf, buflen);
334 v_circuit = (_resp->options & RES_USEVC) || buflen > PACKETSZ;
335 gotsomewhere = 0;
336 connreset = 0;
337 terrno = ETIMEDOUT;
338 badns = 0;
339
340 /*
341 * Send request, RETRY times, or until successful
342 */
343 for (try = 0; try < _resp->retry; try++) {
344 for (ns = 0; ns < _resp->nscount; ns++) {
345 struct sockaddr *nsap = get_nsaddr(ns);
346 socklen_t salen;
347
348 if (nsap->sa_len)
349 salen = nsap->sa_len;
350#ifdef INET6
351 else if (nsap->sa_family == AF_INET6)
352 salen = sizeof(struct sockaddr_in6);
353#endif
354 else if (nsap->sa_family == AF_INET)
355 salen = sizeof(struct sockaddr_in);
356 else
357 salen = 0; /*unknown, die on connect*/
358
359 same_ns:
360 if (badns & (1 << ns)) {
361 res_close();
362 goto next_ns;
363 }
364
365 if (Qhook) {
366 int done = 0, loops = 0;
367
368 do {
369 res_sendhookact act;
370
371 act = (*Qhook)((struct sockaddr_in **)&nsap,
372 &buf, &buflen,
373 ans, anssiz, &resplen);
374 switch (act) {
375 case res_goahead:
376 done = 1;
377 break;
378 case res_nextns:
379 res_close();
380 goto next_ns;
381 case res_done:
382 return (resplen);
383 case res_modified:
384 /* give the hook another try */
385 if (++loops < 42) /*doug adams*/
386 break;
387 /*FALLTHROUGH*/
388 case res_error:
389 /*FALLTHROUGH*/
390 default:
391 return (-1);
392 }
393 } while (!done);
394 }
395
396 Dprint((_resp->options & RES_DEBUG) &&
397 getnameinfo(nsap, salen, abuf, sizeof(abuf),
398 NULL, 0, NI_NUMERICHOST) == 0,
399 (stdout, ";; Querying server (# %d) address = %s\n",
400 ns + 1, abuf));
401
402 if (v_circuit) {
403 int truncated;
404 struct iovec iov[2];
405 u_short len;
406 u_char *cp;
407
408 /*
409 * Use virtual circuit;
410 * at most one attempt per server.
411 */
412 try = _resp->retry;
413 truncated = 0;
414 if ((s < 0) || (!vc) || (af != nsap->sa_family)) {
415 if (s >= 0)
416 res_close();
417
418 af = nsap->sa_family;
419 s = socket(af, SOCK_STREAM, 0);
420 if (s < 0) {
421 terrno = errno;
422 Perror(stderr, "socket(vc)", errno);
423#if 0
424 return (-1);
425#else
426 badns |= (1 << ns);
427 res_close();
428 goto next_ns;
429#endif
430 }
431 errno = 0;
432 if (connect(s, nsap, salen) < 0) {
433 terrno = errno;
434 Aerror(stderr, "connect/vc",
435 errno, nsap);
436 badns |= (1 << ns);
437 res_close();
438 goto next_ns;
439 }
440 vc = 1;
441 }
442 /*
443 * Send length & message
444 */
445 putshort((u_short)buflen, (u_char*)&len);
446 iov[0].iov_base = (caddr_t)&len;
447 iov[0].iov_len = INT16SZ;
448 iov[1].iov_base = (caddr_t)buf;
449 iov[1].iov_len = buflen;
450 if (writev(s, iov, 2) != (INT16SZ + buflen)) {
451 terrno = errno;
452 Perror(stderr, "write failed", errno);
453 badns |= (1 << ns);
454 res_close();
455 goto next_ns;
456 }
457 /*
458 * Receive length & response
459 */
460 read_len:
461 cp = ans;
462 len = INT16SZ;
463 while ((n = read(s, (char *)cp, (int)len)) > 0) {
464 cp += n;
465 if ((len -= n) <= 0)
466 break;
467 }
468 if (n <= 0) {
469 terrno = errno;
470 Perror(stderr, "read failed", errno);
471 res_close();
472 /*
473 * A long running process might get its TCP
474 * connection reset if the remote server was
475 * restarted. Requery the server instead of
476 * trying a new one. When there is only one
477 * server, this means that a query might work
478 * instead of failing. We only allow one reset
479 * per query to prevent looping.
480 */
481 if (terrno == ECONNRESET && !connreset) {
482 connreset = 1;
483 res_close();
484 goto same_ns;
485 }
486 res_close();
487 goto next_ns;
488 }
489 resplen = _getshort(ans);
490 if (resplen > anssiz) {
491 Dprint(_resp->options & RES_DEBUG,
492 (stdout, ";; response truncated\n")
493 );
494 truncated = 1;
495 len = anssiz;
496 } else
497 len = resplen;
498 cp = ans;
499 while (len != 0 &&
500 (n = read(s, (char *)cp, (int)len)) > 0) {
501 cp += n;
502 len -= n;
503 }
504 if (n <= 0) {
505 terrno = errno;
506 Perror(stderr, "read(vc)", errno);
507 res_close();
508 goto next_ns;
509 }
510 if (truncated) {
511 /*
512 * Flush rest of answer
513 * so connection stays in synch.
514 */
515 anhp->tc = 1;
516 len = resplen - anssiz;
517 while (len != 0) {
518 char junk[PACKETSZ];
519
520 n = (len > sizeof(junk)
521 ? sizeof(junk)
522 : len);
523 if ((n = read(s, junk, n)) > 0)
524 len -= n;
525 else
526 break;
527 }
528 }
529 /*
530 * The calling applicating has bailed out of
531 * a previous call and failed to arrange to have
532 * the circuit closed or the server has got
533 * itself confused. Anyway drop the packet and
534 * wait for the correct one.
535 */
536 if (hp->id != anhp->id) {
537 DprintQ((_resp->options & RES_DEBUG) ||
538 (_resp->pfcode & RES_PRF_REPLY),
539 (stdout, ";; old answer (unexpected):\n"),
540 ans, (resplen>anssiz)?anssiz:resplen);
541 goto read_len;
542 }
543 } else {
544 /*
545 * Use datagrams.
546 */
547 struct pollfd pfd;
548 int timeout;
549 struct sockaddr_storage from;
550 socklen_t fromlen;
551
552 if ((s < 0) || vc || (af != nsap->sa_family)) {
553 if (vc)
554 res_close();
555 af = nsap->sa_family;
556 s = socket(af, SOCK_DGRAM, 0);
557 if (s < 0) {
558#if !CAN_RECONNECT
559 bad_dg_sock:
560#endif
561 terrno = errno;
562 Perror(stderr, "socket(dg)", errno);
563#if 0
564 return (-1);
565#else
566 badns |= (1 << ns);
567 res_close();
568 goto next_ns;
569#endif
570 }
571#ifdef IPV6_MINMTU
572 if (af == AF_INET6) {
573 const int yes = 1;
574 (void)setsockopt(s, IPPROTO_IPV6,
575 IPV6_USE_MIN_MTU, &yes,
576 sizeof(yes));
577 }
578#endif
579 connected = 0;
580 }
581 /*
582 * On a 4.3BSD+ machine (client and server,
583 * actually), sending to a nameserver datagram
584 * port with no nameserver will cause an
585 * ICMP port unreachable message to be returned.
586 * If our datagram socket is "connected" to the
587 * server, we get an ECONNREFUSED error on the next
588 * socket operation, and poll returns if the
589 * error message is received. We can thus detect
590 * the absence of a nameserver without timing out.
591 * If we have sent queries to at least two servers,
592 * however, we don't want to remain connected,
593 * as we wish to receive answers from the first
594 * server to respond.
595 */
596 if (!(_resp->options & RES_INSECURE1) &&
597 (_resp->nscount == 1 || (try == 0 && ns == 0))) {
598 /*
599 * Connect only if we are sure we won't
600 * receive a response from another server.
601 */
602 if (!connected) {
603 if (connect(s, nsap, salen) < 0) {
604 Aerror(stderr,
605 "connect(dg)",
606 errno, nsap);
607 badns |= (1 << ns);
608 res_close();
609 goto next_ns;
610 }
611 connected = 1;
612 }
613 if (send(s, (char*)buf, buflen, 0) != buflen) {
614 Perror(stderr, "send", errno);
615 badns |= (1 << ns);
616 res_close();
617 goto next_ns;
618 }
619 } else {
620 /*
621 * Disconnect if we want to listen
622 * for responses from more than one server.
623 */
624 if (connected) {
625#if CAN_RECONNECT
626#ifdef INET6
627 /* XXX: any errornous address */
628#endif /* INET6 */
629 struct sockaddr_in no_addr;
630
631 no_addr.sin_family = AF_INET;
632 no_addr.sin_addr.s_addr = INADDR_ANY;
633 no_addr.sin_port = 0;
634 (void) connect(s,
635 (struct sockaddr *)
636 &no_addr,
637 sizeof(no_addr));
638#else
639 int s1 = socket(af, SOCK_DGRAM,0);
640 if (s1 < 0)
641 goto bad_dg_sock;
642 (void) dup2(s1, s);
643 (void) close(s1);
644 Dprint(_resp->options & RES_DEBUG,
645 (stdout, ";; new DG socket\n"))
646#endif
647#ifdef IPV6_MINMTU
648 if (af == AF_INET6) {
649 const int yes = 1;
650 (void)setsockopt(s, IPPROTO_IPV6,
651 IPV6_USE_MIN_MTU, &yes,
652 sizeof(yes));
653 }
654#endif
655 connected = 0;
656 errno = 0;
657 }
658 if (sendto(s, (char*)buf, buflen, 0,
659 nsap, salen) != buflen) {
660 Aerror(stderr, "sendto", errno, nsap);
661 badns |= (1 << ns);
662 res_close();
663 goto next_ns;
664 }
665 }
666
667 /*
668 * Wait for reply
669 */
670 timeout = 1000 * (_resp->retrans << try);
671 if (try > 0)
672 timeout /= _resp->nscount;
673 if (timeout < 1000)
674 timeout = 1000;
675 wait:
676 pfd.fd = s;
677 pfd.events = POLLIN;
678 n = poll(&pfd, 1, timeout);
679 if (n < 0) {
680 if (errno == EINTR)
681 goto wait;
682 Perror(stderr, "poll", errno);
683 res_close();
684 goto next_ns;
685 }
686 if (n == 0) {
687 /*
688 * timeout
689 */
690 Dprint(_resp->options & RES_DEBUG,
691 (stdout, ";; timeout\n"));
692 gotsomewhere = 1;
693 res_close();
694 goto next_ns;
695 }
696 errno = 0;
697 fromlen = sizeof(from);
698 resplen = recvfrom(s, (char*)ans, anssiz, 0,
699 (struct sockaddr *)&from, &fromlen);
700 if (resplen <= 0) {
701 Perror(stderr, "recvfrom", errno);
702 res_close();
703 goto next_ns;
704 }
705 gotsomewhere = 1;
706 if (hp->id != anhp->id) {
707 /*
708 * response from old query, ignore it.
709 * XXX - potential security hazard could
710 * be detected here.
711 */
712 DprintQ((_resp->options & RES_DEBUG) ||
713 (_resp->pfcode & RES_PRF_REPLY),
714 (stdout, ";; old answer:\n"),
715 ans, (resplen>anssiz)?anssiz:resplen);
716 goto wait;
717 }
718#if CHECK_SRVR_ADDR
719 if (!(_resp->options & RES_INSECURE1) &&
720 !res_isourserver((struct sockaddr_in *)&from)) {
721 /*
722 * response from wrong server? ignore it.
723 * XXX - potential security hazard could
724 * be detected here.
725 */
726 DprintQ((_resp->options & RES_DEBUG) ||
727 (_resp->pfcode & RES_PRF_REPLY),
728 (stdout, ";; not our server:\n"),
729 ans, (resplen>anssiz)?anssiz:resplen);
730 goto wait;
731 }
732#endif
733 if (!(_resp->options & RES_INSECURE2) &&
734 !res_queriesmatch(buf, buf + buflen,
735 ans, ans + anssiz)) {
736 /*
737 * response contains wrong query? ignore it.
738 * XXX - potential security hazard could
739 * be detected here.
740 */
741 DprintQ((_resp->options & RES_DEBUG) ||
742 (_resp->pfcode & RES_PRF_REPLY),
743 (stdout, ";; wrong query name:\n"),
744 ans, (resplen>anssiz)?anssiz:resplen);
745 goto wait;
746 }
747 if (anhp->rcode == SERVFAIL ||
748 anhp->rcode == NOTIMP ||
749 anhp->rcode == REFUSED) {
750 DprintQ(_resp->options & RES_DEBUG,
751 (stdout, "server rejected query:\n"),
752 ans, (resplen>anssiz)?anssiz:resplen);
753 badns |= (1 << ns);
754 res_close();
755 /* don't retry if called from dig */
756 if (!_resp->pfcode)
757 goto next_ns;
758 }
759 if (!(_resp->options & RES_IGNTC) && anhp->tc) {
760 /*
761 * get rest of answer;
762 * use TCP with same server.
763 */
764 Dprint(_resp->options & RES_DEBUG,
765 (stdout, ";; truncated answer\n"));
766 v_circuit = 1;
767 res_close();
768 goto same_ns;
769 }
770 } /*if vc/dg*/
771 Dprint((_resp->options & RES_DEBUG) ||
772 ((_resp->pfcode & RES_PRF_REPLY) &&
773 (_resp->pfcode & RES_PRF_HEAD1)),
774 (stdout, ";; got answer:\n"));
775 DprintQ((_resp->options & RES_DEBUG) ||
776 (_resp->pfcode & RES_PRF_REPLY),
777 (stdout, "%s", ""),
778 ans, (resplen>anssiz)?anssiz:resplen);
779 /*
780 * If using virtual circuits, we assume that the first server
781 * is preferred over the rest (i.e. it is on the local
782 * machine) and only keep that one open.
783 * If we have temporarily opened a virtual circuit,
784 * or if we haven't been asked to keep a socket open,
785 * close the socket.
786 */
787 if ((v_circuit && (!(_resp->options & RES_USEVC) || ns != 0)) ||
788 !(_resp->options & RES_STAYOPEN)) {
789 res_close();
790 }
791 if (Rhook) {
792 int done = 0, loops = 0;
793
794 do {
795 res_sendhookact act;
796
797 act = (*Rhook)((struct sockaddr_in *)nsap,
798 buf, buflen,
799 ans, anssiz, &resplen);
800 switch (act) {
801 case res_goahead:
802 case res_done:
803 done = 1;
804 break;
805 case res_nextns:
806 res_close();
807 goto next_ns;
808 case res_modified:
809 /* give the hook another try */
810 if (++loops < 42) /*doug adams*/
811 break;
812 /*FALLTHROUGH*/
813 case res_error:
814 /*FALLTHROUGH*/
815 default:
816 return (-1);
817 }
818 } while (!done);
819
820 }
821 return (resplen);
822 next_ns: ;
823 } /*foreach ns*/
824 } /*foreach retry*/
825 res_close();
826 if (!v_circuit) {
827 if (!gotsomewhere)
828 errno = ECONNREFUSED; /* no nameservers found */
829 else
830 errno = ETIMEDOUT; /* no answer obtained */
831 } else
832 errno = terrno;
833 return (-1);
834}
835
836/*
837 * This routine is for closing the socket if a virtual circuit is used and
838 * the program wants to close it. This provides support for endhostent()
839 * which expects to close the socket.
840 *
841 * This routine is not expected to be user visible.
842 */
843void
844res_close(void)
845{
846 if (s >= 0) {
847 (void) close(s);
848 s = -1;
849 connected = 0;
850 vc = 0;
851 af = 0;
852 }
853}