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