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