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