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