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