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