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