Annotation of 43BSDReno/usr.sbin/named/tools/nslookup/send.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1985, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are permitted provided
        !             6:  * that: (1) source distributions retain this entire copyright notice and
        !             7:  * comment, and (2) distributions including binaries display the following
        !             8:  * acknowledgement:  ``This product includes software developed by the
        !             9:  * University of California, Berkeley and its contributors'' in the
        !            10:  * documentation or other materials provided with the distribution and in
        !            11:  * all advertising materials mentioning features or use of this software.
        !            12:  * Neither the name of the University nor the names of its contributors may
        !            13:  * be used to endorse or promote products derived from this software without
        !            14:  * specific prior written permission.
        !            15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            18:  */
        !            19: 
        !            20: #ifndef lint
        !            21: static char sccsid[] = "@(#)send.c     5.17 (Berkeley) 6/29/90";
        !            22: #endif /* not lint */
        !            23: 
        !            24: /*
        !            25:  *******************************************************************************
        !            26:  *
        !            27:  *  send.c --
        !            28:  *
        !            29:  *     Routine to send request packets to a name server.
        !            30:  *
        !            31:  *     Based on "@(#)res_send.c  6.25 (Berkeley) 6/1/90".
        !            32:  *
        !            33:  *******************************************************************************
        !            34:  */
        !            35: 
        !            36: 
        !            37: /*
        !            38:  * Send query to name server and wait for reply.
        !            39:  */
        !            40: 
        !            41: #include <sys/param.h>
        !            42: #include <sys/time.h>
        !            43: #include <sys/socket.h>
        !            44: #include <sys/uio.h>
        !            45: #include <netinet/in.h>
        !            46: #include <stdio.h>
        !            47: #include <errno.h>
        !            48: #include <arpa/nameser.h>
        !            49: #include <arpa/inet.h>
        !            50: #include <resolv.h>
        !            51: #include "res.h"
        !            52: 
        !            53: extern int errno;
        !            54: 
        !            55: static int s = -1;     /* socket used for communications */
        !            56: 
        !            57: 
        !            58: #ifndef FD_SET
        !            59: #define        NFDBITS         32
        !            60: #define        FD_SETSIZE      32
        !            61: #define        FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
        !            62: #define        FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
        !            63: #define        FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
        !            64: #define FD_ZERO(p)     bzero((char *)(p), sizeof(*(p)))
        !            65: #endif
        !            66: 
        !            67: #define SR 1           /* SendRequest style */
        !            68: 
        !            69: #ifndef DEBUG
        !            70: #define DEBUG
        !            71: #endif
        !            72: 
        !            73: unsigned short nsport = NAMESERVER_PORT;
        !            74: 
        !            75: 
        !            76: 
        !            77: /*
        !            78:  *******************************************************************************
        !            79:  *
        !            80:  *   SendRequest --
        !            81:  *
        !            82:  *     Sends a request packet to a name server whose address
        !            83:  *     is specified by the first argument and returns with
        !            84:  *     the answer packet.
        !            85:  *
        !            86:  *  Results:
        !            87:  *     SUCCESS         - the request was sent and an answer
        !            88:  *                       was received.
        !            89:  *     TIME_OUT        - the virtual circuit connection timed-out
        !            90:  *                       or a reply to a datagram wasn't received.
        !            91:  *
        !            92:  *
        !            93:  *******************************************************************************
        !            94:  */
        !            95: 
        !            96: int
        !            97: SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
        !            98:        struct in_addr  *nsAddrPtr;
        !            99:        char            *buf;
        !           100:        int             buflen;
        !           101:        char            *answer;
        !           102:        u_int           anslen;
        !           103:        int             *trueLenPtr;
        !           104: {
        !           105:        register int n;
        !           106:        int try, v_circuit, resplen, ns;
        !           107:        int gotsomewhere = 0, connected = 0;
        !           108:        int connreset = 0;
        !           109:        u_short id, len;
        !           110:        char *cp;
        !           111:        fd_set dsmask;
        !           112:        struct timeval timeout;
        !           113:        HEADER *hp = (HEADER *) buf;
        !           114:        HEADER *anhp = (HEADER *) answer;
        !           115:        struct iovec iov[2];
        !           116:        int terrno = ETIMEDOUT;
        !           117:        char junk[512];
        !           118: 
        !           119: #if SR
        !           120:        struct sockaddr_in sin;
        !           121: 
        !           122:        if (_res.options & RES_DEBUG2) {
        !           123:            printf("------------\nSendRequest(), len %d\n", buflen);
        !           124:            Print_query(buf, buf+buflen, 1);
        !           125:        }
        !           126:        sin.sin_family  = AF_INET;
        !           127:        sin.sin_port    = htons(nsport);
        !           128:        sin.sin_addr    = *nsAddrPtr;
        !           129: #else
        !           130: #ifdef DEBUG
        !           131:        if (_res.options & RES_DEBUG) {
        !           132:                printf("res_send()\n");
        !           133:                p_query(buf);
        !           134:        }
        !           135: #endif DEBUG
        !           136:        if (!(_res.options & RES_INIT))
        !           137:                if (res_init() == -1) {
        !           138:                        return(-1);
        !           139:                }
        !           140: #endif /* SR */
        !           141:        v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
        !           142:        id = hp->id;
        !           143:        /*
        !           144:         * Send request, RETRY times, or until successful
        !           145:         */
        !           146:        for (try = 0; try < _res.retry; try++) {
        !           147: #if !SR
        !           148:           for (ns = 0; ns < _res.nscount; ns++) {
        !           149: #ifdef DEBUG
        !           150:                if (_res.options & RES_DEBUG)
        !           151:                        printf("Querying server (# %d) address = %s\n", ns+1,
        !           152:                              inet_ntoa(_res.nsaddr_list[ns].sin_addr));
        !           153: #endif DEBUG
        !           154: #endif /* !SR */
        !           155:        usevc:
        !           156:                if (v_circuit) {
        !           157:                        int truncated = 0;
        !           158: 
        !           159:                        /*
        !           160:                         * Use virtual circuit;
        !           161:                         * at most one attempt per server.
        !           162:                         */
        !           163:                        try = _res.retry;
        !           164:                        if (s < 0) {
        !           165:                                s = socket(AF_INET, SOCK_STREAM, 0);
        !           166:                                if (s < 0) {
        !           167:                                        terrno = errno;
        !           168: #ifdef DEBUG
        !           169:                                        if (_res.options & RES_DEBUG)
        !           170:                                            perror("socket (vc) failed");
        !           171: #endif DEBUG
        !           172:                                        continue;
        !           173:                                }
        !           174: #if SR
        !           175:                                if (connect(s, &sin,
        !           176: #else
        !           177:                                if (connect(s, &(_res.nsaddr_list[ns]),
        !           178: #endif
        !           179:                                   sizeof(struct sockaddr)) < 0) {
        !           180:                                        terrno = errno;
        !           181: #ifdef DEBUG
        !           182:                                        if (_res.options & RES_DEBUG)
        !           183:                                            perror("connect failed");
        !           184: #endif DEBUG
        !           185:                                        (void) close(s);
        !           186:                                        s = -1;
        !           187:                                        continue;
        !           188:                                }
        !           189:                        }
        !           190:                        /*
        !           191:                         * Send length & message
        !           192:                         */
        !           193:                        len = htons((u_short)buflen);
        !           194:                        iov[0].iov_base = (caddr_t)&len;
        !           195:                        iov[0].iov_len = sizeof(len);
        !           196:                        iov[1].iov_base = buf;
        !           197:                        iov[1].iov_len = buflen;
        !           198:                        if (writev(s, iov, 2) != sizeof(len) + buflen) {
        !           199:                                terrno = errno;
        !           200: #ifdef DEBUG
        !           201:                                if (_res.options & RES_DEBUG)
        !           202:                                        perror("write failed");
        !           203: #endif DEBUG
        !           204:                                (void) close(s);
        !           205:                                s = -1;
        !           206:                                continue;
        !           207:                        }
        !           208:                        /*
        !           209:                         * Receive length & response
        !           210:                         */
        !           211:                        cp = answer;
        !           212:                        len = sizeof(short);
        !           213:                        while (len != 0 &&
        !           214:                            (n = read(s, (char *)cp, (int)len)) > 0) {
        !           215:                                cp += n;
        !           216:                                len -= n;
        !           217:                        }
        !           218:                        if (n <= 0) {
        !           219:                                terrno = errno;
        !           220: #ifdef DEBUG
        !           221:                                if (_res.options & RES_DEBUG)
        !           222:                                        perror("read failed");
        !           223: #endif DEBUG
        !           224:                                (void) close(s);
        !           225:                                s = -1;
        !           226:                                /*
        !           227:                                 * A long running process might get its TCP
        !           228:                                 * connection reset if the remote server was
        !           229:                                 * restarted.  Requery the server instead of
        !           230:                                 * trying a new one.  When there is only one
        !           231:                                 * server, this means that a query might work
        !           232:                                 * instead of failing.  We only allow one reset
        !           233:                                 * per query to prevent looping.
        !           234:                                 */
        !           235:                                if (terrno == ECONNRESET && !connreset) {
        !           236:                                        connreset = 1;
        !           237:                                        ns--;
        !           238:                                }
        !           239:                                continue;
        !           240:                        }
        !           241:                        cp = answer;
        !           242:                        if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
        !           243: #ifdef DEBUG
        !           244:                                if (_res.options & RES_DEBUG)
        !           245:                                        fprintf(stderr, "response truncated\n");
        !           246: #endif DEBUG
        !           247:                                len = anslen;
        !           248:                                truncated = 1;
        !           249:                        } else
        !           250:                                len = resplen;
        !           251:                        while (len != 0 &&
        !           252:                           (n = read(s, (char *)cp, (int)len)) > 0) {
        !           253:                                cp += n;
        !           254:                                len -= n;
        !           255:                        }
        !           256:                        if (n <= 0) {
        !           257:                                terrno = errno;
        !           258: #ifdef DEBUG
        !           259:                                if (_res.options & RES_DEBUG)
        !           260:                                        perror("read failed");
        !           261: #endif DEBUG
        !           262:                                (void) close(s);
        !           263:                                s = -1;
        !           264:                                continue;
        !           265:                        }
        !           266:                        if (truncated) {
        !           267:                                /*
        !           268:                                 * Flush rest of answer
        !           269:                                 * so connection stays in synch.
        !           270:                                 */
        !           271:                                anhp->tc = 1;
        !           272:                                len = resplen - anslen;
        !           273:                                while (len != 0) {
        !           274:                                        n = (len > sizeof(junk) ?
        !           275:                                            sizeof(junk) : len);
        !           276:                                        if ((n = read(s, junk, n)) > 0)
        !           277:                                                len -= n;
        !           278:                                        else
        !           279:                                                break;
        !           280:                                }
        !           281:                        }
        !           282:                } else {
        !           283:                        /*
        !           284:                         * Use datagrams.
        !           285:                         */
        !           286:                        if (s < 0) {
        !           287:                                s = socket(AF_INET, SOCK_DGRAM, 0);
        !           288:                                if (s < 0) {
        !           289:                                        terrno = errno;
        !           290: #ifdef DEBUG
        !           291:                                        if (_res.options & RES_DEBUG)
        !           292:                                            perror("socket (dg) failed");
        !           293: #endif DEBUG
        !           294:                                        continue;
        !           295:                                }
        !           296:                        }
        !           297: #if SR
        !           298:                        /*
        !           299:                         * Special case the send code below
        !           300:                         * since we have just 1 server.
        !           301:                         */
        !           302: #if BSD >= 43
        !           303:                                if (connected == 0) {
        !           304:                                        if (connect(s, &sin,
        !           305:                                            sizeof(struct sockaddr)) < 0) {
        !           306:                                                if (_res.options & RES_DEBUG)
        !           307:                                                        perror("connect");
        !           308:                                                continue;
        !           309:                                        }
        !           310:                                        connected = 1;
        !           311:                                }
        !           312:                                if (send(s, buf, buflen, 0) != buflen) {
        !           313:                                        if (_res.options & RES_DEBUG)
        !           314:                                                perror("send");
        !           315:                                        continue;
        !           316:                                }
        !           317: #else /* BSD */
        !           318:                                if (sendto(s, buf, buflen, 0, &sin,
        !           319:                                    sizeof(struct sockaddr)) != buflen) {
        !           320:                                        if (_res.options & RES_DEBUG)
        !           321:                                                perror("sendto");
        !           322:                                        continue;
        !           323:                                }
        !           324: #endif
        !           325: #else /* SR */
        !           326: #if    BSD >= 43
        !           327:                        /*
        !           328:                         * I'm tired of answering this question, so:
        !           329:                         * On a 4.3BSD+ machine (client and server,
        !           330:                         * actually), sending to a nameserver datagram
        !           331:                         * port with no nameserver will cause an
        !           332:                         * ICMP port unreachable message to be returned.
        !           333:                         * If our datagram socket is "connected" to the
        !           334:                         * server, we get an ECONNREFUSED error on the next
        !           335:                         * socket operation, and select returns if the
        !           336:                         * error message is received.  We can thus detect
        !           337:                         * the absence of a nameserver without timing out.
        !           338:                         * If we have sent queries to at least two servers,
        !           339:                         * however, we don't want to remain connected,
        !           340:                         * as we wish to receive answers from the first
        !           341:                         * server to respond.
        !           342:                         */
        !           343:                        if (_res.nscount == 1 || (try == 0 && ns == 0)) {
        !           344:                                /*
        !           345:                                 * Don't use connect if we might
        !           346:                                 * still receive a response
        !           347:                                 * from another server.
        !           348:                                 */
        !           349:                                if (connected == 0) {
        !           350:                                        if (connect(s, &_res.nsaddr_list[ns],
        !           351:                                            sizeof(struct sockaddr)) < 0) {
        !           352: #ifdef DEBUG
        !           353:                                                if (_res.options & RES_DEBUG)
        !           354:                                                        perror("connect");
        !           355: #endif DEBUG
        !           356:                                                continue;
        !           357:                                        }
        !           358:                                        connected = 1;
        !           359:                                }
        !           360:                                if (send(s, buf, buflen, 0) != buflen) {
        !           361: #ifdef DEBUG
        !           362:                                        if (_res.options & RES_DEBUG)
        !           363:                                                perror("send");
        !           364: #endif DEBUG
        !           365:                                        continue;
        !           366:                                }
        !           367:                        } else {
        !           368:                                /*
        !           369:                                 * Disconnect if we want to listen
        !           370:                                 * for responses from more than one server.
        !           371:                                 */
        !           372:                                if (connected) {
        !           373:                                        (void) connect(s, &no_addr,
        !           374:                                            sizeof(no_addr));
        !           375:                                        connected = 0;
        !           376:                                }
        !           377: #endif BSD
        !           378:                                if (sendto(s, buf, buflen, 0,
        !           379:                                    &_res.nsaddr_list[ns],
        !           380:                                    sizeof(struct sockaddr)) != buflen) {
        !           381: #ifdef DEBUG
        !           382:                                        if (_res.options & RES_DEBUG)
        !           383:                                                perror("sendto");
        !           384: #endif DEBUG
        !           385:                                        continue;
        !           386:                                }
        !           387: #if    BSD >= 43
        !           388:                        }
        !           389: #endif
        !           390: #endif /* SR */
        !           391: 
        !           392:                        /*
        !           393:                         * Wait for reply
        !           394:                         */
        !           395:                        timeout.tv_sec = (_res.retrans << try);
        !           396: #if !SR
        !           397:                        if (try > 0)
        !           398:                                timeout.tv_sec /= _res.nscount;
        !           399: #endif /* SR */
        !           400:                        if (timeout.tv_sec <= 0)
        !           401:                                timeout.tv_sec = 1;
        !           402:                        timeout.tv_usec = 0;
        !           403: wait:
        !           404:                        FD_ZERO(&dsmask);
        !           405:                        FD_SET(s, &dsmask);
        !           406:                        n = select(s+1, &dsmask, (fd_set *)NULL,
        !           407:                                (fd_set *)NULL, &timeout);
        !           408:                        if (n < 0) {
        !           409: #ifdef DEBUG
        !           410:                                if (_res.options & RES_DEBUG)
        !           411:                                        perror("select");
        !           412: #endif DEBUG
        !           413:                                continue;
        !           414:                        }
        !           415:                        if (n == 0) {
        !           416:                                /*
        !           417:                                 * timeout
        !           418:                                 */
        !           419: #ifdef DEBUG
        !           420:                                if (_res.options & RES_DEBUG)
        !           421:                                        printf("timeout (%d secs)\n", 
        !           422:                                                timeout.tv_sec);
        !           423: #endif DEBUG
        !           424: #if BSD >= 43
        !           425:                                gotsomewhere = 1;
        !           426: #endif
        !           427:                                continue;
        !           428:                        }
        !           429:                        if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
        !           430: #ifdef DEBUG
        !           431:                                if (_res.options & RES_DEBUG)
        !           432:                                        perror("recvfrom");
        !           433: #endif DEBUG
        !           434:                                continue;
        !           435:                        }
        !           436:                        gotsomewhere = 1;
        !           437:                        if (id != anhp->id) {
        !           438:                                /*
        !           439:                                 * response from old query, ignore it
        !           440:                                 */
        !           441: #if SR
        !           442:                                if (_res.options & RES_DEBUG2) {
        !           443:                                        printf("------------\nOld answer:\n");
        !           444:                                        Print_query(answer, answer+resplen, 1);
        !           445:                                }
        !           446: #else
        !           447: #ifdef DEBUG
        !           448:                                if (_res.options & RES_DEBUG) {
        !           449:                                        printf("old answer:\n");
        !           450:                                        p_query(answer);
        !           451:                                }
        !           452: #endif DEBUG
        !           453: #endif
        !           454:                                goto wait;
        !           455:                        }
        !           456:                        if (!(_res.options & RES_IGNTC) && anhp->tc) {
        !           457:                                /*
        !           458:                                 * get rest of answer;
        !           459:                                 * use TCP with same server.
        !           460:                                 */
        !           461: #ifdef DEBUG
        !           462:                                if (_res.options & RES_DEBUG)
        !           463:                                        printf("truncated answer\n");
        !           464: #endif DEBUG
        !           465:                                (void) close(s);
        !           466:                                s = -1;
        !           467:                                v_circuit = 1;
        !           468:                                goto usevc;
        !           469:                        }
        !           470:                }
        !           471: #if SR
        !           472:                if (_res.options & RES_DEBUG) {
        !           473:                    if (_res.options & RES_DEBUG2)
        !           474:                        printf("------------\nGot answer (%d bytes):\n",
        !           475:                            resplen);
        !           476:                    else
        !           477:                        printf("------------\nGot answer:\n");
        !           478:                    Print_query(answer, answer+resplen, 1);
        !           479:                }
        !           480:                (void) close(s);
        !           481:                s = -1;
        !           482:                *trueLenPtr = resplen;
        !           483:                return (SUCCESS);
        !           484: #else
        !           485: #ifdef DEBUG
        !           486:                if (_res.options & RES_DEBUG) {
        !           487:                        printf("got answer:\n");
        !           488:                        p_query(answer);
        !           489:                }
        !           490: #endif DEBUG
        !           491:                /*
        !           492:                 * If using virtual circuits, we assume that the first server
        !           493:                 * is preferred * over the rest (i.e. it is on the local
        !           494:                 * machine) and only keep that one open.
        !           495:                 * If we have temporarily opened a virtual circuit,
        !           496:                 * or if we haven't been asked to keep a socket open,
        !           497:                 * close the socket.
        !           498:                 */
        !           499:                if ((v_circuit &&
        !           500:                    ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
        !           501:                    (_res.options & RES_STAYOPEN) == 0) {
        !           502:                        (void) close(s);
        !           503:                        s = -1;
        !           504:                }
        !           505:                return (resplen);
        !           506:           }
        !           507: #endif /* SR */
        !           508:        }
        !           509:        if (s >= 0) {
        !           510:                (void) close(s);
        !           511:                s = -1;
        !           512:        }
        !           513: #if SR
        !           514:        if (v_circuit == 0)
        !           515:                if (gotsomewhere == 0)
        !           516:                        return NO_RESPONSE;     /* no nameservers found */
        !           517:                else
        !           518:                        return TIME_OUT;        /* no answer obtained */
        !           519:        else
        !           520:                if (errno == ECONNREFUSED)
        !           521:                        return NO_RESPONSE;
        !           522:                else
        !           523:                        return ERROR;
        !           524: #else
        !           525:        if (v_circuit == 0)
        !           526:                if (gotsomewhere == 0)
        !           527:                        errno = ECONNREFUSED;   /* no nameservers found */
        !           528:                else
        !           529:                        errno = ETIMEDOUT;      /* no answer obtained */
        !           530:        else
        !           531:                errno = terrno;
        !           532:        return (-1);
        !           533: #endif
        !           534: }
        !           535: 
        !           536: /*
        !           537:  * This routine is for closing the socket if a virtual circuit is used and
        !           538:  * the program wants to close it.
        !           539:  *
        !           540:  * Called from the interrupt handler.
        !           541:  */
        !           542: SendRequest_close()
        !           543: {
        !           544:        if (s != -1) {
        !           545:                (void) close(s);
        !           546:                s = -1;
        !           547:        }
        !           548: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.