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