Annotation of embedaddon/dhcp/minires/res_send.c, revision 1.1.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";
1.1.1.1 ! misho      80: static const char rcsid[] = "$Id: res_send.c,v 1.11.116.2 2009/07/24 22:04:52 sar Exp $";
1.1       misho      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>