home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / bind / bind-4.001 / bind-4~ / bind-4.9.3-BETA9 / named / ns_forw.c < prev    next >
C/C++ Source or Header  |  1994-07-23  |  26KB  |  910 lines

  1. #if !defined(lint) && !defined(SABER)
  2. static char sccsid[] = "@(#)ns_forw.c    4.32 (Berkeley) 3/3/91";
  3. static char rcsid[] = "$Id: ns_forw.c,v 4.9.1.17 1994/07/23 23:23:56 vixie Exp $";
  4. #endif /* not lint */
  5.  
  6. /*
  7.  * ++Copyright++ 1986
  8.  * -
  9.  * Copyright (c) 1986
  10.  *    The Regents of the University of California.  All rights reserved.
  11.  * 
  12.  * Redistribution and use in source and binary forms, with or without
  13.  * modification, are permitted provided that the following conditions
  14.  * are met:
  15.  * 1. Redistributions of source code must retain the above copyright
  16.  *    notice, this list of conditions and the following disclaimer.
  17.  * 2. Redistributions in binary form must reproduce the above copyright
  18.  *    notice, this list of conditions and the following disclaimer in the
  19.  *    documentation and/or other materials provided with the distribution.
  20.  * 3. All advertising materials mentioning features or use of this software
  21.  *    must display the following acknowledgement:
  22.  *     This product includes software developed by the University of
  23.  *     California, Berkeley and its contributors.
  24.  * 4. Neither the name of the University nor the names of its contributors
  25.  *    may be used to endorse or promote products derived from this software
  26.  *    without specific prior written permission.
  27.  * 
  28.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  29.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  30.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  32.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  33.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  34.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  37.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  38.  * SUCH DAMAGE.
  39.  * -
  40.  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
  41.  * 
  42.  * Permission to use, copy, modify, and distribute this software for any
  43.  * purpose with or without fee is hereby granted, provided that the above
  44.  * copyright notice and this permission notice appear in all copies, and that
  45.  * the name of Digital Equipment Corporation not be used in advertising or
  46.  * publicity pertaining to distribution of the document or software without
  47.  * specific, written prior permission.
  48.  * 
  49.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  50.  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
  51.  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
  52.  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  53.  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  54.  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  55.  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  56.  * SOFTWARE.
  57.  * -
  58.  * --Copyright--
  59.  */
  60.  
  61. #include <sys/param.h>
  62. #include <sys/socket.h>
  63. #include <netinet/in.h>
  64. #include <arpa/inet.h>
  65. #include <arpa/nameser.h>
  66.  
  67. #include <syslog.h>
  68. #include <resolv.h>
  69. #include <stdio.h>
  70. #include <errno.h>
  71.  
  72. #include "named.h"
  73.  
  74. /*
  75.  * Forward the query to get the answer since its not in the database.
  76.  * Returns FW_OK if a request struct is allocated and the query sent.
  77.  * Returns FW_DUP if this is a duplicate of a pending request. 
  78.  * Returns FW_NOSERVER if there were no addresses for the nameservers.
  79.  * Returns FW_SERVFAIL on malloc error or if asked to do something
  80.  * dangerous, such as fwd to ourselves or fwd to the host that asked us.
  81.  *
  82.  * (no action is taken on errors and qpp is not filled in.)
  83.  */
  84. int
  85. ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np)
  86.     struct databuf *nsp[];
  87.     u_char *msg;
  88.     int msglen;
  89.     struct sockaddr_in *fp;
  90.     struct qstream *qsp;
  91.     int dfd;
  92.     struct qinfo **qpp;
  93.     char *dname;
  94.     struct namebuf *np;
  95. {
  96.     register struct qinfo *qp;
  97.     struct sockaddr_in *nsa;
  98.     HEADER *hp;
  99.     u_int16_t id;
  100.     int n;
  101.  
  102.     dprintf(3, (ddt, "ns_forw()\n"));
  103.  
  104.     hp = (HEADER *) msg;
  105.     id = hp->id;
  106.     /* Look at them all */
  107.     for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
  108.         if (qp->q_id == id &&
  109.             bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
  110.             ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
  111.              bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
  112.             (qp->q_cmsglen == msglen &&
  113.              bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
  114.             dprintf(3, (ddt,
  115.                     "forw: dropped DUP id=%d\n", ntohs(id)));
  116.             nameserIncr(fp->sin_addr, nssRcvdDupQ);
  117.             return (FW_DUP);
  118.         }
  119.     }
  120.  
  121.     qp = qnew();
  122. #ifdef LAME_DELEGATION
  123.     getname(np, qp->q_domain, sizeof qp->q_domain);
  124. #endif
  125.     qp->q_from = *fp;    /* nslookup wants to know this */
  126.     if ((n = nslookup(nsp, qp, dname, "ns_forw")) < 0) {
  127.         dprintf(2, (ddt, "forw: nslookup reports danger\n"));
  128.         qfree(qp);
  129.         return (FW_SERVFAIL);
  130.     } else if (n == 0 && !(forward_only && fwdtab)) {
  131.         dprintf(2, (ddt, "forw: no nameservers found\n"));
  132.         qfree(qp);
  133.         return (FW_NOSERVER);
  134.     }
  135.     qp->q_stream = qsp;
  136.     qp->q_curaddr = 0;
  137.     qp->q_fwd = fwdtab;
  138.     qp->q_dfd = dfd;
  139.     qp->q_id = id;
  140.     qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
  141.     hp->id = qp->q_nsid = htons((u_int16_t)++nsid);
  142.     hp->ancount = 0;
  143.     hp->nscount = 0;
  144.     hp->arcount = 0;
  145.     if ((qp->q_msg = (u_char *)malloc((unsigned)msglen)) == NULL) {
  146.         syslog(LOG_ERR, "forw: %m");
  147.         qfree(qp);
  148.         return (FW_SERVFAIL);
  149.     }
  150.     bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
  151.     if (!qp->q_fwd) {
  152.         hp->rd = 0;
  153.         qp->q_addr[0].stime = tt;
  154.     }
  155.  
  156. #ifdef SLAVE_FORWARD
  157.     if (forward_only)
  158.         schedretry(qp, (time_t)slave_retry);
  159.     else
  160. #endif /* SLAVE_FORWARD */
  161.     schedretry(qp, qp->q_fwd ?(2*RETRYBASE) :retrytime(qp));
  162.  
  163.     nsa = Q_NEXTADDR(qp, 0);
  164.     dprintf(1, (ddt,
  165.         "forw: forw -> [%s].%d ds=%d nsid=%d id=%d %dms retry %dsec\n",
  166.             inet_ntoa(nsa->sin_addr),
  167.             ntohs(nsa->sin_port), ds,
  168.             ntohs(qp->q_nsid), ntohs(qp->q_id),
  169.             (qp->q_addr[0].nsdata != NULL)
  170.                 ? qp->q_addr[0].nsdata->d_nstime
  171.                 : -1,
  172.             qp->q_time - tt.tv_sec));
  173. #ifdef DEBUG
  174.     if (debug >= 10)
  175.         fp_query(msg, ddt);
  176. #endif
  177.     if (sendto(ds, msg, msglen, 0, (struct sockaddr *)nsa,
  178.            sizeof(struct sockaddr_in)) < 0) {
  179.         if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
  180.             syslog(LOG_NOTICE, "ns_forw: sendto([%s].%d): %m",
  181.                    inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
  182.         nameserIncr(nsa->sin_addr, nssSendtoErr);
  183.     }
  184.     nameserIncr(fp->sin_addr, nssRcvdFwdQ);
  185.     nameserIncr(nsa->sin_addr, nssSentFwdQ);
  186.     if (qpp)
  187.         *qpp = qp;
  188.     hp->rd = 1;
  189.     return (0);
  190. }
  191.  
  192. /* struct qdatagram *
  193.  * aIsUs(addr)
  194.  *    scan the datagramq (our list of interface addresses) for "addr"
  195.  * returns:
  196.  *    pointer to qdatagram entry or NULL if no match is found
  197.  * notes:
  198.  *    INADDR_ANY ([0.0.0.0]) is on the datagramq, so it's considered "us"
  199.  * author:
  200.  *    Paul Vixie (DECWRL) April 1991
  201.  */
  202. struct qdatagram *
  203. aIsUs(addr)
  204.     struct in_addr addr;
  205. {
  206.     struct qdatagram *dqp;
  207.  
  208.     for (dqp = datagramq;  dqp != QDATAGRAM_NULL;  dqp = dqp->dq_next) {
  209.         if (addr.s_addr == dqp->dq_addr.s_addr) {
  210.             return dqp;
  211.         }
  212.     }
  213.     return NULL;
  214. }
  215.  
  216. /* haveComplained(tag1, tag2)
  217.  *    check to see if we have complained about (tag1,tag2) recently
  218.  *    (note that these are declared as pointers but are never deref'd)
  219.  * returns:
  220.  *    boolean: have we complained recently?
  221.  * side-effects:
  222.  *    outdated complaint records removed from our static list
  223.  * author:
  224.  *    Paul Vixie (DECWRL) April 1991
  225.  */
  226. int
  227. haveComplained(tag1, tag2)
  228.     char *tag1, *tag2;
  229. {
  230.     struct complaint {
  231.         char *tag1, *tag2;
  232.         time_t expire;
  233.         struct complaint *next;
  234.     };
  235.     static struct complaint *List = NULL;
  236.     struct complaint *cur, *next, *prev;
  237.     int r = 0;
  238.  
  239.     for (cur = List, prev = NULL;  cur;  prev = cur, cur = next) {
  240.         next = cur->next;
  241.         if (tt.tv_sec > cur->expire) {
  242.             if (prev)
  243.                 prev->next = next;
  244.             else
  245.                 List = next;
  246.             free((char*) cur);
  247.             cur = prev;
  248.         } else if ((tag1 == cur->tag1) && (tag2 == cur->tag2)) {
  249.             r++;
  250.         }
  251.     }
  252.     if (!r) {
  253.         cur = (struct complaint *)malloc(sizeof(struct complaint));
  254.         cur->tag1 = tag1;
  255.         cur->tag2 = tag2;
  256.         cur->expire = tt.tv_sec + INIT_REFRESH;    /* "10 minutes" */
  257.         cur->next = NULL;
  258.         if (prev)
  259.             prev->next = cur;
  260.         else
  261.             List = cur;
  262.     }
  263.     return r;
  264. }
  265.  
  266. /* void
  267.  * nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr)
  268.  *    Issue a complaint about a dangerous situation found by nslookup().
  269.  * params:
  270.  *    sysloginfo is a string identifying the complainant.
  271.  *    queryname is the domain name associated with the problem.
  272.  *    complaint is a string describing what is wrong.
  273.  *    dname and a_rr are the problematic other name server.
  274.  */
  275. void
  276. nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr)
  277.     char *sysloginfo, *queryname, *complaint, *dname;
  278.     register struct databuf *a_rr;
  279. {
  280.     dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint));
  281.     if (sysloginfo && queryname && !haveComplained(queryname, complaint))
  282.     {
  283.         char buf[512];
  284.  
  285.         /* syslog only takes 5 params */
  286.         sprintf(buf, "%s: query(%s) %s (%s:%s)",
  287.             sysloginfo, queryname,
  288.             complaint, dname, inet_ntoa(
  289.                 *(struct in_addr*)a_rr->d_data
  290.             ));
  291.         syslog(LOG_INFO, buf);
  292.     }
  293. }
  294.  
  295. /*
  296.  * nslookup(nsp, qp, syslogdname, sysloginfo)
  297.  *    Lookup the address for each nameserver in `nsp' and add it to
  298.  *     the list saved in the qinfo structure pointed to by `qp'.
  299.  *    Omits information about nameservers that we shouldn't ask.
  300.  *    Detects the following dangerous operations:
  301.  *        One of the A records for one of the nameservers in nsp
  302.  *        refers to the address of one of our own interfaces;
  303.  *        One of the A records refers to the nameserver port on
  304.  *        the host that asked us this question.
  305.  * returns: the number of addresses added, or -1 if a dangerous operation
  306.  *    is detected.
  307.  * side effects:
  308.  *    if a dangerous situation is detected and (syslogdname && sysloginfo),
  309.  *    calls syslog.
  310.  */
  311. int
  312. nslookup(nsp, qp, syslogdname, sysloginfo)
  313.     struct databuf *nsp[];
  314.     register struct qinfo *qp;
  315.     char *syslogdname;
  316.     char *sysloginfo;
  317. {
  318.     register struct namebuf *np;
  319.     register struct databuf *dp, *nsdp;
  320.     register struct qserv *qs;
  321.     register int n;
  322.     register unsigned int i;
  323.     struct hashbuf *tmphtp;
  324.     char *dname, *fname;
  325.     int oldn, naddr, class, found_arr;
  326.     time_t curtime;
  327.  
  328.     dprintf(3, (ddt, "nslookup(nsp=0x%x, qp=0x%x, \"%s\")\n",
  329.             nsp, qp, syslogdname));
  330.  
  331.     naddr = n = qp->q_naddr;
  332.     curtime = (u_long) tt.tv_sec;
  333.     while ((nsdp = *nsp++) != NULL) {
  334.         class = nsdp->d_class;
  335.         dname = (char *)nsdp->d_data;
  336.         dprintf(3, (ddt, "nslookup: NS \"%s\" c=%d t=%d (0x%x)\n",
  337.                 dname, class, nsdp->d_type, nsdp->d_flags));
  338.  
  339.         /* don't put in servers we have tried */
  340.         for (i = 0; i < qp->q_nusedns; i++) {
  341.             if (qp->q_usedns[i] == nsdp) {
  342.                 dprintf(2, (ddt,
  343.                         "skipping used NS w/name %s\n",
  344.                         nsdp->d_data));
  345.                 goto skipserver;
  346.             }
  347.         }
  348.  
  349.         tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab);
  350.         np = nlookup(dname, &tmphtp, &fname, 1);
  351.         if (np == NULL || fname != dname) {
  352.             dprintf(3, (ddt, "%s: not found %s %x\n",
  353.                     dname, fname, np));
  354.             continue;
  355.         }
  356.         found_arr = 0;
  357.         oldn = n;
  358.  
  359.         /* look for name server addresses */
  360.         for (dp = np->n_data;  dp != NULL;  dp = dp->d_next) {
  361.             struct in_addr nsa;
  362.  
  363.             if (dp->d_type == T_CNAME && dp->d_class == class)
  364.                 goto skipserver;
  365.             if (dp->d_type != T_A || dp->d_class != class)
  366.                 continue;
  367. #ifdef NCACHE
  368.             if (dp->d_rcode)
  369.                 continue;
  370. #endif
  371.             /*
  372.              * Don't use records that may become invalid to
  373.              * reference later when we do the rtt computation.
  374.              * Never delete our safety-belt information!
  375.              */
  376.             if ((dp->d_zone == 0) &&
  377.                 (dp->d_ttl < (curtime+900)) &&
  378.                 !(dp->d_flags & DB_F_HINT) )
  379.                 {
  380.                 dprintf(3, (ddt,
  381.                         "nslookup: stale entry '%s'\n",
  382.                         np->n_dname));
  383.                 /* Cache invalidate the NS RR's */
  384.                 if (dp->d_ttl < curtime)
  385.                     delete_all(np, class, T_A);
  386.                 n = oldn;
  387.                 break;
  388.             }
  389. #ifdef VALIDATE
  390.             /* anant@isi.edu validation procedure, maintains a
  391.              * table of server names-addresses used recently
  392.              */
  393.             store_name_addr(dname, (struct in_addr *)dp->d_data,
  394.                     syslogdname, sysloginfo);
  395. #endif /*VALIDATE*/
  396.  
  397.             found_arr++;
  398.             nsa = *(struct in_addr *)dp->d_data;
  399.             /* don't put in duplicates */
  400.             qs = qp->q_addr;
  401.             for (i = 0; i < n; i++, qs++)
  402.                 if (qs->ns_addr.sin_addr.s_addr == nsa.s_addr)
  403.                     goto skipaddr;
  404.             qs->ns_addr.sin_family = AF_INET;
  405.             qs->ns_addr.sin_port = ns_port;
  406.             qs->ns_addr.sin_addr = nsa;
  407.             qs->ns = nsdp;
  408.             qs->nsdata = dp;
  409.             qs->nretry = 0;
  410.             /*
  411.              * if we are being asked to fwd a query whose
  412.              * nameserver list includes our own name/address(es),
  413.              * then we have detected a lame delegation and rather
  414.              * than melt down the network and hose down the other
  415.              * servers (who will hose us in return), we'll return
  416.              * -1 here which will cause SERVFAIL to be sent to
  417.              * the client's resolver which will hopefully then
  418.              * shut up.
  419.              *
  420.              * (originally done in nsContainsUs by vix@dec mar92;
  421.              * moved into nslookup by apb@und jan1993)
  422.              */
  423.             if (aIsUs(nsa)) {
  424.                 static char *complaint = "contains our address";
  425.                 nslookupComplain(sysloginfo, syslogdname,
  426.                          complaint, dname, dp);
  427.                 return (-1);
  428.             }
  429.             /*
  430.              * If we want to forward to a host that asked us
  431.              * this question then either we or they are sick
  432.              * (unless they asked from some port other than
  433.              * their nameserver port).  (apb@und jan1993)
  434.              */
  435.             if (bcmp((char *)&qp->q_from, (char *)&qs->ns_addr,
  436.                  sizeof(qp->q_from)) == 0)
  437.             {
  438.                 static char *complaint = "forwarding loop";
  439.                 nslookupComplain(sysloginfo, syslogdname,
  440.                          complaint, dname, dp);
  441.                 return (-1);
  442.             }
  443.             /*
  444.              * Don't forward queries to bogus servers.  Note
  445.              * that this is unlike the previous tests, which
  446.              * are fatal to the query.  Here we just skip the
  447.              * server, which is only fatal if it's the last
  448.              * server.  Note also that we antialias here -- all
  449.              * A RR's of a server are considered the same server,
  450.              * and if any of them is bogus we skip the whole
  451.              * server.  Those of you using multiple A RR's to
  452.              * load-balance your servers will (rightfully) lose
  453.              * here.  But (unfortunately) only if they are bogus.
  454.              */
  455.             if (addr_on_netlist(nsa, boglist))
  456.                 goto skipserver;
  457.  
  458.             n++;
  459.             if (n >= NSMAX)
  460.                 goto out;
  461.     skipaddr:    ;
  462.         }
  463.         dprintf(8, (ddt, "nslookup: %d ns addrs\n", n));
  464.         if (found_arr == 0 && !(qp->q_flags & Q_SYSTEM))
  465.             (void) sysquery(dname, class, T_A, NULL, 0);
  466. skipserver: ;
  467.     }
  468. out:
  469.     dprintf(3, (ddt, "nslookup: %d ns addrs total\n", n));
  470.     qp->q_naddr = n;
  471. #ifdef DATUMREFCNT
  472.     /* must be run before the sort */
  473.     for (i = naddr ; i < n ; i++) {
  474.         qp->q_addr[i].nsdata->d_rcnt++;
  475.         qp->q_addr[i].ns->d_rcnt++;
  476.     }
  477. #endif
  478.     if (n > 1) {
  479.         qsort((char *)qp->q_addr, n, sizeof(struct qserv),
  480.               (int (*)__P((const void *, const void *)))qcomp);
  481.     }
  482.     return (n - naddr);
  483. }
  484.  
  485. /*
  486.  * qcomp - compare two NS addresses, and return a negative, zero, or
  487.  *       positive value depending on whether the first NS address is
  488.  *       "better than", "equally good as", or "inferior to" the second
  489.  *       NS address.
  490.  *
  491.  * How "goodness" is defined (for the purposes of this routine):
  492.  *  - If the estimated round trip times differ by an amount deemed significant
  493.  *    then the one with the smaller estimate is preferred; else
  494.  *  - If we can determine which one is topologically closer then the
  495.  *    closer one is preferred; else
  496.  *  - The one with the smaller estimated round trip time is preferred
  497.  *    (zero is returned if the two estimates are identical).
  498.  *
  499.  * How "topological closeness" is defined (for the purposes of this routine):
  500.  *    Ideally, named could consult some magic map of the Internet and
  501.  *    determine the length of the path to an arbitrary destination.  Sadly,
  502.  *    no such magic map exists.  However, named does have a little bit of
  503.  *    topological information in the form of the sortlist (which includes
  504.  *    the directly connected subnet(s), the directly connected net(s), and
  505.  *    any additional nets that the administrator has added using the "sortlist"
  506.  *    directive in the bootfile.  Thus, if only one of the addresses matches
  507.  *    something in the sortlist then it is considered to be topologically
  508.  *    closer.  If both match, but match different entries in the sortlist,
  509.  *    then the one that matches the entry closer to the beginning of the
  510.  *    sorlist is considered to be topologically closer.  In all other cases,
  511.  *    topological closeness is ignored because it's either indeterminate or
  512.  *    equal.
  513.  *
  514.  * How times are compared:
  515.  *    Both times are rounded to the closest multiple of the NOISE constant
  516.  *    defined below and then compared.  If the rounded values are equal
  517.  *    then the difference in the times is deemed insignificant.  Rounding
  518.  *    is used instead of merely taking the absolute value of the difference
  519.  *    because doing the latter would make the ordering defined by this
  520.  *    routine be incomplete in the mathematical sense (e.g. A > B and
  521.  *    B > C would not imply A > C).  The mathematics are important in
  522.  *    practice to avoid core dumps in qsort().
  523.  *
  524.  * XXX: this doesn't solve the European root nameserver problem very well.
  525.  * XXX: we should detect and mark as inferior nameservers that give bogus
  526.  *      answers
  527.  *
  528.  * (this was originally vixie's stuff but almquist fixed fatal bugs in it
  529.  * and wrote the above documentation)
  530.  */
  531.  
  532. /*
  533.  * RTT delta deemed to be significant, in milliseconds.  With the current
  534.  * definition of RTTROUND it must be a power of 2.
  535.  */
  536. #define NOISE 128        /* milliseconds; 0.128 seconds */
  537.  
  538. #define sign(x) (((x) < 0) ? -1 : ((x) > 0) ? 1 : 0)
  539. #define RTTROUND(rtt) (((rtt) + (NOISE >> 1)) & ~(NOISE - 1))
  540.  
  541. int
  542. qcomp(qs1, qs2)
  543.     struct qserv *qs1, *qs2;
  544. {
  545.     int pos1, pos2, pdiff;
  546.     u_long rtt1, rtt2;
  547.     long tdiff;
  548.  
  549.     if ((!qs1->nsdata) || (!qs2->nsdata))
  550.         return 0;
  551.     rtt1 = qs1->nsdata->d_nstime;
  552.     rtt2 = qs2->nsdata->d_nstime;
  553.  
  554.     dprintf(10, (ddt, "qcomp(%s, %s) %lu (%lu) - %lu (%lu) = %lu",
  555.              inet_ntoa(qs1->ns_addr.sin_addr),
  556.              inet_ntoa(qs2->ns_addr.sin_addr),
  557.              rtt1, RTTROUND(rtt1), rtt2, RTTROUND(rtt2),
  558.              rtt1 - rtt2));
  559.     if (RTTROUND(rtt1) == RTTROUND(rtt2)) {
  560.         pos1 = position_on_netlist(qs1->ns_addr.sin_addr, nettab);
  561.         pos2 = position_on_netlist(qs2->ns_addr.sin_addr, nettab);
  562.         pdiff = pos1 - pos2;
  563.         dprintf(10, (ddt, ", pos1=%d, pos2=%d\n", pos1, pos2));
  564.         if (pdiff)
  565.             return (pdiff);
  566.     } else {
  567.         dprintf(10, (ddt, "\n"));
  568.     }
  569.     tdiff = rtt1 - rtt2;
  570.     return (sign(tdiff));
  571. }
  572. #undef sign
  573. #undef RTTROUND
  574.  
  575. /*
  576.  * Arrange that forwarded query (qp) is retried after t seconds.
  577.  * Query list will be sorted after z_time is updated.
  578.  */
  579. void
  580. schedretry(qp, t)
  581.     struct qinfo *qp;
  582.     time_t t;
  583. {
  584.     register struct qinfo *qp1, *qp2;
  585.  
  586. #ifdef DEBUG
  587.     if (debug > 3) {
  588.         fprintf(ddt,"schedretry(0x%x, %ld sec)\n", qp, (long)t);
  589.         if (qp->q_time)
  590.             fprintf(ddt,
  591.                 "WARNING: schedretry(%#x, %d) q_time already %d\n",
  592.                 qp, t, qp->q_time);
  593.     }
  594. #endif
  595.     t += (u_long) tt.tv_sec;
  596.     qp->q_time = t;
  597.  
  598.     if ((qp1 = retryqp) == NULL) {
  599.         retryqp = qp;
  600.         qp->q_next = NULL;
  601.         return;
  602.     }
  603.     if (t < qp1->q_time) {
  604.         qp->q_next = qp1;
  605.         retryqp = qp;
  606.         return;
  607.     }
  608.     while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
  609.         qp1 = qp2;
  610.     qp1->q_next = qp;
  611.     qp->q_next = qp2;
  612. }
  613.  
  614. /*
  615.  * Unsched is called to remove a forwarded query entry.
  616.  */
  617. void
  618. unsched(qp)
  619.     struct qinfo *qp;
  620. {
  621.     register struct qinfo *np;
  622.  
  623.     dprintf(3, (ddt, "unsched(%#x, %d )\n", qp, ntohs(qp->q_id)));
  624.     if (retryqp == qp) {
  625.         retryqp = qp->q_next;
  626.     } else {
  627.         for (np=retryqp;  np->q_next != QINFO_NULL;  np = np->q_next) {
  628.             if (np->q_next != qp)
  629.                 continue;
  630.             np->q_next = qp->q_next;    /* dequeue */
  631.             break;
  632.         }
  633.     }
  634.     qp->q_next = QINFO_NULL;        /* sanity check */
  635.     qp->q_time = 0;
  636. }
  637.  
  638. /*
  639.  * Retry is called to retransmit query 'qp'.
  640.  */
  641. void
  642. retry(qp)
  643.     register struct qinfo *qp;
  644. {
  645.     register int n;
  646.     register HEADER *hp;
  647.     struct sockaddr_in *nsa;
  648.  
  649.     dprintf(3, (ddt, "retry(x%x) id=%d\n", qp, ntohs(qp->q_id)));
  650.  
  651.     if (qp->q_msg == NULL) {        /* XXX - why? */
  652.         qremove(qp);
  653.         return;
  654.     }
  655.  
  656.     if (qp->q_expire && (qp->q_expire < tt.tv_sec)) {
  657.         dprintf(1, (ddt,
  658.                 "retry(x%x): expired @ %d (%d secs before now (%d))\n",
  659.                 qp, qp->q_expire, tt.tv_sec - qp->q_expire,
  660.                 tt.tv_sec));
  661.         if (qp->q_stream) /* return failure code on stream */
  662.             goto fail;
  663.         qremove(qp);
  664.         return;
  665.     }
  666.  
  667.     /* try next address */
  668.     n = qp->q_curaddr;
  669.     if (qp->q_fwd) {
  670.         qp->q_fwd = qp->q_fwd->next;
  671.         if (qp->q_fwd)
  672.             goto found;
  673.         /* out of forwarders, try direct queries */
  674.     } else
  675.         ++qp->q_addr[n].nretry;
  676.     if (!forward_only) {
  677.         do {
  678.             if (++n >= (int)qp->q_naddr)
  679.                 n = 0;
  680.             if (qp->q_addr[n].nretry < MAXRETRY)
  681.                 goto found;
  682.         } while (n != qp->q_curaddr);
  683.     }
  684. fail:
  685.     /*
  686.      * Give up. Can't reach destination.
  687.      */
  688.     hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
  689.     if (qp->q_flags & Q_PRIMING) {
  690.         /* Can't give up priming */
  691.         unsched(qp);
  692.         schedretry(qp, (time_t)60*60);    /* 1 hour */
  693.         hp->rcode = NOERROR;    /* Lets be safe, reset the query */
  694.         hp->qr = hp->aa = 0;
  695.         qp->q_fwd = fwdtab;
  696.         for (n = 0; n < (int)qp->q_naddr; n++)
  697.             qp->q_addr[n].nretry = 0;
  698.         return;
  699.     }
  700.     dprintf(5, (ddt, "give up\n"));
  701.     n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
  702.     hp->id = qp->q_id;
  703.     hp->qr = 1;
  704.     hp->ra = 1;
  705.     hp->rd = 1;
  706.     hp->rcode = SERVFAIL;
  707. #ifdef DEBUG
  708.     if (debug >= 10)
  709.         fp_query(qp->q_msg, ddt);
  710. #endif
  711.     if (send_msg((u_char *)hp, n, qp)) {
  712.         dprintf(1, (ddt,"gave up retry(x%x) nsid=%d id=%d\n",
  713.                 qp, ntohs(qp->q_nsid), ntohs(qp->q_id)));
  714.     }
  715.     nameserIncr(qp->q_from.sin_addr, nssSentFail);
  716.     qremove(qp);
  717.     return;
  718.  
  719. found:
  720.     if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
  721.         qp->q_addr[n].stime = tt;
  722.     qp->q_curaddr = n;
  723.     hp = (HEADER *)qp->q_msg;
  724.     hp->rd = (qp->q_fwd ? 1 : 0);
  725.     nsa = Q_NEXTADDR(qp, n);
  726.     dprintf(1, (ddt,
  727.             "%s(addr=%d n=%d) -> [%s].%d ds=%d nsid=%d id=%d %dms\n",
  728.             (qp->q_fwd ? "reforw" : "resend"),
  729.             n, qp->q_addr[n].nretry,
  730.             inet_ntoa(nsa->sin_addr),
  731.             ntohs(nsa->sin_port), ds,
  732.             ntohs(qp->q_nsid), ntohs(qp->q_id),
  733.             (qp->q_addr[n].nsdata != 0)
  734.             ? qp->q_addr[n].nsdata->d_nstime
  735.             : (-1)));
  736. #ifdef DEBUG
  737.     if (debug >= 10)
  738.         fp_query(qp->q_msg, ddt);
  739. #endif
  740.     /* NOSTRICT */
  741.     if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
  742.         (struct sockaddr *)nsa,
  743.         sizeof(struct sockaddr_in)) < 0) {
  744.         dprintf(3, (ddt, "error resending msg errno=%d\n", errno));
  745.     }
  746.     hp->rd = 1;    /* leave set to 1 for dup detection */
  747.     nameserIncr(nsa->sin_addr, nssSentDupQ);
  748.     unsched(qp);
  749. #ifdef SLAVE_FORWARD
  750.     if(forward_only)
  751.         schedretry(qp, (time_t)slave_retry);
  752.     else
  753. #endif /* SLAVE_FORWARD */
  754.     schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
  755. }
  756.  
  757. /*
  758.  * Compute retry time for the next server for a query.
  759.  * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
  760.  * service time; * back off exponentially on retries, but place a 45-sec.
  761.  * ceiling on retry times for now.  (This is because we don't hold a reference
  762.  * on servers or their addresses, and we have to finish before they time out.)
  763.  */
  764. time_t
  765. retrytime(qp)
  766.     struct qinfo *qp;
  767. {
  768.     time_t t, u, v;
  769.     struct qserv *ns = &qp->q_addr[qp->q_curaddr];
  770.  
  771.     if (ns->nsdata != NULL)
  772.         t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
  773.     else
  774.         t = (time_t) RETRYBASE;
  775.     u = t << ns->nretry;
  776.     v = MIN(u, RETRY_TIMEOUT);    /* max. retry timeout for now */
  777.     dprintf(3, (ddt, "retrytime: nstime%ldms t%ld nretry%ld u%ld : v%ld\n",
  778.             ns->nsdata ?(long)(ns->nsdata->d_nstime / 1000) :(long)-1,
  779.             (long)t, (long)ns->nretry, (long)u, (long)v));
  780.     return (v);
  781. }
  782.  
  783. void
  784. qflush()
  785. {
  786.     while (qhead)
  787.         qremove(qhead);
  788.     qhead = QINFO_NULL;
  789. }
  790.  
  791. void
  792. qremove(qp)
  793.     register struct qinfo *qp;
  794. {
  795.     dprintf(3, (ddt, "qremove(x%x)\n", qp));
  796.  
  797.     if (qp->q_flags & Q_ZSERIAL)
  798.         qserial_answer(qp, 0);
  799.     unsched(qp);
  800.     qfree(qp);
  801. }
  802.  
  803. #if defined(__STDC__) || defined(__GNUC__)
  804. struct qinfo *
  805. qfindid(u_int16_t id)
  806. #else
  807. struct qinfo *
  808. qfindid(id)
  809.     register u_int16_t id;
  810. #endif
  811. {
  812.     register struct qinfo *qp;
  813.  
  814.     dprintf(3, (ddt, "qfindid(%d)\n", ntohs(id)));
  815.     for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
  816.         if (qp->q_nsid == id)
  817.             return(qp);
  818.     }
  819.     dprintf(5, (ddt, "qp not found\n"));
  820.     return (NULL);
  821. }
  822.  
  823. struct qinfo *
  824. #ifdef DMALLOC
  825. qnew_tagged(file, line)
  826.     char *file;
  827.     int line;
  828. #else
  829. qnew()
  830. #endif
  831. {
  832.     register struct qinfo *qp;
  833.  
  834.     if ((qp = (struct qinfo *)
  835. #ifdef DMALLOC
  836.                   dcalloc(file, line,
  837. #else
  838.                   calloc(
  839. #endif
  840.                      1, sizeof(struct qinfo))) == NULL) {
  841.         dprintf(5, (ddt, "qnew: calloc error\n"));
  842.         syslog(LOG_ERR, "forw: %m");
  843.         exit(12);
  844.     }
  845.     dprintf(5, (ddt, "qnew(x%x)\n", qp));
  846.     qp->q_link = qhead;
  847.     qhead = qp;
  848.     return (qp);
  849. }
  850.  
  851. void
  852. qfree(qp)
  853.     struct qinfo *qp;
  854. {
  855.     register struct qinfo *np;
  856.     register struct databuf *dp;
  857. #ifdef    DATUMREFCNT
  858.     int i;
  859. #endif
  860.  
  861. #ifdef DEBUG
  862.     if(debug > 3)
  863.         fprintf(ddt,"Qfree( x%x )\n", qp);
  864.     if(debug && qp->q_next)
  865.         fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
  866. #endif
  867.     if (qp->q_msg)
  868.          free(qp->q_msg);
  869.      if (qp->q_cmsg)
  870.          free(qp->q_cmsg);
  871. #ifdef    DATUMREFCNT
  872.     for (i = 0 ; i < (int)qp->q_naddr ; i++) {
  873.         dp = qp->q_addr[i].ns;
  874.         if (dp)
  875.             if (--(dp->d_rcnt)) {
  876.                 dprintf(3, (ddt, "qfree: ns %s rcnt %d\n",
  877.                         dp->d_data,
  878.                         dp->d_rcnt));
  879.             } else {
  880.                 dprintf(3, (ddt, "qfree: ns %s rcnt %d delayed\n",
  881.                         dp->d_data,
  882.                         dp->d_rcnt));
  883.                 free((char*)dp);
  884.             }
  885.         dp = qp->q_addr[i].nsdata;
  886.         if (dp)
  887.             if ((--(dp->d_rcnt))) {
  888.                 dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d\n",
  889.                     *(int32_t *)(dp->d_data),
  890.                     dp->d_rcnt));
  891.             } else {
  892.                 dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d delayed\n",
  893.                     *(int32_t *)(dp->d_data),
  894.                     dp->d_rcnt));
  895.             free((char*)dp);
  896.             }
  897.     }
  898. #endif
  899.     if( qhead == qp )  {
  900.         qhead = qp->q_link;
  901.     } else {
  902.         for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
  903.             if( np->q_link != qp )  continue;
  904.             np->q_link = qp->q_link;    /* dequeue */
  905.             break;
  906.         }
  907.     }
  908.     free((char *)qp);
  909. }
  910.