This commit was generated by cvs2svn to compensate for changes in r2,
[ircu2.10.12-pk.git] / ircd / res.c
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
9 #include "sys.h"
10 #include <signal.h>
11 #include <sys/socket.h>
12 #if HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 #include <netinet/in.h>
16 #include <arpa/inet.h>
17 #include <arpa/nameser.h>
18 #include <resolv.h>
19 /* dn_skipname is really an internal function,
20    we shouldn't be using it in res.c */
21 #if !defined(dn_skipname) && !defined(__dn_skipname)
22 extern int dn_skipname(const unsigned char *, const unsigned char *);
23 #endif
24 #include "h.h"
25 #include "res.h"
26 #include "struct.h"
27 #include "numeric.h"
28 #include "send.h"
29 #include "s_misc.h"
30 #include "s_bsd.h"
31 #include "ircd.h"
32 #include "s_ping.h"
33 #include "support.h"
34 #include "common.h"
35 #include "sprintf_irc.h"
36
37 RCSTAG_CC("$Id$");
38
39 #define MAXPACKET       1024
40
41 #define RES_MAXADDRS    35
42 #define RES_MAXALIASES  35
43
44 #define ALIASBLEN ((RES_MAXALIASES + 1) * sizeof(char *))
45 #define ADDRSBLEN ((RES_MAXADDRS + 1) * sizeof(struct in_addr *))
46 #define ADDRSDLEN (RES_MAXADDRS * sizeof(struct in_addr))
47 #define ALIASDLEN (MAXPACKET)
48 #define MAXGETHOSTLEN (ALIASBLEN + ADDRSBLEN + ADDRSDLEN + ALIASDLEN)
49
50 #define AR_TTL          600     /* TTL in seconds for dns cache entries */
51
52 #define ARES_CACSIZE    512
53 #define MAXCACHED       2048
54
55 #ifndef INT16SZ
56 #define INT16SZ 2
57 #endif
58 #ifndef INT32SZ
59 #define INT32SZ 4
60 #endif
61
62 /*
63  * Building the Hostent
64  * The Hostent struct is arranged like this:
65  *          +-------------------------------+
66  * Hostent: | struct hostent h              |
67  *          |-------------------------------|
68  *          | char *buf                     |
69  *          +-------------------------------+
70  *
71  * allocated:
72  *
73  *          +-------------------------------+
74  * buf:     | h_aliases pointer array       | Max size: ALIASBLEN;
75  *          | NULL                          | contains `char *'s
76  *          |-------------------------------|
77  *          | h_addr_list pointer array     | Max size: ADDRSBLEN;
78  *          | NULL                          | contains `struct in_addr *'s
79  *          |-------------------------------|
80  *          | h_addr_list addresses         | Max size: ADDRSDLEN;
81  *          |                               | contains `struct in_addr's
82  *          |-------------------------------|
83  *          | storage for hostname strings  | Max size: ALIASDLEN;
84  *          +-------------------------------+ contains `char's
85  *
86  *  For requests the size of the h_aliases, and h_addr_list pointer
87  *  array sizes are set to MAXALISES and MAXADDRS respectively, and
88  *  buf is a fixed size with enough space to hold the largest expected
89  *  reply from a nameserver, see RFC 1034 and RFC 1035.
90  *  For cached entries the sizes are dependent on the actual number
91  *  of aliases and addresses. If new aliases and addresses are found
92  *  for cached entries, the buffer is grown and the new entries are added.
93  *  The hostent struct is filled in with the addresses of the entries in
94  *  the Hostent buf as follows:
95  *  h_name      - contains a pointer to the start of the hostname string area,
96  *                or NULL if none is set.  The h_name is followed by the
97  *                aliases, in the storage for hostname strings area.
98  *  h_aliases   - contains a pointer to the start of h_aliases pointer array.
99  *                This array contains pointers to the storage for hostname
100  *                strings area and is terminated with a NULL.  The first alias
101  *                is stored directly after the h_name.
102  *  h_addr_list - contains a pointer to the start of h_addr_list pointer array.
103  *                This array contains pointers to in_addr structures in the
104  *                h_addr_list addresses area and is terminated with a NULL.
105  *
106  *  Filling the buffer this way allows for proper alignment of the h_addr_list
107  *  addresses.
108  *
109  *  This arrangement allows us to alias a Hostent struct pointer as a
110  *  real struct hostent* without lying. It also allows us to change the
111  *  values contained in the cached entries and requests without changing
112  *  the actual hostent pointer, which is saved in a client struct and can't
113  *  be changed without blowing things up or a lot more fiddling around.
114  *  It also allows for defered allocation of the fixed size buffers until
115  *  they are really needed.
116  *  Nov. 17, 1997 --Bleep
117  */
118
119 typedef struct Hostent {
120   struct hostent h;
121   char *buf;
122 } aHostent;
123
124 typedef struct reslist {
125   int id;
126   int sent;                     /* number of requests sent */
127   int srch;
128   time_t ttl;
129   char type;
130   char retries;                 /* retry counter */
131   char sends;                   /* number of sends (>1 means resent) */
132   char resend;                  /* send flag. 0 == dont resend */
133   time_t sentat;
134   time_t timeout;
135   struct in_addr addr;
136   char *name;
137   struct reslist *next;
138   Link cinfo;
139   aHostent he;
140 } ResRQ;
141
142 typedef struct cache {
143   time_t expireat;
144   time_t ttl;
145   aHostent he;
146   struct cache *hname_next, *hnum_next, *list_next;
147 } aCache;
148
149 typedef struct cachetable {
150   aCache *num_list;
151   aCache *name_list;
152 } CacheTable;
153
154 extern int resfd;               /* defined in s_bsd.c */
155
156 static char hostbuf[HOSTLEN + 1];
157 static char dot[] = ".";
158 static int incache = 0;
159 static CacheTable hashtable[ARES_CACSIZE];
160 static aCache *cachetop = NULL;
161 static ResRQ *last, *first;
162
163 static void rem_cache(aCache *);
164 static void rem_request(ResRQ *);
165 static int do_query_name(Link *, char *, ResRQ *);
166 static int do_query_number(Link *, struct in_addr *, ResRQ *);
167 static void resend_query(ResRQ *);
168 static int proc_answer(ResRQ *, HEADER *, unsigned char *, unsigned char *);
169 static int query_name(char *, int, int, ResRQ *);
170 static aCache *make_cache(ResRQ *);
171 static aCache *find_cache_name(char *);
172 static aCache *find_cache_number(ResRQ *, struct in_addr *);
173 static int add_request(ResRQ *);
174 static ResRQ *make_request(Link *);
175 static int send_res_msg(char *, int, int);
176 static ResRQ *find_id(int);
177 static int hash_number(unsigned char *);
178 static void update_list(ResRQ *, aCache *);
179 static int hash_name(const char *);
180
181 static struct cacheinfo {
182   int ca_adds;
183   int ca_dels;
184   int ca_expires;
185   int ca_lookups;
186   int ca_na_hits;
187   int ca_nu_hits;
188   int ca_updates;
189 } cainfo;
190
191 static struct resinfo {
192   int re_errors;
193   int re_nu_look;
194   int re_na_look;
195   int re_replies;
196   int re_requests;
197   int re_resends;
198   int re_sent;
199   int re_timeouts;
200   int re_shortttl;
201   int re_unkrep;
202 } reinfo;
203
204 int init_resolver(void)
205 {
206   int on = 1;
207   int fd = -1;
208
209   memset(&reinfo, 0, sizeof(reinfo));
210   memset(&cainfo, 0, sizeof(cainfo));
211   memset(hashtable, 0, sizeof(hashtable));
212
213   first = last = NULL;
214
215   /* res_init() always returns 0 */
216   (void)res_init();
217
218   if (!_res.nscount)
219   {
220     _res.nscount = 1;
221     _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
222   }
223 #ifdef DEBUGMODE
224   _res.options |= RES_DEBUG;
225 #endif
226
227   alarm(2);
228   fd = socket(AF_INET, SOCK_DGRAM, 0);
229   alarm(0);
230   if (fd < 0)
231   {
232     if (errno == EMFILE || errno == ENOBUFS)
233     {
234       /*
235        * Only try this one more time, if we can't create the resolver
236        * socket at initialization time, it's pointless to continue.
237        */
238       alarm(2);
239       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
240       {
241         alarm(0);
242         Debug((DEBUG_ERROR, "init_resolver: socket: No more sockets"));
243         return -1;
244       }
245       alarm(0);
246     }
247     else
248     {
249       Debug((DEBUG_ERROR, "init_resolver: socket: %s", strerror(errno)));
250       return -1;
251     }
252   }
253   setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (OPT_TYPE *)&on, sizeof(on));
254   return fd;
255 }
256
257 static int add_request(ResRQ *new_request)
258 {
259   if (!new_request)
260     return -1;
261   if (!first)
262     first = last = new_request;
263   else
264   {
265     last->next = new_request;
266     last = new_request;
267   }
268   new_request->next = NULL;
269   reinfo.re_requests++;
270   return 0;
271 }
272
273 /*
274  * Remove a request from the list. This must also free any memory that has
275  * been allocated for temporary storage of DNS results.
276  */
277 static void rem_request(ResRQ *old_request)
278 {
279   ResRQ **rptr;
280   ResRQ *r2ptr = NULL;
281
282   if (old_request)
283   {
284     for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next)
285     {
286       if (*rptr == old_request)
287       {
288         *rptr = old_request->next;
289         if (last == old_request)
290           last = r2ptr;
291         break;
292       }
293     }
294     Debug((DEBUG_DNS, "rem_request:Remove %p at %p %p",
295         old_request, *rptr, r2ptr));
296
297     if (old_request->he.buf)
298       RunFree(old_request->he.buf);
299     if (old_request->name)
300       RunFree(old_request->name);
301     RunFree(old_request);
302   }
303 }
304
305 /*
306  * Create a DNS request record for the server.
307  */
308 static ResRQ *make_request(Link *lp)
309 {
310   ResRQ *nreq;
311
312   if ((nreq = (ResRQ *)RunMalloc(sizeof(ResRQ))) == NULL)
313     return NULL;
314   memset(nreq, 0, sizeof(ResRQ));
315   nreq->sentat = now;
316   nreq->retries = 3;
317   nreq->resend = 1;
318   nreq->srch = -1;
319   if (lp)
320     memcpy(&nreq->cinfo, lp, sizeof(Link));
321   else
322     memset(&nreq->cinfo, 0, sizeof(Link));
323   nreq->timeout = 4;            /* start at 4 and exponential inc. */
324   nreq->addr.s_addr = INADDR_NONE;
325
326   nreq->he.h.h_addrtype = AF_INET;
327   nreq->he.h.h_length = sizeof(struct in_addr);
328   add_request(nreq);
329   return nreq;
330 }
331
332 /*
333  * Remove queries from the list which have been there too long without
334  * being resolved.
335  */
336 time_t timeout_query_list(void)
337 {
338   ResRQ *rptr;
339   ResRQ *r2ptr;
340   time_t next = 0;
341   time_t tout = 0;
342   aClient *cptr;
343
344   Debug((DEBUG_DNS, "timeout_query_list at %s", myctime(now)));
345   for (rptr = first; rptr; rptr = r2ptr)
346   {
347     r2ptr = rptr->next;
348     tout = rptr->sentat + rptr->timeout;
349     if (now >= tout)
350     {
351       if (--rptr->retries <= 0)
352       {
353         Debug((DEBUG_DNS, "timeout %p now " TIME_T_FMT " cptr %p",
354             rptr, now, rptr->cinfo.value.cptr));
355         reinfo.re_timeouts++;
356         cptr = rptr->cinfo.value.cptr;
357         switch (rptr->cinfo.flags)
358         {
359           case ASYNC_CLIENT:
360             ClearDNS(cptr);
361             if (!DoingAuth(cptr))
362               SetAccess(cptr);
363             break;
364           case ASYNC_PING:
365             sendto_ops("Host %s unknown", rptr->name);
366             end_ping(cptr);
367             break;
368           case ASYNC_CONNECT:
369             sendto_ops("Host %s unknown", rptr->name);
370             break;
371         }
372         rem_request(rptr);
373         rptr = NULL;
374         continue;
375       }
376       else
377       {
378         rptr->sentat = now;
379         rptr->timeout += rptr->timeout;
380         resend_query(rptr);
381         tout = now + rptr->timeout;
382         Debug((DEBUG_DNS, "r %p now " TIME_T_FMT " retry %d c %p",
383             rptr, now, rptr->retries, rptr->cinfo.value.cptr));
384       }
385     }
386     if (!next || tout < next)
387       next = tout;
388   }
389   Debug((DEBUG_DNS, "Next timeout_query_list() at %s, %ld",
390       myctime((next > now) ? next : (now + AR_TTL)),
391       (next > now) ? (next - now) : AR_TTL));
392   return (next > now) ? next : (now + AR_TTL);
393 }
394
395 /*
396  * del_queries
397  *
398  * Called by the server to cleanup outstanding queries for
399  * which there no longer exist clients or conf lines.
400  */
401 void del_queries(char *cp)
402 {
403   ResRQ *rptr, *r2ptr;
404
405   for (rptr = first; rptr; rptr = r2ptr)
406   {
407     r2ptr = rptr->next;
408     if (cp == rptr->cinfo.value.cp)
409       rem_request(rptr);
410   }
411 }
412
413 /*
414  * send_res_msg
415  *
416  * sends msg to all nameservers found in the "_res" structure.
417  * This should reflect /etc/resolv.conf. We will get responses
418  * which arent needed but is easier than checking to see if nameserver
419  * isnt present. Returns number of messages successfully sent to
420  * nameservers or -1 if no successful sends.
421  */
422 static int send_res_msg(char *msg, int len, int rcount)
423 {
424   int i;
425   int sent = 0, max;
426
427   if (!msg)
428     return -1;
429
430   max = MIN(_res.nscount, rcount);
431   if (_res.options & RES_PRIMARY)
432     max = 1;
433   if (!max)
434     max = 1;
435
436   for (i = 0; i < max; ++i)
437   {
438     _res.nsaddr_list[i].sin_family = AF_INET;
439     if (sendto(resfd, msg, len, 0, (struct sockaddr *)&(_res.nsaddr_list[i]),
440         sizeof(struct sockaddr)) == len)
441     {
442       reinfo.re_sent++;
443       sent++;
444     }
445     else
446       Debug((DEBUG_ERROR, "s_r_m:sendto: %s on %d", strerror(errno), resfd));
447   }
448   return (sent) ? sent : -1;
449 }
450
451 /*
452  * find a dns request id (id is determined by dn_mkquery)
453  */
454 static ResRQ *find_id(int id)
455 {
456   ResRQ *rptr;
457
458   for (rptr = first; rptr; rptr = rptr->next)
459     if (rptr->id == id)
460       return rptr;
461   return NULL;
462 }
463
464 /*
465  * add_local_domain
466  *
467  * Add the domain to hostname, if it is missing
468  * (as suggested by eps@TOASTER.SFSU.EDU)
469  */
470 void add_local_domain(char *hname, int size)
471 {
472   /* try to fix up unqualified names */
473   if (!strchr(hname, '.'))
474   {
475     if (_res.defdname[0] && size > 0)
476     {
477       strcat(hname, ".");
478       strncat(hname, _res.defdname, size - 1);
479     }
480   }
481 }
482
483 struct hostent *gethost_byname(char *name, Link *lp)
484 {
485   aCache *cp;
486
487   reinfo.re_na_look++;
488   if ((cp = find_cache_name(name)))
489     return &cp->he.h;
490   if (lp)
491     do_query_name(lp, name, NULL);
492   return NULL;
493 }
494
495 struct hostent *gethost_byaddr(struct in_addr *addr, Link *lp)
496 {
497   aCache *cp;
498
499   reinfo.re_nu_look++;
500   if ((cp = find_cache_number(NULL, addr)))
501     return &cp->he.h;
502   if (!lp)
503     return NULL;
504   do_query_number(lp, addr, NULL);
505   return NULL;
506 }
507
508 static int do_query_name(Link *lp, char *name, ResRQ *rptr)
509 {
510   char hname[HOSTLEN + 1];
511   int len;
512
513   strncpy(hname, name, sizeof(hname) - 1);
514   hname[sizeof(hname) - 1] = 0;
515   len = strlen(hname);
516
517   if (rptr && !strchr(hname, '.') && _res.options & RES_DEFNAMES)
518   {
519     strncat(hname, dot, sizeof(hname) - len - 1);
520     len++;
521     strncat(hname, _res.defdname, sizeof(hname) - len - 1);
522   }
523
524   /*
525    * Store the name passed as the one to lookup and generate other host
526    * names to pass onto the nameserver(s) for lookups.
527    */
528   if (!rptr)
529   {
530     if ((rptr = make_request(lp)) == NULL)
531       return -1;
532     rptr->type = T_A;
533     rptr->name = (char *)RunMalloc(strlen(name) + 1);
534     strcpy(rptr->name, name);
535   }
536   return (query_name(hname, C_IN, T_A, rptr));
537 }
538
539 /*
540  * Use this to do reverse IP# lookups.
541  */
542 static int do_query_number(Link *lp, struct in_addr *numb, ResRQ *rptr)
543 {
544   char ipbuf[32];
545   Reg2 unsigned char *cp = (unsigned char *)&numb->s_addr;
546
547   sprintf_irc(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
548       (unsigned int)(cp[3]), (unsigned int)(cp[2]),
549       (unsigned int)(cp[1]), (unsigned int)(cp[0]));
550
551   if (!rptr)
552   {
553     if ((rptr = make_request(lp)) == NULL)
554       return -1;
555     rptr->type = T_PTR;
556     rptr->addr.s_addr = numb->s_addr;
557   }
558   return (query_name(ipbuf, C_IN, T_PTR, rptr));
559 }
560
561 /*
562  * generate a query based on class, type and name.
563  */
564 static int query_name(char *name, int q_class, int type, ResRQ *rptr)
565 {
566   struct timeval tv;
567   char buf[MAXPACKET];
568   int r, s, k = 0;
569   HEADER *hptr;
570
571   Debug((DEBUG_DNS, "query_name: na %s cl %d ty %d", name, q_class, type));
572   memset(buf, 0, sizeof(buf));
573   r = res_mkquery(QUERY, name, q_class, type, NULL, 0, NULL,
574       (unsigned char *)buf, sizeof(buf));
575   if (r <= 0)
576   {
577     h_errno = NO_RECOVERY;
578     return r;
579   }
580   hptr = (HEADER *) buf;
581   gettimeofday(&tv, NULL);
582   do
583   {
584     /* htons/ntohs can be assembler macros, which cannot
585        be nested. Thus two lines.   -Vesa */
586     unsigned short int nstmp = ntohs(hptr->id) + k
587         + (unsigned short int)(tv.tv_usec & 0xffff);
588     hptr->id = htons(nstmp);
589     k++;
590   }
591   while (find_id(ntohs(hptr->id)));
592   rptr->id = ntohs(hptr->id);
593   rptr->sends++;
594   s = send_res_msg(buf, r, rptr->sends);
595   if (s == -1)
596   {
597     h_errno = TRY_AGAIN;
598     return -1;
599   }
600   else
601     rptr->sent += s;
602   return 0;
603 }
604
605 static void resend_query(ResRQ *rptr)
606 {
607   if (rptr->resend == 0)
608     return;
609   reinfo.re_resends++;
610   switch (rptr->type)
611   {
612     case T_PTR:
613       do_query_number(NULL, &rptr->addr, rptr);
614       break;
615     case T_A:
616       do_query_name(NULL, rptr->name, rptr);
617       break;
618     default:
619       break;
620   }
621   return;
622 }
623
624 /*
625  * proc_answer
626  *
627  * Process name server reply.
628  */
629 static int proc_answer(ResRQ *rptr, HEADER * hptr, unsigned char *buf,
630     unsigned char *eob)
631 {
632   unsigned char *cp = buf + sizeof(HEADER);
633   char **alias;
634   char **addr;
635   char *p;                      /* pointer to strings */
636   char *a;                      /* pointer to address list */
637   char *endp;                   /* end of our buffer */
638   struct hostent *hp = &rptr->he.h;
639   int addr_class, type, dlen, ans = 0, n;
640   int addr_count = 0;
641   int alias_count = 0;
642
643   /*
644    * Lazy allocation of rptr->he.buf, we don't allocate a buffer
645    * unless there's something to put in it.
646    */
647   if (!rptr->he.buf)
648   {
649     if ((rptr->he.buf = (char *)RunMalloc(MAXGETHOSTLEN)) == NULL)
650       return 0;
651     /* 
652      * Array of alias list pointers starts at beginning of buf 
653      */
654     rptr->he.h.h_aliases = (char **)rptr->he.buf;
655     rptr->he.h.h_aliases[0] = NULL;
656     /* 
657      * Array of address list pointers starts after alias list pointers.
658      * The actual addresses follow the address list pointers.
659      */
660     rptr->he.h.h_addr_list = (char **)(rptr->he.buf + ALIASBLEN);
661     a = (char *)rptr->he.h.h_addr_list + ADDRSBLEN;
662     /*
663        * don't copy the host address to the beginning of h_addr_list
664        * make it just a little bit harder for the script kiddies
665      */
666     rptr->he.h.h_addr_list[0] = NULL;
667   }
668   endp = &rptr->he.buf[MAXGETHOSTLEN];
669
670   /* find the end of the address list */
671   addr = hp->h_addr_list;
672   while (*addr)
673   {
674     ++addr;
675     ++addr_count;
676   }
677   /* make 'a' point to the first available empty address slot */
678   a = (char *)hp->h_addr_list + ADDRSBLEN +
679       (addr_count * sizeof(struct in_addr));
680
681   /* find the end of the alias list */
682   alias = hp->h_aliases;
683   while (*alias)
684   {
685     ++alias;
686     ++alias_count;
687   }
688   /* make p point to the first available space in rptr->buf */
689   if (alias_count > 0)
690   {
691     p = (char *)hp->h_aliases[alias_count - 1];
692     p += (strlen(p) + 1);
693   }
694   else if (hp->h_name)
695     p = (char *)(hp->h_name + strlen(hp->h_name) + 1);
696   else
697     p = (char *)rptr->he.h.h_addr_list + ADDRSBLEN + ADDRSDLEN;
698
699   /*
700    * Skip past query's
701    */
702 #ifdef SOL2                     /* brain damaged compiler (Solaris2) it seems */
703   for (; hptr->qdcount > 0; hptr->qdcount--)
704 #else
705   while (hptr->qdcount-- > 0)
706 #endif
707   {
708     if ((n = dn_skipname(cp, eob)) == -1)
709       break;
710     else
711       cp += (n + QFIXEDSZ);
712   }
713   /*
714    * Proccess each answer sent to us blech.
715    */
716   while (hptr->ancount-- > 0 && cp && cp < eob && p < endp)
717   {
718     if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) <= 0)
719     {
720       Debug((DEBUG_DNS, "dn_expand failed"));
721       break;
722     }
723
724     cp += n;
725     /* XXX magic numbers, this checks for truncated packets */
726     if ((cp + INT16SZ + INT16SZ + INT32SZ + INT16SZ) >= eob)
727       break;
728
729     /*
730      * I have no idea why - maybe a bug in the linker? But _getshort
731      * and _getlong don't work anymore.  So lets do it ourselfs:
732      * --Run
733      */
734
735     type = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
736     cp += INT16SZ;
737     addr_class = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
738     cp += INT16SZ;
739     rptr->ttl =
740         ((u_int32_t) cp[0] << 24) | ((u_int32_t) cp[1] << 16) | ((u_int32_t)
741         cp[2] << 8) | ((u_int32_t) cp[3]);
742     cp += INT32SZ;
743     dlen = ((u_int16_t) cp[0] << 8) | ((u_int16_t) cp[1]);
744     cp += INT16SZ;
745
746     rptr->type = type;
747
748     /* check for bad dlen */
749     if ((cp + dlen) > eob)
750       break;
751
752     /* 
753      * Add default domain name to returned host name if host name
754      * doesn't contain any dot separators.
755      * Name server never returns with trailing '.'
756      */
757     if (!strchr(hostbuf, '.') && (_res.options & RES_DEFNAMES))
758     {
759       strcat(hostbuf, dot);
760       strncat(hostbuf, _res.defdname, HOSTLEN - strlen(hostbuf));
761       hostbuf[HOSTLEN] = 0;
762     }
763
764     switch (type)
765     {
766       case T_A:
767         /* check for invalid dlen or too many addresses */
768         if (dlen != sizeof(struct in_addr) || ++addr_count >= RES_MAXADDRS)
769           break;
770         if (ans == 1)
771           hp->h_addrtype = (addr_class == C_IN) ? AF_INET : AF_UNSPEC;
772
773         memcpy(a, cp, sizeof(struct in_addr));
774         *addr++ = a;
775         *addr = 0;
776         a += sizeof(struct in_addr);
777
778         if (!hp->h_name)
779         {
780           strncpy(p, hostbuf, endp - p);
781           hp->h_name = p;
782           p += (strlen(p) + 1);
783         }
784         cp += dlen;
785         Debug((DEBUG_DNS, "got ip # %s for %s",
786             inetntoa(*((struct in_addr *)hp->h_addr_list[addr_count - 1])),
787             hostbuf));
788         ans++;
789         break;
790       case T_PTR:
791         if ((n = dn_expand(buf, eob, cp, hostbuf, sizeof(hostbuf))) < 0)
792         {
793           cp = NULL;
794           break;
795         }
796         cp += n;
797         Debug((DEBUG_DNS, "got host %s", hostbuf));
798         /*
799          * Copy the returned hostname into the host name or alias field if
800          * there is a known hostname already.
801          */
802         if (hp->h_name)
803         {
804           if (++alias_count >= RES_MAXALIASES)
805             break;
806           strncpy(p, hostbuf, endp - p);
807           endp[-1] = 0;
808           *alias++ = p;
809           *alias = NULL;
810         }
811         else
812         {
813           strncpy(p, hostbuf, endp - p);
814           hp->h_name = p;
815         }
816         p += (strlen(p) + 1);
817         ans++;
818         break;
819       case T_CNAME:
820         cp += dlen;
821         Debug((DEBUG_DNS, "got cname %s", hostbuf));
822         if (++alias_count >= RES_MAXALIASES)
823           break;
824         strncpy(p, hostbuf, endp - p);
825         endp[-1] = 0;
826         *alias++ = p;
827         *alias = NULL;
828         p += (strlen(p) + 1);
829         ans++;
830         break;
831       default:
832         Debug((DEBUG_DNS, "proc_answer: type:%d for:%s", type, hostbuf));
833         break;
834     }
835   }
836   return ans;
837 }
838
839 /*
840  * Read a dns reply from the nameserver and process it.
841  */
842 struct hostent *get_res(char *lp)
843 {
844   static unsigned char buf[sizeof(HEADER) + MAXPACKET];
845   Reg1 HEADER *hptr;
846   Reg2 ResRQ *rptr = NULL;
847   aCache *cp = NULL;
848   struct sockaddr_in sin;
849   int a, max;
850   size_t rc, len = sizeof(sin);
851
852   alarm(4);
853   rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len);
854   alarm(0);
855
856   if (rc <= sizeof(HEADER))
857     return NULL;
858   /*
859    * Convert DNS reply reader from Network byte order to CPU byte order.
860    */
861   hptr = (HEADER *) buf;
862   hptr->id = ntohs(hptr->id);
863   hptr->ancount = ntohs(hptr->ancount);
864   hptr->qdcount = ntohs(hptr->qdcount);
865   hptr->nscount = ntohs(hptr->nscount);
866   hptr->arcount = ntohs(hptr->arcount);
867 #ifdef  DEBUG
868   Debug((DEBUG_NOTICE, "get_res:id = %d rcode = %d ancount = %d",
869       hptr->id, hptr->rcode, hptr->ancount));
870 #endif
871   reinfo.re_replies++;
872   /*
873    * Response for an id which we have already received an answer for
874    * just ignore this response.
875    */
876   if ((rptr = find_id(hptr->id)) == NULL)
877   {
878     Debug((DEBUG_DNS, "find_id %d failed", hptr->id));
879     return NULL;
880   }
881   /*
882    * Check against possibly fake replies
883    */
884   max = MIN(_res.nscount, rptr->sends);
885   if (!max)
886     max = 1;
887
888   for (a = 0; a < max; a++)
889   {
890     if (!_res.nsaddr_list[a].sin_addr.s_addr ||
891         !memcmp((char *)&sin.sin_addr, (char *)&_res.nsaddr_list[a].sin_addr,
892         sizeof(struct in_addr)))
893       break;
894   }
895   if (a == max)
896   {
897     reinfo.re_unkrep++;
898     Debug((DEBUG_DNS, "got response from unknown ns"));
899     goto getres_err;
900   }
901
902   if ((hptr->rcode != NOERROR) || (hptr->ancount == 0))
903   {
904     switch (hptr->rcode)
905     {
906       case NXDOMAIN:
907         h_errno = TRY_AGAIN;
908         break;
909       case SERVFAIL:
910         h_errno = TRY_AGAIN;
911         break;
912       case NOERROR:
913         h_errno = NO_DATA;
914         break;
915       case FORMERR:
916       case NOTIMP:
917       case REFUSED:
918       default:
919         h_errno = NO_RECOVERY;
920         break;
921     }
922     reinfo.re_errors++;
923     /*
924      * If a bad error was returned, we stop here and dont send
925      * send any more (no retries granted).
926      */
927     if (h_errno != TRY_AGAIN)
928     {
929       Debug((DEBUG_DNS, "Fatal DNS error %d for %d", h_errno, hptr->rcode));
930       rptr->resend = 0;
931       rptr->retries = 0;
932     }
933     goto getres_err;
934   }
935   /* 
936    * If this fails we didn't get a buffer to hold the hostent or
937    * there was an error decoding the received packet, try it again
938    * and hope it works the next time.
939    */
940   a = proc_answer(rptr, hptr, buf, &buf[rc]);
941   Debug((DEBUG_DNS, "get_res:Proc answer = %d", a));
942
943   if (a && rptr->type == T_PTR)
944   {
945     struct hostent *hp2 = NULL;
946
947     if (BadPtr(rptr->he.h.h_name))      /* Kludge!      960907/Vesa */
948       goto getres_err;
949
950     Debug((DEBUG_DNS, "relookup %s <-> %s", rptr->he.h.h_name,
951         inetntoa(rptr->addr)));
952     /*
953      * Lookup the 'authoritive' name that we were given for the
954      * ip#.  By using this call rather than regenerating the
955      * type we automatically gain the use of the cache with no
956      * extra kludges.
957      */
958     if ((hp2 = gethost_byname((char *)rptr->he.h.h_name, &rptr->cinfo)))
959     {
960       if (lp)
961         memcpy(lp, &rptr->cinfo, sizeof(Link));
962     }
963     /*
964      * If name wasn't found, a request has been queued and it will
965      * be the last one queued.  This is rather nasty way to keep
966      * a host alias with the query. -avalon
967      */
968     else if (*rptr->he.h.h_aliases)
969     {
970       if (last->he.buf)
971         RunFree(last->he.buf);
972       last->he.buf = rptr->he.buf;
973       rptr->he.buf = NULL;
974       memcpy(&last->he.h, &rptr->he.h, sizeof(struct hostent));
975     }
976     rem_request(rptr);
977     return hp2;
978   }
979
980   if (a > 0)
981   {
982     if (lp)
983       memcpy(lp, &rptr->cinfo, sizeof(Link));
984     cp = make_cache(rptr);
985     Debug((DEBUG_DNS, "get_res:cp=%p rptr=%p (made)", cp, rptr));
986     rem_request(rptr);
987   }
988   else if (!rptr->sent)
989     rem_request(rptr);
990   return cp ? &cp->he.h : NULL;
991
992 getres_err:
993   /*
994    * Reprocess an error if the nameserver didnt tell us to "TRY_AGAIN".
995    */
996   if (rptr)
997   {
998     if (h_errno != TRY_AGAIN)
999     {
1000       /*
1001        * If we havent tried with the default domain and its
1002        * set, then give it a try next.
1003        */
1004       if (_res.options & RES_DEFNAMES && ++rptr->srch == 0)
1005       {
1006         rptr->retries = _res.retry;
1007         rptr->sends = 0;
1008         rptr->resend = 1;
1009         resend_query(rptr);
1010       }
1011       else
1012         resend_query(rptr);
1013     }
1014     else if (lp)
1015       memcpy(lp, &rptr->cinfo, sizeof(Link));
1016   }
1017   return NULL;
1018 }
1019
1020 /*
1021  * Duplicate a hostent struct, allocate only enough memory for
1022  * the data we're putting in it.
1023  */
1024 static int dup_hostent(aHostent *new_hp, struct hostent *hp)
1025 {
1026   char *p;
1027   char **ap;
1028   char **pp;
1029   int alias_count = 0;
1030   int addr_count = 0;
1031   size_t bytes_needed = 0;
1032
1033   if (!new_hp || !hp)
1034     return 0;
1035
1036   /* how much buffer do we need? */
1037   bytes_needed += (strlen(hp->h_name) + 1);
1038
1039   pp = hp->h_aliases;
1040   while (*pp)
1041   {
1042     bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
1043     ++alias_count;
1044   }
1045   pp = hp->h_addr_list;
1046   while (*pp++)
1047   {
1048     bytes_needed += (hp->h_length + sizeof(void *));
1049     ++addr_count;
1050   }
1051   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1052   bytes_needed += (2 * sizeof(void *));
1053
1054   /* Allocate memory */
1055   if ((new_hp->buf = (char *)RunMalloc(bytes_needed)) == NULL)
1056     return -1;
1057
1058   new_hp->h.h_addrtype = hp->h_addrtype;
1059   new_hp->h.h_length = hp->h_length;
1060
1061   /* first write the address list */
1062   pp = hp->h_addr_list;
1063   ap = new_hp->h.h_addr_list =
1064       (char **)(new_hp->buf + ((alias_count + 1) * sizeof(void *)));
1065   p = (char *)ap + ((addr_count + 1) * sizeof(void *));
1066   while (*pp)
1067   {
1068     *ap++ = p;
1069     memcpy(p, *pp++, hp->h_length);
1070     p += hp->h_length;
1071   }
1072   *ap = 0;
1073   /* next write the name */
1074   new_hp->h.h_name = p;
1075   strcpy(p, hp->h_name);
1076   p += (strlen(p) + 1);
1077
1078   /* last write the alias list */
1079   pp = hp->h_aliases;
1080   ap = new_hp->h.h_aliases = (char **)new_hp->buf;
1081   while (*pp)
1082   {
1083     *ap++ = p;
1084     strcpy(p, *pp++);
1085     p += (strlen(p) + 1);
1086   }
1087   *ap = 0;
1088
1089   return 0;
1090 }
1091
1092 /*
1093  * Add records to a Hostent struct in place.
1094  */
1095 static int update_hostent(aHostent *hp, char **addr, char **alias)
1096 {
1097   char *p;
1098   char **ap;
1099   char **pp;
1100   int alias_count = 0;
1101   int addr_count = 0;
1102   char *buf = NULL;
1103   size_t bytes_needed = 0;
1104
1105   if (!hp || !hp->buf)
1106     return -1;
1107
1108   /* how much buffer do we need? */
1109   bytes_needed = strlen(hp->h.h_name) + 1;
1110   pp = hp->h.h_aliases;
1111   while (*pp)
1112   {
1113     bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
1114     ++alias_count;
1115   }
1116   if (alias)
1117   {
1118     pp = alias;
1119     while (*pp)
1120     {
1121       bytes_needed += (strlen(*pp++) + 1 + sizeof(void *));
1122       ++alias_count;
1123     }
1124   }
1125   pp = hp->h.h_addr_list;
1126   while (*pp++)
1127   {
1128     bytes_needed += (hp->h.h_length + sizeof(void *));
1129     ++addr_count;
1130   }
1131   if (addr)
1132   {
1133     pp = addr;
1134     while (*pp++)
1135     {
1136       bytes_needed += (hp->h.h_length + sizeof(void *));
1137       ++addr_count;
1138     }
1139   }
1140   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1141   bytes_needed += 2 * sizeof(void *);
1142
1143   /* Allocate memory */
1144   if ((buf = (char *)RunMalloc(bytes_needed)) == NULL)
1145     return -1;
1146
1147   /* first write the address list */
1148   pp = hp->h.h_addr_list;
1149   ap = hp->h.h_addr_list =
1150       (char **)(buf + ((alias_count + 1) * sizeof(void *)));
1151   p = (char *)ap + ((addr_count + 1) * sizeof(void *));
1152   while (*pp)
1153   {
1154     memcpy(p, *pp++, hp->h.h_length);
1155     *ap++ = p;
1156     p += hp->h.h_length;
1157   }
1158   if (addr)
1159   {
1160     while (*addr)
1161     {
1162       memcpy(p, *addr++, hp->h.h_length);
1163       *ap++ = p;
1164       p += hp->h.h_length;
1165     }
1166   }
1167   *ap = 0;
1168
1169   /* next write the name */
1170   strcpy(p, hp->h.h_name);
1171   hp->h.h_name = p;
1172   p += (strlen(p) + 1);
1173
1174   /* last write the alias list */
1175   pp = hp->h.h_aliases;
1176   ap = hp->h.h_aliases = (char **)buf;
1177   while (*pp)
1178   {
1179     strcpy(p, *pp++);
1180     *ap++ = p;
1181     p += (strlen(p) + 1);
1182   }
1183   if (alias)
1184   {
1185     while (*alias)
1186     {
1187       strcpy(p, *alias++);
1188       *ap++ = p;
1189       p += (strlen(p) + 1);
1190     }
1191   }
1192   *ap = 0;
1193   /* release the old buffer */
1194   p = hp->buf;
1195   hp->buf = buf;
1196   RunFree(p);
1197   return 0;
1198 }
1199
1200 static int hash_number(unsigned char *ip)
1201 {
1202   unsigned int hashv = 0;
1203
1204   /* could use loop but slower */
1205   hashv += (int)*ip++;
1206   hashv += hashv + (int)*ip++;
1207   hashv += hashv + (int)*ip++;
1208   hashv += hashv + (int)*ip++;
1209   hashv %= ARES_CACSIZE;
1210   return (hashv);
1211 }
1212
1213 static int hash_name(const char *name)
1214 {
1215   unsigned int hashv = 0;
1216
1217   for (; *name && *name != '.'; name++)
1218     hashv += *name;
1219   hashv %= ARES_CACSIZE;
1220   return (hashv);
1221 }
1222
1223 /*
1224  * Add a new cache item to the queue and hash table.
1225  */
1226 static aCache *add_to_cache(aCache *ocp)
1227 {
1228   aCache *cp = NULL;
1229   int hashv;
1230
1231   Debug((DEBUG_DNS,
1232       "add_to_cache:ocp %p he %p name %p addrl %p 0 %p",
1233       ocp, &ocp->he, ocp->he.h.h_name, ocp->he.h.h_addr_list,
1234       ocp->he.h.h_addr_list[0]));
1235
1236   ocp->list_next = cachetop;
1237   cachetop = ocp;
1238
1239   hashv = hash_name(ocp->he.h.h_name);
1240   ocp->hname_next = hashtable[hashv].name_list;
1241   hashtable[hashv].name_list = ocp;
1242
1243   hashv = hash_number((unsigned char *)ocp->he.h.h_addr_list[0]);
1244   ocp->hnum_next = hashtable[hashv].num_list;
1245   hashtable[hashv].num_list = ocp;
1246
1247   Debug((DEBUG_DNS, "add_to_cache:added %s[%p] cache %p.",
1248       ocp->he.h.h_name, ocp->he.h.h_addr_list[0], ocp));
1249   Debug((DEBUG_DNS,
1250       "add_to_cache:h1 %d h2 %#x lnext %p namnext %p numnext %p",
1251       hash_name(ocp->he.h.h_name), hashv, ocp->list_next,
1252       ocp->hname_next, ocp->hnum_next));
1253
1254   /*
1255    * LRU deletion of excessive cache entries.
1256    */
1257   if (++incache > MAXCACHED)
1258   {
1259     for (cp = cachetop; cp->list_next; cp = cp->list_next);
1260     rem_cache(cp);
1261   }
1262   cainfo.ca_adds++;
1263
1264   return ocp;
1265 }
1266
1267 /*
1268  * update_list
1269  *
1270  * Does not alter the cache structure passed. It is assumed that
1271  * it already contains the correct expire time, if it is a new entry. Old
1272  * entries have the expirey time updated.
1273  */
1274 static void update_list(ResRQ *rptr, aCache *cp)
1275 {
1276   aCache **cpp;
1277   char *s;
1278   char **ap;
1279   const char *t;
1280   int i, j;
1281   static char *addrs[RES_MAXADDRS + 1];
1282   static char *aliases[RES_MAXALIASES + 1];
1283
1284   /*
1285    * Search for the new cache item in the cache list by hostname.
1286    * If found, move the entry to the top of the list and return.
1287    */
1288   cainfo.ca_updates++;
1289
1290   for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next))
1291   {
1292     if (cp == *cpp)
1293       break;
1294   }
1295   if (!*cpp)
1296     return;
1297   *cpp = cp->list_next;
1298   cp->list_next = cachetop;
1299   cachetop = cp;
1300   if (!rptr)
1301     return;
1302
1303   Debug((DEBUG_DNS, "u_l:cp %p na %p al %p ad %p",
1304       cp, cp->he.h.h_name, cp->he.h.h_aliases, cp->he.h.h_addr_list[0]));
1305   Debug((DEBUG_DNS, "u_l:rptr %p h_n %p", rptr, rptr->he.h.h_name));
1306   /*
1307    * Compare the cache entry against the new record.  Add any
1308    * previously missing names for this entry.
1309    */
1310
1311   *aliases = 0;
1312   ap = aliases;
1313   for (i = 0, s = (char *)rptr->he.h.h_name; s; s = rptr->he.h.h_aliases[i++])
1314   {
1315     for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++])
1316     {
1317       if (!strCasediff(t, s))
1318         break;
1319     }
1320     if (!t)
1321     {
1322       *ap++ = s;
1323       *ap = 0;
1324     }
1325   }
1326
1327   /*
1328    * Do the same again for IP#'s.
1329    */
1330   *addrs = 0;
1331   ap = addrs;
1332   for (i = 0; (s = rptr->he.h.h_addr_list[i]); i++)
1333   {
1334     for (j = 0; (t = cp->he.h.h_addr_list[j]); j++)
1335     {
1336       if (!memcmp(t, s, sizeof(struct in_addr)))
1337         break;
1338     }
1339     if (!t)
1340     {
1341       *ap++ = s;
1342       *ap = 0;
1343     }
1344   }
1345   if (*addrs || *aliases)
1346     update_hostent(&cp->he, addrs, aliases);
1347 }
1348
1349 static aCache *find_cache_name(char *name)
1350 {
1351   aCache *cp;
1352   const char *s;
1353   int hashv;
1354   int i;
1355
1356   hashv = hash_name(name);
1357
1358   cp = hashtable[hashv].name_list;
1359   Debug((DEBUG_DNS, "find_cache_name:find %s : hashv = %d", name, hashv));
1360
1361   for (; cp; cp = cp->hname_next)
1362   {
1363     for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++])
1364     {
1365       if (strCasediff(s, name) == 0)
1366       {
1367         cainfo.ca_na_hits++;
1368         update_list(0, cp);
1369         return cp;
1370       }
1371     }
1372   }
1373
1374   for (cp = cachetop; cp; cp = cp->list_next)
1375   {
1376     /*
1377      * If no aliases or the hash value matches, we've already
1378      * done this entry and all possiblilities concerning it.
1379      */
1380     if (!*cp->he.h.h_aliases)
1381       continue;
1382     if (hashv == hash_name(cp->he.h.h_name))
1383       continue;
1384     for (i = 0; (s = cp->he.h.h_aliases[i]); ++i)
1385     {
1386       if (!strCasediff(name, s))
1387       {
1388         cainfo.ca_na_hits++;
1389         update_list(0, cp);
1390         return cp;
1391       }
1392     }
1393   }
1394   return NULL;
1395 }
1396
1397 /*
1398  * Find a cache entry by ip# and update its expire time
1399  */
1400 static aCache *find_cache_number(ResRQ *rptr, struct in_addr *numb)
1401 {
1402   Reg1 aCache *cp;
1403   Reg2 int hashv, i;
1404
1405   hashv = hash_number((unsigned char *)numb);
1406
1407   cp = hashtable[hashv].num_list;
1408   Debug((DEBUG_DNS, "find_cache_number:find %s[%08x]: hashv = %d",
1409       inetntoa(*numb), ntohl(numb->s_addr), hashv));
1410
1411   for (; cp; cp = cp->hnum_next)
1412   {
1413     for (i = 0; cp->he.h.h_addr_list[i]; ++i)
1414     {
1415       if (!memcmp(cp->he.h.h_addr_list[i], (char *)numb,
1416           sizeof(struct in_addr)))
1417       {
1418         cainfo.ca_nu_hits++;
1419         update_list(rptr, cp);
1420         return cp;
1421       }
1422     }
1423   }
1424
1425   for (cp = cachetop; cp; cp = cp->list_next)
1426   {
1427     /*
1428      * Single address entry...would have been done by hashed search above...
1429      */
1430     if (!cp->he.h.h_addr_list[1])
1431       continue;
1432     /*
1433      * If the first IP# has the same hashnumber as the IP# we
1434      * are looking for, its been done already.
1435      */
1436     if (hashv == hash_number((unsigned char *)cp->he.h.h_addr_list[0]))
1437       continue;
1438     for (i = 1; cp->he.h.h_addr_list[i]; ++i)
1439     {
1440       if (!memcmp(cp->he.h.h_addr_list[i], (char *)numb,
1441           sizeof(struct in_addr)))
1442       {
1443         cainfo.ca_nu_hits++;
1444         update_list(rptr, cp);
1445         return cp;
1446       }
1447     }
1448   }
1449   return NULL;
1450 }
1451
1452 static aCache *make_cache(ResRQ *rptr)
1453 {
1454   aCache *cp;
1455   int i;
1456   struct hostent *hp = &rptr->he.h;
1457
1458   /*
1459    * Shouldn't happen but it just might...
1460    */
1461   if (!hp->h_name || !hp->h_addr_list[0])
1462     return NULL;
1463   /*
1464    * Make cache entry.  First check to see if the cache already exists
1465    * and if so, return a pointer to it.
1466    */
1467   for (i = 0; hp->h_addr_list[i]; ++i)
1468   {
1469     if ((cp = find_cache_number(rptr, (struct in_addr *)hp->h_addr_list[i])))
1470       return cp;
1471   }
1472
1473   /*
1474    * A matching entry wasnt found in the cache so go and make one up.
1475    */
1476   if ((cp = (aCache *)RunMalloc(sizeof(aCache))) == NULL)
1477     return NULL;
1478   memset(cp, 0, sizeof(aCache));
1479   dup_hostent(&cp->he, hp);
1480
1481   if (rptr->ttl < 600)
1482   {
1483     reinfo.re_shortttl++;
1484     cp->ttl = 600;
1485   }
1486   else
1487     cp->ttl = rptr->ttl;
1488   cp->expireat = now + cp->ttl;
1489   Debug((DEBUG_INFO, "make_cache:made cache %p", cp));
1490   return add_to_cache(cp);
1491 }
1492
1493 /*
1494  * rem_cache
1495  *
1496  * Delete a cache entry from the cache structures and lists and return
1497  * all memory used for the cache back to the memory pool.
1498  */
1499 static void rem_cache(aCache *ocp)
1500 {
1501   aCache **cp;
1502   struct hostent *hp = &ocp->he.h;
1503   int hashv;
1504   aClient *cptr;
1505
1506   Debug((DEBUG_DNS, "rem_cache: ocp %p hp %p l_n %p aliases %p",
1507       ocp, hp, ocp->list_next, hp->h_aliases));
1508
1509   /*
1510    * Cleanup any references to this structure by destroying the pointer.
1511    */
1512   for (hashv = highest_fd; hashv >= 0; --hashv)
1513   {
1514     if ((cptr = loc_clients[hashv]) && (cptr->hostp == hp))
1515       cptr->hostp = NULL;
1516   }
1517   /*
1518    * Remove cache entry from linked list.
1519    */
1520   for (cp = &cachetop; *cp; cp = &((*cp)->list_next))
1521   {
1522     if (*cp == ocp)
1523     {
1524       *cp = ocp->list_next;
1525       break;
1526     }
1527   }
1528   /*
1529    * Remove cache entry from hashed name lists.
1530    */
1531   hashv = hash_name(hp->h_name);
1532
1533   Debug((DEBUG_DNS, "rem_cache: h_name %s hashv %d next %p first %p",
1534       hp->h_name, hashv, ocp->hname_next, hashtable[hashv].name_list));
1535
1536   for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next))
1537   {
1538     if (*cp == ocp)
1539     {
1540       *cp = ocp->hname_next;
1541       break;
1542     }
1543   }
1544   /*
1545    * Remove cache entry from hashed number list
1546    */
1547   hashv = hash_number((unsigned char *)hp->h_addr_list[0]);
1548
1549   Debug((DEBUG_DNS, "rem_cache: h_addr %s hashv %d next %p first %p",
1550       inetntoa(*((struct in_addr *)hp->h_addr_list[0])), hashv,
1551       ocp->hnum_next, hashtable[hashv].num_list));
1552   for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next))
1553   {
1554     if (*cp == ocp)
1555     {
1556       *cp = ocp->hnum_next;
1557       break;
1558     }
1559   }
1560
1561   if (ocp->he.buf)
1562     RunFree(ocp->he.buf);
1563   RunFree((char *)ocp);
1564
1565   incache--;
1566   cainfo.ca_dels++;
1567 }
1568
1569 /*
1570  * Removes entries from the cache which are older than their expirey times.
1571  * returns the time at which the server should next poll the cache.
1572  */
1573 time_t expire_cache(void)
1574 {
1575   Reg1 aCache *cp, *cp2;
1576   Reg2 time_t next = 0;
1577
1578   for (cp = cachetop; cp; cp = cp2)
1579   {
1580     cp2 = cp->list_next;
1581
1582     if (now >= cp->expireat)
1583     {
1584       cainfo.ca_expires++;
1585       rem_cache(cp);
1586     }
1587     else if (!next || next > cp->expireat)
1588       next = cp->expireat;
1589   }
1590   return (next > now) ? next : (now + AR_TTL);
1591 }
1592
1593 /*
1594  * Remove all dns cache entries.
1595  */
1596 void flush_cache(void)
1597 {
1598   Reg1 aCache *cp;
1599
1600   while ((cp = cachetop))
1601     rem_cache(cp);
1602 }
1603
1604 int m_dns(aClient *cptr, aClient *sptr, int UNUSED(parc), char *parv[])
1605 {
1606   aCache *cp;
1607   int i;
1608   struct hostent *h;
1609
1610   if (parv[1] && *parv[1] == 'l')
1611   {
1612     if (!IsAnOper(cptr))
1613     {
1614       return 0;
1615     }
1616     for (cp = cachetop; cp; cp = cp->list_next)
1617     {
1618       h = &cp->he.h;
1619       sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
1620           parv[0], (int)(cp->expireat - now), (int)cp->ttl,
1621           h->h_name, inetntoa(*((struct in_addr *)h->h_addr_list[0])));
1622       for (i = 0; h->h_aliases[i]; i++)
1623         sendto_one(sptr, "NOTICE %s : %s = %s (CN)",
1624             parv[0], h->h_name, h->h_aliases[i]);
1625       for (i = 1; h->h_addr_list[i]; i++)
1626         sendto_one(sptr, "NOTICE %s : %s = %s (IP)", parv[0],
1627             h->h_name, inetntoa(*((struct in_addr *)h->h_addr_list[i])));
1628     }
1629     return 0;
1630   }
1631   sendto_one(sptr, "NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
1632       sptr->name, cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
1633       cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits,
1634       cainfo.ca_updates);
1635   sendto_one(sptr, "NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
1636       sptr->name, reinfo.re_errors, reinfo.re_nu_look,
1637       reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
1638   sendto_one(sptr, "NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
1639       reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
1640       reinfo.re_resends, reinfo.re_timeouts);
1641   return 0;
1642 }
1643
1644 size_t cres_mem(aClient *sptr)
1645 {
1646   aCache *c = cachetop;
1647   struct hostent *h;
1648   int i;
1649   size_t nm = 0, im = 0, sm = 0, ts = 0;
1650
1651   for (; c; c = c->list_next)
1652   {
1653     sm += sizeof(*c);
1654     h = &c->he.h;
1655     for (i = 0; h->h_addr_list[i]; i++)
1656     {
1657       im += sizeof(char *);
1658       im += sizeof(struct in_addr);
1659     }
1660     im += sizeof(char *);
1661     for (i = 0; h->h_aliases[i]; i++)
1662     {
1663       nm += sizeof(char *);
1664       nm += strlen(h->h_aliases[i]);
1665     }
1666     nm += i - 1;
1667     nm += sizeof(char *);
1668     if (h->h_name)
1669       nm += strlen(h->h_name);
1670   }
1671   ts = ARES_CACSIZE * sizeof(CacheTable);
1672   sendto_one(sptr, ":%s %d %s :RES table " SIZE_T_FMT,
1673       me.name, RPL_STATSDEBUG, sptr->name, ts);
1674   sendto_one(sptr, ":%s %d %s :Structs " SIZE_T_FMT
1675       " IP storage " SIZE_T_FMT " Name storage " SIZE_T_FMT,
1676       me.name, RPL_STATSDEBUG, sptr->name, sm, im, nm);
1677   return ts + sm + im + nm;
1678 }