Annotation of embedaddon/dhcp/minires/res_send.c, revision 1.1

1.1     ! misho       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) 2004,2008-2009
        !            56:  * by Internet Systems Consortium, Inc. ("ISC")
        !            57:  * Portions Copyright (c) 1996-2003 by Internet Software Consortium
        !            58:  *
        !            59:  * Permission to use, copy, modify, and distribute this software for any
        !            60:  * purpose with or without fee is hereby granted, provided that the above
        !            61:  * copyright notice and this permission notice appear in all copies.
        !            62:  *
        !            63:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            64:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            65:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            66:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            67:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            68:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            69:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            70:  *
        !            71:  *   Internet Systems Consortium, Inc.
        !            72:  *   950 Charter Street
        !            73:  *   Redwood City, CA 94063
        !            74:  *   <info@isc.org>
        !            75:  *   https://www.isc.org/
        !            76:  */
        !            77: 
        !            78: #if defined(LIBC_SCCS) && !defined(lint)
        !            79: static const char sccsid[] = "@(#)res_send.c   8.1 (Berkeley) 6/4/93";
        !            80: static const char rcsid[] = "$Id: res_send.c,v 1.11.116.2 2009-07-24 22:04:52 sar Exp $";
        !            81: #endif /* LIBC_SCCS and not lint */
        !            82: 
        !            83: /*
        !            84:  * Send query to name server and wait for reply.
        !            85:  */
        !            86: 
        !            87: #include <sys/types.h>
        !            88: #include <sys/param.h>
        !            89: #include <sys/time.h>
        !            90: #include <sys/socket.h>
        !            91: #include <sys/uio.h>
        !            92: 
        !            93: #include <netinet/in.h>
        !            94: #include <arpa/inet.h>
        !            95: 
        !            96: #include <errno.h>
        !            97: #include <netdb.h>
        !            98: #include <signal.h>
        !            99: #include <stdio.h>
        !           100: #include <stdlib.h>
        !           101: #include <string.h>
        !           102: #include <unistd.h>
        !           103: 
        !           104: #include "minires/minires.h"
        !           105: #include "arpa/nameser.h"
        !           106: 
        !           107: /* Rename the I/O functions in case we're tracing. */
        !           108: #include <omapip/omapip_p.h>
        !           109: 
        !           110: ssize_t trace_mr_send(int, const void *, size_t, int);
        !           111: ssize_t trace_mr_recvfrom(int s, void *, size_t, int,
        !           112:                           struct sockaddr *, socklen_t *);
        !           113: ssize_t trace_mr_read(int, void *, size_t);
        !           114: int trace_mr_connect(int s, struct sockaddr *, socklen_t);
        !           115: int trace_mr_socket(int, int, int);
        !           116: int trace_mr_bind(int, struct sockaddr *, socklen_t);
        !           117: int trace_mr_close(int);
        !           118: time_t trace_mr_time(time_t *);
        !           119: int trace_mr_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
        !           120: unsigned int trace_mr_res_randomid(unsigned int);
        !           121: 
        !           122: #undef send
        !           123: #define send            trace_mr_send
        !           124: #undef recvfrom
        !           125: #define recvfrom        trace_mr_recvfrom
        !           126: #undef read
        !           127: #define read            trace_mr_read
        !           128: #undef connect
        !           129: #define connect         trace_mr_connect
        !           130: #undef socket
        !           131: #define socket          trace_mr_socket
        !           132: #undef bind
        !           133: #define bind            trace_mr_bind
        !           134: #undef close
        !           135: #define close           trace_mr_close
        !           136: #undef select
        !           137: #define select          trace_mr_select
        !           138: #undef time
        !           139: #define time            trace_mr_time
        !           140: 
        !           141: #define        CHECK_SRVR_ADDR
        !           142:                
        !           143: static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2);
        !           144: void res_pquery(const res_state, const u_char *, int, FILE *);
        !           145: 
        !           146: /* int
        !           147:  * res_isourserver(ina)
        !           148:  *     looks up "ina" in _res.ns_addr_list[]
        !           149:  * returns:
        !           150:  *     0  : not found
        !           151:  *     >0 : found
        !           152:  * author:
        !           153:  *     paul vixie, 29may94
        !           154:  */
        !           155: int
        !           156: res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) {
        !           157:        struct sockaddr_in ina;
        !           158:        int ns;
        !           159: 
        !           160:        ina = *inp;
        !           161:        for (ns = 0;  ns < statp->nscount;  ns++) {
        !           162:                const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
        !           163: 
        !           164:                if (srv->sin_family == ina.sin_family &&
        !           165:                    srv->sin_port == ina.sin_port &&
        !           166:                    (srv->sin_addr.s_addr == INADDR_ANY ||
        !           167:                     srv->sin_addr.s_addr == ina.sin_addr.s_addr))
        !           168:                        return (1);
        !           169:        }
        !           170:        return (0);
        !           171: }
        !           172: 
        !           173: /* int
        !           174:  * res_nameinquery(name, type, class, buf, eom)
        !           175:  *     look for (name,type,class) in the query section of packet (buf,eom)
        !           176:  * requires:
        !           177:  *     buf + HFIXEDSZ <= eom
        !           178:  * returns:
        !           179:  *     -1 : format error
        !           180:  *     0  : not found
        !           181:  *     >0 : found
        !           182:  * author:
        !           183:  *     paul vixie, 29may94
        !           184:  */
        !           185: int
        !           186: res_nameinquery(const char *name, int type, int class,
        !           187:                const u_char *buf, const u_char *eom)
        !           188: {
        !           189:        const u_char *cp = buf + HFIXEDSZ;
        !           190:        int qdcount = ntohs(((const HEADER *)buf)->qdcount);
        !           191: 
        !           192:        while (qdcount-- > 0) {
        !           193:                char tname[MAXDNAME+1];
        !           194:                int n, ttype, tclass;
        !           195: 
        !           196:                n = dn_expand(buf, eom, cp, tname, sizeof tname);
        !           197:                if (n < 0)
        !           198:                        return (-1);
        !           199:                cp += n;
        !           200:                if (cp + 2 * INT16SZ > eom)
        !           201:                        return (-1);
        !           202:                ttype = getUShort(cp); cp += INT16SZ;
        !           203:                tclass = getUShort(cp); cp += INT16SZ;
        !           204:                if (ttype == type && tclass == class &&
        !           205:                    ns_samename(tname, name) == 1)
        !           206:                        return (1);
        !           207:        }
        !           208:        return (0);
        !           209: }
        !           210: 
        !           211: /* int
        !           212:  * res_queriesmatch(buf1, eom1, buf2, eom2)
        !           213:  *     is there a 1:1 mapping of (name,type,class)
        !           214:  *     in (buf1,eom1) and (buf2,eom2)?
        !           215:  * returns:
        !           216:  *     -1 : format error
        !           217:  *     0  : not a 1:1 mapping
        !           218:  *     >0 : is a 1:1 mapping
        !           219:  * author:
        !           220:  *     paul vixie, 29may94
        !           221:  */
        !           222: int
        !           223: res_queriesmatch(const u_char *buf1, const u_char *eom1,
        !           224:                 const u_char *buf2, const u_char *eom2)
        !           225: {
        !           226:        const u_char *cp = buf1 + HFIXEDSZ;
        !           227:        int qdcount = ntohs(((const HEADER *)buf1)->qdcount);
        !           228: 
        !           229:        if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
        !           230:                return (-1);
        !           231: 
        !           232:        /*
        !           233:         * Only header section present in replies to
        !           234:         * dynamic update packets.
        !           235:         */
        !           236:        if ( (((const HEADER *)buf1)->opcode == ns_o_update) &&
        !           237:             (((const HEADER *)buf2)->opcode == ns_o_update) )
        !           238:                return (1);
        !           239: 
        !           240:        if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
        !           241:                return (0);
        !           242:        while (qdcount-- > 0) {
        !           243:                char tname[MAXDNAME+1];
        !           244:                int n, ttype, tclass;
        !           245: 
        !           246:                n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
        !           247:                if (n < 0)
        !           248:                        return (-1);
        !           249:                cp += n;
        !           250:                if (cp + 2 * INT16SZ > eom1)
        !           251:                        return (-1);
        !           252:                ttype = getUShort(cp);  cp += INT16SZ;
        !           253:                tclass = getUShort(cp); cp += INT16SZ;
        !           254:                if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
        !           255:                        return (0);
        !           256:        }
        !           257:        return (1);
        !           258: }
        !           259: 
        !           260: isc_result_t
        !           261: res_nsend(res_state statp,
        !           262:          double *buf, unsigned buflen,
        !           263:          double *ans, unsigned anssiz, unsigned *ansret)
        !           264: {
        !           265:        HEADER *hp = (HEADER *) buf;
        !           266:        HEADER *anhp = (HEADER *) ans;
        !           267:        int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
        !           268:        u_int badns;    /* XXX NSMAX can't exceed #/bits in this variable */
        !           269:        static int highestFD = FD_SETSIZE - 1;
        !           270: 
        !           271:        if (anssiz < HFIXEDSZ) {
        !           272:                return ISC_R_INVALIDARG;
        !           273:        }
        !           274:        DprintQ((statp->options & RES_DEBUG) ||
        !           275:                (statp->pfcode & RES_PRF_QUERY),
        !           276:                (stdout, ";; res_send()\n"), buf, buflen);
        !           277:        v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
        !           278:        gotsomewhere = 0;
        !           279:        connreset = 0;
        !           280:        terrno = ISC_R_TIMEDOUT;
        !           281:        badns = 0;
        !           282: 
        !           283:        /*
        !           284:         * Some callers want to even out the load on their resolver list.
        !           285:         */
        !           286:        if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) {
        !           287:                struct sockaddr_in ina;
        !           288:                int lastns = statp->nscount - 1;
        !           289: 
        !           290:                ina = statp->nsaddr_list[0];
        !           291:                for (ns = 0; ns < lastns; ns++)
        !           292:                        statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
        !           293:                statp->nsaddr_list[lastns] = ina;
        !           294:        }
        !           295: 
        !           296: #if defined (TRACING)
        !           297:        trace_mr_statp_setup (statp);
        !           298: #endif
        !           299: 
        !           300:        /*
        !           301:         * Send request, RETRY times, or until successful
        !           302:         */
        !           303:        for (try = 0; try < statp->retry; try++) {
        !           304:            for (ns = 0; ns < statp->nscount; ns++) {
        !           305:                struct sockaddr_in *nsap = &statp->nsaddr_list[ns];
        !           306:  same_ns:
        !           307:                if (badns & (1 << ns)) {
        !           308:                        res_nclose(statp);
        !           309:                        goto next_ns;
        !           310:                }
        !           311: 
        !           312:                if (statp->qhook) {
        !           313:                        int done = 0, loops = 0;
        !           314: 
        !           315:                        do {
        !           316:                                res_sendhookact act;
        !           317: 
        !           318:                                act = (*statp->qhook)(&nsap, &buf, &buflen,
        !           319:                                                      ans, anssiz, &resplen);
        !           320:                                switch (act) {
        !           321:                                case res_goahead:
        !           322:                                        done = 1;
        !           323:                                        break;
        !           324:                                case res_nextns:
        !           325:                                        res_nclose(statp);
        !           326:                                        goto next_ns;
        !           327:                                case res_done:
        !           328:                                        return (resplen);
        !           329:                                case res_modified:
        !           330:                                        /* give the hook another try */
        !           331:                                        if (++loops < 42) /*doug adams*/
        !           332:                                                break;
        !           333:                                        /*FALLTHROUGH*/
        !           334:                                case res_error:
        !           335:                                        /*FALLTHROUGH*/
        !           336:                                default:
        !           337:                                        return ISC_R_UNEXPECTED;
        !           338:                                }
        !           339:                        } while (!done);
        !           340:                }
        !           341: 
        !           342:                Dprint(statp->options & RES_DEBUG,
        !           343:                       (stdout, ";; Querying server (# %d) address = %s\n",
        !           344:                        ns + 1, inet_ntoa(nsap->sin_addr)));
        !           345: 
        !           346:                if (v_circuit) {
        !           347:                        int truncated;
        !           348:                        struct iovec iov[2];
        !           349:                        u_short len;
        !           350:                        u_char *cp;
        !           351: 
        !           352:                        /* Use VC; at most one attempt per server. */
        !           353:                        try = statp->retry;
        !           354:                        truncated = 0;
        !           355: 
        !           356:                        /* Are we still talking to whom we want to talk to? */
        !           357:                        if (statp->_sock >= 0 &&
        !           358:                            (statp->_flags & RES_F_VC) != 0) {
        !           359:                                struct sockaddr_in peer;
        !           360:                                SOCKLEN_T size = sizeof(peer);
        !           361: 
        !           362:                                if (getpeername(statp->_sock,
        !           363:                                                (struct sockaddr *)&peer,
        !           364:                                                &size) < 0) {
        !           365:                                        res_nclose(statp);
        !           366:                                        statp->_flags &= ~RES_F_VC;
        !           367:                                } else if (!cmpsock(&peer, nsap)) {
        !           368:                                        res_nclose(statp);
        !           369:                                        statp->_flags &= ~RES_F_VC;
        !           370:                                }
        !           371:                        }
        !           372: 
        !           373:                        if (statp->_sock < 0 ||
        !           374:                            (statp->_flags & RES_F_VC) == 0) {
        !           375:                                if (statp->_sock >= 0)
        !           376:                                        res_nclose(statp);
        !           377: 
        !           378:                                statp->_sock = socket(PF_INET,
        !           379:                                                       SOCK_STREAM, 0);
        !           380:                                if (statp->_sock < 0 ||
        !           381:                                    statp->_sock > highestFD) {
        !           382:                                        terrno = uerr2isc (errno);
        !           383:                                        Perror(statp, stderr,
        !           384:                                               "socket(vc)", errno);
        !           385:                                        return (-1);
        !           386:                                }
        !           387:                                errno = 0;
        !           388:                                if (connect(statp->_sock,
        !           389:                                            (struct sockaddr *)nsap,
        !           390:                                            sizeof *nsap) < 0) {
        !           391:                                        terrno = uerr2isc (errno);
        !           392:                                        Aerror(statp, stderr, "connect/vc",
        !           393:                                               errno, *nsap);
        !           394:                                        badns |= (1 << ns);
        !           395:                                        res_nclose(statp);
        !           396:                                        goto next_ns;
        !           397:                                }
        !           398:                                statp->_flags |= RES_F_VC;
        !           399:                        }
        !           400:                        /*
        !           401:                         * Send length & message
        !           402:                         */
        !           403:                        putUShort((u_char*)&len, buflen);
        !           404:                        iov[0].iov_base = (caddr_t)&len;
        !           405:                        iov[0].iov_len = INT16SZ;
        !           406:                        iov[1].iov_base = (const caddr_t)buf;
        !           407:                        iov[1].iov_len = buflen;
        !           408:                        if (writev(statp->_sock, iov, 2) !=
        !           409:                            (INT16SZ + buflen)) {
        !           410:                                terrno = uerr2isc (errno);
        !           411:                                Perror(statp, stderr, "write failed", errno);
        !           412:                                badns |= (1 << ns);
        !           413:                                res_nclose(statp);
        !           414:                                goto next_ns;
        !           415:                        }
        !           416:                        /*
        !           417:                         * Receive length & response
        !           418:                         */
        !           419:  read_len:
        !           420:                        cp = (u_char *)ans;
        !           421:                        len = INT16SZ;
        !           422:                        while ((n = read(statp->_sock,
        !           423:                                         (char *)cp, (unsigned)len)) > 0) {
        !           424:                                cp += n;
        !           425:                                if ((len -= n) <= 0)
        !           426:                                        break;
        !           427:                        }
        !           428:                        if (n <= 0) {
        !           429:                                terrno = uerr2isc (errno);
        !           430:                                Perror(statp, stderr, "read failed", errno);
        !           431:                                res_nclose(statp);
        !           432:                                /*
        !           433:                                 * A long running process might get its TCP
        !           434:                                 * connection reset if the remote server was
        !           435:                                 * restarted.  Requery the server instead of
        !           436:                                 * trying a new one.  When there is only one
        !           437:                                 * server, this means that a query might work
        !           438:                                 * instead of failing.  We only allow one reset
        !           439:                                 * per query to prevent looping.
        !           440:                                 */
        !           441:                                if (terrno == ISC_R_CONNREFUSED &&
        !           442:                                    !connreset) {
        !           443:                                        connreset = 1;
        !           444:                                        res_nclose(statp);
        !           445:                                        goto same_ns;
        !           446:                                }
        !           447:                                res_nclose(statp);
        !           448:                                goto next_ns;
        !           449:                        }
        !           450:                        resplen = getUShort ((unsigned char *)ans);
        !           451:                        if (resplen > anssiz) {
        !           452:                                Dprint(statp->options & RES_DEBUG,
        !           453:                                       (stdout, ";; response truncated\n")
        !           454:                                       );
        !           455:                                truncated = 1;
        !           456:                                len = anssiz;
        !           457:                        } else
        !           458:                                len = resplen;
        !           459:                        if (len < HFIXEDSZ) {
        !           460:                                /*
        !           461:                                 * Undersized message.
        !           462:                                 */
        !           463:                                Dprint(statp->options & RES_DEBUG,
        !           464:                                       (stdout, ";; undersized: %d\n", len));
        !           465:                                terrno = ISC_R_NOSPACE;
        !           466:                                badns |= (1 << ns);
        !           467:                                res_nclose(statp);
        !           468:                                goto next_ns;
        !           469:                        }
        !           470:                        cp = (u_char *)ans;
        !           471:                        while (len != 0 &&
        !           472:                               (n = read(statp->_sock,
        !           473:                                         (char *)cp, (unsigned)len))
        !           474:                               > 0) {
        !           475:                                cp += n;
        !           476:                                len -= n;
        !           477:                        }
        !           478:                        if (n <= 0) {
        !           479:                                terrno = uerr2isc (errno);
        !           480:                                Perror(statp, stderr, "read(vc)", errno);
        !           481:                                res_nclose(statp);
        !           482:                                goto next_ns;
        !           483:                        }
        !           484:                        if (truncated) {
        !           485:                                /*
        !           486:                                 * Flush rest of answer
        !           487:                                 * so connection stays in synch.
        !           488:                                 */
        !           489:                                anhp->tc = 1;
        !           490:                                len = resplen - anssiz;
        !           491:                                while (len != 0) {
        !           492:                                        char junk[PACKETSZ];
        !           493: 
        !           494:                                        n = (len > sizeof(junk)
        !           495:                                             ? sizeof(junk)
        !           496:                                             : len);
        !           497:                                        n = read(statp->_sock,
        !           498:                                                 junk, (unsigned)n);
        !           499:                                        if (n > 0)
        !           500:                                                len -= n;
        !           501:                                        else
        !           502:                                                break;
        !           503:                                }
        !           504:                        }
        !           505:                        /*
        !           506:                         * The calling applicating has bailed out of
        !           507:                         * a previous call and failed to arrange to have
        !           508:                         * the circuit closed or the server has got
        !           509:                         * itself confused. Anyway drop the packet and
        !           510:                         * wait for the correct one.
        !           511:                         */
        !           512:                        if (hp->id != anhp->id) {
        !           513:                                DprintQ((statp->options & RES_DEBUG) ||
        !           514:                                        (statp->pfcode & RES_PRF_REPLY),
        !           515:                                        (stdout,
        !           516:                                         ";; old answer (unexpected):\n"),
        !           517:                                        ans, (resplen>anssiz)?anssiz:resplen);
        !           518:                                goto read_len;
        !           519:                        }
        !           520:                } else {
        !           521:                        /*
        !           522:                         * Use datagrams.
        !           523:                         */
        !           524:                        int start, timeout, finish;
        !           525:                        fd_set dsmask;
        !           526:                        struct sockaddr_in from;
        !           527:                        SOCKLEN_T fromlen;
        !           528:                        int seconds;
        !           529: 
        !           530:                        if (statp->_sock < 0 ||
        !           531:                            (statp->_flags & RES_F_VC) != 0) {
        !           532:                                if ((statp->_flags & RES_F_VC) != 0)
        !           533:                                        res_nclose(statp);
        !           534:                                statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);
        !           535:                                if (statp->_sock < 0 ||
        !           536:                                    statp->_sock > highestFD) {
        !           537: #ifndef CAN_RECONNECT
        !           538:  bad_dg_sock:
        !           539: #endif
        !           540:                                        terrno = uerr2isc (errno);
        !           541:                                        Perror(statp, stderr,
        !           542:                                               "socket(dg)", errno);
        !           543:                                        return terrno;
        !           544:                                }
        !           545:                                statp->_flags &= ~RES_F_CONN;
        !           546:                        }
        !           547: #ifndef CANNOT_CONNECT_DGRAM
        !           548:                        /*
        !           549:                         * On a 4.3BSD+ machine (client and server,
        !           550:                         * actually), sending to a nameserver datagram
        !           551:                         * port with no nameserver will cause an
        !           552:                         * ICMP port unreachable message to be returned.
        !           553:                         * If our datagram socket is "connected" to the
        !           554:                         * server, we get an ECONNREFUSED error on the next
        !           555:                         * socket operation, and select returns if the
        !           556:                         * error message is received.  We can thus detect
        !           557:                         * the absence of a nameserver without timing out.
        !           558:                         * If we have sent queries to at least two servers,
        !           559:                         * however, we don't want to remain connected,
        !           560:                         * as we wish to receive answers from the first
        !           561:                         * server to respond.
        !           562:                         */
        !           563:                        if (statp->nscount == 1 || (try == 0 && ns == 0)) {
        !           564:                                /*
        !           565:                                 * Connect only if we are sure we won't
        !           566:                                 * receive a response from another server.
        !           567:                                 */
        !           568:                                if ((statp->_flags & RES_F_CONN) == 0) {
        !           569:                                        if (connect(statp->_sock,
        !           570:                                                    (struct sockaddr *)nsap,
        !           571:                                                    sizeof *nsap) < 0) {
        !           572:                                                Aerror(statp, stderr,
        !           573:                                                       "connect(dg)",
        !           574:                                                       errno, *nsap);
        !           575:                                                badns |= (1 << ns);
        !           576:                                                res_nclose(statp);
        !           577:                                                goto next_ns;
        !           578:                                        }
        !           579:                                        statp->_flags |= RES_F_CONN;
        !           580:                                }
        !           581:                               if (send(statp->_sock,
        !           582:                                       (const char*)buf, (unsigned)buflen, 0)
        !           583:                                  != buflen) {
        !           584:                                        Perror(statp, stderr, "send", errno);
        !           585:                                        badns |= (1 << ns);
        !           586:                                        res_nclose(statp);
        !           587:                                        goto next_ns;
        !           588:                                }
        !           589:                        } else {
        !           590:                                /*
        !           591:                                 * Disconnect if we want to listen
        !           592:                                 * for responses from more than one server.
        !           593:                                 */
        !           594:                                if ((statp->_flags & RES_F_CONN) != 0) {
        !           595: #ifdef CAN_RECONNECT
        !           596:                                        struct sockaddr_in no_addr;
        !           597: 
        !           598:                                        no_addr.sin_family = AF_INET;
        !           599:                                        no_addr.sin_addr.s_addr = INADDR_ANY;
        !           600:                                        no_addr.sin_port = 0;
        !           601:                                        (void) connect(statp->_sock,
        !           602:                                                       (struct sockaddr *)
        !           603:                                                        &no_addr,
        !           604:                                                       sizeof no_addr);
        !           605: #else
        !           606:                                        struct sockaddr_in local_addr;
        !           607:                                        SOCKLEN_T len;
        !           608:                                        int result, s1;
        !           609: 
        !           610:                                        len = sizeof(local_addr);
        !           611:                                        s1 = socket(PF_INET, SOCK_DGRAM, 0);
        !           612:                                        result = getsockname(statp->_sock,
        !           613:                                                (struct sockaddr *)&local_addr,
        !           614:                                                             &len);
        !           615:                                        if (s1 < 0)
        !           616:                                                goto bad_dg_sock;
        !           617:                                        (void) dup2(s1, statp->_sock);
        !           618:                                        (void) close(s1);
        !           619:                                        if (result == 0) {
        !           620:                                                /*
        !           621:                                                 * Attempt to rebind to old
        !           622:                                                 * port.  Note connected socket
        !           623:                                                 * has an sin_addr set.
        !           624:                                                 */
        !           625:                                                local_addr.sin_addr.s_addr =
        !           626:                                                        htonl(0);
        !           627:                                                (void)bind(statp->_sock,
        !           628:                                                           (struct sockaddr *)
        !           629:                                                           &local_addr,
        !           630:                                                           (unsigned)len);
        !           631:                                        }
        !           632:                                        Dprint(statp->options & RES_DEBUG,
        !           633:                                               (stdout, ";; new DG socket\n"));
        !           634: #endif /* CAN_RECONNECT */
        !           635:                                        statp->_flags &= ~RES_F_CONN;
        !           636:                                        errno = 0;
        !           637:                                }
        !           638: #endif /* !CANNOT_CONNECT_DGRAM */
        !           639:                                if (sendto(statp->_sock,
        !           640:                                           (const char *)buf, buflen, 0,
        !           641:                                           (struct sockaddr *)nsap,
        !           642:                                           sizeof *nsap)
        !           643:                                    != buflen) {
        !           644:                                        Aerror(statp, stderr, "sendto", errno, *nsap);
        !           645:                                        badns |= (1 << ns);
        !           646:                                        res_nclose(statp);
        !           647:                                        goto next_ns;
        !           648:                                }
        !           649: #ifndef CANNOT_CONNECT_DGRAM
        !           650:                        }
        !           651: #endif /* !CANNOT_CONNECT_DGRAM */
        !           652: 
        !           653:                        if (statp->_sock < 0 || statp->_sock > highestFD) {
        !           654:                                Perror(statp, stderr,
        !           655:                                       "fd out-of-bounds", EMFILE);
        !           656:                                res_nclose(statp);
        !           657:                                goto next_ns;
        !           658:                        }
        !           659: 
        !           660:                        /*
        !           661:                         * Wait for reply
        !           662:                         */
        !           663:                        seconds = (statp->retrans << try);
        !           664:                        if (try > 0)
        !           665:                                seconds /= statp->nscount;
        !           666:                        if (seconds <= 0)
        !           667:                                seconds = 1;
        !           668:                        start = cur_time;
        !           669:                        timeout = seconds;
        !           670:                        finish = start + timeout;
        !           671:  wait:
        !           672:                        FD_ZERO(&dsmask);
        !           673:                        FD_SET(statp->_sock, &dsmask);
        !           674:                        {
        !           675:                                struct timeval t;
        !           676:                                t.tv_sec = timeout;
        !           677:                                t.tv_usec = 0;
        !           678:                                n = select(statp->_sock + 1,
        !           679:                                           &dsmask, NULL, NULL, &t);
        !           680:                        }
        !           681:                        if (n == 0) {
        !           682:                                Dprint(statp->options & RES_DEBUG,
        !           683:                                       (stdout, ";; timeout\n"));
        !           684:                                gotsomewhere = 1;
        !           685:                                goto next_ns;
        !           686:                        }
        !           687:                        if (n < 0) {
        !           688:                                if (errno == EINTR) {
        !           689:                                        if (finish >= cur_time) {
        !           690:                                                timeout = finish - cur_time;
        !           691:                                                goto wait;
        !           692:                                        }
        !           693:                                }
        !           694:                                Perror(statp, stderr, "select", errno);
        !           695:                                res_nclose(statp);
        !           696:                                goto next_ns;
        !           697:                        }
        !           698:                        errno = 0;
        !           699:                        fromlen = sizeof(struct sockaddr_in);
        !           700:                        resplen = recvfrom(statp->_sock,
        !           701:                                           (char *)ans, anssiz, 0,
        !           702:                                           (struct sockaddr *)&from, &fromlen);
        !           703:                        if (resplen <= 0) {
        !           704:                                Perror(statp, stderr, "recvfrom", errno);
        !           705:                                res_nclose(statp);
        !           706:                                goto next_ns;
        !           707:                        }
        !           708:                        gotsomewhere = 1;
        !           709:                        if (resplen < HFIXEDSZ) {
        !           710:                                /*
        !           711:                                 * Undersized message.
        !           712:                                 */
        !           713:                                Dprint(statp->options & RES_DEBUG,
        !           714:                                       (stdout, ";; undersized: %d\n",
        !           715:                                        resplen));
        !           716:                                terrno = ISC_R_NOSPACE;
        !           717:                                badns |= (1 << ns);
        !           718:                                res_nclose(statp);
        !           719:                                goto next_ns;
        !           720:                        }
        !           721:                        if (hp->id != anhp->id) {
        !           722:                                /*
        !           723:                                 * response from old query, ignore it.
        !           724:                                 * XXX - potential security hazard could
        !           725:                                 *       be detected here.
        !           726:                                 */
        !           727:                                DprintQ((statp->options & RES_DEBUG) ||
        !           728:                                        (statp->pfcode & RES_PRF_REPLY),
        !           729:                                        (stdout, ";; old answer:\n"),
        !           730:                                        ans, (resplen>anssiz)?anssiz:resplen);
        !           731:                                goto wait;
        !           732:                        }
        !           733: #ifdef CHECK_SRVR_ADDR
        !           734:                        if (!(statp->options & RES_INSECURE1) &&
        !           735:                            !res_ourserver_p(statp, &from)) {
        !           736:                                /*
        !           737:                                 * response from wrong server? ignore it.
        !           738:                                 * XXX - potential security hazard could
        !           739:                                 *       be detected here.
        !           740:                                 */
        !           741:                                DprintQ((statp->options & RES_DEBUG) ||
        !           742:                                        (statp->pfcode & RES_PRF_REPLY),
        !           743:                                        (stdout, ";; not our server:\n"),
        !           744:                                        ans, (resplen>anssiz)?anssiz:resplen);
        !           745:                                goto wait;
        !           746:                        }
        !           747: #endif
        !           748:                        if (!(statp->options & RES_INSECURE2) &&
        !           749:                            !res_queriesmatch((u_char *)buf,
        !           750:                                              ((u_char *)buf) + buflen,
        !           751:                                              (u_char *)ans,
        !           752:                                              ((u_char *)ans) + anssiz)) {
        !           753:                                /*
        !           754:                                 * response contains wrong query? ignore it.
        !           755:                                 * XXX - potential security hazard could
        !           756:                                 *       be detected here.
        !           757:                                 */
        !           758:                                DprintQ((statp->options & RES_DEBUG) ||
        !           759:                                        (statp->pfcode & RES_PRF_REPLY),
        !           760:                                        (stdout, ";; wrong query name:\n"),
        !           761:                                        ans, (resplen>anssiz)?anssiz:resplen);
        !           762:                                goto wait;
        !           763:                        }
        !           764:                        if (anhp->rcode == SERVFAIL ||
        !           765:                            anhp->rcode == NOTIMP ||
        !           766:                            anhp->rcode == REFUSED) {
        !           767:                                DprintQ(statp->options & RES_DEBUG,
        !           768:                                        (stdout, "server rejected query:\n"),
        !           769:                                        ans, (resplen>anssiz)?anssiz:resplen);
        !           770:                                badns |= (1 << ns);
        !           771:                                res_nclose(statp);
        !           772:                                /* don't retry if called from dig */
        !           773:                                if (!statp->pfcode)
        !           774:                                        goto next_ns;
        !           775:                        }
        !           776:                        if (!(statp->options & RES_IGNTC) && anhp->tc) {
        !           777:                                /*
        !           778:                                 * get rest of answer;
        !           779:                                 * use TCP with same server.
        !           780:                                 */
        !           781:                                Dprint(statp->options & RES_DEBUG,
        !           782:                                       (stdout, ";; truncated answer\n"));
        !           783:                                v_circuit = 1;
        !           784:                                res_nclose(statp);
        !           785:                                goto same_ns;
        !           786:                        }
        !           787:                } /*if vc/dg*/
        !           788:                Dprint((statp->options & RES_DEBUG) ||
        !           789:                       ((statp->pfcode & RES_PRF_REPLY) &&
        !           790:                        (statp->pfcode & RES_PRF_HEAD1)),
        !           791:                       (stdout, ";; got answer:\n"));
        !           792:                DprintQ((statp->options & RES_DEBUG) ||
        !           793:                        (statp->pfcode & RES_PRF_REPLY),
        !           794:                        (stdout, ""),
        !           795:                        ans, (resplen>anssiz)?anssiz:resplen);
        !           796:                /*
        !           797:                 * If using virtual circuits, we assume that the first server
        !           798:                 * is preferred over the rest (i.e. it is on the local
        !           799:                 * machine) and only keep that one open.
        !           800:                 * If we have temporarily opened a virtual circuit,
        !           801:                 * or if we haven't been asked to keep a socket open,
        !           802:                 * close the socket.
        !           803:                 */
        !           804:                if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||
        !           805:                    !(statp->options & RES_STAYOPEN)) {
        !           806:                        res_nclose(statp);
        !           807:                }
        !           808:                if (statp->rhook) {
        !           809:                        int done = 0, loops = 0;
        !           810: 
        !           811:                        do {
        !           812:                                res_sendhookact act;
        !           813: 
        !           814:                                act = (*statp->rhook)(nsap, buf, buflen,
        !           815:                                                      ans, anssiz, &resplen);
        !           816:                                switch (act) {
        !           817:                                case res_goahead:
        !           818:                                case res_done:
        !           819:                                        done = 1;
        !           820:                                        break;
        !           821:                                case res_nextns:
        !           822:                                        res_nclose(statp);
        !           823:                                        goto next_ns;
        !           824:                                case res_modified:
        !           825:                                        /* give the hook another try */
        !           826:                                        if (++loops < 42) /*doug adams*/
        !           827:                                                break;
        !           828:                                        /*FALLTHROUGH*/
        !           829:                                case res_error:
        !           830:                                        /*FALLTHROUGH*/
        !           831:                                default:
        !           832:                                        return ISC_R_UNEXPECTED;
        !           833:                                }
        !           834:                        } while (!done);
        !           835: 
        !           836:                }
        !           837:                *ansret = resplen;
        !           838:                return ISC_R_SUCCESS;
        !           839:  next_ns: ;
        !           840:           } /*foreach ns*/
        !           841:        } /*foreach retry*/
        !           842:        res_nclose(statp);
        !           843:        if (!v_circuit) {
        !           844:                if (!gotsomewhere)
        !           845:                        terrno = ISC_R_CONNREFUSED;  /* no nameservers found */
        !           846:                else
        !           847:                        errno = ISC_R_TIMEDOUT; /* no answer obtained */
        !           848:        }
        !           849:        return terrno;
        !           850: }
        !           851: 
        !           852: /*
        !           853:  * This routine is for closing the socket if a virtual circuit is used and
        !           854:  * the program wants to close it.  This provides support for endhostent()
        !           855:  * which expects to close the socket.
        !           856:  *
        !           857:  * This routine is not expected to be user visible.
        !           858:  */
        !           859: void
        !           860: res_nclose(res_state statp) {
        !           861:        if (statp->_sock >= 0) {
        !           862:                (void) close(statp->_sock);
        !           863:                statp->_sock = -1;
        !           864:                statp->_flags &= ~(RES_F_VC | RES_F_CONN);
        !           865:        }
        !           866: }
        !           867: 
        !           868: /* Private */
        !           869: static int
        !           870: cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {
        !           871:        return ((a1->sin_family == a2->sin_family) &&
        !           872:                (a1->sin_port == a2->sin_port) &&
        !           873:                (a1->sin_addr.s_addr == a2->sin_addr.s_addr));
        !           874: }
        !           875: 
        !           876: #ifdef NEED_PSELECT
        !           877: /* XXX needs to move to the porting library. */
        !           878: static int
        !           879: pselect(int nfds, void *rfds, void *wfds, void *efds,
        !           880:        struct timespec *tsp,
        !           881:        const sigset_t *sigmask)
        !           882: {
        !           883:        struct timeval tv, *tvp;
        !           884:        sigset_t sigs;
        !           885:        int n;
        !           886: 
        !           887:        if (tsp) {
        !           888:                tvp = &tv;
        !           889:                tv = evTimeVal(*tsp);
        !           890:        } else
        !           891:                tvp = NULL;
        !           892:        if (sigmask)
        !           893:                sigprocmask(SIG_SETMASK, sigmask, &sigs);
        !           894:        n = select(nfds, rfds, wfds, efds, tvp);
        !           895:        if (sigmask)
        !           896:                sigprocmask(SIG_SETMASK, &sigs, NULL);
        !           897:        if (tsp)
        !           898:                *tsp = evTimeSpec(tv);
        !           899:        return (n);
        !           900: }
        !           901: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>