home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / other / irc / ircd / res.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-14  |  30.7 KB  |  1,390 lines

  1. /*
  2.  * ircd/res.c (C)opyright 1992, 1993, 1994 Darren Reed. All rights reserved.
  3.  * This file may not be distributed without the author's prior permission in
  4.  * any shape or form. The author takes no responsibility for any damage or
  5.  * loss of property which results from the use of this software.  Distribution
  6.  * of this file must include this notice.
  7.  */
  8. #include "struct.h"
  9. #include "common.h"
  10. #include "sys.h"
  11. #include "res.h"
  12. #include "numeric.h"
  13. #include "h.h"
  14.  
  15. #include <signal.h>
  16. #include <sys/time.h>
  17. #include <sys/socket.h>
  18. #include "nameser.h"
  19. #include "resolv.h"
  20.  
  21. #ifndef lint
  22. static  char sccsid[] = "@(#)res.c    2.38 4/13/94 (C) 1992 Darren Reed";
  23. #endif
  24.  
  25. #undef    DEBUG    /* because there is a lot of debug code in here :-) */
  26.  
  27. extern    int    dn_expand PROTO((char *, char *, char *, char *, int));
  28. extern    int    dn_skipname PROTO((char *, char *));
  29. extern    int    res_mkquery PROTO((int, char *, int, int, char *, int,
  30.                    struct rrec *, char *, int));
  31.  
  32. extern    int    errno, h_errno;
  33. extern    int    highest_fd;
  34. extern    aClient    *local[];
  35.  
  36. static    char    hostbuf[HOSTLEN+1];
  37. static    char    dot[] = ".";
  38. static    int    incache = 0;
  39. static    CacheTable    hashtable[ARES_CACSIZE];
  40. static    aCache    *cachetop = NULL;
  41. static    ResRQ    *last, *first;
  42.  
  43. static    void    rem_cache PROTO((aCache *));
  44. static    void    rem_request PROTO((ResRQ *));
  45. static    int    do_query_name PROTO((Link *, char *, ResRQ *));
  46. static    int    do_query_number PROTO((Link *, struct in_addr *, ResRQ *));
  47. static    void    resend_query PROTO((ResRQ *));
  48. static    int    proc_answer PROTO((ResRQ *, HEADER *, char *, char *));
  49. static    int    query_name PROTO((char *, int, int, ResRQ *));
  50. static    aCache    *make_cache PROTO((ResRQ *));
  51. static    aCache    *find_cache_name PROTO((char *));
  52. static    aCache    *find_cache_number PROTO((ResRQ *, char *));
  53. static    int    add_request PROTO((ResRQ *));
  54. static    ResRQ    *make_request PROTO((Link *));
  55. static    int    send_res_msg PROTO((char *, int, int));
  56. static    ResRQ    *find_id PROTO((int));
  57. static    int    hash_number PROTO((unsigned char *));
  58. static    void    update_list PROTO((ResRQ *, aCache *));
  59. static    int    hash_name PROTO((char *));
  60.  
  61. static    struct cacheinfo {
  62.     int    ca_adds;
  63.     int    ca_dels;
  64.     int    ca_expires;
  65.     int    ca_lookups;
  66.     int    ca_na_hits;
  67.     int    ca_nu_hits;
  68.     int    ca_updates;
  69. } cainfo;
  70.  
  71. static    struct    resinfo {
  72.     int    re_errors;
  73.     int    re_nu_look;
  74.     int    re_na_look;
  75.     int    re_replies;
  76.     int    re_requests;
  77.     int    re_resends;
  78.     int    re_sent;
  79.     int    re_timeouts;
  80.     int    re_shortttl;
  81.     int    re_unkrep;
  82. } reinfo;
  83.  
  84. int    init_resolver(op)
  85. int    op;
  86. {
  87.     int    ret = 0;
  88.  
  89. #ifdef    LRAND48
  90.     srand48(time(NULL));
  91. #endif
  92.     if (op & RES_INITLIST)
  93.         {
  94.         bzero((char *)&reinfo, sizeof(reinfo));
  95.         first = last = NULL;
  96.         }
  97.     if (op & RES_CALLINIT)
  98.         {
  99.         ret = res_init();
  100.         if (!_res.nscount)
  101.             {
  102.             _res.nscount = 1;
  103.             _res.nsaddr_list[0].sin_addr.s_addr =
  104.                 inet_addr("127.0.0.1");
  105.             }
  106.         }
  107.  
  108.     if (op & RES_INITSOCK)
  109.         {
  110.         int    on = 0;
  111.  
  112.         ret = resfd = socket(AF_INET, SOCK_DGRAM, 0);
  113.         (void) setsockopt(ret, SOL_SOCKET, SO_BROADCAST,
  114.                   (char *)&on, sizeof(on));
  115.         }
  116. #ifdef DEBUG
  117.     if (op & RES_INITDEBG);
  118.         _res.options |= RES_DEBUG;
  119. #endif
  120.     if (op & RES_INITCACH)
  121.         {
  122.         bzero((char *)&cainfo, sizeof(cainfo));
  123.         bzero((char *)hashtable, sizeof(hashtable));
  124.         }
  125.     if (op == 0)
  126.         ret = resfd;
  127.     return ret;
  128. }
  129.  
  130. static    int    add_request(new)
  131. ResRQ *new;
  132. {
  133.     if (!new)
  134.         return -1;
  135.     if (!first)
  136.         first = last = new;
  137.     else
  138.         {
  139.         last->next = new;
  140.         last = new;
  141.         }
  142.     new->next = NULL;
  143.     reinfo.re_requests++;
  144.     return 0;
  145. }
  146.  
  147. /*
  148.  * remove a request from the list. This must also free any memory that has
  149.  * been allocated for temporary storage of DNS results.
  150.  */
  151. static    void    rem_request(old)
  152. ResRQ    *old;
  153. {
  154.     Reg1    ResRQ    **rptr, *r2ptr = NULL;
  155.     Reg2    int    i;
  156.     Reg3    char    *s;
  157.  
  158.     if (!old)
  159.         return;
  160.     for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next)
  161.         if (*rptr == old)
  162.             {
  163.             *rptr = old->next;
  164.             if (last == old)
  165.                 last = r2ptr;
  166.             break;
  167.             }
  168. #ifdef    DEBUG
  169.     Debug((DEBUG_INFO,"rem_request:Remove %#x at %#x %#x",
  170.         old, *rptr, r2ptr));
  171. #endif
  172.     r2ptr = old;
  173.     if (r2ptr->he.h_name)
  174.         MyFree((char *)r2ptr->he.h_name);
  175.     for (i = 0; i < MAXALIASES; i++)
  176.         if ((s = r2ptr->he.h_aliases[i]))
  177.             MyFree(s);
  178.     if (r2ptr->name)
  179.         MyFree(r2ptr->name);
  180.     MyFree(r2ptr);
  181.  
  182.     return;
  183. }
  184.  
  185. /*
  186.  * Create a DNS request record for the server.
  187.  */
  188. static    ResRQ    *make_request(lp)
  189. Link    *lp;
  190. {
  191.     Reg1    ResRQ    *nreq;
  192.  
  193.     nreq = (ResRQ *)MyMalloc(sizeof(ResRQ));
  194.     bzero((char *)nreq, sizeof(ResRQ));
  195.     nreq->next = NULL; /* where NULL is non-zero ;) */
  196.     nreq->sentat = time(NULL);
  197.     nreq->retries = 3;
  198.     nreq->resend = 1;
  199.     nreq->srch = -1;
  200.     if (lp)
  201.         bcopy((char *)lp, (char *)&nreq->cinfo, sizeof(Link));
  202.     else
  203.         bzero((char *)&nreq->cinfo, sizeof(Link));
  204.     nreq->timeout = 4;    /* start at 4 and exponential inc. */
  205.     nreq->he.h_addrtype = AF_INET;
  206.     nreq->he.h_name = NULL;
  207.     nreq->he.h_aliases[0] = NULL;
  208.     (void)add_request(nreq);
  209.     return nreq;
  210. }
  211.  
  212. /*
  213.  * Remove queries from the list which have been there too long without
  214.  * being resolved.
  215.  */
  216. time_t    timeout_query_list(now)
  217. time_t    now;
  218. {
  219.     Reg1    ResRQ    *rptr, *r2ptr;
  220.     Reg2    time_t    next = 0, tout;
  221.     aClient    *cptr;
  222.  
  223.     Debug((DEBUG_DNS,"timeout_query_list at %s",myctime(now)));
  224.     for (rptr = first; rptr; rptr = r2ptr)
  225.         {
  226.         r2ptr = rptr->next;
  227.         tout = rptr->sentat + rptr->timeout;
  228.         if (now >= tout)
  229.             if (--rptr->retries <= 0)
  230.                 {
  231. #ifdef DEBUG
  232.                 Debug((DEBUG_ERROR,"timeout %x now %d cptr %x",
  233.                     rptr, now, rptr->cinfo.value.cptr));
  234. #endif
  235.                 reinfo.re_timeouts++;
  236.                 cptr = rptr->cinfo.value.cptr;
  237.                 switch (rptr->cinfo.flags)
  238.                 {
  239.                 case ASYNC_CLIENT :
  240.                     ClearDNS(cptr);
  241.                     if (!DoingAuth(cptr))
  242.                         SetAccess(cptr);
  243.                     break;
  244.                 case ASYNC_CONNECT :
  245.                     sendto_ops("Host %s unknown",
  246.                            rptr->name);
  247.                     break;
  248.                 }
  249.                 rem_request(rptr);
  250.                 continue;
  251.                 }
  252.             else
  253.                 {
  254.                 rptr->sentat = now;
  255.                 rptr->timeout += rptr->timeout;
  256.                 resend_query(rptr);
  257. #ifdef DEBUG
  258.                 Debug((DEBUG_INFO,"r %x now %d retry %d c %x",
  259.                     rptr, now, rptr->retries,
  260.                     rptr->cinfo.value.cptr));
  261. #endif
  262.                 }
  263.         if (!next || tout < next)
  264.             next = tout;
  265.         }
  266.     return (next > now) ? next : (now + AR_TTL);
  267. }
  268.  
  269. /*
  270.  * del_queries - called by the server to cleanup outstanding queries for
  271.  * which there no longer exist clients or conf lines.
  272.  */
  273. void    del_queries(cp)
  274. char    *cp;
  275. {
  276.     Reg1    ResRQ    *rptr, *r2ptr;
  277.  
  278.     for (rptr = first; rptr; rptr = r2ptr)
  279.         {
  280.         r2ptr = rptr->next;
  281.         if (cp == rptr->cinfo.value.cp)
  282.             rem_request(rptr);
  283.         }
  284. }
  285.  
  286. /*
  287.  * sends msg to all nameservers found in the "_res" structure.
  288.  * This should reflect /etc/resolv.conf. We will get responses
  289.  * which arent needed but is easier than checking to see if nameserver
  290.  * isnt present. Returns number of messages successfully sent to 
  291.  * nameservers or -1 if no successful sends.
  292.  */
  293. static    int    send_res_msg(msg, len, rcount)
  294. char    *msg;
  295. int    len, rcount;
  296. {
  297.     Reg1    int    i;
  298.     int    sent = 0, max;
  299.  
  300.     if (!msg)
  301.         return -1;
  302.  
  303.     max = MIN(_res.nscount, rcount);
  304.     if (_res.options & RES_PRIMARY)
  305.         max = 1;
  306.     if (!max)
  307.         max = 1;
  308.  
  309.     for (i = 0; i < max; i++)
  310.         {
  311.         _res.nsaddr_list[i].sin_family = AF_INET;
  312.         if (sendto(resfd, msg, len, 0, &(_res.nsaddr_list[i]),
  313.                sizeof(struct sockaddr)) == len)
  314.             {
  315.             reinfo.re_sent++;
  316.             sent++;
  317.             }
  318.         else
  319.             Debug((DEBUG_ERROR,"s_r_m:sendto: %d on %d",
  320.                 errno, resfd));
  321.         }
  322.  
  323.     return (sent) ? sent : -1;
  324. }
  325.  
  326.  
  327. /*
  328.  * find a dns request id (id is determined by dn_mkquery)
  329.  */
  330. static    ResRQ    *find_id(id)
  331. int    id;
  332. {
  333.     Reg1    ResRQ    *rptr;
  334.  
  335.     for (rptr = first; rptr; rptr = rptr->next)
  336.         if (rptr->id == id)
  337.             return rptr;
  338.     return NULL;
  339. }
  340.  
  341. struct    hostent    *gethost_byname(name, lp)
  342. char    *name;
  343. Link    *lp;
  344. {
  345.     Reg1    aCache    *cp;
  346.  
  347.     reinfo.re_na_look++;
  348.     if ((cp = find_cache_name(name)))
  349.         return (struct hostent *)&(cp->he);
  350.     if (!lp)
  351.         return NULL;
  352.     (void)do_query_name(lp, name, NULL);
  353.     return NULL;
  354. }
  355.  
  356. struct    hostent    *gethost_byaddr(addr, lp)
  357. char    *addr;
  358. Link    *lp;
  359. {
  360.     aCache    *cp;
  361.  
  362.     reinfo.re_nu_look++;
  363.     if ((cp = find_cache_number(NULL, addr)))
  364.         return (struct hostent *)&(cp->he);
  365.     if (!lp)
  366.         return NULL;
  367.     (void)do_query_number(lp, (struct in_addr *)addr, NULL);
  368.     return NULL;
  369. }
  370.  
  371. static    int    do_query_name(lp, name, rptr)
  372. Link    *lp;
  373. char    *name;
  374. Reg1    ResRQ    *rptr;
  375. {
  376.     char    hname[HOSTLEN+1];
  377.     int    len;
  378.  
  379.     (void)strncpy(hname, name, sizeof(hname) - 1);
  380.     len = strlen(hname);
  381.  
  382.     if (rptr && !index(hname, '.') && _res.options & RES_DEFNAMES)
  383.         {
  384.         (void)strncat(hname, dot, sizeof(hname) - len - 1);
  385.         len++;
  386.         (void)strncat(hname, _res.defdname, sizeof(hname) - len -1);
  387.         }
  388.  
  389.     /*
  390.      * Store the name passed as the one to lookup and generate other host
  391.      * names to pass onto the nameserver(s) for lookups.
  392.      */
  393.     if (!rptr)
  394.         {
  395.         rptr = make_request(lp);
  396.         rptr->type = T_A;
  397.         rptr->name = (char *)MyMalloc(strlen(name) + 1);
  398.         (void)strcpy(rptr->name, name);
  399.         }
  400.     return (query_name(hname, C_IN, T_A, rptr));
  401. }
  402.  
  403. /*
  404.  * Use this to do reverse IP# lookups.
  405.  */
  406. static    int    do_query_number(lp, numb, rptr)
  407. Link    *lp;
  408. struct    in_addr    *numb;
  409. Reg1    ResRQ    *rptr;
  410. {
  411.     char    ipbuf[32];
  412.     Reg2    u_char    *cp;
  413.  
  414.     cp = (u_char *)&numb->s_addr;
  415.     (void)sprintf(ipbuf,"%u.%u.%u.%u.in-addr.arpa.",
  416.         (u_int)(cp[3]), (u_int)(cp[2]),
  417.         (u_int)(cp[1]), (u_int)(cp[0]));
  418.  
  419.     if (!rptr)
  420.         {
  421.         rptr = make_request(lp);
  422.         rptr->type = T_PTR;
  423.         rptr->addr.s_addr = numb->s_addr;
  424.         bcopy((char *)&numb->s_addr,
  425.             (char *)&rptr->he.h_addr, sizeof(struct in_addr));
  426.         rptr->he.h_length = sizeof(struct in_addr);
  427.         }
  428.     return (query_name(ipbuf, C_IN, T_PTR, rptr));
  429. }
  430.  
  431. /*
  432.  * generate a query based on class, type and name.
  433.  */
  434. static    int    query_name(name, class, type, rptr)
  435. char    *name;
  436. int    class, type;
  437. ResRQ    *rptr;
  438. {
  439.     struct    timeval    tv;
  440.     char    buf[MAXPACKET];
  441.     int    r,s,k = 0;
  442.     HEADER    *hptr;
  443.  
  444.     bzero(buf, sizeof(buf));
  445.     r = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
  446.             buf, sizeof(buf));
  447.     if (r <= 0)
  448.         {
  449.         h_errno = NO_RECOVERY;
  450.         return r;
  451.         }
  452.     hptr = (HEADER *)buf;
  453. #ifdef LRAND48
  454.         do {
  455.         hptr->id = htons(ntohs(hptr->id) + k + lrand48() & 0xffff);
  456. #else
  457.     (void) gettimeofday(&tv, NULL);
  458.     do {
  459.         /* htons/ntohs can be assembler macros, which cannot
  460.            be nested. Thus two lines.    -Vesa            */
  461.         u_short nstmp = ntohs(hptr->id) + k +
  462.                 (u_short)(tv.tv_usec & 0xffff);
  463.         hptr->id = htons(nstmp);
  464. #endif /* LRAND48 */
  465.         k++;
  466.     } while (find_id(ntohs(hptr->id)));
  467.     rptr->id = ntohs(hptr->id);
  468.     rptr->sends++;
  469.     s = send_res_msg(buf, r, rptr->sends);
  470.     if (s == -1)
  471.         {
  472.         h_errno = TRY_AGAIN;
  473.         return -1;
  474.         }
  475.     else
  476.         rptr->sent += s;
  477.     return 0;
  478. }
  479.  
  480. static    void    resend_query(rptr)
  481. ResRQ    *rptr;
  482. {
  483.     if (rptr->resend == 0)
  484.         return;
  485.     reinfo.re_resends++;
  486.     switch(rptr->type)
  487.     {
  488.     case T_PTR:
  489.         (void)do_query_number(NULL, &rptr->addr, rptr);
  490.         break;
  491.     case T_A:
  492.         (void)do_query_name(NULL, rptr->name, rptr);
  493.         break;
  494.     default:
  495.         break;
  496.     }
  497.     return;
  498. }
  499.  
  500. /*
  501.  * process name server reply.
  502.  */
  503. static    int    proc_answer(rptr, hptr, buf, eob)
  504. ResRQ    *rptr;
  505. char    *buf, *eob;
  506. HEADER    *hptr;
  507. {
  508.     Reg1    char    *cp, **alias;
  509.     Reg2    struct    hent    *hp;
  510.     int    class, type, dlen, len, ans = 0, n;
  511.     struct    in_addr    dr, *adr;
  512.  
  513.     cp = buf + sizeof(HEADER);
  514.     hp = (struct hent *)&(rptr->he);
  515.     adr = &hp->h_addr;
  516.     while (adr->s_addr)
  517.         adr++;
  518.     alias = hp->h_aliases;
  519.     while (*alias)
  520.         alias++;
  521. #ifdef    SOL20        /* brain damaged compiler (Solaris2) it seems */
  522.     for (; hptr->qdcount > 0; hptr->qdcount--)
  523. #else
  524.     while (hptr->qdcount-- > 0)
  525. #endif
  526.         if ((n = dn_skipname(cp, eob)) == -1)
  527.             break;
  528.         else
  529.             cp += (n + QFIXEDSZ);
  530.     /*
  531.      * proccess each answer sent to us blech.
  532.      */
  533.     while (hptr->ancount-- > 0 && cp && cp < eob) {
  534.         n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf));
  535.         if (n <= 0)
  536.             break;
  537.  
  538.         cp += n;
  539.         type = (int)_getshort(cp);
  540.         cp += sizeof(short);
  541.         class = (int)_getshort(cp);
  542.         cp += sizeof(short);
  543.         rptr->ttl = _getlong(cp);
  544.         cp += sizeof(rptr->ttl);
  545.         dlen =  (int)_getshort(cp);
  546.         cp += sizeof(short);
  547.         rptr->type = type;
  548.  
  549.         len = strlen(hostbuf);
  550.         /* name server never returns with trailing '.' */
  551.         if (!index(hostbuf,'.') && (_res.options & RES_DEFNAMES))
  552.             {
  553.             (void)strcat(hostbuf, dot);
  554.             len++;
  555.             (void)strncat(hostbuf, _res.defdname,
  556.                 sizeof(hostbuf) - 1 - len);
  557.             len = MIN(len + strlen(_res.defdname),
  558.                   sizeof(hostbuf) - 1);
  559.             }
  560.  
  561.         switch(type)
  562.         {
  563.         case T_A :
  564.             hp->h_length = dlen;
  565.             if (ans == 1)
  566.                 hp->h_addrtype =  (class == C_IN) ?
  567.                             AF_INET : AF_UNSPEC;
  568.             bcopy(cp, (char *)&dr, dlen);
  569.             adr->s_addr = dr.s_addr;
  570.             Debug((DEBUG_INFO,"got ip # %s for %s",
  571.                 inetntoa((char *)adr), hostbuf));
  572.             if (!hp->h_name)
  573.                 {
  574.                 hp->h_name =(char *)MyMalloc(len+1);
  575.                 (void)strcpy(hp->h_name, hostbuf);
  576.                 }
  577.             ans++;
  578.             adr++;
  579.             cp += dlen;
  580.              break;
  581.         case T_PTR :
  582.             if((n = dn_expand(buf, eob, cp, hostbuf,
  583.                       sizeof(hostbuf) )) < 0)
  584.                 {
  585.                 cp = NULL;
  586.                 break;
  587.                 }
  588.             cp += n;
  589.             len = strlen(hostbuf);
  590.             Debug((DEBUG_INFO,"got host %s",hostbuf));
  591.             /*
  592.              * copy the returned hostname into the host name
  593.              * or alias field if there is a known hostname
  594.              * already.
  595.              */
  596.             if (hp->h_name)
  597.                 {
  598.                 if (alias >= &(hp->h_aliases[MAXALIASES-1]))
  599.                     break;
  600.                 *alias = (char *)MyMalloc(len + 1);
  601.                 (void)strcpy(*alias++, hostbuf);
  602.                 *alias = NULL;
  603.                 }
  604.             else
  605.                 {
  606.                 hp->h_name = (char *)MyMalloc(len + 1);
  607.                 (void)strcpy(hp->h_name, hostbuf);
  608.                 }
  609.             ans++;
  610.             break;
  611.         case T_CNAME :
  612.             cp += dlen;
  613.             Debug((DEBUG_INFO,"got cname %s", hostbuf));
  614.             if (alias >= &(hp->h_aliases[MAXALIASES-1]))
  615.                 break;
  616.             *alias = (char *)MyMalloc(len + 1);
  617.             (void)strcpy(*alias++, hostbuf);
  618.             *alias = NULL;
  619.             ans++;
  620.             break;
  621.         default :
  622. #ifdef DEBUG
  623.             Debug((DEBUG_INFO,"proc_answer: type:%d for:%s",
  624.                   type, hostbuf));
  625. #endif
  626.             break;
  627.         }
  628.     }
  629.     return ans;
  630. }
  631.  
  632. /*
  633.  * read a dns reply from the nameserver and process it.
  634.  */
  635. struct    hostent    *get_res(lp)
  636. char    *lp;
  637. {
  638.     static    char    buf[sizeof(HEADER) + MAXPACKET];
  639.     Reg1    HEADER    *hptr;
  640.     Reg2    ResRQ    *rptr = NULL;
  641.     aCache    *cp;
  642.     struct    sockaddr_in    sin;
  643.     int    rc, a, len = sizeof(sin), max;
  644.  
  645.     (void)alarm((unsigned)4);
  646.     rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin,
  647.               &len);
  648.     (void)alarm((unsigned)0);
  649.     if (rc <= sizeof(HEADER))
  650.         goto getres_err;
  651.     /*
  652.      * convert DNS reply reader from Network byte order to CPU byte order.
  653.      */
  654.     hptr = (HEADER *)buf;
  655.     hptr->id = ntohs(hptr->id);
  656.     hptr->ancount = ntohs(hptr->ancount);
  657.     hptr->qdcount = ntohs(hptr->qdcount);
  658.     hptr->nscount = ntohs(hptr->nscount);
  659.     hptr->arcount = ntohs(hptr->arcount);
  660. #ifdef    DEBUG
  661.     Debug((DEBUG_NOTICE, "get_res:id = %d rcode = %d ancount = %d",
  662.         hptr->id, hptr->rcode, hptr->ancount));
  663. #endif
  664.     reinfo.re_replies++;
  665.     /*
  666.      * response for an id which we have already received an answer for
  667.      * just ignore this response.
  668.      */
  669.     rptr = find_id(hptr->id);
  670.     if (!rptr)
  671.         goto getres_err;
  672.     /*
  673.      * check against possibly fake replies
  674.      */
  675.     max = MIN(_res.nscount, rptr->sends);
  676.     if (!max)
  677.         max = 1;
  678.  
  679.     for (a = 0; a < max; a++)
  680.         if (!_res.nsaddr_list[a].sin_addr.s_addr ||
  681.             !bcmp((char *)&sin.sin_addr,
  682.               (char *)&_res.nsaddr_list[a].sin_addr,
  683.               sizeof(struct in_addr)))
  684.             break;
  685.     if (a == max)
  686.         {
  687.         reinfo.re_unkrep++;
  688.         goto getres_err;
  689.         }
  690.  
  691.     if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
  692.         {
  693.         switch (hptr->rcode)
  694.         {
  695.         case NXDOMAIN:
  696.             h_errno = TRY_AGAIN;
  697.             break;
  698.         case SERVFAIL:
  699.             h_errno = TRY_AGAIN;
  700.             break;
  701.         case NOERROR:
  702.             h_errno = NO_DATA;
  703.             break;
  704.         case FORMERR:
  705.         case NOTIMP:
  706.         case REFUSED:
  707.         default:
  708.             h_errno = NO_RECOVERY;
  709.             break;
  710.         }
  711.         reinfo.re_errors++;
  712.         /*
  713.         ** If a bad error was returned, we stop here and dont send
  714.         ** send any more (no retries granted).
  715.         */
  716.         if (h_errno != TRY_AGAIN)
  717.             {
  718.             Debug((DEBUG_DNS, "Fatal DNS error %d for %d",
  719.                 h_errno, hptr->rcode));
  720.             rptr->resend = 0;
  721.             rptr->retries = 0;
  722.             }
  723.         goto getres_err;
  724.         }
  725.     a = proc_answer(rptr, hptr, buf, buf+rc);
  726. #ifdef DEBUG
  727.     Debug((DEBUG_INFO,"get_res:Proc answer = %d",a));
  728. #endif
  729.     if (a && rptr->type == T_PTR)
  730.         {
  731.         struct    hostent    *hp2 = NULL;
  732.  
  733.         Debug((DEBUG_DNS, "relookup %s <-> %s",
  734.             rptr->he.h_name, inetntoa((char *)&rptr->he.h_addr)));
  735.         /*
  736.          * Lookup the 'authoritive' name that we were given for the
  737.          * ip#.  By using this call rather than regenerating the
  738.          * type we automatically gain the use of the cache with no
  739.          * extra kludges.
  740.          */
  741.         if ((hp2 = gethost_byname(rptr->he.h_name, &rptr->cinfo)))
  742.             if (lp)
  743.                 bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
  744.         /*
  745.          * If name wasn't found, a request has been queued and it will
  746.          * be the last one queued.  This is rather nasty way to keep
  747.          * a host alias with the query. -avalon
  748.          */
  749.         if (!hp2 && rptr->he.h_aliases[0])
  750.             for (a = 0; rptr->he.h_aliases[a]; a++)
  751.                 {
  752.                 Debug((DEBUG_DNS, "Copied CNAME %s for %s",
  753.                     rptr->he.h_aliases[a],
  754.                     rptr->he.h_name));
  755.                 last->he.h_aliases[a] = rptr->he.h_aliases[a];
  756.                 rptr->he.h_aliases[a] = NULL;
  757.                 }
  758.  
  759.         rem_request(rptr);
  760.         return hp2;
  761.         }
  762.  
  763.     if (a > 0)
  764.         {
  765.         if (lp)
  766.             bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
  767.         cp = make_cache(rptr);
  768. #ifdef    DEBUG
  769.     Debug((DEBUG_INFO,"get_res:cp=%#x rptr=%#x (made)",cp,rptr));
  770. #endif
  771.  
  772.         rem_request(rptr);
  773.         }
  774.     else
  775.         if (!rptr->sent)
  776.             rem_request(rptr);
  777.     return cp ? (struct hostent *)&cp->he : NULL;
  778.  
  779. getres_err:
  780.     /*
  781.      * Reprocess an error if the nameserver didnt tell us to "TRY_AGAIN".
  782.      */
  783.     if (rptr)
  784.         {
  785.         if (h_errno != TRY_AGAIN)
  786.             {
  787.             /*
  788.              * If we havent tried with the default domain and its
  789.              * set, then give it a try next.
  790.              */
  791.             if (_res.options & RES_DEFNAMES && ++rptr->srch == 0)
  792.                 {
  793.                 rptr->retries = _res.retry;
  794.                 rptr->sends = 0;
  795.                 rptr->resend = 1;
  796.                 resend_query(rptr);
  797.                 }
  798.             else
  799.                 resend_query(rptr);
  800.             }
  801.         else if (lp)
  802.             bcopy((char *)&rptr->cinfo, lp, sizeof(Link));
  803.         }
  804.     return (struct hostent *)NULL;
  805. }
  806.  
  807. static    int    hash_number(ip)
  808. Reg1 unsigned char *ip;
  809. {
  810.     Reg1    u_int    hashv = 0;
  811.  
  812.     /* could use loop but slower */
  813.     hashv += (int)*ip++;
  814.     hashv += hashv + (int)*ip++;
  815.     hashv += hashv + (int)*ip++;
  816.     hashv += hashv + (int)*ip++;
  817.     hashv %= ARES_CACSIZE;
  818.     return (hashv);
  819. }
  820.  
  821. static    int    hash_name(name)
  822. register    char    *name;
  823. {
  824.     Reg1    u_int    hashv = 0;
  825.  
  826.     for (; *name && *name != '.'; name++)
  827.         hashv += *name;
  828.     hashv %= ARES_CACSIZE;
  829.     return (hashv);
  830. }
  831.  
  832. /*
  833. ** Add a new cache item to the queue and hash table.
  834. */
  835. static    aCache    *add_to_cache(ocp)
  836. Reg1    aCache    *ocp;
  837. {
  838.     Reg1    aCache    *cp = NULL;
  839.     Reg2    int    hashv;
  840.  
  841. #ifdef DEBUG
  842.     Debug((DEBUG_INFO,
  843.           "add_to_cache:ocp %#x he %#x name %#x addrl %#x 0 %#x",
  844.         ocp, &ocp->he, ocp->he.h_name, ocp->he.h_addr_list,
  845.         ocp->he.h_addr_list[0]));
  846. #endif
  847.     ocp->list_next = cachetop;
  848.     cachetop = ocp;
  849.  
  850.     hashv = hash_name(ocp->he.h_name);
  851.     ocp->hname_next = hashtable[hashv].name_list;
  852.     hashtable[hashv].name_list = ocp;
  853.  
  854.     hashv = hash_number((u_char *)ocp->he.h_addr);
  855.     ocp->hnum_next = hashtable[hashv].num_list;
  856.     hashtable[hashv].num_list = ocp;
  857.  
  858. #ifdef    DEBUG
  859.     Debug((DEBUG_INFO, "add_to_cache:added %s[%08x] cache %#x.",
  860.         ocp->he.h_name, ocp->he.h_addr_list[0], ocp));
  861.     Debug((DEBUG_INFO,
  862.         "add_to_cache:h1 %d h2 %x lnext %#x namnext %#x numnext %#x",
  863.         hash_name(ocp->he.h_name), hashv, ocp->list_next,
  864.         ocp->hname_next, ocp->hnum_next));
  865. #endif
  866.  
  867.     /*
  868.      * LRU deletion of excessive cache entries.
  869.      */
  870.     if (++incache > MAXCACHED)
  871.         {
  872.         for (cp = cachetop; cp->list_next; cp = cp->list_next)
  873.             ;
  874.         rem_cache(cp);
  875.         }
  876.     cainfo.ca_adds++;
  877.  
  878.     return ocp;
  879. }
  880.  
  881. /*
  882. ** update_list does not alter the cache structure passed. It is assumed that
  883. ** it already contains the correct expire time, if it is a new entry. Old
  884. ** entries have the expirey time updated.
  885. */
  886. static    void    update_list(rptr, cachep)
  887. ResRQ    *rptr;
  888. aCache    *cachep;
  889. {
  890.     Reg1    aCache    **cpp, *cp = cachep;
  891.     Reg2    char    *s, *t, **base;
  892.     Reg3    int    i, j;
  893.     int    addrcount;
  894.  
  895.     /*
  896.     ** search for the new cache item in the cache list by hostname.
  897.     ** If found, move the entry to the top of the list and return.
  898.     */
  899.     cainfo.ca_updates++;
  900.  
  901.     for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next))
  902.         if (cp == *cpp)
  903.             break;
  904.     if (!*cpp)
  905.         return;
  906.     *cpp = cp->list_next;
  907.     cp->list_next = cachetop;
  908.     cachetop = cp;
  909.     if (!rptr)
  910.         return;
  911.  
  912. #ifdef    DEBUG
  913.     Debug((DEBUG_DEBUG,"u_l:cp %#x na %#x al %#x ad %#x",
  914.         cp,cp->he.h_name,cp->he.h_aliases,cp->he.h_addr));
  915.     Debug((DEBUG_DEBUG,"u_l:rptr %#x h_n %#x", rptr, rptr->he.h_name));
  916. #endif
  917.     /*
  918.      * Compare the cache entry against the new record.  Add any
  919.      * previously missing names for this entry.
  920.      */
  921.     for (i = 0; cp->he.h_aliases[i]; i++)
  922.         ;
  923.     addrcount = i;
  924.     for (i = 0, s = rptr->he.h_name; s && i < MAXALIASES;
  925.          s = rptr->he.h_aliases[i++])
  926.         {
  927.         for (j = 0, t = cp->he.h_name; t && j < MAXALIASES;
  928.              t = cp->he.h_aliases[j++])
  929.             if (!mycmp(t, s))
  930.                 break;
  931.         if (!t && j < MAXALIASES-1)
  932.             {
  933.             base = cp->he.h_aliases;
  934.  
  935.             addrcount++;
  936.             base = (char **)MyRealloc((char *)base,
  937.                     sizeof(char *) * (addrcount + 1));
  938.             cp->he.h_aliases = base;
  939. #ifdef    DEBUG
  940.             Debug((DEBUG_DNS,"u_l:add name %s hal %x ac %d",
  941.                 s, cp->he.h_aliases, addrcount));
  942. #endif
  943.             base[addrcount-1] = s;
  944.             base[addrcount] = NULL;
  945.             if (i)
  946.                 rptr->he.h_aliases[i-1] = NULL;
  947.             else
  948.                 rptr->he.h_name = NULL;
  949.             }
  950.         }
  951.     for (i = 0; cp->he.h_addr_list[i]; i++)
  952.         ;
  953.     addrcount = i;
  954.  
  955.     /*
  956.      * Do the same again for IP#'s.
  957.      */
  958.     for (s = (char *)&rptr->he.h_addr.s_addr;
  959.          ((struct in_addr *)s)->s_addr; s += sizeof(struct in_addr))
  960.         {
  961.         for (i = 0; (t = cp->he.h_addr_list[i]); i++)
  962.             if (!bcmp(s, t, sizeof(struct in_addr)))
  963.                 break;
  964.         if (i >= MAXADDRS || addrcount >= MAXADDRS)
  965.             break;
  966.         /*
  967.          * Oh man this is bad...I *HATE* it. -avalon
  968.          *
  969.          * Whats it do ?  Reallocate two arrays, one of pointers
  970.          * to "char *" and the other of IP addresses.  Contents of
  971.          * the IP array *MUST* be preserved and the pointers into
  972.          * it recalculated.
  973.          */
  974.         if (!t)
  975.             {
  976.             base = cp->he.h_addr_list;
  977.             addrcount++;
  978.             t = (char *)MyRealloc(*base,
  979.                     addrcount * sizeof(struct in_addr));
  980.             base = (char **)MyRealloc((char *)base,
  981.                     (addrcount + 1) * sizeof(char *));
  982.             cp->he.h_addr_list = base;
  983. #ifdef    DEBUG
  984.             Debug((DEBUG_DNS,"u_l:add IP %x hal %x ac %d",
  985.                 ntohl(((struct in_addr *)s)->s_addr),
  986.                 cp->he.h_addr_list,
  987.                 addrcount));
  988. #endif
  989.             for (; addrcount; addrcount--)
  990.                 {
  991.                 *base++ = t;
  992.                 t += sizeof(struct in_addr);
  993.                 }
  994.             *base = NULL;
  995.             bcopy(s, *--base, sizeof(struct in_addr));
  996.             }
  997.         }
  998.     return;
  999. }
  1000.  
  1001. static    aCache    *find_cache_name(name)
  1002. char    *name;
  1003. {
  1004.     Reg1    aCache    *cp;
  1005.     Reg2    char    *s;
  1006.     Reg3    int    hashv, i;
  1007.  
  1008.     hashv = hash_name(name);
  1009.  
  1010.     cp = hashtable[hashv].name_list;
  1011. #ifdef    DEBUG
  1012.     Debug((DEBUG_DNS,"find_cache_name:find %s : hashv = %d",name,hashv));
  1013. #endif
  1014.  
  1015.     for (; cp; cp = cp->hname_next)
  1016.         for (i = 0, s = cp->he.h_name; s; s = cp->he.h_aliases[i++])
  1017.             if (mycmp(s, name) == 0)
  1018.                 {
  1019.                 cainfo.ca_na_hits++;
  1020.                 update_list(NULL, cp);
  1021.                 return cp;
  1022.                 }
  1023.  
  1024.     for (cp = cachetop; cp; cp = cp->list_next)
  1025.         {
  1026.         /*
  1027.          * if no aliases or the hash value matches, we've already
  1028.          * done this entry and all possiblilities concerning it.
  1029.          */
  1030.         if (!*cp->he.h_aliases)
  1031.             continue;
  1032.         if (hashv == hash_name(cp->he.h_name))
  1033.             continue;
  1034.         for (i = 0, s = cp->he.h_aliases[i]; s && i < MAXALIASES; i++)
  1035.             if (!mycmp(name, s)) {
  1036.                 cainfo.ca_na_hits++;
  1037.                 update_list(NULL, cp);
  1038.                 return cp;
  1039.                 }
  1040.         }
  1041.     return NULL;
  1042. }
  1043.  
  1044. /*
  1045.  * find a cache entry by ip# and update its expire time
  1046.  */
  1047. static    aCache    *find_cache_number(rptr, numb)
  1048. ResRQ    *rptr;
  1049. char    *numb;
  1050. {
  1051.     Reg1    aCache    *cp;
  1052.     Reg2    int    hashv,i;
  1053. #ifdef    DEBUG
  1054.     struct    in_addr    *ip = (struct in_addr *)numb;
  1055. #endif
  1056.  
  1057.     hashv = hash_number((u_char *)numb);
  1058.  
  1059.     cp = hashtable[hashv].num_list;
  1060. #ifdef DEBUG
  1061.     Debug((DEBUG_DNS,"find_cache_number:find %s[%08x]: hashv = %d",
  1062.         inetntoa(numb), ntohl(ip->s_addr), hashv));
  1063. #endif
  1064.  
  1065.     for (; cp; cp = cp->hnum_next)
  1066.         for (i = 0; cp->he.h_addr_list[i]; i++)
  1067.             if (!bcmp(cp->he.h_addr_list[i], numb,
  1068.                   sizeof(struct in_addr)))
  1069.                 {
  1070.                 cainfo.ca_nu_hits++;
  1071.                 update_list(rptr, cp);
  1072.                 return cp;
  1073.                 }
  1074.  
  1075.     for (cp = cachetop; cp; cp = cp->list_next)
  1076.         {
  1077.         /*
  1078.          * single address entry...would have been done by hashed
  1079.          * search above...
  1080.          */
  1081.         if (!cp->he.h_addr_list[1])
  1082.             continue;
  1083.         /*
  1084.          * if the first IP# has the same hashnumber as the IP# we
  1085.          * are looking for, its been done already.
  1086.          */
  1087.         if (hashv == hash_number((u_char *)cp->he.h_addr_list[0]))
  1088.             continue;
  1089.         for (i = 1; cp->he.h_addr_list[i]; i++)
  1090.             if (!bcmp(cp->he.h_addr_list[i], numb,
  1091.                   sizeof(struct in_addr)))
  1092.                 {
  1093.                 cainfo.ca_nu_hits++;
  1094.                 update_list(rptr, cp);
  1095.                 return cp;
  1096.                 }
  1097.         }
  1098.     return NULL;
  1099. }
  1100.  
  1101. static    aCache    *make_cache(rptr)
  1102. ResRQ    *rptr;
  1103. {
  1104.     Reg1    aCache    *cp;
  1105.     Reg2    int    i, n;
  1106.     Reg3    struct    hostent    *hp;
  1107.     Reg3    char    *s, **t;
  1108.  
  1109.     /*
  1110.     ** shouldn't happen but it just might...
  1111.     */
  1112.     if (!rptr->he.h_name || !rptr->he.h_addr.s_addr)
  1113.         return NULL;
  1114.     /*
  1115.     ** Make cache entry.  First check to see if the cache already exists
  1116.     ** and if so, return a pointer to it.
  1117.     */
  1118.     if ((cp = find_cache_number(rptr, (char *)&rptr->he.h_addr.s_addr)))
  1119.         return cp;
  1120.     for (i = 1; rptr->he.h_addr_list[i].s_addr; i++)
  1121.         if ((cp = find_cache_number(rptr,
  1122.                 (char *)&(rptr->he.h_addr_list[i].s_addr))))
  1123.             return cp;
  1124.  
  1125.     /*
  1126.     ** a matching entry wasnt found in the cache so go and make one up.
  1127.     */ 
  1128.     cp = (aCache *)MyMalloc(sizeof(aCache));
  1129.     bzero((char *)cp, sizeof(aCache));
  1130.     hp = &cp->he;
  1131.     for (i = 0; i < MAXADDRS; i++)
  1132.         if (!rptr->he.h_addr_list[i].s_addr)
  1133.             break;
  1134.  
  1135.     /*
  1136.     ** build two arrays, one for IP#'s, another of pointers to them.
  1137.     */
  1138.     t = hp->h_addr_list = (char **)MyMalloc(sizeof(char *) * (i+1));
  1139.     bzero((char *)t, sizeof(char *) * (i+1));
  1140.  
  1141.     s = (char *)MyMalloc(sizeof(struct in_addr) * i);
  1142.     bzero(s, sizeof(struct in_addr) * i);
  1143.  
  1144.     for (n = 0; n < i; n++, s += sizeof(struct in_addr))
  1145.         {
  1146.         *t++ = s;
  1147.         bcopy((char *)&(rptr->he.h_addr_list[n].s_addr), s,
  1148.               sizeof(struct in_addr));
  1149.         }
  1150.     *t = (char *)NULL;
  1151.  
  1152.     /*
  1153.     ** an array of pointers to CNAMEs.
  1154.     */
  1155.     for (i = 0; i < MAXALIASES; i++)
  1156.         if (!rptr->he.h_aliases[i])
  1157.             break;
  1158.     i++;
  1159.     t = hp->h_aliases = (char **)MyMalloc(sizeof(char *) * i);
  1160.     for (n = 0; n < i; n++, t++)
  1161.         {
  1162.         *t = rptr->he.h_aliases[n];
  1163.         rptr->he.h_aliases[n] = NULL;
  1164.         }
  1165.  
  1166.     hp->h_addrtype = rptr->he.h_addrtype;
  1167.     hp->h_length = rptr->he.h_length;
  1168.     hp->h_name = rptr->he.h_name;
  1169.     if (rptr->ttl < 600)
  1170.         {
  1171.         reinfo.re_shortttl++;
  1172.         cp->ttl = 600;
  1173.         }
  1174.     else
  1175.         cp->ttl = rptr->ttl;
  1176.     cp->expireat = time(NULL) + cp->ttl;
  1177.     rptr->he.h_name = NULL;
  1178. #ifdef DEBUG
  1179.     Debug((DEBUG_INFO,"make_cache:made cache %#x", cp));
  1180. #endif
  1181.     return add_to_cache(cp);
  1182. }
  1183.  
  1184. /*
  1185.  * rem_cache
  1186.  *     delete a cache entry from the cache structures and lists and return
  1187.  *     all memory used for the cache back to the memory pool.
  1188.  */
  1189. static    void    rem_cache(ocp)
  1190. aCache    *ocp;
  1191. {
  1192.     Reg1    aCache    **cp;
  1193.     Reg2    struct    hostent *hp = &ocp->he;
  1194.     Reg3    int    hashv;
  1195.     Reg4    aClient    *cptr;
  1196.  
  1197. #ifdef    DEBUG
  1198.     Debug((DEBUG_DNS, "rem_cache: ocp %#x hp %#x l_n %#x aliases %#x",
  1199.         ocp, hp, ocp->list_next, hp->h_aliases));
  1200. #endif
  1201.     /*
  1202.     ** Cleanup any references to this structure by destroying the
  1203.     ** pointer.
  1204.     */
  1205.     for (hashv = highest_fd; hashv >= 0; hashv--)
  1206.         if ((cptr = local[hashv]) && (cptr->hostp == hp))
  1207.             cptr->hostp = NULL;
  1208.     /*
  1209.      * remove cache entry from linked list
  1210.      */
  1211.     for (cp = &cachetop; *cp; cp = &((*cp)->list_next))
  1212.         if (*cp == ocp)
  1213.             {
  1214.             *cp = ocp->list_next;
  1215.             break;
  1216.             }
  1217.     /*
  1218.      * remove cache entry from hashed name lists
  1219.      */
  1220.     hashv = hash_name(hp->h_name);
  1221. #ifdef    DEBUG
  1222.     Debug((DEBUG_DEBUG,"rem_cache: h_name %s hashv %d next %#x first %#x",
  1223.         hp->h_name, hashv, ocp->hname_next,
  1224.         hashtable[hashv].name_list));
  1225. #endif
  1226.     for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next))
  1227.         if (*cp == ocp)
  1228.             {
  1229.             *cp = ocp->hname_next;
  1230.             break;
  1231.             }
  1232.     /*
  1233.      * remove cache entry from hashed number list
  1234.      */
  1235.     hashv = hash_number((u_char *)hp->h_addr);
  1236. #ifdef    DEBUG
  1237.     Debug((DEBUG_DEBUG,"rem_cache: h_addr %s hashv %d next %#x first %#x",
  1238.         inetntoa(hp->h_addr), hashv, ocp->hnum_next,
  1239.         hashtable[hashv].num_list));
  1240. #endif
  1241.     for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next))
  1242.         if (*cp == ocp)
  1243.             {
  1244.             *cp = ocp->hnum_next;
  1245.             break;
  1246.             }
  1247.  
  1248.     /*
  1249.      * free memory used to hold the various host names and the array
  1250.      * of alias pointers.
  1251.      */
  1252.     if (hp->h_name)
  1253.         MyFree(hp->h_name);
  1254.     if (hp->h_aliases)
  1255.         {
  1256.         for (hashv = 0; hp->h_aliases[hashv]; hashv++)
  1257.             MyFree(hp->h_aliases[hashv]);
  1258.         MyFree((char *)hp->h_aliases);
  1259.         }
  1260.  
  1261.     /*
  1262.      * free memory used to hold ip numbers and the array of them.
  1263.      */
  1264.     if (hp->h_addr_list)
  1265.         {
  1266.         if (*hp->h_addr_list)
  1267.             MyFree((char *)*hp->h_addr_list);
  1268.         MyFree((char *)hp->h_addr_list);
  1269.         }
  1270.  
  1271.     MyFree((char *)ocp);
  1272.  
  1273.     incache--;
  1274.     cainfo.ca_dels++;
  1275.  
  1276.     return;
  1277. }
  1278.  
  1279. /*
  1280.  * removes entries from the cache which are older than their expirey times.
  1281.  * returns the time at which the server should next poll the cache.
  1282.  */
  1283. time_t    expire_cache(now)
  1284. time_t    now;
  1285. {
  1286.     Reg1    aCache    *cp, *cp2;
  1287.     Reg2    time_t    next = 0;
  1288.  
  1289.     for (cp = cachetop; cp; cp = cp2)
  1290.         {
  1291.         cp2 = cp->list_next;
  1292.  
  1293.         if (now >= cp->expireat)
  1294.             {
  1295.             cainfo.ca_expires++;
  1296.             rem_cache(cp);
  1297.             }
  1298.         else if (!next || next > cp->expireat)
  1299.             next = cp->expireat;
  1300.         }
  1301.     return (next > now) ? next : (now + AR_TTL);
  1302. }
  1303.  
  1304. /*
  1305.  * remove all dns cache entries.
  1306.  */
  1307. void    flush_cache()
  1308. {
  1309.     Reg1    aCache    *cp;
  1310.  
  1311.     while ((cp = cachetop))
  1312.         rem_cache(cp);
  1313. }
  1314.  
  1315. int    m_dns(cptr, sptr, parc, parv)
  1316. aClient *cptr, *sptr;
  1317. int    parc;
  1318. char    *parv[];
  1319. {
  1320.     Reg1    aCache    *cp;
  1321.     Reg2    int    i;
  1322.  
  1323.     if (parv[1] && *parv[1] == 'l') {
  1324.         for(cp = cachetop; cp; cp = cp->list_next)
  1325.             {
  1326.             sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
  1327.                    parv[0], cp->expireat - time(NULL), cp->ttl,
  1328.                    cp->he.h_name, inetntoa(cp->he.h_addr));
  1329.             for (i = 0; cp->he.h_aliases[i]; i++)
  1330.                 sendto_one(sptr,"NOTICE %s : %s = %s (CN)",
  1331.                        parv[0], cp->he.h_name,
  1332.                        cp->he.h_aliases[i]);
  1333.             for (i = 1; cp->he.h_addr_list[i]; i++)
  1334.                 sendto_one(sptr,"NOTICE %s : %s = %s (IP)",
  1335.                        parv[0], cp->he.h_name,
  1336.                        inetntoa(cp->he.h_addr_list[i]));
  1337.             }
  1338.         return 0;
  1339.     }
  1340.     sendto_one(sptr,"NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
  1341.            sptr->name,
  1342.            cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
  1343.            cainfo.ca_lookups,
  1344.            cainfo.ca_na_hits, cainfo.ca_nu_hits, cainfo.ca_updates);
  1345.  
  1346.     sendto_one(sptr,"NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
  1347.            sptr->name, reinfo.re_errors, reinfo.re_nu_look,
  1348.            reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
  1349.     sendto_one(sptr,"NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
  1350.            reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
  1351.            reinfo.re_resends, reinfo.re_timeouts);
  1352.     return 0;
  1353. }
  1354.  
  1355. u_long    cres_mem(sptr)
  1356. aClient    *sptr;
  1357. {
  1358.     register aCache    *c = cachetop;
  1359.     register struct    hostent    *h;
  1360.     register int    i;
  1361.     u_long    nm = 0, im = 0, sm = 0, ts = 0;
  1362.  
  1363.     for ( ;c ; c = c->list_next)
  1364.         {
  1365.         sm += sizeof(*c);
  1366.         h = &c->he;
  1367.         for (i = 0; h->h_addr_list[i]; i++)
  1368.             {
  1369.             im += sizeof(char *);
  1370.             im += sizeof(struct in_addr);
  1371.             }
  1372.         im += sizeof(char *);
  1373.         for (i = 0; h->h_aliases[i]; i++)
  1374.             {
  1375.             nm += sizeof(char *);
  1376.             nm += strlen(h->h_aliases[i]);
  1377.             }
  1378.         nm += i - 1;
  1379.         nm += sizeof(char *);
  1380.         if (h->h_name)
  1381.             nm += strlen(h->h_name);
  1382.         }
  1383.     ts = ARES_CACSIZE * sizeof(CacheTable);
  1384.     sendto_one(sptr, ":%s %d %s :RES table %d",
  1385.            me.name, RPL_STATSDEBUG, sptr->name, ts);
  1386.     sendto_one(sptr, ":%s %d %s :Structs %d IP storage %d Name storage %d",
  1387.            me.name, RPL_STATSDEBUG, sptr->name, sm, im, nm);
  1388.     return ts + sm + im + nm;
  1389. }
  1390.