Annotation of 43BSDReno/usr.sbin/named/tools/nslookup/send.c, revision 1.1.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.