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