Author: Bleep <tomh@inxpress.net>
[ircu2.10.12-pk.git] / ircd / res.c
1 /*
2  * src/res.c (C)opyright 1992 Darren Reed. All rights reserved.
3  * This file may not be distributed without the author's permission in any
4  * shape or form. The author takes no responsibility for any damage or loss
5  * of property which results from the use of this software.
6  *
7  * $Id$
8  *
9  * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code,
10  *     added callbacks and reference counting of returned hostents.
11  *     --Bleep (Thomas Helvey <tomh@inxpress.net>)
12  */
13 #include "res.h"
14 #include "client.h"
15 #include "ircd.h"
16 #include "ircd_alloc.h"
17 #include "ircd_log.h"
18 #include "ircd_osdep.h"
19 #include "ircd_string.h"
20 #include "numeric.h"
21 #include "s_bsd.h"
22 #include "s_debug.h"
23 #include "s_misc.h"
24 #include "send.h"
25 #include "sprintf_irc.h"
26 #include "struct.h"
27 #include "support.h"
28 #include "sys.h"
29
30 #include <assert.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <sys/time.h>
35 #include <sys/socket.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38
39 #include <arpa/nameser.h>
40 #include <resolv.h>
41 #include <netdb.h>
42 #include <arpa/inet.h>
43
44 #include <limits.h>
45 #if (CHAR_BIT != 8)
46 #error this code needs to be able to address individual octets 
47 #endif
48
49 /*
50  * Some systems do not define INADDR_NONE (255.255.255.255)
51  * INADDR_NONE is actually a valid address, but it should never
52  * be returned from any nameserver.
53  * NOTE: The bit pattern for INADDR_NONE and INADDR_ANY (0.0.0.0) should be 
54  * the same on all hosts so we shouldn't need to use htonl or ntohl to
55  * compare or set the values.
56  */ 
57 #ifndef INADDR_NONE
58 #define INADDR_NONE ((unsigned int) 0xffffffff)
59 #endif
60
61 #define MAXPACKET       1024  /* rfc sez 512 but we expand names so ... */
62 #define RES_MAXALIASES  35    /* maximum aliases allowed */
63 #define RES_MAXADDRS    35    /* maximum addresses allowed */
64
65 /*
66  * macros used to calulate offsets into fixed query buffer
67  */
68 #define ALIAS_BLEN (size_t) ((RES_MAXALIASES + 1) * sizeof(char*))
69 #define ADDRS_BLEN (size_t) ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
70
71 #define ADDRS_OFFSET  (size_t) (ALIAS_BLEN + ADDRS_BLEN)
72 #define ADDRS_DLEN    (size_t) (RES_MAXADDRS * sizeof(struct in_addr))
73 #define NAMES_OFFSET  (size_t) (ADDRS_OFFSET + ADDRS_DLEN)
74 #define MAXGETHOSTLEN (size_t) (NAMES_OFFSET + MAXPACKET)
75
76 #define AR_TTL          600   /* TTL in seconds for dns cache entries */
77
78 /*
79  * the following values should be prime
80  */
81 #define ARES_CACSIZE    307
82 #define MAXCACHED       281
83
84 /*
85  * RFC 1104/1105 wasn't very helpful about what these fields
86  * should be named, so for now, we'll just name them this way.
87  * we probably should look at what named calls them or something.
88  */
89 #define TYPE_SIZE       (size_t) 2
90 #define CLASS_SIZE      (size_t) 2
91 #define TTL_SIZE        (size_t) 4
92 #define RDLENGTH_SIZE   (size_t) 2
93 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
94
95 /*
96  * Building the Hostent
97  * The Hostent struct is arranged like this:
98  *          +-------------------------------+
99  * Hostent: | struct hostent h              |
100  *          |-------------------------------|
101  *          | char *buf                     |
102  *          +-------------------------------+
103  *
104  * allocated:
105  *
106  *          +-------------------------------+
107  * buf:     | h_aliases pointer array       | Max size: ALIAS_BLEN;
108  *          | NULL                          | contains `char *'s
109  *          |-------------------------------|
110  *          | h_addr_list pointer array     | Max size: ADDRS_BLEN;
111  *          | NULL                          | contains `struct in_addr *'s
112  *          |-------------------------------|
113  *          | h_addr_list addresses         | Max size: ADDRS_DLEN;
114  *          |                               | contains `struct in_addr's
115  *          |-------------------------------|
116  *          | storage for hostname strings  | Max size: ALIAS_DLEN;
117  *          +-------------------------------+ contains `char's
118  *
119  *  For requests the size of the h_aliases, and h_addr_list pointer
120  *  array sizes are set to MAXALISES and MAXADDRS respectively, and
121  *  buf is a fixed size with enough space to hold the largest expected
122  *  reply from a nameserver, see RFC 1034 and RFC 1035.
123  *  For cached entries the sizes are dependent on the actual number
124  *  of aliases and addresses. If new aliases and addresses are found
125  *  for cached entries, the buffer is grown and the new entries are added.
126  *  The hostent struct is filled in with the addresses of the entries in
127  *  the Hostent buf as follows:
128  *  h_name      - contains a pointer to the start of the hostname string area,
129  *                or NULL if none is set.  The h_name is followed by the
130  *                aliases, in the storage for hostname strings area.
131  *  h_aliases   - contains a pointer to the start of h_aliases pointer array.
132  *                This array contains pointers to the storage for hostname
133  *                strings area and is terminated with a NULL.  The first alias
134  *                is stored directly after the h_name.
135  *  h_addr_list - contains a pointer to the start of h_addr_list pointer array.
136  *                This array contains pointers to in_addr structures in the
137  *                h_addr_list addresses area and is terminated with a NULL.
138  *
139  *  Filling the buffer this way allows for proper alignment of the h_addr_list
140  *  addresses.
141  *
142  *  This arrangement allows us to alias a Hostent struct pointer as a
143  *  real struct hostent* without lying. It also allows us to change the
144  *  values contained in the cached entries and requests without changing
145  *  the actual hostent pointer, which is saved in a client struct and can't
146  *  be changed without blowing things up or a lot more fiddling around.
147  *  It also allows for defered allocation of the fixed size buffers until
148  *  they are really needed.
149  *  Nov. 17, 1997 --Bleep
150  */
151
152 typedef struct Hostent {
153   struct hostent h;      /* the hostent struct we are passing around */
154   char*          buf;    /* buffer for data pointed to from hostent */
155 } aHostent;
156
157 struct ResRequest {
158   struct ResRequest* next;
159   int                id;
160   int                sent;          /* number of requests sent */
161   time_t             ttl;
162   char               type;
163   char               retries;       /* retry counter */
164   char               sends;         /* number of sends (>1 means resent) */
165   char               resend;        /* send flag. 0 == dont resend */
166   time_t             sentat;
167   time_t             timeout;
168   struct in_addr     addr;
169   char*              name;
170   struct DNSQuery    query;         /* query callback for this request */
171   aHostent           he;
172 };
173
174 struct CacheEntry {
175   struct CacheEntry* hname_next;
176   struct CacheEntry* hnum_next;
177   struct CacheEntry* list_next;
178   time_t             expireat;
179   time_t             ttl;
180   struct Hostent     he;
181   struct DNSReply    reply;
182 };
183
184 struct CacheTable {
185   struct CacheEntry* num_list;
186   struct CacheEntry* name_list;
187 };
188
189
190 int ResolverFileDescriptor    = -1;   /* GLOBAL - used in s_bsd.c */
191
192 static time_t nextDNSCheck    = 0;
193 static time_t nextCacheExpire = 1;
194
195 /*
196  * Keep a spare file descriptor open. res_init calls fopen to read the
197  * resolv.conf file. If ircd is hogging all the file descriptors below 256,
198  * on systems with crippled FILE structures this will cause wierd bugs.
199  * This is definitely needed for Solaris which uses an unsigned char to
200  * hold the file descriptor.  --Dianora
201  */ 
202 static int                spare_fd = -1;
203
204 static int                cachedCount = 0;
205 static struct CacheTable  hashtable[ARES_CACSIZE];
206 static struct CacheEntry* cacheTop;
207 static struct ResRequest* requestListHead;   /* head of resolver request list */
208 static struct ResRequest* requestListTail;   /* tail of resolver request list */
209
210
211 static void     add_request(struct ResRequest* request);
212 static void     rem_request(struct ResRequest* request);
213 static struct ResRequest*   make_request(const struct DNSQuery* query);
214 static void     rem_cache(struct CacheEntry*);
215 static void     do_query_name(const struct DNSQuery* query, 
216                               const char* name, 
217                               struct ResRequest* request);
218 static void     do_query_number(const struct DNSQuery* query,
219                                 const struct in_addr*, 
220                                 struct ResRequest* request);
221 static void     query_name(const char* name, 
222                            int query_class, 
223                            int query_type, 
224                            struct ResRequest* request);
225 static void     resend_query(struct ResRequest* request);
226 static struct CacheEntry*  make_cache(struct ResRequest* request);
227 static struct CacheEntry*  find_cache_name(const char* name);
228 static struct CacheEntry*  find_cache_number(struct ResRequest* request, 
229                                              const char* addr);
230 static struct ResRequest*   find_id(int);
231
232 static  struct cacheinfo {
233   int  ca_adds;
234   int  ca_dels;
235   int  ca_expires;
236   int  ca_lookups;
237   int  ca_na_hits;
238   int  ca_nu_hits;
239   int  ca_updates;
240 } cainfo;
241
242 static  struct  resinfo {
243   int  re_errors;
244   int  re_nu_look;
245   int  re_na_look;
246   int  re_replies;
247   int  re_requests;
248   int  re_resends;
249   int  re_sent;
250   int  re_timeouts;
251   int  re_shortttl;
252   int  re_unkrep;
253 } reinfo;
254
255
256 /*
257  * From bind 8.3, these aren't declared in earlier versions of bind
258  */
259 extern u_short  _getshort(const u_char *);
260 extern u_int    _getlong(const u_char *);
261 /*
262  * int
263  * res_isourserver(ina)
264  *      looks up "ina" in _res.ns_addr_list[]
265  * returns:
266  *      0  : not found
267  *      >0 : found
268  * author:
269  *      paul vixie, 29may94
270  */
271 static int
272 res_ourserver(const struct __res_state* statp, const struct sockaddr_in *inp) 
273 {
274   struct sockaddr_in ina;
275   int ns;
276
277   ina = *inp;
278   for (ns = 0;  ns < statp->nscount;  ns++) {
279     const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
280
281     if (srv->sin_family == ina.sin_family &&
282          srv->sin_port == ina.sin_port &&
283          (srv->sin_addr.s_addr == INADDR_ANY ||
284           srv->sin_addr.s_addr == ina.sin_addr.s_addr))
285              return (1);
286   }
287   return (0);
288 }
289
290 /*
291  * start_resolver - do everything we need to read the resolv.conf file
292  * and initialize the resolver file descriptor if needed
293  */
294 static void start_resolver(void)
295 {
296   Debug((DEBUG_DNS, "Resolver: start_resolver"));
297   /*
298    * close the spare file descriptor so res_init can read resolv.conf
299    * successfully. Needed on Solaris
300    */
301   if (spare_fd > -1)
302     close(spare_fd);
303
304   res_init();      /* res_init always returns 0 */
305   /*
306    * make sure we have a valid file descriptor below 256 so we can
307    * do this again. Needed on Solaris
308    */
309   spare_fd = open("/dev/null",O_RDONLY,0);
310   if ((spare_fd < 0) || (spare_fd > 255)) {
311     char sparemsg[80];
312     sprintf_irc(sparemsg, "invalid spare_fd %d", spare_fd);
313     server_restart(sparemsg);
314   }
315
316   if (!_res.nscount) {
317     _res.nscount = 1;
318     _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
319   }
320   _res.options |= RES_NOALIASES;
321
322   if (ResolverFileDescriptor < 0) {
323     ResolverFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
324     if (-1 == ResolverFileDescriptor) {
325       report_error("Resolver: error creating socket for %s: %s", 
326                    me.name, errno);
327       return;
328     }
329     if (!os_set_nonblocking(ResolverFileDescriptor))
330       report_error("Resolver: error setting non-blocking for %s: %s", 
331                    me.name, errno);
332   }
333 }
334
335 /*
336  * init_resolver - initialize resolver and resolver library
337  */
338 int init_resolver(void)
339 {
340   Debug((DEBUG_DNS, "Resolver: init_resolver"));
341 #ifdef  LRAND48
342   srand48(CurrentTime);
343 #endif
344   memset(&cainfo,   0, sizeof(cainfo));
345   memset(hashtable, 0, sizeof(hashtable));
346   memset(&reinfo,   0, sizeof(reinfo));
347
348   requestListHead = requestListTail = NULL;
349
350   errno = h_errno = 0;
351   start_resolver();
352   Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s",
353          ResolverFileDescriptor, errno, h_errno, strerror(errno)));
354   return ResolverFileDescriptor;
355 }
356
357 /*
358  * restart_resolver - flush the cache, reread resolv.conf, reopen socket
359  */
360 void restart_resolver(void)
361 {
362   /* flush_cache();  flush the dns cache */
363   start_resolver();
364 }
365
366 /*
367  * add_local_domain - Add the domain to hostname, if it is missing
368  * (as suggested by eps@TOASTER.SFSU.EDU)
369  */
370 void add_local_domain(char* hname, size_t size)
371 {
372   assert(0 != hname);
373   /* 
374    * try to fix up unqualified names 
375    */
376   if ((_res.options & RES_DEFNAMES) && !strchr(hname, '.')) {
377     if (_res.defdname[0]) {
378       size_t len = strlen(hname);
379       if ((strlen(_res.defdname) + len + 2) < size) {
380         hname[len++] = '.';
381         strcpy(hname + len, _res.defdname);
382       }
383     }
384   }
385 }
386
387 /*
388  * add_request - place a new request in the request list
389  */
390 static void add_request(struct ResRequest* request)
391 {
392   assert(0 != request);
393   if (!requestListHead)
394     requestListHead = requestListTail = request;
395   else {
396     requestListTail->next = request;
397     requestListTail = request;
398   }
399   request->next = NULL;
400   ++reinfo.re_requests;
401 }
402
403 /*
404  * rem_request - remove a request from the list. 
405  * This must also free any memory that has been allocated for 
406  * temporary storage of DNS results.
407  */
408 static void rem_request(struct ResRequest* request)
409 {
410   struct ResRequest** current;
411   struct ResRequest*  prev = NULL;
412
413   assert(0 != request);
414   for (current = &requestListHead; *current; ) {
415     if (*current == request) {
416       *current = request->next;
417       if (requestListTail == request)
418         requestListTail = prev;
419       break;
420     } 
421     prev    = *current;
422     current = &(*current)->next;
423   }
424   MyFree(request->he.buf);
425   MyFree(request->name);
426   MyFree(request);
427 }
428
429 /*
430  * make_request - Create a DNS request record for the server.
431  */
432 static struct ResRequest* make_request(const struct DNSQuery* query)
433 {
434   struct ResRequest* request;
435   assert(0 != query);
436   request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
437   memset(request, 0, sizeof(struct ResRequest));
438
439   request->sentat           = CurrentTime;
440   request->retries          = 3;
441   request->resend           = 1;
442   request->timeout          = 5;    /* start at 5 per RFC1123 */
443   request->addr.s_addr      = INADDR_NONE;
444   request->he.h.h_addrtype  = AF_INET;
445   request->he.h.h_length    = sizeof(struct in_addr);
446   request->query.vptr       = query->vptr;
447   request->query.callback   = query->callback;
448
449 #if defined(NULL_POINTER_NOT_ZERO)
450   request->next             = NULL;
451   request->he.buf           = NULL;
452   request->he.h.h_name      = NULL;
453   request->he.h.h_aliases   = NULL;
454   request->he.h.h_addr_list = NULL;
455 #endif
456   add_request(request);
457   return request;
458 }
459
460 /*
461  * timeout_query_list - Remove queries from the list which have been 
462  * there too long without being resolved.
463  */
464 static time_t timeout_query_list(time_t now)
465 {
466   struct ResRequest* request;
467   struct ResRequest* next_request = 0;
468   time_t             next_time    = 0;
469   time_t             timeout      = 0;
470
471   Debug((DEBUG_DNS, "Resolver: timeout_query_list at %s", myctime(now)));
472   for (request = requestListHead; request; request = next_request) {
473     next_request = request->next;
474     timeout = request->sentat + request->timeout;
475     if (timeout < now) {
476       if (--request->retries <= 0) {
477         ++reinfo.re_timeouts;
478         (*request->query.callback)(request->query.vptr, 0);
479         rem_request(request);
480         continue;
481       }
482       else {
483         request->sentat = now;
484         request->timeout += request->timeout;
485         resend_query(request);
486       }
487     }
488     if (!next_time || timeout < next_time) {
489       next_time = timeout;
490     }
491   }
492   return (next_time > now) ? next_time : (now + AR_TTL);
493 }
494
495 /*
496  * expire_cache - removes entries from the cache which are older 
497  * than their expiry times. returns the time at which the server 
498  * should next poll the cache.
499  */
500 static time_t expire_cache(time_t now)
501 {
502   struct CacheEntry* cp;
503   struct CacheEntry* cp_next;
504   time_t             expire = 0;
505
506   Debug((DEBUG_DNS, "Resolver: expire_cache at %s", myctime(now)));
507   for (cp = cacheTop; cp; cp = cp_next) {
508     cp_next = cp->list_next;
509     if (cp->expireat < now) {
510       ++cainfo.ca_expires;
511       rem_cache(cp);
512     }
513     else if (!expire || expire > cp->expireat)
514       expire = cp->expireat;
515   }
516   return (expire > now) ? expire : (now + AR_TTL);
517 }
518
519 /*
520  * timeout_resolver - check request list and cache for expired entries
521  */
522 time_t timeout_resolver(time_t now)
523 {
524   if (nextDNSCheck < now)
525     nextDNSCheck = timeout_query_list(now);
526   if (nextCacheExpire < now)
527     nextCacheExpire = expire_cache(now);
528   return IRCD_MIN(nextDNSCheck, nextCacheExpire);
529 }
530
531
532 /*
533  * delete_resolver_queries - cleanup outstanding queries 
534  * for which there no longer exist clients or conf lines.
535  */
536 void delete_resolver_queries(const void* vptr)
537 {
538   struct ResRequest* request;
539   struct ResRequest* next_request;
540
541   for (request = requestListHead; request; request = next_request) {
542     next_request = request->next;
543     if (vptr == request->query.vptr)
544       rem_request(request);
545   }
546 }
547
548 /*
549  * send_res_msg - sends msg to all nameservers found in the "_res" structure.
550  * This should reflect /etc/resolv.conf. We will get responses
551  * which arent needed but is easier than checking to see if nameserver
552  * isnt present. Returns number of messages successfully sent to 
553  * nameservers or -1 if no successful sends.
554  */
555 static int send_res_msg(const u_char* msg, int len, int rcount)
556 {
557   int i;
558   int sent = 0;
559   int max_queries = IRCD_MIN(_res.nscount, rcount);
560
561   assert(0 != msg);
562   /*
563    * RES_PRIMARY option is not implemented
564    * if (_res.options & RES_PRIMARY || 0 == max_queries)
565    */
566   if (0 == max_queries)
567     max_queries = 1;
568
569   Debug((DEBUG_DNS, "Resolver: sendto %d", max_queries));
570
571   for (i = 0; i < max_queries; i++) {
572     if (sendto(ResolverFileDescriptor, msg, len, 0, 
573                (struct sockaddr*) &(_res.nsaddr_list[i]),
574                sizeof(struct sockaddr_in)) == len) {
575       ++reinfo.re_sent;
576       ++sent;
577     }
578     else
579       ircd_log(L_ERROR, "Resolver: send failed %s", strerror(errno));
580   }
581   return sent;
582 }
583
584 /*
585  * find_id - find a dns request id (id is determined by dn_mkquery)
586  */
587 static struct ResRequest* find_id(int id)
588 {
589   struct ResRequest* request;
590
591   for (request = requestListHead; request; request = request->next) {
592     if (request->id == id)
593       return request;
594   }
595   return NULL;
596 }
597
598 /*
599  * gethost_byname - get host address from name
600  */
601 struct DNSReply* gethost_byname(const char* name, 
602                                const struct DNSQuery* query)
603 {
604   struct CacheEntry* cp;
605   assert(0 != name);
606
607   Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
608   ++reinfo.re_na_look;
609   if ((cp = find_cache_name(name)))
610     return &(cp->reply);
611
612   do_query_name(query, name, NULL);
613   nextDNSCheck = 1;
614   return NULL;
615 }
616
617 /*
618  * gethost_byaddr - get host name from address
619  */
620 struct DNSReply* gethost_byaddr(const char* addr,
621                                 const struct DNSQuery* query)
622 {
623   struct CacheEntry *cp;
624
625   assert(0 != addr);
626
627   Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
628
629   ++reinfo.re_nu_look;
630   if ((cp = find_cache_number(NULL, addr)))
631     return &(cp->reply);
632
633   do_query_number(query, (const struct in_addr*) addr, NULL);
634   nextDNSCheck = 1;
635   return NULL;
636 }
637
638 /*
639  * do_query_name - nameserver lookup name
640  */
641 static void do_query_name(const struct DNSQuery* query, 
642                           const char* name, struct ResRequest* request)
643 {
644   char  hname[HOSTLEN + 1];
645   assert(0 != name);
646
647   ircd_strncpy(hname, name, HOSTLEN);
648   hname[HOSTLEN] = '\0';
649 #if 0
650   /*
651    * removed, this is incorrect for anything it's used for
652    */
653   add_local_domain(hname, HOSTLEN);
654 #endif
655
656   if (!request) {
657     request       = make_request(query);
658     request->type = T_A;
659     request->name = (char*) MyMalloc(strlen(hname) + 1);
660     strcpy(request->name, hname);
661   }
662   query_name(hname, C_IN, T_A, request);
663 }
664
665 /*
666  * do_query_number - Use this to do reverse IP# lookups.
667  */
668 static void do_query_number(const struct DNSQuery* query, 
669                             const struct in_addr* addr,
670                             struct ResRequest* request)
671 {
672   char  ipbuf[32];
673   const unsigned char* cp;
674
675   assert(0 != addr);
676   cp = (const unsigned char*) &addr->s_addr;
677   sprintf_irc(ipbuf, "%u.%u.%u.%u.in-addr.arpa.",
678               (unsigned int)(cp[3]), (unsigned int)(cp[2]),
679               (unsigned int)(cp[1]), (unsigned int)(cp[0]));
680
681   if (!request) {
682     request              = make_request(query);
683     request->type        = T_PTR;
684     request->addr.s_addr = addr->s_addr;
685   }
686   query_name(ipbuf, C_IN, T_PTR, request);
687 }
688
689 /*
690  * query_name - generate a query based on class, type and name.
691  */
692 static void query_name(const char* name, int query_class,
693                        int type, struct ResRequest* request)
694 {
695   char buf[MAXPACKET];
696   int  request_len = 0;
697
698   assert(0 != name);
699   assert(0 != request);
700
701   Debug((DEBUG_DNS, "Resolver: query_name: %s %d %d", name, query_class, type));
702   memset(buf, 0, sizeof(buf));
703   if ((request_len = res_mkquery(QUERY, name, query_class, type, 
704                                  NULL, 0, NULL, buf, sizeof(buf))) > 0) {
705     HEADER* header = (HEADER*) buf;
706 #ifndef LRAND48
707     int            k = 0;
708     struct timeval tv;
709 #endif
710     /*
711      * generate a unique id
712      * NOTE: we don't have to worry about converting this to and from
713      * network byte order, the nameserver does not interpret this value
714      * and returns it unchanged
715      */
716 #ifdef LRAND48
717     do {
718       header->id = (header->id + lrand48()) & 0xffff;
719     } while (find_id(header->id));
720 #else
721     gettimeofday(&tv, NULL);
722     do {
723       header->id = (header->id + k + tv.tv_usec) & 0xffff;
724       ++k;
725     } while (find_id(header->id));
726 #endif /* LRAND48 */
727     request->id = header->id;
728     ++request->sends;
729     Debug((DEBUG_DNS, "Resolver: query_name %d: %s %d %d", request->id, 
730           name, query_class, type));
731     request->sent += send_res_msg(buf, request_len, request->sends);
732   }
733 }
734
735 static void resend_query(struct ResRequest* request)
736 {
737   assert(0 != request);
738
739   if (request->resend == 0)
740     return;
741   ++reinfo.re_resends;
742   switch(request->type) {
743   case T_PTR:
744     do_query_number(NULL, &request->addr, request);
745     break;
746   case T_A:
747     do_query_name(NULL, request->name, request);
748     break;
749   default:
750     break;
751   }
752 }
753
754 /*
755  * proc_answer - process name server reply
756  * build a hostent struct in the passed request
757  */
758 static int proc_answer(struct ResRequest* request, HEADER* header,
759                        u_char* buf, u_char* eob)
760 {
761   char   hostbuf[HOSTLEN + 1]; /* working buffer */
762   u_char* current;             /* current position in buf */
763   char** alias;                /* alias list */
764   char** addr;                 /* address list */
765   char*  name;                 /* pointer to name string */
766   char*  address;              /* pointer to address */
767   char*  endp;                 /* end of our buffer */
768   int    query_class;          /* answer class */
769   int    type;                 /* answer type */
770   int    rd_length;            /* record data length */
771   int    answer_count = 0;     /* answer counter */
772   int    n;                    /* temp count */
773   int    addr_count  = 0;      /* number of addresses in hostent */
774   int    alias_count = 0;      /* number of aliases in hostent */
775   struct hostent* hp;          /* hostent getting filled */
776
777   assert(0 != request);
778   assert(0 != header);
779   assert(0 != buf);
780   assert(0 != eob);
781   
782   current = buf + sizeof(HEADER);
783   hp = &(request->he.h);
784   /*
785    * lazy allocation of request->he.buf, we don't allocate a buffer
786    * unless there is something to put in it.
787    */
788   if (!request->he.buf) {
789     request->he.buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
790     request->he.buf[MAXGETHOSTLEN] = '\0';
791     /*
792      * array of alias list pointers starts at beginning of buf
793      */
794     hp->h_aliases = (char**) request->he.buf;
795     hp->h_aliases[0] = NULL;
796     /*
797      * array of address list pointers starts after alias list pointers
798      * the actual addresses follow the the address list pointers
799      */ 
800     hp->h_addr_list = (char**)(request->he.buf + ALIAS_BLEN);
801     /*
802      * don't copy the host address to the beginning of h_addr_list
803      */
804     hp->h_addr_list[0] = NULL;
805   }
806   endp = request->he.buf + MAXGETHOSTLEN;
807   /*
808    * find the end of the address list
809    */
810   addr = hp->h_addr_list;
811   while (*addr) {
812     ++addr;
813     ++addr_count;
814   }
815   /*
816    * make address point to first available address slot
817    */
818   address = request->he.buf + ADDRS_OFFSET +
819                     (sizeof(struct in_addr) * addr_count);
820   /*
821    * find the end of the alias list
822    */
823   alias = hp->h_aliases;
824   while (*alias) {
825     ++alias;
826     ++alias_count;
827   }
828   /*
829    * make name point to first available space in request->buf
830    */
831   if (alias_count > 0) {
832     name = hp->h_aliases[alias_count - 1];
833     name += (strlen(name) + 1);
834   }
835   else if (hp->h_name)
836     name = hp->h_name + strlen(hp->h_name) + 1;
837   else
838     name = request->he.buf + ADDRS_OFFSET + ADDRS_DLEN;
839  
840   /*
841    * skip past queries
842    */ 
843   while (header->qdcount-- > 0) {
844     if ((n = dn_skipname(current, eob)) < 0)
845       break;
846     current += (n + QFIXEDSZ);
847   }
848   /*
849    * process each answer sent to us blech.
850    */
851   while (header->ancount-- > 0 && current < eob && name < endp) {
852     n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
853     if (n <= 0) {
854       /*
855        * no more answers left
856        */
857       return answer_count;
858     }
859     hostbuf[HOSTLEN] = '\0';
860     /* 
861      * With Address arithmetic you have to be very anal
862      * this code was not working on alpha due to that
863      * (spotted by rodder/jailbird/dianora)
864      */
865     current += (size_t) n;
866
867     if (!((current + ANSWER_FIXED_SIZE) < eob))
868       break;
869
870     type = _getshort(current);
871     current += TYPE_SIZE;
872
873     query_class = _getshort(current);
874     current += CLASS_SIZE;
875
876     request->ttl = _getlong(current);
877     current += TTL_SIZE;
878
879     rd_length = _getshort(current);
880     current += RDLENGTH_SIZE;
881
882     /* 
883      * Wait to set request->type until we verify this structure 
884      */
885 #if 0
886     add_local_domain(hostbuf, HOSTLEN);
887 #endif
888
889     switch(type) {
890     case T_A:
891       /*
892        * check for invalid rd_length or too many addresses
893        */
894       if (rd_length != sizeof(struct in_addr))
895         return answer_count;
896       if (++addr_count < RES_MAXADDRS) {
897         if (answer_count == 1)
898           hp->h_addrtype = (query_class == C_IN) ?  AF_INET : AF_UNSPEC;
899
900         memcpy(address, current, sizeof(struct in_addr));
901         *addr++ = address;
902         *addr = 0;
903         address += sizeof(struct in_addr);
904
905         if (!hp->h_name) {
906           strcpy(name, hostbuf);
907           hp->h_name = name;
908           name += strlen(name) + 1;
909         }
910         Debug((DEBUG_DNS, "Resolver: A %s for %s", 
911                ircd_ntoa((char*) hp->h_addr_list[addr_count - 1]), hostbuf));
912       }
913       current += rd_length;
914       ++answer_count;
915       break;
916     case T_PTR:
917       n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
918       if (n < 0) {
919         /*
920          * broken message
921          */
922         return 0;
923       }
924       else if (n == 0) {
925         /*
926          * no more answers left
927          */
928         return answer_count;
929       }
930       /*
931        * This comment is based on analysis by Shadowfax, Wohali and johan, 
932        * not me.  (Dianora) I am only commenting it.
933        *
934        * dn_expand is guaranteed to not return more than sizeof(hostbuf)
935        * but do all implementations of dn_expand also guarantee
936        * buffer is terminated with null byte? Lets not take chances.
937        *  -Dianora
938        */
939       hostbuf[HOSTLEN] = '\0';
940       current += (size_t) n;
941
942       Debug((DEBUG_DNS, "Resolver: PTR %s", hostbuf));
943       /*
944        * copy the returned hostname into the host name
945        * ignore duplicate ptr records
946        */
947       if (!hp->h_name) {
948         strcpy(name, hostbuf);
949         hp->h_name = name;
950         name += strlen(name) + 1;
951       }
952       ++answer_count;
953       break;
954     case T_CNAME:
955       Debug((DEBUG_DNS, "Resolver: CNAME %s", hostbuf));
956       if (++alias_count < RES_MAXALIASES) {
957         ircd_strncpy(name, hostbuf, endp - name);
958         *alias++ = name;
959         *alias   = 0;
960         name += strlen(name) + 1;
961       }
962       current += rd_length;
963       ++answer_count;
964       break;
965     default :
966       Debug((DEBUG_DNS,"Resolver: proc_answer type: %d for: %s", type, hostbuf));
967       break;
968     }
969   }
970   return answer_count;
971 }
972
973 /*
974  * resolver_read - read a dns reply from the nameserver and process it.
975  * return 0 if nothing was read from the socket, otherwise return 1
976  */
977 int resolver_read(void)
978 {
979   u_char             buf[sizeof(HEADER) + MAXPACKET];
980   HEADER*            header       = 0;
981   struct ResRequest* request      = 0;
982   struct CacheEntry* cp           = 0;
983   unsigned int       rc           = 0;
984   int                answer_count = 0;
985   struct sockaddr_in sin;
986
987   Debug((DEBUG_DNS, "Resolver: read"));
988   if (IO_SUCCESS != os_recvfrom_nonb(ResolverFileDescriptor,
989                                      buf, sizeof(buf), &rc, &sin)) {
990     return 0;
991   }
992   if (rc < sizeof(HEADER)) {
993     Debug((DEBUG_DNS, "Resolver: short reply %d: %s", rc, strerror(errno)));
994     return 0;
995   }
996   /*
997    * convert DNS reply reader from Network byte order to CPU byte order.
998    */
999   header = (HEADER*) buf;
1000   /* header->id = ntohs(header->id); */
1001   header->ancount = ntohs(header->ancount);
1002   header->qdcount = ntohs(header->qdcount);
1003   header->nscount = ntohs(header->nscount);
1004   header->arcount = ntohs(header->arcount);
1005   ++reinfo.re_replies;
1006   /*
1007    * response for an id which we have already received an answer for
1008    * just ignore this response.
1009    */
1010   if (0 == (request = find_id(header->id))) {
1011     Debug((DEBUG_DNS, "Resolver: can't find request id: %d", header->id));
1012     return 1;
1013   }
1014   /*
1015    * check against possibly fake replies
1016    */
1017   if (!res_ourserver(&_res, &sin)) {
1018     Debug((DEBUG_DNS, "Resolver: fake reply from: %s",
1019            (const char*) &sin.sin_addr));
1020     ++reinfo.re_unkrep;
1021     return 1;
1022   }
1023
1024   if ((header->rcode != NOERROR) || (header->ancount == 0)) {
1025     ++reinfo.re_errors;
1026     if (SERVFAIL == header->rcode)
1027       resend_query(request);
1028     else {
1029       /*
1030        * If a bad error was returned, we stop here and dont send
1031        * send any more (no retries granted).
1032        * Isomer: Perhaps we should return these error messages back to
1033        *         the client?
1034        */
1035 #ifdef DEBUGMODE
1036       switch (header->rcode) {
1037         case NOERROR:
1038           Debug((DEBUG_DNS, "Fatal DNS error: No Error"));
1039           break;
1040         case FORMERR:
1041           Debug((DEBUG_DNS, "Fatal DNS error: Format Error"));
1042           break;
1043         case SERVFAIL:
1044           Debug((DEBUG_DNS, "Fatal DNS error: Server Failure"));
1045           break;
1046         case NXDOMAIN:
1047           Debug((DEBUG_DNS, "DNS error: Non Existant Domain"));
1048           break;
1049         case NOTIMP:
1050           Debug((DEBUG_DNS, "Fatal DNS error: Not Implemented"));
1051           break;
1052         case REFUSED:
1053           Debug((DEBUG_DNS, "Fatal DNS error: Query Refused"));
1054           break;
1055         default:
1056           Debug((DEBUG_DNS, "Unassigned fatal DNS error: %i", header->rcode));
1057           break;
1058       }
1059 #endif /* DEBUGMODE */
1060       (*request->query.callback)(request->query.vptr, 0);
1061       rem_request(request);
1062     } 
1063     return 1;
1064   }
1065   /*
1066    * If this fails there was an error decoding the received packet, 
1067    * try it again and hope it works the next time.
1068    */
1069   answer_count = proc_answer(request, header, buf, buf + rc);
1070   if (answer_count) {
1071     if (T_PTR == request->type) {
1072       struct DNSReply* reply = NULL;
1073       if (0 == request->he.h.h_name) {
1074         /*
1075          * got a PTR response with no name, something bogus is happening
1076          * don't bother trying again, the client address doesn't resolve 
1077          */
1078         (*request->query.callback)(request->query.vptr, reply);
1079         rem_request(request); 
1080         return 1;
1081       }
1082       Debug((DEBUG_DNS, "relookup %s <-> %s",
1083              request->he.h.h_name, ircd_ntoa((char*) &request->addr)));
1084       /*
1085        * Lookup the 'authoritive' name that we were given for the
1086        * ip#.  By using this call rather than regenerating the
1087        * type we automatically gain the use of the cache with no
1088        * extra kludges.
1089        */
1090       reply = gethost_byname(request->he.h.h_name, &request->query);
1091       if (0 == reply) {
1092         /*
1093          * If name wasn't found, a request has been queued and it will
1094          * be the last one queued.  This is rather nasty way to keep
1095          * a host alias with the query. -avalon
1096          */
1097         MyFree(requestListTail->he.buf);
1098         requestListTail->he.buf = request->he.buf;
1099         request->he.buf = 0;
1100         memcpy(&requestListTail->he.h, &request->he.h, sizeof(struct hostent));
1101       }
1102       else
1103         (*request->query.callback)(request->query.vptr, reply);
1104       rem_request(request);
1105     }
1106     else {
1107       /*
1108        * got a name and address response, client resolved
1109        * XXX - Bug found here by Dianora -
1110        * make_cache() occasionally returns a NULL pointer when a
1111        * PTR returned a CNAME, cp was not checked before so the
1112        * callback was being called with a value of 0x2C != NULL.
1113        */
1114       cp = make_cache(request);
1115       (*request->query.callback)(request->query.vptr,
1116                                  (cp) ? &cp->reply : 0);
1117       rem_request(request);
1118     }
1119   }
1120   else if (!request->sent) {
1121     /*
1122      * XXX - we got a response for a query we didn't send with a valid id?
1123      * this should never happen, bail here and leave the client unresolved
1124      */
1125     (*request->query.callback)(request->query.vptr, 0);
1126     rem_request(request);
1127   }
1128   return 1;
1129 }
1130
1131 /*
1132  * resolver_read_multiple - process up to count reads
1133  */
1134 void resolver_read_multiple(int count)
1135 {
1136   int i = 0;
1137   for ( ; i < count; ++i) {
1138     if (0 == resolver_read())
1139       return;
1140   }
1141 }
1142
1143 static size_t calc_hostent_buffer_size(const struct hostent* hp)
1144 {
1145   char** p;
1146   size_t count = 0;
1147   assert(0 != hp);
1148
1149   /*
1150    * space for name
1151    */
1152   count += (strlen(hp->h_name) + 1);
1153   /*
1154    * space for aliases
1155    */
1156   for (p = hp->h_aliases; *p; ++p)
1157     count += (strlen(*p) + 1 + sizeof(char*));
1158   /*
1159    * space for addresses
1160    */
1161   for (p = hp->h_addr_list; *p; ++p)
1162     count += (hp->h_length + sizeof(char*));
1163   /*
1164    * space for 2 nulls to terminate h_aliases and h_addr_list 
1165    */
1166   count += (2 * sizeof(char*));
1167   return count;
1168 }
1169
1170
1171 /*
1172  * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
1173  * the data we're putting in it.
1174  */
1175 static void dup_hostent(aHostent* new_hp, struct hostent* hp)
1176 {
1177   char*  p;
1178   char** ap;
1179   char** pp;
1180   int    alias_count = 0;
1181   int    addr_count = 0;
1182   size_t bytes_needed = 0;
1183
1184   assert(0 != new_hp);
1185   assert(0 != hp);
1186
1187   /* how much buffer do we need? */
1188   bytes_needed += (strlen(hp->h_name) + 1);
1189
1190   pp = hp->h_aliases;
1191   while (*pp) {
1192     bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
1193     ++alias_count;
1194   }
1195   pp = hp->h_addr_list;
1196   while (*pp++) {
1197     bytes_needed += (hp->h_length + sizeof(char*));
1198     ++addr_count;
1199   }
1200   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1201   bytes_needed += (2 * sizeof(char*));
1202
1203   /* Allocate memory */
1204   new_hp->buf = (char*) MyMalloc(bytes_needed);
1205
1206   new_hp->h.h_addrtype = hp->h_addrtype;
1207   new_hp->h.h_length = hp->h_length;
1208
1209   /* first write the address list */
1210   pp = hp->h_addr_list;
1211   ap = new_hp->h.h_addr_list =
1212       (char**)(new_hp->buf + ((alias_count + 1) * sizeof(char*)));
1213   p = (char*)ap + ((addr_count + 1) * sizeof(char*));
1214   while (*pp)
1215   {
1216     *ap++ = p;
1217     memcpy(p, *pp++, hp->h_length);
1218     p += hp->h_length;
1219   }
1220   *ap = 0;
1221   /* next write the name */
1222   new_hp->h.h_name = p;
1223   strcpy(p, hp->h_name);
1224   p += (strlen(p) + 1);
1225
1226   /* last write the alias list */
1227   pp = hp->h_aliases;
1228   ap = new_hp->h.h_aliases = (char**) new_hp->buf;
1229   while (*pp) {
1230     *ap++ = p;
1231     strcpy(p, *pp++);
1232     p += (strlen(p) + 1);
1233   }
1234   *ap = 0;
1235 }
1236
1237 /*
1238  * update_hostent - Add records to a Hostent struct in place.
1239  */
1240 static void update_hostent(aHostent* hp, char** addr, char** alias)
1241 {
1242   char*  p;
1243   char** ap;
1244   char** pp;
1245   int    alias_count = 0;
1246   int    addr_count = 0;
1247   char*  buf = NULL;
1248   size_t bytes_needed = 0;
1249
1250   if (!hp || !hp->buf)
1251     return;
1252
1253   /* how much buffer do we need? */
1254   bytes_needed = strlen(hp->h.h_name) + 1;
1255   pp = hp->h.h_aliases;
1256   while (*pp) {
1257     bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
1258     ++alias_count;
1259   }
1260   if (alias) {
1261     pp = alias;
1262     while (*pp) {
1263       bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
1264       ++alias_count;
1265     }
1266   }
1267   pp = hp->h.h_addr_list;
1268   while (*pp++) {
1269     bytes_needed += (hp->h.h_length + sizeof(char*));
1270     ++addr_count;
1271   }
1272   if (addr) {
1273     pp = addr;
1274     while (*pp++) {
1275       bytes_needed += (hp->h.h_length + sizeof(char*));
1276       ++addr_count;
1277     }
1278   }
1279   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1280   bytes_needed += 2 * sizeof(char*);
1281
1282   /* Allocate memory */
1283   buf = (char*) MyMalloc(bytes_needed);
1284   assert(0 != buf);
1285
1286   /* first write the address list */
1287   pp = hp->h.h_addr_list;
1288   ap = hp->h.h_addr_list =
1289       (char**)(buf + ((alias_count + 1) * sizeof(char*)));
1290   p = (char*)ap + ((addr_count + 1) * sizeof(char*));
1291   while (*pp) {
1292     memcpy(p, *pp++, hp->h.h_length);
1293     *ap++ = p;
1294     p += hp->h.h_length;
1295   }
1296   if (addr) {
1297     while (*addr) {
1298       memcpy(p, *addr++, hp->h.h_length);
1299       *ap++ = p;
1300       p += hp->h.h_length;
1301     }
1302   }
1303   *ap = 0;
1304
1305   /* next write the name */
1306   strcpy(p, hp->h.h_name);
1307   hp->h.h_name = p;
1308   p += (strlen(p) + 1);
1309
1310   /* last write the alias list */
1311   pp = hp->h.h_aliases;
1312   ap = hp->h.h_aliases = (char**) buf;
1313   while (*pp) {
1314     strcpy(p, *pp++);
1315     *ap++ = p;
1316     p += (strlen(p) + 1);
1317   }
1318   if (alias) {
1319     while (*alias) {
1320       strcpy(p, *alias++);
1321       *ap++ = p;
1322       p += (strlen(p) + 1);
1323     }
1324   }
1325   *ap = 0;
1326   /* release the old buffer */
1327   p = hp->buf;
1328   hp->buf = buf;
1329   MyFree(p);
1330 }
1331
1332 /*
1333  * hash_number - IP address hash function
1334  */
1335 static int hash_number(const unsigned char* ip)
1336 {
1337   /* could use loop but slower */
1338   unsigned int hashv;
1339   const u_char* p = (const u_char*) ip;
1340
1341   assert(0 != p);
1342
1343   hashv = *p++;
1344   hashv += hashv + *p++;
1345   hashv += hashv + *p++;
1346   hashv += hashv + *p;
1347   hashv %= ARES_CACSIZE;
1348   return hashv;
1349 }
1350
1351 /*
1352  * hash_name - hostname hash function
1353  */
1354 static int hash_name(const char* name)
1355 {
1356   unsigned int hashv = 0;
1357   const u_char* p = (const u_char*) name;
1358
1359   assert(0 != p);
1360
1361   for (; *p && *p != '.'; ++p)
1362     hashv += *p;
1363   hashv %= ARES_CACSIZE;
1364   return hashv;
1365 }
1366
1367 /*
1368  * add_to_cache - Add a new cache item to the queue and hash table.
1369  */
1370 static struct CacheEntry* add_to_cache(struct CacheEntry* ocp)
1371 {
1372   int  hashv;
1373
1374   assert(0 != ocp);
1375
1376   ocp->list_next = cacheTop;
1377   cacheTop = ocp;
1378
1379   hashv = hash_name(ocp->he.h.h_name);
1380
1381   ocp->hname_next = hashtable[hashv].name_list;
1382   hashtable[hashv].name_list = ocp;
1383
1384   hashv = hash_number(ocp->he.h.h_addr);
1385
1386   ocp->hnum_next = hashtable[hashv].num_list;
1387   hashtable[hashv].num_list = ocp;
1388
1389   /*
1390    * LRU deletion of excessive cache entries.
1391    */
1392   if (++cachedCount > MAXCACHED) {
1393     struct CacheEntry* cp;
1394     struct CacheEntry* cp_next;
1395     for (cp = ocp->list_next; cp; cp = cp_next) {
1396       cp_next = cp->list_next;
1397       rem_cache(cp);
1398     }
1399   }
1400   ++cainfo.ca_adds;
1401   return ocp;
1402 }
1403
1404 /*
1405  * update_list - does not alter the cache structure passed. It is assumed that
1406  * it already contains the correct expire time, if it is a new entry. Old
1407  * entries have the expirey time updated.
1408 */
1409 static void update_list(struct ResRequest* request, struct CacheEntry* cachep)
1410 {
1411 #if 0
1412   struct CacheEntry** cpp;
1413 #endif
1414   struct CacheEntry*  cp = cachep;
1415   char*    s;
1416   char*    t;
1417   int      i;
1418   int      j;
1419   char**   ap;
1420   char*    addrs[RES_MAXADDRS + 1];
1421   char*    aliases[RES_MAXALIASES + 1];
1422
1423   /*
1424    * search for the new cache item in the cache list by hostname.
1425    * If found, move the entry to the top of the list and return.
1426    */
1427   ++cainfo.ca_updates;
1428 #if 0
1429   for (cpp = &cacheTop; *cpp; cpp = &((*cpp)->list_next)) {
1430     if (cp == *cpp)
1431       break;
1432   }
1433   if (!*cpp)
1434     return;
1435   *cpp = cp->list_next;
1436   cp->list_next = cacheTop;
1437   cacheTop = cp;
1438 #endif
1439
1440   if (!request)
1441     return;
1442   /*
1443    * Compare the cache entry against the new record.  Add any
1444    * previously missing names for this entry.
1445    */
1446   *aliases = 0;
1447   ap = aliases;
1448   for (i = 0, s = request->he.h.h_name; s; s = request->he.h.h_aliases[i++]) {
1449     for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++]) {
1450       if (0 == ircd_strcmp(t, s))
1451         break;
1452     }
1453     if (!t) {
1454       *ap++ = s;
1455       *ap = 0;
1456     }
1457   }
1458   /*
1459    * Do the same again for IP#'s.
1460    */
1461   *addrs = 0;
1462   ap = addrs;
1463   for (i = 0; (s = request->he.h.h_addr_list[i]); i++) {
1464     for (j = 0; (t = cp->he.h.h_addr_list[j]); j++) {
1465       if (!memcmp(t, s, sizeof(struct in_addr)))
1466         break;
1467     }
1468     if (!t) {
1469       *ap++ = s;
1470       *ap = 0;
1471     }
1472   }
1473   if (*addrs || *aliases)
1474     update_hostent(&cp->he, addrs, aliases);
1475 }
1476
1477 /*
1478  * find_cache_name - find name in nameserver cache
1479  */
1480 static struct CacheEntry* find_cache_name(const char* name)
1481 {
1482   struct CacheEntry* cp;
1483   char*   s;
1484   int     hashv;
1485   int     i;
1486
1487   assert(0 != name);
1488   hashv = hash_name(name);
1489
1490   cp = hashtable[hashv].name_list;
1491
1492   for (; cp; cp = cp->hname_next) {
1493     for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++]) {
1494       if (0 == ircd_strcmp(s, name)) {
1495         ++cainfo.ca_na_hits;
1496         return cp;
1497       }
1498     }
1499   }
1500
1501   for (cp = cacheTop; cp; cp = cp->list_next) {
1502     /*
1503      * if no aliases or the hash value matches, we've already
1504      * done this entry and all possiblilities concerning it.
1505      */
1506     if (!cp->he.h.h_name || hashv == hash_name(cp->he.h.h_name))
1507       continue;
1508     for (i = 0, s = cp->he.h.h_aliases[i]; s; s = cp->he.h.h_aliases[++i]) {
1509       if (0 == ircd_strcmp(name, s)) {
1510         ++cainfo.ca_na_hits;
1511         return cp;
1512       }
1513     }
1514   }
1515   return NULL;
1516 }
1517
1518 /*
1519  * find_cache_number - find a cache entry by ip# and update its expire time
1520  */
1521 static struct CacheEntry* find_cache_number(struct ResRequest* request,
1522                                             const char* addr)
1523 {
1524   struct CacheEntry* cp;
1525   int     hashv;
1526   int     i;
1527
1528   assert(0 != addr);
1529   hashv = hash_number(addr);
1530   cp = hashtable[hashv].num_list;
1531
1532   for (; cp; cp = cp->hnum_next) {
1533     for (i = 0; cp->he.h.h_addr_list[i]; ++i) {
1534       if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
1535         ++cainfo.ca_nu_hits;
1536         return cp;
1537       }
1538     }
1539   }
1540   for (cp = cacheTop; cp; cp = cp->list_next) {
1541     /*
1542      * single address entry...would have been done by hashed
1543      * search above...
1544      * if the first IP# has the same hashnumber as the IP# we
1545      * are looking for, its been done already.
1546      */
1547     if (!cp->he.h.h_addr_list[1] || 
1548         hashv == hash_number(cp->he.h.h_addr_list[0]))
1549       continue;
1550     for (i = 1; cp->he.h.h_addr_list[i]; ++i) {
1551       if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
1552         ++cainfo.ca_nu_hits;
1553         return cp;
1554       }
1555     }
1556   }
1557   return NULL;
1558 }
1559
1560 static struct CacheEntry* make_cache(struct ResRequest* request)
1561 {
1562   struct CacheEntry* cp;
1563   int     i;
1564   struct hostent* hp;
1565   assert(0 != request);
1566
1567   hp = &request->he.h;
1568   /*
1569    * shouldn't happen but it just might...
1570    */
1571   assert(0 != hp->h_name);
1572   assert(0 != hp->h_addr_list[0]);
1573   if (!hp->h_name || !hp->h_addr_list[0])
1574     return NULL;
1575   /*
1576    * Make cache entry.  First check to see if the cache already exists
1577    * and if so, return a pointer to it.
1578    */
1579   for (i = 0; hp->h_addr_list[i]; ++i) {
1580     if ((cp = find_cache_number(request, hp->h_addr_list[i]))) {
1581       update_list(request, cp);
1582       return cp;
1583     }
1584   }
1585   /*
1586    * a matching entry wasnt found in the cache so go and make one up.
1587    */ 
1588   cp = (struct CacheEntry*) MyMalloc(sizeof(struct CacheEntry));
1589   assert(0 != cp);
1590
1591   memset(cp, 0, sizeof(struct CacheEntry));
1592   dup_hostent(&cp->he, hp);
1593   cp->reply.hp = &cp->he.h;
1594   /*
1595    * hmmm... we could time out the cache after 10 minutes regardless
1596    * would that be reasonable since we don't save the reply?
1597    */ 
1598   if (request->ttl < AR_TTL) {
1599     ++reinfo.re_shortttl;
1600     cp->ttl = AR_TTL;
1601   }
1602   else
1603     cp->ttl = request->ttl;
1604   cp->expireat = CurrentTime + cp->ttl;
1605   return add_to_cache(cp);
1606 }
1607
1608 /*
1609  * rem_cache - delete a cache entry from the cache structures 
1610  * and lists and return all memory used for the cache back to the memory pool.
1611  */
1612 static void rem_cache(struct CacheEntry* ocp)
1613 {
1614   struct CacheEntry** cp;
1615   int                 hashv;
1616   struct hostent*     hp;
1617   assert(0 != ocp);
1618
1619
1620   if (0 < ocp->reply.ref_count) {
1621     if (ocp->expireat < CurrentTime) {
1622       ocp->expireat = CurrentTime + AR_TTL;
1623       Debug((DEBUG_DNS, "Resolver: referenced cache entry not removed for: %s",
1624             ocp->he.h.h_name));
1625     }
1626     return;
1627   }
1628   /*
1629    * remove cache entry from linked list
1630    */
1631   for (cp = &cacheTop; *cp; cp = &((*cp)->list_next)) {
1632     if (*cp == ocp) {
1633       *cp = ocp->list_next;
1634       break;
1635     }
1636   }
1637   hp = &ocp->he.h;
1638   /*
1639    * remove cache entry from hashed name list
1640    */
1641   assert(0 != hp->h_name);
1642   hashv = hash_name(hp->h_name);
1643
1644   for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next)) {
1645     if (*cp == ocp) {
1646       *cp = ocp->hname_next;
1647       break;
1648     }
1649   }
1650   /*
1651    * remove cache entry from hashed number list
1652    */
1653   hashv = hash_number(hp->h_addr);
1654   assert(-1 < hashv);
1655
1656   for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next)) {
1657     if (*cp == ocp) {
1658       *cp = ocp->hnum_next;
1659       break;
1660     }
1661   }
1662   /*
1663    * free memory used to hold the various host names and the array
1664    * of alias pointers.
1665    */
1666   MyFree(ocp->he.buf);
1667   MyFree(ocp);
1668   --cachedCount;
1669   ++cainfo.ca_dels;
1670 }
1671
1672 void flush_resolver_cache(void)
1673 {
1674   /*
1675    * stubbed - iterate cache and remove everything that isn't referenced
1676    */
1677 }
1678
1679 /*
1680  * m_dns - dns status query
1681  */
1682 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1683 {
1684 #if !defined(NDEBUG)
1685   struct CacheEntry* cp;
1686   int     i;
1687   struct hostent* hp;
1688
1689   if (parv[1] && *parv[1] == 'l') {
1690     for(cp = cacheTop; cp; cp = cp->list_next) {
1691       hp = &cp->he.h;
1692       sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)",
1693                  parv[0], cp->expireat - CurrentTime, cp->ttl,
1694                  hp->h_name, ircd_ntoa(hp->h_addr));
1695       for (i = 0; hp->h_aliases[i]; i++)
1696         sendto_one(sptr,"NOTICE %s : %s = %s (CN)",
1697                    parv[0], hp->h_name, hp->h_aliases[i]);
1698       for (i = 1; hp->h_addr_list[i]; i++)
1699         sendto_one(sptr,"NOTICE %s : %s = %s (IP)",
1700                    parv[0], hp->h_name, ircd_ntoa(hp->h_addr_list[i]));
1701     }
1702     return 0;
1703   }
1704   if (parv[1] && *parv[1] == 'd') {
1705     sendto_one(sptr, "NOTICE %s :ResolverFileDescriptor = %d", 
1706                parv[0], ResolverFileDescriptor);
1707     return 0;
1708   }
1709   sendto_one(sptr,"NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d",
1710              sptr->name,
1711              cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
1712              cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits, 
1713              cainfo.ca_updates);
1714   
1715   sendto_one(sptr,"NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d",
1716              sptr->name, reinfo.re_errors, reinfo.re_nu_look,
1717              reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
1718   sendto_one(sptr,"NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name,
1719              reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
1720              reinfo.re_resends, reinfo.re_timeouts);
1721 #endif
1722   return 0;
1723 }
1724
1725 unsigned long cres_mem(struct Client* sptr)
1726 {
1727   struct CacheEntry* entry;
1728   struct ResRequest* request;
1729   size_t cache_mem     = 0;
1730   int    cache_count   = 0;
1731   size_t request_mem   = 0;
1732   int    request_count = 0;
1733
1734   for (entry = cacheTop; entry; entry = entry->list_next) {
1735     cache_mem += sizeof(struct CacheEntry);
1736     cache_mem += calc_hostent_buffer_size(&entry->he.h); 
1737     ++cache_count;
1738   }
1739   for (request = requestListHead; request; request = request->next) {
1740     request_mem += sizeof(struct ResRequest);
1741     if (request->name)
1742       request_mem += strlen(request->name) + 1; 
1743     if (request->he.buf)
1744       request_mem += MAXGETHOSTLEN + 1;
1745     ++request_count;
1746   }
1747   if (cachedCount != cache_count) {
1748     sendto_one(sptr, 
1749                ":%s %d %s :Resolver: cache count mismatch: %d != %d",
1750                me.name, RPL_STATSDEBUG, sptr->name, cachedCount, cache_count);
1751     assert(cachedCount == cache_count);
1752   }
1753   sendto_one(sptr, ":%s %d %s :Resolver: cache %d(%d) requests %d(%d)",
1754              me.name, RPL_STATSDEBUG, sptr->name, cache_count, cache_mem,
1755              request_count, request_mem);
1756   return cache_mem + request_mem;
1757 }
1758