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

  1. /*-
  2.  * Copyright (c) 1986 The 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[] = "@(#)ns_forw.c    4.32 (Berkeley) 3/3/91";
  36. #endif /* not lint */
  37.  
  38. #include <sys/param.h>
  39. #include <sys/time.h>
  40. #include <sys/socket.h>
  41. #include <netinet/in.h>
  42. #include <syslog.h>
  43. #include <arpa/nameser.h>
  44. #include <resolv.h>
  45. #include <stdio.h>
  46. #include "ns.h"
  47. #include "db.h"
  48.  
  49. struct    qinfo *qhead = QINFO_NULL;    /* head of allocated queries */
  50. struct    qinfo *retryqp = QINFO_NULL;    /* list of queries to retry */
  51. struct    fwdinfo *fwdtab;        /* list of forwarding hosts */
  52.  
  53. int    nsid;                /* next forwarded query id */
  54. extern int forward_only;        /* you are only a slave */
  55. extern int errno;
  56. extern u_short ns_port;
  57.  
  58. time_t    retrytime();
  59.  
  60. /*
  61.  * Forward the query to get the answer since its not in the database.
  62.  * Returns FW_OK if a request struct is allocated and the query sent.
  63.  * Returns FW_DUP if this is a duplicate of a pending request. 
  64.  * Returns FW_NOSERVER if there were no addresses for the nameservers.
  65.  * Returns FW_SERVFAIL on malloc error.
  66.  * (no action is taken on errors and qpp is not filled in.)
  67.  */
  68. ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp)
  69.     struct databuf *nsp[];
  70.     char *msg;
  71.     int msglen;
  72.     struct sockaddr_in *fp;
  73.     struct qstream *qsp;
  74.     int dfd;
  75.     struct qinfo **qpp;
  76. {
  77.     register struct qinfo *qp;
  78.     HEADER *hp;
  79.     u_short id;
  80.     extern char *calloc();
  81.  
  82. #ifdef DEBUG
  83.     if (debug >= 3)
  84.         fprintf(ddt,"ns_forw()\n");
  85. #endif
  86.  
  87.     /* Don't forward if we're already working on it. */
  88.     hp = (HEADER *) msg;
  89.     id = hp->id;
  90.     /* Look at them all */
  91.     for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
  92.         if (qp->q_id == id &&
  93.             bcmp((char *)&qp->q_from, fp, sizeof(qp->q_from)) == 0 &&
  94.             ((qp->q_cmsglen == 0 && qp->q_msglen == msglen &&
  95.              bcmp((char *)qp->q_msg+2, msg+2, msglen-2) == 0) ||
  96.             (qp->q_cmsglen == msglen &&
  97.              bcmp((char *)qp->q_cmsg+2, msg+2, msglen-2) == 0))) {
  98. #ifdef DEBUG
  99.             if (debug >= 3)
  100.                 fprintf(ddt,"forw: dropped DUP id=%d\n", ntohs(id));
  101. #endif
  102. #ifdef STATS
  103.             stats[S_DUPQUERIES].cnt++;
  104. #endif
  105.             return (FW_DUP);
  106.         }
  107.     }
  108.  
  109.     qp = qnew();
  110.     if (nslookup(nsp, qp) == 0) {
  111. #ifdef DEBUG
  112.         if (debug >= 2)
  113.             fprintf(ddt,"forw: no nameservers found\n");
  114. #endif
  115.         qfree(qp);
  116.         return (FW_NOSERVER);
  117.     }
  118.     qp->q_stream = qsp;
  119.     qp->q_curaddr = 0;
  120.     qp->q_fwd = fwdtab;
  121.     qp->q_dfd = dfd;
  122.     qp->q_id = id;
  123.     hp->id = qp->q_nsid = htons((u_short)++nsid);
  124.     hp->ancount = 0;
  125.     hp->nscount = 0;
  126.     hp->arcount = 0;
  127.     qp->q_from = *fp;
  128.     if ((qp->q_msg = malloc((unsigned)msglen)) == NULL) {
  129.         syslog(LOG_ERR, "forw: %m");
  130.         qfree(qp);
  131.         return (FW_SERVFAIL);
  132.     }
  133.     bcopy(msg, qp->q_msg, qp->q_msglen = msglen);
  134.     if (!qp->q_fwd) {
  135.         hp->rd = 0;
  136.         qp->q_addr[0].stime = tt;
  137.     }
  138.  
  139.     schedretry(qp, retrytime(qp));
  140. #ifdef DEBUG
  141.     if (debug)
  142.         fprintf(ddt,
  143.            "forw: forw -> %s %d (%d) nsid=%d id=%d %dms retry %d sec\n",
  144.             inet_ntoa(Q_NEXTADDR(qp,0)->sin_addr),
  145.             ds, ntohs(Q_NEXTADDR(qp,0)->sin_port),
  146.             ntohs(qp->q_nsid), ntohs(qp->q_id),
  147.             qp->q_addr[0].nsdata->d_nstime,
  148.             qp->q_time - tt.tv_sec);
  149.     if ( debug >= 10)
  150.         fp_query(msg, ddt);
  151. #endif
  152.     if (sendto(ds, msg, msglen, 0, (struct sockaddr *)Q_NEXTADDR(qp,0),
  153.            sizeof(struct sockaddr_in)) < 0){
  154. #ifdef DEBUG
  155.         if (debug >= 5)
  156.             fprintf(ddt,"error returning msg errno=%d\n",errno);
  157. #endif
  158.     }
  159. #ifdef STATS
  160.     stats[S_OUTPKTS].cnt++;
  161. #endif
  162.     if (qpp)
  163.         *qpp = qp;
  164.     hp->rd = 1;
  165.     return (0);
  166. }
  167.  
  168. /*
  169.  * Lookup the address for each nameserver in `nsp' and add it to
  170.  * the list saved in the qinfo structure.
  171.  */
  172. nslookup(nsp, qp)
  173.     struct databuf *nsp[];
  174.     register struct qinfo *qp;
  175. {
  176.     register struct namebuf *np;
  177.     register struct databuf *dp, *nsdp;
  178.     register struct qserv *qs;
  179.     register int n, i;
  180.     struct hashbuf *tmphtp;
  181.     char *dname, *fname;
  182.     int oldn, naddr, class, found_arr;
  183.     time_t curtime;
  184.     int qcomp();
  185.  
  186. #ifdef DEBUG
  187.     if (debug >= 3)
  188.         fprintf(ddt,"nslookup(nsp=x%x,qp=x%x)\n",nsp,qp);
  189. #endif
  190.  
  191.     naddr = n = qp->q_naddr;
  192.     curtime = (u_long) tt.tv_sec;
  193.     while ((nsdp = *nsp++) != NULL) {
  194.         class = nsdp->d_class;
  195.         dname = nsdp->d_data;
  196. #ifdef DEBUG
  197.         if (debug >= 3)
  198.             fprintf(ddt,"nslookup: NS %s c%d t%d (x%x)\n",
  199.                 dname, class, nsdp->d_type, nsdp->d_flags);
  200. #endif
  201.         /* don't put in people we have tried */
  202.         for (i = 0; i < qp->q_nusedns; i++)
  203.             if (qp->q_usedns[i] == nsdp) {
  204. #ifdef DEBUG
  205.                 if (debug >= 2)
  206. fprintf(ddt, "skipping used NS w/name %s\n", nsdp->d_data);
  207. #endif DEBUG
  208.                 goto skipserver;
  209.             }
  210.  
  211.         tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
  212.         np = nlookup(dname, &tmphtp, &fname, 1);
  213.         if (np == NULL || fname != dname) {
  214. #ifdef DEBUG
  215.             if (debug >= 3)
  216.                 fprintf(ddt,"%s: not found %s %x\n",dname,fname,np);
  217. #endif
  218.             continue;
  219.         }
  220.         found_arr = 0;
  221.         oldn = n;
  222.         /* look for name server addresses */
  223.         for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
  224.             if (dp->d_type != T_A || dp->d_class != class)
  225.                 continue;
  226.             /*
  227.              * Don't use records that may become invalid to
  228.              * reference later when we do the rtt computation.
  229.              * Never delete our safety-belt information!
  230.              */
  231.             if ((dp->d_zone == 0) &&
  232.                 (dp->d_ttl < (curtime+900)) &&
  233.                 !(dp->d_flags & DB_F_HINT) )
  234.                 {
  235. #ifdef DEBUG
  236.                 if (debug >= 3)
  237.                     fprintf(ddt,"nslookup: stale entry '%s'\n",
  238.                         np->n_dname);
  239. #endif
  240.                 /* Cache invalidate the NS RR's */
  241.                 if (dp->d_ttl < curtime)
  242.                     delete_all(np, class, T_A);
  243.                 n = oldn;
  244.                 break;
  245.             }
  246.  
  247.             found_arr++;
  248.             /* don't put in duplicates */
  249.             qs = qp->q_addr;
  250.             for (i = 0; i < n; i++, qs++)
  251.                 if (bcmp((char *)&qs->ns_addr.sin_addr,
  252.                     dp->d_data, sizeof(struct in_addr)) == 0)
  253.                     goto skipaddr;
  254.             qs->ns_addr.sin_family = AF_INET;
  255.             qs->ns_addr.sin_port = ns_port;
  256.             qs->ns_addr.sin_addr = 
  257.                     *(struct in_addr *)dp->d_data;
  258.             qs->ns = nsdp;
  259.             qs->nsdata = dp;
  260.             qp->q_addr[n].nretry = 0;
  261.             n++;
  262.             if (n >= NSMAX)
  263.                 goto out;
  264.     skipaddr:    ;
  265.         }
  266. #ifdef DEBUG
  267.         if (debug >= 3)
  268.             fprintf(ddt,"nslookup: %d ns addrs\n", n);
  269. #endif
  270.         if (found_arr == 0 && qp->q_system == 0)
  271.             (void) sysquery(dname, class, T_A);
  272. skipserver:    ;
  273.     }
  274. out:
  275. #ifdef DEBUG
  276.     if (debug >= 3)
  277.         fprintf(ddt,"nslookup: %d ns addrs total\n", n);
  278. #endif
  279.     qp->q_naddr = n;
  280.     if (n > 1)
  281.         qsort((char *)qp->q_addr, n, sizeof(struct qserv), qcomp);
  282.     return (n - naddr);
  283. }
  284.  
  285. qcomp(qs1, qs2)
  286.     struct qserv *qs1, *qs2;
  287. {
  288.  
  289.     return (qs1->nsdata->d_nstime - qs2->nsdata->d_nstime);
  290. }
  291.  
  292. /*
  293.  * Arrange that forwarded query (qp) is retried after t seconds.
  294.  */
  295. schedretry(qp, t)
  296.     struct qinfo *qp;
  297.     time_t t;
  298. {
  299.     register struct qinfo *qp1, *qp2;
  300.  
  301. #ifdef DEBUG
  302.     if (debug > 3) {
  303.         fprintf(ddt,"schedretry(%#x, %dsec)\n", qp, t);
  304.         if (qp->q_time)
  305.            fprintf(ddt,"WARNING: schedretry(%x,%d) q_time already %d\n", qp->q_time);
  306.     }
  307. #endif
  308.     t += (u_long) tt.tv_sec;
  309.     qp->q_time = t;
  310.  
  311.     if ((qp1 = retryqp) == NULL) {
  312.         retryqp = qp;
  313.         qp->q_next = NULL;
  314.         return;
  315.     }
  316.     if (t < qp1->q_time) {
  317.         qp->q_next = qp1;
  318.         retryqp = qp;
  319.         return;
  320.     }
  321.     while ((qp2 = qp1->q_next) != NULL && qp2->q_time < t)
  322.         qp1 = qp2;
  323.     qp1->q_next = qp;
  324.     qp->q_next = qp2;
  325. }
  326.  
  327. /*
  328.  * Unsched is called to remove a forwarded query entry.
  329.  */
  330. unsched(qp)
  331.     struct qinfo *qp;
  332. {
  333.     register struct qinfo *np;
  334.  
  335. #ifdef DEBUG
  336.     if (debug > 3) {
  337.         fprintf(ddt,"unsched(%#x, %d )\n", qp, ntohs(qp->q_id));
  338.     }
  339. #endif
  340.     if( retryqp == qp )  {
  341.         retryqp = qp->q_next;
  342.     } else {
  343.         for( np=retryqp; np->q_next != QINFO_NULL; np = np->q_next ) {
  344.             if( np->q_next != qp)
  345.                 continue;
  346.             np->q_next = qp->q_next;    /* dequeue */
  347.             break;
  348.         }
  349.     }
  350.     qp->q_next = QINFO_NULL;        /* sanity check */
  351.     qp->q_time = 0;
  352. }
  353.  
  354. /*
  355.  * Retry is called to retransmit query 'qp'.
  356.  */
  357. retry(qp)
  358.     register struct qinfo *qp;
  359. {
  360.     register int n;
  361.     register HEADER *hp;
  362.  
  363. #ifdef DEBUG
  364.     if (debug > 3)
  365.         fprintf(ddt,"retry(x%x) id=%d\n", qp, ntohs(qp->q_id));
  366. #endif
  367.     if((HEADER *)qp->q_msg == NULL) {        /*** XXX ***/
  368.         qremove(qp);
  369.         return;
  370.     }                        /*** XXX ***/
  371.  
  372.     /* try next address */
  373.     n = qp->q_curaddr;
  374.     if (qp->q_fwd) {
  375.         qp->q_fwd = qp->q_fwd->next;
  376.         if (qp->q_fwd)
  377.             goto found;
  378.         /* out of forwarders, try direct queries */
  379.     } else
  380.         ++qp->q_addr[n].nretry;
  381.     if (!forward_only) {
  382.         do {
  383.             if (++n >= qp->q_naddr)
  384.                 n = 0;
  385.             if (qp->q_addr[n].nretry < MAXRETRY)
  386.                 goto found;
  387.         } while (n != qp->q_curaddr);
  388.     }
  389.     /*
  390.      * Give up. Can't reach destination.
  391.      */
  392.     hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
  393.     if (qp->q_system == PRIMING_CACHE) {
  394.         /* Can't give up priming */
  395.         unsched(qp);
  396.         schedretry(qp, (time_t)60*60);    /* 1 hour */
  397.         hp->rcode = NOERROR;    /* Lets be safe, reset the query */
  398.         hp->qr = hp->aa = 0;
  399.         qp->q_fwd = fwdtab;
  400.         for (n = 0; n < qp->q_naddr; n++)
  401.             qp->q_addr[n].nretry = 0;
  402.         return;
  403.     }
  404. #ifdef DEBUG
  405.     if (debug >= 5)
  406.         fprintf(ddt,"give up\n");
  407. #endif
  408.     n = ((HEADER *)qp->q_cmsg ? qp->q_cmsglen : qp->q_msglen);
  409.     hp->id = qp->q_id;
  410.     hp->qr = 1;
  411.     hp->ra = 1;
  412.     hp->rd = 1;
  413.     hp->rcode = SERVFAIL;
  414. #ifdef DEBUG
  415.     if (debug >= 10)
  416.         fp_query(qp->q_msg, ddt);
  417. #endif
  418.     if (send_msg((char *)hp, n, qp)) {
  419. #ifdef DEBUG
  420.         if (debug)
  421.             fprintf(ddt,"gave up retry(x%x) nsid=%d id=%d\n",
  422.                 qp, ntohs(qp->q_nsid), ntohs(qp->q_id));
  423. #endif
  424.     }
  425.     qremove(qp);
  426.     return;
  427.  
  428. found:
  429.     if (qp->q_fwd == 0 && qp->q_addr[n].nretry == 0)
  430.         qp->q_addr[n].stime = tt;
  431.     qp->q_curaddr = n;
  432.     hp = (HEADER *)qp->q_msg;
  433.     hp->rd = (qp->q_fwd ? 1 : 0);
  434. #ifdef DEBUG
  435.     if (debug)
  436.         fprintf(ddt,"%s(addr=%d n=%d) -> %s %d (%d) nsid=%d id=%d %dms\n",
  437.             (qp->q_fwd ? "reforw" : "resend"),
  438.             n, qp->q_addr[n].nretry,
  439.             inet_ntoa(Q_NEXTADDR(qp,n)->sin_addr),
  440.             ds, ntohs(Q_NEXTADDR(qp,n)->sin_port),
  441.             ntohs(qp->q_nsid), ntohs(qp->q_id),
  442.             qp->q_addr[n].nsdata->d_nstime);
  443.     if ( debug >= 10)
  444.         fp_query(qp->q_msg, ddt);
  445. #endif
  446.     /* NOSTRICT */
  447.     if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
  448.         (struct sockaddr *)Q_NEXTADDR(qp,n),
  449.         sizeof(struct sockaddr_in)) < 0){
  450. #ifdef DEBUG
  451.         if (debug > 3)
  452.             fprintf(ddt,"error resending msg errno=%d\n",errno);
  453. #endif
  454.     }
  455.     hp->rd = 1;    /* leave set to 1 for dup detection */
  456. #ifdef STATS
  457.     stats[S_OUTPKTS].cnt++;
  458. #endif
  459.     unsched(qp);
  460.     schedretry(qp, qp->q_fwd ? (2*RETRYBASE) : retrytime(qp));
  461. }
  462.  
  463. /*
  464.  * Compute retry time for the next server for a query.
  465.  * Use a minimum time of RETRYBASE (4 sec.) or twice the estimated
  466.  * service time; * back off exponentially on retries, but place a 45-sec.
  467.  * ceiling on retry times for now.  (This is because we don't hold a reference
  468.  * on servers or their addresses, and we have to finish before they time out.)
  469.  */
  470. time_t
  471. retrytime(qp)
  472. register struct qinfo *qp;
  473. {
  474.     time_t t;
  475.     struct qserv *ns = &qp->q_addr[qp->q_curaddr];
  476.  
  477. #ifdef DEBUG
  478.     if (debug > 3)
  479.         fprintf(ddt,"retrytime: nstime %dms.\n",
  480.             ns->nsdata->d_nstime / 1000);
  481. #endif
  482.     t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
  483.     t <<= ns->nretry;
  484.     t = MIN(t, 45);            /* max. retry timeout for now */
  485. #ifdef notdef
  486.     if (qp->q_system)
  487.         return ((2 * t) + 5);    /* system queries can wait. */
  488. #endif
  489.     return (t);
  490. }
  491.  
  492. qflush()
  493. {
  494.     while (qhead)
  495.         qremove(qhead);
  496.     qhead = QINFO_NULL;
  497. }
  498.  
  499. qremove(qp)
  500. register struct qinfo *qp;
  501. {
  502. #ifdef DEBUG
  503.     if(debug > 3)
  504.         fprintf(ddt,"qremove(x%x)\n", qp);
  505. #endif
  506.     unsched(qp);            /* get off queue first */
  507.     qfree(qp);
  508. }
  509.  
  510. struct qinfo *
  511. qfindid(id)
  512. register u_short id;
  513. {
  514.     register struct qinfo *qp;
  515.  
  516. #ifdef DEBUG
  517.     if(debug > 3)
  518.         fprintf(ddt,"qfindid(%d)\n", ntohs(id));
  519. #endif
  520.     for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
  521.         if (qp->q_nsid == id)
  522.             return(qp);
  523.     }
  524. #ifdef DEBUG
  525.     if (debug >= 5)
  526.         fprintf(ddt,"qp not found\n");
  527. #endif
  528.     return(NULL);
  529. }
  530.  
  531. struct qinfo *
  532. qnew()
  533. {
  534.     register struct qinfo *qp;
  535.  
  536.     if ((qp = (struct qinfo *)calloc(1, sizeof(struct qinfo))) == NULL) {
  537. #ifdef DEBUG
  538.         if (debug >= 5)
  539.             fprintf(ddt,"qnew: calloc error\n");
  540. #endif
  541.         syslog(LOG_ERR, "forw: %m");
  542.         exit(12);
  543.     }
  544. #ifdef DEBUG
  545.     if (debug >= 5)
  546.         fprintf(ddt,"qnew(x%x)\n", qp);
  547. #endif
  548.     qp->q_link = qhead;
  549.     qhead = qp;
  550.     return( qp );
  551. }
  552.  
  553. qfree(qp)
  554. struct qinfo *qp;
  555. {
  556.     register struct qinfo *np;
  557.  
  558. #ifdef DEBUG
  559.     if(debug > 3)
  560.         fprintf(ddt,"qfree( x%x )\n", qp);
  561.     if(debug && qp->q_next)
  562.         fprintf(ddt,"WARNING:  qfree of linked ptr x%x\n", qp);
  563. #endif
  564.     if (qp->q_msg)
  565.          free(qp->q_msg);
  566.      if (qp->q_cmsg)
  567.          free(qp->q_cmsg);
  568.     if( qhead == qp )  {
  569.         qhead = qp->q_link;
  570.     } else {
  571.         for( np=qhead; np->q_link != QINFO_NULL; np = np->q_link )  {
  572.             if( np->q_link != qp )  continue;
  573.             np->q_link = qp->q_link;    /* dequeue */
  574.             break;
  575.         }
  576.     }
  577.     (void)free((char *)qp);
  578. }
  579.