home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / named / tools / nslookup / send.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-24  |  13.3 KB  |  564 lines

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