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