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