Return to res_send.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / minires |
1.1 misho 1: /*
2: * Copyright (c) 1985, 1989, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. 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:
34: /*
35: * Portions Copyright (c) 1993 by Digital Equipment Corporation.
36: *
37: * Permission to use, copy, modify, and distribute this software for any
38: * purpose with or without fee is hereby granted, provided that the above
39: * copyright notice and this permission notice appear in all copies, and that
40: * the name of Digital Equipment Corporation not be used in advertising or
41: * publicity pertaining to distribution of the document or software without
42: * specific, written prior permission.
43: *
44: * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45: * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46: * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47: * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50: * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51: * SOFTWARE.
52: */
53:
54: /*
55: * Portions Copyright (c) 2004,2008-2009
56: * by Internet Systems Consortium, Inc. ("ISC")
57: * Portions Copyright (c) 1996-2003 by Internet Software Consortium
58: *
59: * Permission to use, copy, modify, and distribute this software for any
60: * purpose with or without fee is hereby granted, provided that the above
61: * copyright notice and this permission notice appear in all copies.
62: *
63: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
64: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
65: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
66: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
67: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
68: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
69: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
70: *
71: * Internet Systems Consortium, Inc.
72: * 950 Charter Street
73: * Redwood City, CA 94063
74: * <info@isc.org>
75: * https://www.isc.org/
76: */
77:
78: #if defined(LIBC_SCCS) && !defined(lint)
79: static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
1.1.1.1 ! misho 80: static const char rcsid[] = "$Id: res_send.c,v 1.11.116.2 2009/07/24 22:04:52 sar Exp $";
1.1 misho 81: #endif /* LIBC_SCCS and not lint */
82:
83: /*
84: * Send query to name server and wait for reply.
85: */
86:
87: #include <sys/types.h>
88: #include <sys/param.h>
89: #include <sys/time.h>
90: #include <sys/socket.h>
91: #include <sys/uio.h>
92:
93: #include <netinet/in.h>
94: #include <arpa/inet.h>
95:
96: #include <errno.h>
97: #include <netdb.h>
98: #include <signal.h>
99: #include <stdio.h>
100: #include <stdlib.h>
101: #include <string.h>
102: #include <unistd.h>
103:
104: #include "minires/minires.h"
105: #include "arpa/nameser.h"
106:
107: /* Rename the I/O functions in case we're tracing. */
108: #include <omapip/omapip_p.h>
109:
110: ssize_t trace_mr_send(int, const void *, size_t, int);
111: ssize_t trace_mr_recvfrom(int s, void *, size_t, int,
112: struct sockaddr *, socklen_t *);
113: ssize_t trace_mr_read(int, void *, size_t);
114: int trace_mr_connect(int s, struct sockaddr *, socklen_t);
115: int trace_mr_socket(int, int, int);
116: int trace_mr_bind(int, struct sockaddr *, socklen_t);
117: int trace_mr_close(int);
118: time_t trace_mr_time(time_t *);
119: int trace_mr_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
120: unsigned int trace_mr_res_randomid(unsigned int);
121:
122: #undef send
123: #define send trace_mr_send
124: #undef recvfrom
125: #define recvfrom trace_mr_recvfrom
126: #undef read
127: #define read trace_mr_read
128: #undef connect
129: #define connect trace_mr_connect
130: #undef socket
131: #define socket trace_mr_socket
132: #undef bind
133: #define bind trace_mr_bind
134: #undef close
135: #define close trace_mr_close
136: #undef select
137: #define select trace_mr_select
138: #undef time
139: #define time trace_mr_time
140:
141: #define CHECK_SRVR_ADDR
142:
143: static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2);
144: void res_pquery(const res_state, const u_char *, int, FILE *);
145:
146: /* int
147: * res_isourserver(ina)
148: * looks up "ina" in _res.ns_addr_list[]
149: * returns:
150: * 0 : not found
151: * >0 : found
152: * author:
153: * paul vixie, 29may94
154: */
155: int
156: res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) {
157: struct sockaddr_in ina;
158: int ns;
159:
160: ina = *inp;
161: for (ns = 0; ns < statp->nscount; ns++) {
162: const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
163:
164: if (srv->sin_family == ina.sin_family &&
165: srv->sin_port == ina.sin_port &&
166: (srv->sin_addr.s_addr == INADDR_ANY ||
167: srv->sin_addr.s_addr == ina.sin_addr.s_addr))
168: return (1);
169: }
170: return (0);
171: }
172:
173: /* int
174: * res_nameinquery(name, type, class, buf, eom)
175: * look for (name,type,class) in the query section of packet (buf,eom)
176: * requires:
177: * buf + HFIXEDSZ <= eom
178: * returns:
179: * -1 : format error
180: * 0 : not found
181: * >0 : found
182: * author:
183: * paul vixie, 29may94
184: */
185: int
186: res_nameinquery(const char *name, int type, int class,
187: const u_char *buf, const u_char *eom)
188: {
189: const u_char *cp = buf + HFIXEDSZ;
190: int qdcount = ntohs(((const HEADER *)buf)->qdcount);
191:
192: while (qdcount-- > 0) {
193: char tname[MAXDNAME+1];
194: int n, ttype, tclass;
195:
196: n = dn_expand(buf, eom, cp, tname, sizeof tname);
197: if (n < 0)
198: return (-1);
199: cp += n;
200: if (cp + 2 * INT16SZ > eom)
201: return (-1);
202: ttype = getUShort(cp); cp += INT16SZ;
203: tclass = getUShort(cp); cp += INT16SZ;
204: if (ttype == type && tclass == class &&
205: ns_samename(tname, name) == 1)
206: return (1);
207: }
208: return (0);
209: }
210:
211: /* int
212: * res_queriesmatch(buf1, eom1, buf2, eom2)
213: * is there a 1:1 mapping of (name,type,class)
214: * in (buf1,eom1) and (buf2,eom2)?
215: * returns:
216: * -1 : format error
217: * 0 : not a 1:1 mapping
218: * >0 : is a 1:1 mapping
219: * author:
220: * paul vixie, 29may94
221: */
222: int
223: res_queriesmatch(const u_char *buf1, const u_char *eom1,
224: const u_char *buf2, const u_char *eom2)
225: {
226: const u_char *cp = buf1 + HFIXEDSZ;
227: int qdcount = ntohs(((const HEADER *)buf1)->qdcount);
228:
229: if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
230: return (-1);
231:
232: /*
233: * Only header section present in replies to
234: * dynamic update packets.
235: */
236: if ( (((const HEADER *)buf1)->opcode == ns_o_update) &&
237: (((const HEADER *)buf2)->opcode == ns_o_update) )
238: return (1);
239:
240: if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
241: return (0);
242: while (qdcount-- > 0) {
243: char tname[MAXDNAME+1];
244: int n, ttype, tclass;
245:
246: n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
247: if (n < 0)
248: return (-1);
249: cp += n;
250: if (cp + 2 * INT16SZ > eom1)
251: return (-1);
252: ttype = getUShort(cp); cp += INT16SZ;
253: tclass = getUShort(cp); cp += INT16SZ;
254: if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
255: return (0);
256: }
257: return (1);
258: }
259:
260: isc_result_t
261: res_nsend(res_state statp,
262: double *buf, unsigned buflen,
263: double *ans, unsigned anssiz, unsigned *ansret)
264: {
265: HEADER *hp = (HEADER *) buf;
266: HEADER *anhp = (HEADER *) ans;
267: int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
268: u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */
269: static int highestFD = FD_SETSIZE - 1;
270:
271: if (anssiz < HFIXEDSZ) {
272: return ISC_R_INVALIDARG;
273: }
274: DprintQ((statp->options & RES_DEBUG) ||
275: (statp->pfcode & RES_PRF_QUERY),
276: (stdout, ";; res_send()\n"), buf, buflen);
277: v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
278: gotsomewhere = 0;
279: connreset = 0;
280: terrno = ISC_R_TIMEDOUT;
281: badns = 0;
282:
283: /*
284: * Some callers want to even out the load on their resolver list.
285: */
286: if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) {
287: struct sockaddr_in ina;
288: int lastns = statp->nscount - 1;
289:
290: ina = statp->nsaddr_list[0];
291: for (ns = 0; ns < lastns; ns++)
292: statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
293: statp->nsaddr_list[lastns] = ina;
294: }
295:
296: #if defined (TRACING)
297: trace_mr_statp_setup (statp);
298: #endif
299:
300: /*
301: * Send request, RETRY times, or until successful
302: */
303: for (try = 0; try < statp->retry; try++) {
304: for (ns = 0; ns < statp->nscount; ns++) {
305: struct sockaddr_in *nsap = &statp->nsaddr_list[ns];
306: same_ns:
307: if (badns & (1 << ns)) {
308: res_nclose(statp);
309: goto next_ns;
310: }
311:
312: if (statp->qhook) {
313: int done = 0, loops = 0;
314:
315: do {
316: res_sendhookact act;
317:
318: act = (*statp->qhook)(&nsap, &buf, &buflen,
319: ans, anssiz, &resplen);
320: switch (act) {
321: case res_goahead:
322: done = 1;
323: break;
324: case res_nextns:
325: res_nclose(statp);
326: goto next_ns;
327: case res_done:
328: return (resplen);
329: case res_modified:
330: /* give the hook another try */
331: if (++loops < 42) /*doug adams*/
332: break;
333: /*FALLTHROUGH*/
334: case res_error:
335: /*FALLTHROUGH*/
336: default:
337: return ISC_R_UNEXPECTED;
338: }
339: } while (!done);
340: }
341:
342: Dprint(statp->options & RES_DEBUG,
343: (stdout, ";; Querying server (# %d) address = %s\n",
344: ns + 1, inet_ntoa(nsap->sin_addr)));
345:
346: if (v_circuit) {
347: int truncated;
348: struct iovec iov[2];
349: u_short len;
350: u_char *cp;
351:
352: /* Use VC; at most one attempt per server. */
353: try = statp->retry;
354: truncated = 0;
355:
356: /* Are we still talking to whom we want to talk to? */
357: if (statp->_sock >= 0 &&
358: (statp->_flags & RES_F_VC) != 0) {
359: struct sockaddr_in peer;
360: SOCKLEN_T size = sizeof(peer);
361:
362: if (getpeername(statp->_sock,
363: (struct sockaddr *)&peer,
364: &size) < 0) {
365: res_nclose(statp);
366: statp->_flags &= ~RES_F_VC;
367: } else if (!cmpsock(&peer, nsap)) {
368: res_nclose(statp);
369: statp->_flags &= ~RES_F_VC;
370: }
371: }
372:
373: if (statp->_sock < 0 ||
374: (statp->_flags & RES_F_VC) == 0) {
375: if (statp->_sock >= 0)
376: res_nclose(statp);
377:
378: statp->_sock = socket(PF_INET,
379: SOCK_STREAM, 0);
380: if (statp->_sock < 0 ||
381: statp->_sock > highestFD) {
382: terrno = uerr2isc (errno);
383: Perror(statp, stderr,
384: "socket(vc)", errno);
385: return (-1);
386: }
387: errno = 0;
388: if (connect(statp->_sock,
389: (struct sockaddr *)nsap,
390: sizeof *nsap) < 0) {
391: terrno = uerr2isc (errno);
392: Aerror(statp, stderr, "connect/vc",
393: errno, *nsap);
394: badns |= (1 << ns);
395: res_nclose(statp);
396: goto next_ns;
397: }
398: statp->_flags |= RES_F_VC;
399: }
400: /*
401: * Send length & message
402: */
403: putUShort((u_char*)&len, buflen);
404: iov[0].iov_base = (caddr_t)&len;
405: iov[0].iov_len = INT16SZ;
406: iov[1].iov_base = (const caddr_t)buf;
407: iov[1].iov_len = buflen;
408: if (writev(statp->_sock, iov, 2) !=
409: (INT16SZ + buflen)) {
410: terrno = uerr2isc (errno);
411: Perror(statp, stderr, "write failed", errno);
412: badns |= (1 << ns);
413: res_nclose(statp);
414: goto next_ns;
415: }
416: /*
417: * Receive length & response
418: */
419: read_len:
420: cp = (u_char *)ans;
421: len = INT16SZ;
422: while ((n = read(statp->_sock,
423: (char *)cp, (unsigned)len)) > 0) {
424: cp += n;
425: if ((len -= n) <= 0)
426: break;
427: }
428: if (n <= 0) {
429: terrno = uerr2isc (errno);
430: Perror(statp, stderr, "read failed", errno);
431: res_nclose(statp);
432: /*
433: * A long running process might get its TCP
434: * connection reset if the remote server was
435: * restarted. Requery the server instead of
436: * trying a new one. When there is only one
437: * server, this means that a query might work
438: * instead of failing. We only allow one reset
439: * per query to prevent looping.
440: */
441: if (terrno == ISC_R_CONNREFUSED &&
442: !connreset) {
443: connreset = 1;
444: res_nclose(statp);
445: goto same_ns;
446: }
447: res_nclose(statp);
448: goto next_ns;
449: }
450: resplen = getUShort ((unsigned char *)ans);
451: if (resplen > anssiz) {
452: Dprint(statp->options & RES_DEBUG,
453: (stdout, ";; response truncated\n")
454: );
455: truncated = 1;
456: len = anssiz;
457: } else
458: len = resplen;
459: if (len < HFIXEDSZ) {
460: /*
461: * Undersized message.
462: */
463: Dprint(statp->options & RES_DEBUG,
464: (stdout, ";; undersized: %d\n", len));
465: terrno = ISC_R_NOSPACE;
466: badns |= (1 << ns);
467: res_nclose(statp);
468: goto next_ns;
469: }
470: cp = (u_char *)ans;
471: while (len != 0 &&
472: (n = read(statp->_sock,
473: (char *)cp, (unsigned)len))
474: > 0) {
475: cp += n;
476: len -= n;
477: }
478: if (n <= 0) {
479: terrno = uerr2isc (errno);
480: Perror(statp, stderr, "read(vc)", errno);
481: res_nclose(statp);
482: goto next_ns;
483: }
484: if (truncated) {
485: /*
486: * Flush rest of answer
487: * so connection stays in synch.
488: */
489: anhp->tc = 1;
490: len = resplen - anssiz;
491: while (len != 0) {
492: char junk[PACKETSZ];
493:
494: n = (len > sizeof(junk)
495: ? sizeof(junk)
496: : len);
497: n = read(statp->_sock,
498: junk, (unsigned)n);
499: if (n > 0)
500: len -= n;
501: else
502: break;
503: }
504: }
505: /*
506: * The calling applicating has bailed out of
507: * a previous call and failed to arrange to have
508: * the circuit closed or the server has got
509: * itself confused. Anyway drop the packet and
510: * wait for the correct one.
511: */
512: if (hp->id != anhp->id) {
513: DprintQ((statp->options & RES_DEBUG) ||
514: (statp->pfcode & RES_PRF_REPLY),
515: (stdout,
516: ";; old answer (unexpected):\n"),
517: ans, (resplen>anssiz)?anssiz:resplen);
518: goto read_len;
519: }
520: } else {
521: /*
522: * Use datagrams.
523: */
524: int start, timeout, finish;
525: fd_set dsmask;
526: struct sockaddr_in from;
527: SOCKLEN_T fromlen;
528: int seconds;
529:
530: if (statp->_sock < 0 ||
531: (statp->_flags & RES_F_VC) != 0) {
532: if ((statp->_flags & RES_F_VC) != 0)
533: res_nclose(statp);
534: statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);
535: if (statp->_sock < 0 ||
536: statp->_sock > highestFD) {
537: #ifndef CAN_RECONNECT
538: bad_dg_sock:
539: #endif
540: terrno = uerr2isc (errno);
541: Perror(statp, stderr,
542: "socket(dg)", errno);
543: return terrno;
544: }
545: statp->_flags &= ~RES_F_CONN;
546: }
547: #ifndef CANNOT_CONNECT_DGRAM
548: /*
549: * On a 4.3BSD+ machine (client and server,
550: * actually), sending to a nameserver datagram
551: * port with no nameserver will cause an
552: * ICMP port unreachable message to be returned.
553: * If our datagram socket is "connected" to the
554: * server, we get an ECONNREFUSED error on the next
555: * socket operation, and select returns if the
556: * error message is received. We can thus detect
557: * the absence of a nameserver without timing out.
558: * If we have sent queries to at least two servers,
559: * however, we don't want to remain connected,
560: * as we wish to receive answers from the first
561: * server to respond.
562: */
563: if (statp->nscount == 1 || (try == 0 && ns == 0)) {
564: /*
565: * Connect only if we are sure we won't
566: * receive a response from another server.
567: */
568: if ((statp->_flags & RES_F_CONN) == 0) {
569: if (connect(statp->_sock,
570: (struct sockaddr *)nsap,
571: sizeof *nsap) < 0) {
572: Aerror(statp, stderr,
573: "connect(dg)",
574: errno, *nsap);
575: badns |= (1 << ns);
576: res_nclose(statp);
577: goto next_ns;
578: }
579: statp->_flags |= RES_F_CONN;
580: }
581: if (send(statp->_sock,
582: (const char*)buf, (unsigned)buflen, 0)
583: != buflen) {
584: Perror(statp, stderr, "send", errno);
585: badns |= (1 << ns);
586: res_nclose(statp);
587: goto next_ns;
588: }
589: } else {
590: /*
591: * Disconnect if we want to listen
592: * for responses from more than one server.
593: */
594: if ((statp->_flags & RES_F_CONN) != 0) {
595: #ifdef CAN_RECONNECT
596: struct sockaddr_in no_addr;
597:
598: no_addr.sin_family = AF_INET;
599: no_addr.sin_addr.s_addr = INADDR_ANY;
600: no_addr.sin_port = 0;
601: (void) connect(statp->_sock,
602: (struct sockaddr *)
603: &no_addr,
604: sizeof no_addr);
605: #else
606: struct sockaddr_in local_addr;
607: SOCKLEN_T len;
608: int result, s1;
609:
610: len = sizeof(local_addr);
611: s1 = socket(PF_INET, SOCK_DGRAM, 0);
612: result = getsockname(statp->_sock,
613: (struct sockaddr *)&local_addr,
614: &len);
615: if (s1 < 0)
616: goto bad_dg_sock;
617: (void) dup2(s1, statp->_sock);
618: (void) close(s1);
619: if (result == 0) {
620: /*
621: * Attempt to rebind to old
622: * port. Note connected socket
623: * has an sin_addr set.
624: */
625: local_addr.sin_addr.s_addr =
626: htonl(0);
627: (void)bind(statp->_sock,
628: (struct sockaddr *)
629: &local_addr,
630: (unsigned)len);
631: }
632: Dprint(statp->options & RES_DEBUG,
633: (stdout, ";; new DG socket\n"));
634: #endif /* CAN_RECONNECT */
635: statp->_flags &= ~RES_F_CONN;
636: errno = 0;
637: }
638: #endif /* !CANNOT_CONNECT_DGRAM */
639: if (sendto(statp->_sock,
640: (const char *)buf, buflen, 0,
641: (struct sockaddr *)nsap,
642: sizeof *nsap)
643: != buflen) {
644: Aerror(statp, stderr, "sendto", errno, *nsap);
645: badns |= (1 << ns);
646: res_nclose(statp);
647: goto next_ns;
648: }
649: #ifndef CANNOT_CONNECT_DGRAM
650: }
651: #endif /* !CANNOT_CONNECT_DGRAM */
652:
653: if (statp->_sock < 0 || statp->_sock > highestFD) {
654: Perror(statp, stderr,
655: "fd out-of-bounds", EMFILE);
656: res_nclose(statp);
657: goto next_ns;
658: }
659:
660: /*
661: * Wait for reply
662: */
663: seconds = (statp->retrans << try);
664: if (try > 0)
665: seconds /= statp->nscount;
666: if (seconds <= 0)
667: seconds = 1;
668: start = cur_time;
669: timeout = seconds;
670: finish = start + timeout;
671: wait:
672: FD_ZERO(&dsmask);
673: FD_SET(statp->_sock, &dsmask);
674: {
675: struct timeval t;
676: t.tv_sec = timeout;
677: t.tv_usec = 0;
678: n = select(statp->_sock + 1,
679: &dsmask, NULL, NULL, &t);
680: }
681: if (n == 0) {
682: Dprint(statp->options & RES_DEBUG,
683: (stdout, ";; timeout\n"));
684: gotsomewhere = 1;
685: goto next_ns;
686: }
687: if (n < 0) {
688: if (errno == EINTR) {
689: if (finish >= cur_time) {
690: timeout = finish - cur_time;
691: goto wait;
692: }
693: }
694: Perror(statp, stderr, "select", errno);
695: res_nclose(statp);
696: goto next_ns;
697: }
698: errno = 0;
699: fromlen = sizeof(struct sockaddr_in);
700: resplen = recvfrom(statp->_sock,
701: (char *)ans, anssiz, 0,
702: (struct sockaddr *)&from, &fromlen);
703: if (resplen <= 0) {
704: Perror(statp, stderr, "recvfrom", errno);
705: res_nclose(statp);
706: goto next_ns;
707: }
708: gotsomewhere = 1;
709: if (resplen < HFIXEDSZ) {
710: /*
711: * Undersized message.
712: */
713: Dprint(statp->options & RES_DEBUG,
714: (stdout, ";; undersized: %d\n",
715: resplen));
716: terrno = ISC_R_NOSPACE;
717: badns |= (1 << ns);
718: res_nclose(statp);
719: goto next_ns;
720: }
721: if (hp->id != anhp->id) {
722: /*
723: * response from old query, ignore it.
724: * XXX - potential security hazard could
725: * be detected here.
726: */
727: DprintQ((statp->options & RES_DEBUG) ||
728: (statp->pfcode & RES_PRF_REPLY),
729: (stdout, ";; old answer:\n"),
730: ans, (resplen>anssiz)?anssiz:resplen);
731: goto wait;
732: }
733: #ifdef CHECK_SRVR_ADDR
734: if (!(statp->options & RES_INSECURE1) &&
735: !res_ourserver_p(statp, &from)) {
736: /*
737: * response from wrong server? ignore it.
738: * XXX - potential security hazard could
739: * be detected here.
740: */
741: DprintQ((statp->options & RES_DEBUG) ||
742: (statp->pfcode & RES_PRF_REPLY),
743: (stdout, ";; not our server:\n"),
744: ans, (resplen>anssiz)?anssiz:resplen);
745: goto wait;
746: }
747: #endif
748: if (!(statp->options & RES_INSECURE2) &&
749: !res_queriesmatch((u_char *)buf,
750: ((u_char *)buf) + buflen,
751: (u_char *)ans,
752: ((u_char *)ans) + anssiz)) {
753: /*
754: * response contains wrong query? ignore it.
755: * XXX - potential security hazard could
756: * be detected here.
757: */
758: DprintQ((statp->options & RES_DEBUG) ||
759: (statp->pfcode & RES_PRF_REPLY),
760: (stdout, ";; wrong query name:\n"),
761: ans, (resplen>anssiz)?anssiz:resplen);
762: goto wait;
763: }
764: if (anhp->rcode == SERVFAIL ||
765: anhp->rcode == NOTIMP ||
766: anhp->rcode == REFUSED) {
767: DprintQ(statp->options & RES_DEBUG,
768: (stdout, "server rejected query:\n"),
769: ans, (resplen>anssiz)?anssiz:resplen);
770: badns |= (1 << ns);
771: res_nclose(statp);
772: /* don't retry if called from dig */
773: if (!statp->pfcode)
774: goto next_ns;
775: }
776: if (!(statp->options & RES_IGNTC) && anhp->tc) {
777: /*
778: * get rest of answer;
779: * use TCP with same server.
780: */
781: Dprint(statp->options & RES_DEBUG,
782: (stdout, ";; truncated answer\n"));
783: v_circuit = 1;
784: res_nclose(statp);
785: goto same_ns;
786: }
787: } /*if vc/dg*/
788: Dprint((statp->options & RES_DEBUG) ||
789: ((statp->pfcode & RES_PRF_REPLY) &&
790: (statp->pfcode & RES_PRF_HEAD1)),
791: (stdout, ";; got answer:\n"));
792: DprintQ((statp->options & RES_DEBUG) ||
793: (statp->pfcode & RES_PRF_REPLY),
794: (stdout, ""),
795: ans, (resplen>anssiz)?anssiz:resplen);
796: /*
797: * If using virtual circuits, we assume that the first server
798: * is preferred over the rest (i.e. it is on the local
799: * machine) and only keep that one open.
800: * If we have temporarily opened a virtual circuit,
801: * or if we haven't been asked to keep a socket open,
802: * close the socket.
803: */
804: if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||
805: !(statp->options & RES_STAYOPEN)) {
806: res_nclose(statp);
807: }
808: if (statp->rhook) {
809: int done = 0, loops = 0;
810:
811: do {
812: res_sendhookact act;
813:
814: act = (*statp->rhook)(nsap, buf, buflen,
815: ans, anssiz, &resplen);
816: switch (act) {
817: case res_goahead:
818: case res_done:
819: done = 1;
820: break;
821: case res_nextns:
822: res_nclose(statp);
823: goto next_ns;
824: case res_modified:
825: /* give the hook another try */
826: if (++loops < 42) /*doug adams*/
827: break;
828: /*FALLTHROUGH*/
829: case res_error:
830: /*FALLTHROUGH*/
831: default:
832: return ISC_R_UNEXPECTED;
833: }
834: } while (!done);
835:
836: }
837: *ansret = resplen;
838: return ISC_R_SUCCESS;
839: next_ns: ;
840: } /*foreach ns*/
841: } /*foreach retry*/
842: res_nclose(statp);
843: if (!v_circuit) {
844: if (!gotsomewhere)
845: terrno = ISC_R_CONNREFUSED; /* no nameservers found */
846: else
847: errno = ISC_R_TIMEDOUT; /* no answer obtained */
848: }
849: return terrno;
850: }
851:
852: /*
853: * This routine is for closing the socket if a virtual circuit is used and
854: * the program wants to close it. This provides support for endhostent()
855: * which expects to close the socket.
856: *
857: * This routine is not expected to be user visible.
858: */
859: void
860: res_nclose(res_state statp) {
861: if (statp->_sock >= 0) {
862: (void) close(statp->_sock);
863: statp->_sock = -1;
864: statp->_flags &= ~(RES_F_VC | RES_F_CONN);
865: }
866: }
867:
868: /* Private */
869: static int
870: cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {
871: return ((a1->sin_family == a2->sin_family) &&
872: (a1->sin_port == a2->sin_port) &&
873: (a1->sin_addr.s_addr == a2->sin_addr.s_addr));
874: }
875:
876: #ifdef NEED_PSELECT
877: /* XXX needs to move to the porting library. */
878: static int
879: pselect(int nfds, void *rfds, void *wfds, void *efds,
880: struct timespec *tsp,
881: const sigset_t *sigmask)
882: {
883: struct timeval tv, *tvp;
884: sigset_t sigs;
885: int n;
886:
887: if (tsp) {
888: tvp = &tv;
889: tv = evTimeVal(*tsp);
890: } else
891: tvp = NULL;
892: if (sigmask)
893: sigprocmask(SIG_SETMASK, sigmask, &sigs);
894: n = select(nfds, rfds, wfds, efds, tvp);
895: if (sigmask)
896: sigprocmask(SIG_SETMASK, &sigs, NULL);
897: if (tsp)
898: *tsp = evTimeSpec(tv);
899: return (n);
900: }
901: #endif