Author: Alex Badea <vampire@p16.pub.ro>
[ircu2.10.12-pk.git] / ircd / res_adns.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 "config.h"
14
15 #include "adns.h"
16 #include "res.h"
17 #include "client.h"
18 #include "ircd.h"
19 #include "ircd_alloc.h"
20 #include "ircd_events.h"
21 #include "ircd_log.h"
22 #include "ircd_osdep.h"
23 #include "ircd_reply.h"
24 #include "ircd_snprintf.h"
25 #include "ircd_string.h"
26 #include "msg.h"
27 #include "numeric.h"
28 #include "s_bsd.h"
29 #include "s_debug.h"
30 #include "s_misc.h"
31 #include "send.h"
32 #include "struct.h"
33 #include "support.h"
34 #include "sys.h"
35
36 #include <assert.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <sys/time.h>
41 #include <sys/socket.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <regex.h>
45
46 #include <arpa/nameser.h>
47 #include <resolv.h>
48 #include <netdb.h>
49 #include <arpa/inet.h>
50
51 #include <limits.h>
52 #if (CHAR_BIT != 8)
53 #error this code needs to be able to address individual octets 
54 #endif
55
56 /*
57  * Some systems do not define INADDR_NONE (255.255.255.255)
58  * INADDR_NONE is actually a valid address, but it should never
59  * be returned from any nameserver.
60  * NOTE: The bit pattern for INADDR_NONE and INADDR_ANY (0.0.0.0) should be 
61  * the same on all hosts so we shouldn't need to use htonl or ntohl to
62  * compare or set the values.
63  */ 
64 #ifndef INADDR_NONE
65 #define INADDR_NONE ((unsigned int) 0xffffffff)
66 #endif
67
68 #define MAXPACKET       1024  /* rfc sez 512 but we expand names so ... */
69 #define RES_MAXALIASES  35    /* maximum aliases allowed */
70 #define RES_MAXADDRS    35    /* maximum addresses allowed */
71 /*
72  * OSF1 doesn't have RES_NOALIASES
73  */
74 #ifndef RES_NOALIASES
75 #define RES_NOALIASES 0
76 #endif
77
78 /*
79  * macros used to calulate offsets into fixed query buffer
80  */
81 #define ALIAS_BLEN  ((RES_MAXALIASES + 1) * sizeof(char*))
82 #define ADDRS_BLEN  ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
83
84 #define ADDRS_OFFSET   (ALIAS_BLEN + ADDRS_BLEN)
85 #define ADDRS_DLEN     (RES_MAXADDRS * sizeof(struct in_addr))
86 #define NAMES_OFFSET   (ADDRS_OFFSET + ADDRS_DLEN)
87 #define MAXGETHOSTLEN  (NAMES_OFFSET + MAXPACKET)
88
89 #define AR_TTL          600   /* TTL in seconds for dns cache entries */
90
91 /*
92  * the following values should be prime
93  */
94 #define ARES_CACSIZE    307
95 #define MAXCACHED       17
96 //#define MAXCACHED       281
97
98 /*
99  * Building the Hostent
100  * The Hostent struct is arranged like this:
101  *          +-------------------------------+
102  * Hostent: | struct hostent h              |
103  *          |-------------------------------|
104  *          | char *buf                     |
105  *          +-------------------------------+
106  *
107  * allocated:
108  *
109  *          +-------------------------------+
110  * buf:     | h_aliases pointer array       | Max size: ALIAS_BLEN;
111  *          | NULL                          | contains `char *'s
112  *          |-------------------------------|
113  *          | h_addr_list pointer array     | Max size: ADDRS_BLEN;
114  *          | NULL                          | contains `struct in_addr *'s
115  *          |-------------------------------|
116  *          | h_addr_list addresses         | Max size: ADDRS_DLEN;
117  *          |                               | contains `struct in_addr's
118  *          |-------------------------------|
119  *          | storage for hostname strings  | Max size: ALIAS_DLEN;
120  *          +-------------------------------+ contains `char's
121  *
122  *  For requests the size of the h_aliases, and h_addr_list pointer
123  *  array sizes are set to MAXALISES and MAXADDRS respectively, and
124  *  buf is a fixed size with enough space to hold the largest expected
125  *  reply from a nameserver, see RFC 1034 and RFC 1035.
126  *  For cached entries the sizes are dependent on the actual number
127  *  of aliases and addresses. If new aliases and addresses are found
128  *  for cached entries, the buffer is grown and the new entries are added.
129  *  The hostent struct is filled in with the addresses of the entries in
130  *  the Hostent buf as follows:
131  *  h_name      - contains a pointer to the start of the hostname string area,
132  *                or NULL if none is set.  The h_name is followed by the
133  *                aliases, in the storage for hostname strings area.
134  *  h_aliases   - contains a pointer to the start of h_aliases pointer array.
135  *                This array contains pointers to the storage for hostname
136  *                strings area and is terminated with a NULL.  The first alias
137  *                is stored directly after the h_name.
138  *  h_addr_list - contains a pointer to the start of h_addr_list pointer array.
139  *                This array contains pointers to in_addr structures in the
140  *                h_addr_list addresses area and is terminated with a NULL.
141  *
142  *  Filling the buffer this way allows for proper alignment of the h_addr_list
143  *  addresses.
144  *
145  *  This arrangement allows us to alias a Hostent struct pointer as a
146  *  real struct hostent* without lying. It also allows us to change the
147  *  values contained in the cached entries and requests without changing
148  *  the actual hostent pointer, which is saved in a client struct and can't
149  *  be changed without blowing things up or a lot more fiddling around.
150  *  It also allows for defered allocation of the fixed size buffers until
151  *  they are really needed.
152  *  Nov. 17, 1997 --Bleep
153  */
154
155 struct Hostent {
156   struct hostent h;      /* the hostent struct we are passing around */
157   char*          buf;    /* buffer for data pointed to from hostent */
158 };
159
160 struct ResRequest {
161   struct ResRequest* next;
162
163   adns_rrtype        type;
164   adns_query         aq;
165
166   struct in_addr     addr;
167   char*              name;
168   struct DNSQuery    query;         /* query callback for this request */
169   struct Hostent     he;
170 };
171
172 struct CacheEntry {
173   struct CacheEntry* hname_next;
174   struct CacheEntry* hnum_next;
175   struct CacheEntry* list_next;
176   time_t             expireat;
177   time_t             ttl;
178   struct Hostent     he;
179   struct DNSReply    reply;
180 };
181
182 struct CacheTable {
183   struct CacheEntry* num_list;
184   struct CacheEntry* name_list;
185 };
186
187
188 int ResolverFileDescriptor    = -1;   /* GLOBAL - used in s_bsd.c */
189
190 static struct Socket resSock;           /* Socket describing resolver */
191 static struct Timer  resExpireDNS;      /* Timer for DNS expiration */
192 static struct Timer  resExpireCache;    /* Timer for cache expiration */
193 static adns_state adns = NULL;
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 time_t   timeout_query_list(time_t now);
215 static time_t   expire_cache(time_t now);
216 static void     rem_cache(struct CacheEntry*);
217 static void     do_query_name(const struct DNSQuery* query, 
218                               const char* name, 
219                               struct ResRequest* request);
220 static void     do_query_number(const struct DNSQuery* query,
221                                 const struct in_addr*, 
222                                 struct ResRequest* request);
223 static struct CacheEntry*  make_cache(struct ResRequest* request);
224 static struct CacheEntry*  find_cache_name(const char* name);
225 static struct CacheEntry*  find_cache_number(struct ResRequest* request, 
226                                              const char* addr);
227 static void res_adns_callback(adns_state state, adns_query q, void *context);
228
229 static struct cacheinfo {
230   int  ca_adds;
231   int  ca_dels;
232   int  ca_expires;
233   int  ca_lookups;
234   int  ca_na_hits;
235   int  ca_nu_hits;
236   int  ca_updates;
237 } cainfo;
238
239 static  struct  resinfo {
240   int  re_errors;
241   int  re_nu_look;
242   int  re_na_look;
243   int  re_replies;
244   int  re_requests;
245   int  re_resends;
246   int  re_sent;
247   int  re_timeouts;
248   int  re_shortttl;
249   int  re_unkrep;
250 } reinfo;
251
252
253 /*
254  * int
255  * res_isourserver(ina)
256  *      looks up "ina" in _res.ns_addr_list[]
257  * returns:
258  *      0  : not found
259  *      >0 : found
260  * author:
261  *      paul vixie, 29may94
262  */
263 static int
264 res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp) 
265 {
266   struct sockaddr_in ina;
267   int ns;
268
269   ina = *inp;
270   for (ns = 0;  ns < statp->nscount;  ns++) {
271     const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
272
273     if (srv->sin_family == ina.sin_family &&
274          srv->sin_port == ina.sin_port &&
275          (srv->sin_addr.s_addr == INADDR_ANY ||
276           srv->sin_addr.s_addr == ina.sin_addr.s_addr))
277              return (1);
278   }
279   return (0);
280 }
281
282 /* Socket callback for resolver */
283 static void res_socket_callback(struct Event* ev)
284 {
285   struct timeval tv;
286
287   assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
288
289   tv.tv_sec = CurrentTime;
290   tv.tv_usec = 0;
291   adns_processreadable(adns, ResolverFileDescriptor, &tv);
292 }
293
294 /*
295  * start_resolver - do everything we need to read the resolv.conf file
296  * and initialize the resolver file descriptor if needed
297  */
298 static void start_resolver(void)
299 {
300   int res;
301
302   Debug((DEBUG_DNS, "Resolver: start_resolver"));
303   /*
304    * close the spare file descriptor so res_init can read resolv.conf
305    * successfully. Needed on Solaris
306    */
307   if (spare_fd > -1)
308     close(spare_fd);
309
310   /*
311    * make sure we have a valid file descriptor below 256 so we can
312    * do this again. Needed on Solaris
313    */
314   spare_fd = open("/dev/null",O_RDONLY,0);
315   if ((spare_fd < 0) || (spare_fd > 255)) {
316     char sparemsg[80];
317     ircd_snprintf(0, sparemsg, sizeof(sparemsg), "invalid spare_fd %d",
318                   spare_fd);
319     server_restart(sparemsg);
320   }
321
322   if (adns)
323     return;
324
325   if ((res = adns_init(&adns, adns_if_debug /*| adns_if_noautosys*/, NULL))) {
326     report_error("Resolver: error initializing adns for %s: %s", cli_name(&me), res);
327     errno = res;
328     return;
329   }
330   errno = 0;
331   
332   ResolverFileDescriptor = adns_get_fd(adns);
333
334   if (!socket_add(&resSock, res_socket_callback, 0, SS_DATAGRAM,
335                   SOCK_EVENT_READABLE, ResolverFileDescriptor))
336     report_error("Resolver: unable to queue resolver file descriptor for %s",
337                  cli_name(&me), ENFILE);
338 }
339
340 /* Call the query timeout function */
341 static void expire_DNS_callback(struct Event* ev)
342 {
343   time_t next;
344
345   next = timeout_query_list(CurrentTime);
346
347   timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
348 }
349
350 /* Call the cache expire function */
351 static void expire_cache_callback(struct Event* ev)
352 {
353   time_t next;
354
355   next = expire_cache(CurrentTime);
356
357   timer_add(&resExpireCache, expire_cache_callback, 0, TT_ABSOLUTE, next);
358 }
359
360 /*
361  * init_resolver - initialize resolver and resolver library
362  */
363 int init_resolver(void)
364 {
365   Debug((DEBUG_DNS, "Resolver: init_resolver"));
366 #ifdef  LRAND48
367   srand48(CurrentTime);
368 #endif
369   memset(&cainfo,   0, sizeof(cainfo));
370   memset(hashtable, 0, sizeof(hashtable));
371   memset(&reinfo,   0, sizeof(reinfo));
372
373   requestListHead = requestListTail = 0;
374
375   /* initiate the resolver timers */
376   timer_add(timer_init(&resExpireDNS), expire_DNS_callback, 0,
377             TT_RELATIVE, 1);
378   timer_add(timer_init(&resExpireCache), expire_cache_callback, 0,
379             TT_RELATIVE, 1);
380
381   errno = h_errno = 0;
382
383   start_resolver();
384   Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s",
385          ResolverFileDescriptor, errno, h_errno, 
386          (strerror(errno)) ? strerror(errno) : "Unknown"));
387   return ResolverFileDescriptor;
388 }
389
390 /*
391  * restart_resolver - flush the cache, reread resolv.conf, reopen socket
392  */
393 void restart_resolver(void)
394 {
395   /* flush_cache();  flush the dns cache */
396   start_resolver();
397 }
398
399 /*
400  * add_request - place a new request in the request list
401  */
402 static void add_request(struct ResRequest* request)
403 {
404   assert(0 != request);
405   if (!requestListHead)
406     requestListHead = requestListTail = request;
407   else {
408     requestListTail->next = request;
409     requestListTail = request;
410   }
411   request->next = NULL;
412   ++reinfo.re_requests;
413 }
414
415 /*
416  * rem_request - remove a request from the list. 
417  * This must also free any memory that has been allocated for 
418  * temporary storage of DNS results.
419  */
420 static void rem_request(struct ResRequest* request)
421 {
422   struct ResRequest** current;
423   struct ResRequest*  prev = NULL;
424
425   assert(0 != request);
426   for (current = &requestListHead; *current; ) {
427     if (*current == request) {
428       *current = request->next;
429       if (requestListTail == request)
430         requestListTail = prev;
431       break;
432     } 
433     prev    = *current;
434     current = &(*current)->next;
435   }
436   if (request->aq)
437     adns_cancel(request->aq);
438   MyFree(request->he.buf);
439   MyFree(request->name);
440   MyFree(request);
441 }
442
443 /*
444  * make_request - Create a DNS request record for the server.
445  */
446 static struct ResRequest* make_request(const struct DNSQuery* query)
447 {
448   struct ResRequest* request;
449   assert(0 != query);
450   request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
451   memset(request, 0, sizeof(struct ResRequest));
452
453   request->addr.s_addr      = INADDR_NONE;
454   request->he.h.h_addrtype  = AF_INET;
455   request->he.h.h_length    = sizeof(struct in_addr);
456   request->query.vptr       = query->vptr;
457   request->query.callback   = query->callback;
458
459 #if defined(NULL_POINTER_NOT_ZERO)
460   request->next             = NULL;
461   request->he.buf           = NULL;
462   request->he.h.h_name      = NULL;
463   request->he.h.h_aliases   = NULL;
464   request->he.h.h_addr_list = NULL;
465 #endif
466   add_request(request);
467   return request;
468 }
469
470 /*
471  * timeout_query_list - Remove queries from the list which have been 
472  * there too long without being resolved.
473  */
474 static time_t timeout_query_list(time_t now)
475 {
476   struct timeval tv, tv_buf, *tv_mod = NULL;
477   time_t next;
478   
479   Debug((DEBUG_DNS, "Resolver: timeout_query_list at %s", myctime(now)));
480
481   tv.tv_sec = now;
482   tv.tv_usec = 0;
483   adns_processtimeouts(adns, &tv);
484   adns_firsttimeout(adns, &tv_mod, &tv_buf, tv);
485   next = tv_mod ? tv_mod->tv_sec : AR_TTL;
486   if (!next)
487     next = 1;
488
489   Debug((DEBUG_DNS, "Resolver: next timeout_query_list in %d seconds", next));
490   return now + next;
491 }
492
493 /*
494  * expire_cache - removes entries from the cache which are older 
495  * than their expiry times. returns the time at which the server 
496  * should next poll the cache.
497  */
498 static time_t expire_cache(time_t now)
499 {
500   struct CacheEntry* cp;
501   struct CacheEntry* cp_next;
502   time_t             expire = 0;
503
504   Debug((DEBUG_DNS, "Resolver: expire_cache at %s", myctime(now)));
505   for (cp = cacheTop; cp; cp = cp_next) {
506     cp_next = cp->list_next;
507     if (cp->expireat < now) {
508       ++cainfo.ca_expires;
509       rem_cache(cp);
510     }
511     else if (!expire || expire > cp->expireat)
512       expire = cp->expireat;
513   }
514   return (expire > now) ? expire : (now + AR_TTL);
515 }
516
517 /*
518  * delete_resolver_queries - cleanup outstanding queries 
519  * for which there no longer exist clients or conf lines.
520  */
521 void delete_resolver_queries(const void* vptr)
522 {
523   struct ResRequest* request;
524   struct ResRequest* next_request;
525
526   for (request = requestListHead; request; request = next_request) {
527     next_request = request->next;
528     if (vptr == request->query.vptr)
529       rem_request(request);
530   }
531 }
532
533 /*
534  * gethost_byname - get host address from name
535  */
536 struct DNSReply* gethost_byname(const char* name, 
537                                const struct DNSQuery* query)
538 {
539   struct CacheEntry* cp;
540   assert(0 != name);
541
542   Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
543   ++reinfo.re_na_look;
544   if ((cp = find_cache_name(name)))
545     return &(cp->reply);
546
547   do_query_name(query, name, NULL);
548   return NULL;
549 }
550
551 /*
552  * gethost_byaddr - get host name from address
553  */
554 struct DNSReply* gethost_byaddr(const char* addr,
555                                 const struct DNSQuery* query)
556 {
557   struct CacheEntry *cp;
558
559   assert(0 != addr);
560
561   Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
562
563   ++reinfo.re_nu_look;
564   if ((cp = find_cache_number(NULL, addr)))
565     return &(cp->reply);
566
567   do_query_number(query, (const struct in_addr*) addr, NULL);
568   return NULL;
569 }
570
571 /*
572  * do_query_name - nameserver lookup name
573  */
574 static void do_query_name(const struct DNSQuery* query, 
575                           const char* name, struct ResRequest* request)
576 {
577   char  hname[HOSTLEN + 1];
578   int   res;
579   assert(0 != name);
580
581   ircd_strncpy(hname, name, HOSTLEN);
582   hname[HOSTLEN] = '\0';
583
584   if (!request) {
585     request       = make_request(query);
586     request->type = adns_r_a;
587     request->name = (char*) MyMalloc(strlen(hname) + 1);
588     strcpy(request->name, hname);
589   }
590   res = adns_submit_callback(adns, hname, adns_r_a, adns_qf_owner, request, &request->aq, res_adns_callback);
591   assert(!res);
592   timer_chg(&resExpireDNS, TT_RELATIVE, 1);
593 }
594
595 /*
596  * do_query_number - Use this to do reverse IP# lookups.
597  */
598 static void do_query_number(const struct DNSQuery* query, 
599                             const struct in_addr* addr,
600                             struct ResRequest* request)
601 {
602   char  ipbuf[32];
603   const unsigned char* cp;
604   int   res;
605
606   assert(0 != addr);
607   cp = (const unsigned char*) &addr->s_addr;
608   ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
609                 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
610                 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
611
612   if (!request) {
613     request              = make_request(query);
614     request->type        = adns_r_ptr;
615     request->addr.s_addr = addr->s_addr;
616   }
617   res = adns_submit_callback(adns, ipbuf, adns_r_ptr, adns_qf_owner, request, &request->aq, res_adns_callback);
618   assert(!res);
619   timer_chg(&resExpireDNS, TT_RELATIVE, 1);
620 }
621
622 /* Returns true if this is a valid name */
623 static int validate_name(char *name)
624 {
625   while (*name) {
626     if ((*name<'A' || *name>'Z') 
627      && (*name<'a' || *name>'z') 
628      && (*name<'0' || *name>'9')
629      && (*name!='-')) {
630       return 0;
631     }
632     name++;
633   }
634   return 1;
635 }
636
637 static void res_adns_callback(adns_state state, adns_query q, void *context)
638 {
639   struct ResRequest *request = (struct ResRequest *) context;
640   adns_answer *answer = NULL;
641   int res, k;
642   struct hostent* hp;          /* hostent getting filled */
643   char** alias;                /* alias list */
644   char** addr;                 /* address list */
645   char** base_addr;            /* original pointer to address list */
646   char*  name;                 /* pointer to name string */
647   char*  address;              /* pointer to address */
648   char*  base_address;         /* original pointer to address */
649   char*  endp;                 /* end of our buffer */
650   int    addr_count  = 0;      /* number of addresses in hostent */
651   int    alias_count = 0;      /* number of aliases in hostent */
652   struct CacheEntry* cp           = 0;
653   
654   assert(request);
655   assert(q);
656   assert(request->aq == q);
657   res = adns_check(adns, &q, &answer, NULL);
658   request->aq = NULL;
659
660   if (res) {
661     /* adns_check returned an error, bail */
662     Debug((DEBUG_DNS, "Resolver: adns_check result %d", res));
663
664     (*request->query.callback)(request->query.vptr, 0);
665     rem_request(request);
666     return;
667   }
668
669   Debug((DEBUG_DNS, "Resolver: adns_check status %d nrrs %d", answer->status, answer->nrrs));
670   
671   /* No error, we have a valid answer structure */
672   if (answer->status != adns_s_ok || !answer->nrrs) {
673     /* Status is not 'ok', or there were no RRs found */
674     ++reinfo.re_errors;
675     (*request->query.callback)(request->query.vptr, 0);
676   } else {
677     ++reinfo.re_replies;
678     hp = &(request->he.h);    
679     if (!request->he.buf) {
680       request->he.buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
681       request->he.buf[MAXGETHOSTLEN] = '\0';
682       /*
683        * array of alias list pointers starts at beginning of buf
684        */
685       hp->h_aliases = (char**) request->he.buf;
686       hp->h_aliases[0] = NULL;
687       /*
688        * array of address list pointers starts after alias list pointers
689        * the actual addresses follow the the address list pointers
690        */ 
691       hp->h_addr_list = (char**)(request->he.buf + ALIAS_BLEN);
692       /*
693        * don't copy the host address to the beginning of h_addr_list
694        */
695       hp->h_addr_list[0] = NULL;
696     }
697
698     hp->h_addrtype = AF_INET;
699
700     endp = request->he.buf + MAXGETHOSTLEN;
701     /*
702      * find the end of the address list
703      */
704     addr = hp->h_addr_list;
705     while (*addr) {
706       ++addr;
707       ++addr_count;
708     }
709     base_addr = addr;
710     /*
711      * make address point to first available address slot
712      */
713     address = request->he.buf + ADDRS_OFFSET +
714                       (sizeof(struct in_addr) * addr_count);
715     base_address = address;
716
717     /*
718      * find the end of the alias list
719      */
720     alias = hp->h_aliases;
721     while (*alias) {
722       ++alias;
723       ++alias_count;
724     }
725     /*
726      * make name point to first available space in request->buf
727      */
728     if (alias_count > 0) {
729       name = hp->h_aliases[alias_count - 1];
730       name += (strlen(name) + 1);
731     }
732     else if (hp->h_name)
733       name = hp->h_name + strlen(hp->h_name) + 1;
734     else
735       name = request->he.buf + ADDRS_OFFSET + ADDRS_DLEN;
736
737     switch (request->type) {
738     case adns_r_a:
739       for (k = 0; k < answer->nrrs; k++) {
740         if (++addr_count < RES_MAXADDRS) {
741           memcpy(address, &answer->rrs.inaddr[k], sizeof(struct in_addr));
742           *addr++ = address;
743           *addr = 0;
744           address += sizeof(struct in_addr);
745         }
746         Debug((DEBUG_DNS, "Resolver: A %s for %s", ircd_ntoa((char*) &answer->rrs.inaddr[k]), answer->owner));
747       }
748       if (!hp->h_name) {
749         strcpy(name, answer->owner);
750         hp->h_name = name;
751         name += strlen(name) + 1;
752       }
753       break;
754     case adns_r_ptr:
755       strcpy(name, answer->rrs.str[0]);
756       hp->h_name = name;
757       name += strlen(name) + 1;
758
759       Debug((DEBUG_DNS, "Resolver: PTR %s for %s", hp->h_name, answer->owner));
760       break;
761     default:
762       /* ignore */
763       break;
764     }
765
766     if (answer->cname) {
767       alias_count++;
768       ircd_strncpy(name, answer->cname, endp - name);
769       *alias++ = name;
770       *alias   = 0;
771       name += strlen(name) + 1;
772       Debug((DEBUG_DNS, "Resolver: CNAME %s for %s", answer->cname, answer->owner));
773     }
774
775     if (request->type == adns_r_ptr) {
776       struct DNSReply* reply;
777
778       Debug((DEBUG_DNS, "relookup %s <-> %s",
779              request->he.h.h_name, ircd_ntoa((char*) &request->addr)));
780       /*
781        * Lookup the 'authoritive' name that we were given for the
782        * ip#.  By using this call rather than regenerating the
783        * type we automatically gain the use of the cache with no
784        * extra kludges.
785        */
786       reply = gethost_byname(request->he.h.h_name, &request->query);
787       if (reply) {
788         (*request->query.callback)(request->query.vptr, reply);
789       } else {
790         /*
791          * If name wasn't found, a request has been queued and it will
792          * be the last one queued.  This is rather nasty way to keep
793          * a host alias with the query. -avalon
794          */
795         MyFree(requestListTail->he.buf);
796         requestListTail->he.buf = request->he.buf;
797         request->he.buf = 0;
798         memcpy(&requestListTail->he.h, &request->he.h, sizeof(struct hostent));
799       }
800     } else {
801       /*
802        * got a name and address response, client resolved
803        * XXX - Bug found here by Dianora -
804        * make_cache() occasionally returns a NULL pointer when a
805        * PTR returned a CNAME, cp was not checked before so the
806        * callback was being called with a value of 0x2C != NULL.
807        */
808       struct DNSReply* reply = 0;
809       if ((cp = make_cache(request)))
810         reply = &cp->reply;
811       (*request->query.callback)(request->query.vptr, reply);
812     }
813   }
814   
815   rem_request(request);
816   
817   /*
818    * adns doesn't use MyMalloc, so we don't use MyFree
819    */
820   free(answer);
821 }
822
823
824 static size_t calc_hostent_buffer_size(const struct hostent* hp)
825 {
826   char** p;
827   size_t count = 0;
828   assert(0 != hp);
829
830   /*
831    * space for name
832    */
833   count += (strlen(hp->h_name) + 1);
834   /*
835    * space for aliases
836    */
837   for (p = hp->h_aliases; *p; ++p)
838     count += (strlen(*p) + 1 + sizeof(char*));
839   /*
840    * space for addresses
841    */
842   for (p = hp->h_addr_list; *p; ++p)
843     count += (hp->h_length + sizeof(char*));
844   /*
845    * space for 2 nulls to terminate h_aliases and h_addr_list 
846    */
847   count += (2 * sizeof(char*));
848   return count;
849 }
850
851
852 /*
853  * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
854  * the data we're putting in it.
855  */
856 static void dup_hostent(struct Hostent* new_hp, struct hostent* hp)
857 {
858   char*  p;
859   char** ap;
860   char** pp;
861   int    alias_count = 0;
862   int    addr_count = 0;
863   size_t bytes_needed = 0;
864
865   assert(0 != new_hp);
866   assert(0 != hp);
867
868   /* how much buffer do we need? */
869   bytes_needed += (strlen(hp->h_name) + 1);
870
871   pp = hp->h_aliases;
872   while (*pp) {
873     bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
874     ++alias_count;
875   }
876   pp = hp->h_addr_list;
877   while (*pp++) {
878     bytes_needed += (hp->h_length + sizeof(char*));
879     ++addr_count;
880   }
881   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
882   bytes_needed += (2 * sizeof(char*));
883
884   /* Allocate memory */
885   new_hp->buf = (char*) MyMalloc(bytes_needed);
886
887   new_hp->h.h_addrtype = hp->h_addrtype;
888   new_hp->h.h_length = hp->h_length;
889
890   /* first write the address list */
891   pp = hp->h_addr_list;
892   ap = new_hp->h.h_addr_list =
893       (char**)(new_hp->buf + ((alias_count + 1) * sizeof(char*)));
894   p = (char*)ap + ((addr_count + 1) * sizeof(char*));
895   while (*pp)
896   {
897     *ap++ = p;
898     memcpy(p, *pp++, hp->h_length);
899     p += hp->h_length;
900   }
901   *ap = 0;
902   /* next write the name */
903   new_hp->h.h_name = p;
904   strcpy(p, hp->h_name);
905   p += (strlen(p) + 1);
906
907   /* last write the alias list */
908   pp = hp->h_aliases;
909   ap = new_hp->h.h_aliases = (char**) new_hp->buf;
910   while (*pp) {
911     *ap++ = p;
912     strcpy(p, *pp++);
913     p += (strlen(p) + 1);
914   }
915   *ap = 0;
916 }
917
918 /*
919  * update_hostent - Add records to a Hostent struct in place.
920  */
921 static void update_hostent(struct Hostent* hp, char** addr, char** alias)
922 {
923   char*  p;
924   char** ap;
925   char** pp;
926   int    alias_count = 0;
927   int    addr_count = 0;
928   char*  buf = NULL;
929   size_t bytes_needed = 0;
930
931   if (!hp || !hp->buf)
932     return;
933
934   /* how much buffer do we need? */
935   bytes_needed = strlen(hp->h.h_name) + 1;
936   pp = hp->h.h_aliases;
937   while (*pp) {
938     bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
939     ++alias_count;
940   }
941   if (alias) {
942     pp = alias;
943     while (*pp) {
944       bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
945       ++alias_count;
946     }
947   }
948   pp = hp->h.h_addr_list;
949   while (*pp++) {
950     bytes_needed += (hp->h.h_length + sizeof(char*));
951     ++addr_count;
952   }
953   if (addr) {
954     pp = addr;
955     while (*pp++) {
956       bytes_needed += (hp->h.h_length + sizeof(char*));
957       ++addr_count;
958     }
959   }
960   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
961   bytes_needed += 2 * sizeof(char*);
962
963   /* Allocate memory */
964   buf = (char*) MyMalloc(bytes_needed);
965   assert(0 != buf);
966
967   /* first write the address list */
968   pp = hp->h.h_addr_list;
969   ap = hp->h.h_addr_list =
970       (char**)(buf + ((alias_count + 1) * sizeof(char*)));
971   p = (char*)ap + ((addr_count + 1) * sizeof(char*));
972   while (*pp) {
973     memcpy(p, *pp++, hp->h.h_length);
974     *ap++ = p;
975     p += hp->h.h_length;
976   }
977   if (addr) {
978     while (*addr) {
979       memcpy(p, *addr++, hp->h.h_length);
980       *ap++ = p;
981       p += hp->h.h_length;
982     }
983   }
984   *ap = 0;
985
986   /* next write the name */
987   strcpy(p, hp->h.h_name);
988   hp->h.h_name = p;
989   p += (strlen(p) + 1);
990
991   /* last write the alias list */
992   pp = hp->h.h_aliases;
993   ap = hp->h.h_aliases = (char**) buf;
994   while (*pp) {
995     strcpy(p, *pp++);
996     *ap++ = p;
997     p += (strlen(p) + 1);
998   }
999   if (alias) {
1000     while (*alias) {
1001       strcpy(p, *alias++);
1002       *ap++ = p;
1003       p += (strlen(p) + 1);
1004     }
1005   }
1006   *ap = 0;
1007   /* release the old buffer */
1008   p = hp->buf;
1009   hp->buf = buf;
1010   MyFree(p);
1011 }
1012
1013 /*
1014  * hash_number - IP address hash function
1015  */
1016 static int hash_number(const unsigned char* ip)
1017 {
1018   /* could use loop but slower */
1019   unsigned int hashv;
1020   const u_char* p = (const u_char*) ip;
1021
1022   assert(0 != p);
1023
1024   hashv = *p++;
1025   hashv += hashv + *p++;
1026   hashv += hashv + *p++;
1027   hashv += hashv + *p;
1028   hashv %= ARES_CACSIZE;
1029   return hashv;
1030 }
1031
1032 /*
1033  * hash_name - hostname hash function
1034  */
1035 static int hash_name(const char* name)
1036 {
1037   unsigned int hashv = 0;
1038   const u_char* p = (const u_char*) name;
1039
1040   assert(0 != p);
1041
1042   for (; *p && *p != '.'; ++p)
1043     hashv += *p;
1044   hashv %= ARES_CACSIZE;
1045   return hashv;
1046 }
1047
1048 /*
1049  * add_to_cache - Add a new cache item to the queue and hash table.
1050  */
1051 static struct CacheEntry* add_to_cache(struct CacheEntry* ocp)
1052 {
1053   int  hashv;
1054
1055   assert(0 != ocp);
1056
1057   ocp->list_next = cacheTop;
1058   cacheTop = ocp;
1059
1060   hashv = hash_name(ocp->he.h.h_name);
1061
1062   ocp->hname_next = hashtable[hashv].name_list;
1063   hashtable[hashv].name_list = ocp;
1064
1065   hashv = hash_number((const unsigned char*) ocp->he.h.h_addr);
1066
1067   ocp->hnum_next = hashtable[hashv].num_list;
1068   hashtable[hashv].num_list = ocp;
1069
1070   /*
1071    * LRU deletion of excessive cache entries.
1072    */
1073   if (++cachedCount > MAXCACHED) {
1074     struct CacheEntry* cp;
1075     struct CacheEntry* cp_next;
1076     for (cp = ocp->list_next; cp; cp = cp_next) {
1077       cp_next = cp->list_next;
1078       rem_cache(cp);
1079     }
1080   }
1081   ++cainfo.ca_adds;
1082   return ocp;
1083 }
1084
1085 /*
1086  * update_list - does not alter the cache structure passed. It is assumed that
1087  * it already contains the correct expire time, if it is a new entry. Old
1088  * entries have the expirey time updated.
1089 */
1090 static void update_list(struct ResRequest* request, struct CacheEntry* cachep)
1091 {
1092   struct CacheEntry*  cp = cachep;
1093   char*    s;
1094   char*    t;
1095   int      i;
1096   int      j;
1097   char**   ap;
1098   char*    addrs[RES_MAXADDRS + 1];
1099   char*    aliases[RES_MAXALIASES + 1];
1100
1101   /*
1102    * search for the new cache item in the cache list by hostname.
1103    * If found, move the entry to the top of the list and return.
1104    */
1105   ++cainfo.ca_updates;
1106
1107   if (!request)
1108     return;
1109   /*
1110    * Compare the cache entry against the new record.  Add any
1111    * previously missing names for this entry.
1112    */
1113   *aliases = 0;
1114   ap = aliases;
1115   for (i = 0, s = request->he.h.h_name; s; s = request->he.h.h_aliases[i++]) {
1116     for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++]) {
1117       if (0 == ircd_strcmp(t, s))
1118         break;
1119     }
1120     if (!t) {
1121       *ap++ = s;
1122       *ap = 0;
1123     }
1124   }
1125   /*
1126    * Do the same again for IP#'s.
1127    */
1128   *addrs = 0;
1129   ap = addrs;
1130   for (i = 0; (s = request->he.h.h_addr_list[i]); i++) {
1131     for (j = 0; (t = cp->he.h.h_addr_list[j]); j++) {
1132       if (!memcmp(t, s, sizeof(struct in_addr)))
1133         break;
1134     }
1135     if (!t) {
1136       *ap++ = s;
1137       *ap = 0;
1138     }
1139   }
1140   if (*addrs || *aliases)
1141     update_hostent(&cp->he, addrs, aliases);
1142 }
1143
1144 /*
1145  * find_cache_name - find name in nameserver cache
1146  */
1147 static struct CacheEntry* find_cache_name(const char* name)
1148 {
1149   struct CacheEntry* cp;
1150   char*   s;
1151   int     hashv;
1152   int     i;
1153
1154   assert(0 != name);
1155   hashv = hash_name(name);
1156
1157   cp = hashtable[hashv].name_list;
1158
1159   for (; cp; cp = cp->hname_next) {
1160     for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++]) {
1161       if (0 == ircd_strcmp(s, name)) {
1162         ++cainfo.ca_na_hits;
1163         return cp;
1164       }
1165     }
1166   }
1167
1168   for (cp = cacheTop; cp; cp = cp->list_next) {
1169     /*
1170      * if no aliases or the hash value matches, we've already
1171      * done this entry and all possiblilities concerning it.
1172      */
1173     if (!cp->he.h.h_name || hashv == hash_name(cp->he.h.h_name))
1174       continue;
1175     for (i = 0, s = cp->he.h.h_aliases[i]; s; s = cp->he.h.h_aliases[++i]) {
1176       if (0 == ircd_strcmp(name, s)) {
1177         ++cainfo.ca_na_hits;
1178         return cp;
1179       }
1180     }
1181   }
1182   return NULL;
1183 }
1184
1185 /*
1186  * find_cache_number - find a cache entry by ip# and update its expire time
1187  */
1188 static struct CacheEntry* find_cache_number(struct ResRequest* request,
1189                                             const char* addr)
1190 {
1191   struct CacheEntry* cp;
1192   int     hashv;
1193   int     i;
1194
1195   assert(0 != addr);
1196   hashv = hash_number((const unsigned char*) addr);
1197   cp = hashtable[hashv].num_list;
1198
1199   for (; cp; cp = cp->hnum_next) {
1200     for (i = 0; cp->he.h.h_addr_list[i]; ++i) {
1201       if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
1202         ++cainfo.ca_nu_hits;
1203         return cp;
1204       }
1205     }
1206   }
1207   for (cp = cacheTop; cp; cp = cp->list_next) {
1208     /*
1209      * single address entry...would have been done by hashed
1210      * search above...
1211      * if the first IP# has the same hashnumber as the IP# we
1212      * are looking for, its been done already.
1213      */
1214     if (!cp->he.h.h_addr_list[1] || 
1215         hashv == hash_number((const unsigned char*) cp->he.h.h_addr_list[0]))
1216       continue;
1217     for (i = 1; cp->he.h.h_addr_list[i]; ++i) {
1218       if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
1219         ++cainfo.ca_nu_hits;
1220         return cp;
1221       }
1222     }
1223   }
1224   return NULL;
1225 }
1226
1227 static struct CacheEntry* make_cache(struct ResRequest* request)
1228 {
1229   struct CacheEntry* cp;
1230   int     i;
1231   struct hostent* hp;
1232   assert(0 != request);
1233
1234   hp = &request->he.h;
1235   /*
1236    * shouldn't happen but it just might...
1237    */
1238   assert(0 != hp->h_name);
1239 /*    assert(0 != hp->h_addr_list[0]); */
1240   if (!hp->h_name || !hp->h_addr_list[0])
1241     return NULL;
1242   /*
1243    * Make cache entry.  First check to see if the cache already exists
1244    * and if so, return a pointer to it.
1245    */
1246   for (i = 0; hp->h_addr_list[i]; ++i) {
1247     if ((cp = find_cache_number(request, hp->h_addr_list[i]))) {
1248       update_list(request, cp);
1249       return cp;
1250     }
1251   }
1252   /*
1253    * a matching entry wasnt found in the cache so go and make one up.
1254    */ 
1255   cp = (struct CacheEntry*) MyMalloc(sizeof(struct CacheEntry));
1256   assert(0 != cp);
1257
1258   memset(cp, 0, sizeof(struct CacheEntry));
1259   dup_hostent(&cp->he, hp);
1260   cp->reply.hp = &cp->he.h;
1261   /*
1262    * hmmm... we could time out the cache after 10 minutes regardless
1263    * would that be reasonable since we don't save the reply?
1264    */ 
1265 #if 0
1266   if (request->ttl < AR_TTL) {
1267     ++reinfo.re_shortttl;
1268     cp->ttl = AR_TTL;
1269   }
1270   else
1271     cp->ttl = request->ttl;
1272 #else
1273   cp->ttl = AR_TTL;
1274 #endif
1275   cp->expireat = CurrentTime + cp->ttl;
1276   return add_to_cache(cp);
1277 }
1278
1279 /*
1280  * rem_cache - delete a cache entry from the cache structures 
1281  * and lists and return all memory used for the cache back to the memory pool.
1282  */
1283 static void rem_cache(struct CacheEntry* ocp)
1284 {
1285   struct CacheEntry** cp;
1286   int                 hashv;
1287   struct hostent*     hp;
1288   assert(0 != ocp);
1289
1290
1291   if (0 < ocp->reply.ref_count) {
1292     if (ocp->expireat < CurrentTime) {
1293       ocp->expireat = CurrentTime + AR_TTL;
1294       Debug((DEBUG_DNS, "Resolver: referenced cache entry not removed for: %s",
1295             ocp->he.h.h_name));
1296     }
1297     return;
1298   }
1299   /*
1300    * remove cache entry from linked list
1301    */
1302   for (cp = &cacheTop; *cp; cp = &((*cp)->list_next)) {
1303     if (*cp == ocp) {
1304       *cp = ocp->list_next;
1305       break;
1306     }
1307   }
1308   hp = &ocp->he.h;
1309   /*
1310    * remove cache entry from hashed name list
1311    */
1312   assert(0 != hp->h_name);
1313   hashv = hash_name(hp->h_name);
1314
1315   for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next)) {
1316     if (*cp == ocp) {
1317       *cp = ocp->hname_next;
1318       break;
1319     }
1320   }
1321   /*
1322    * remove cache entry from hashed number list
1323    */
1324   hashv = hash_number((const unsigned char*) hp->h_addr);
1325   assert(-1 < hashv);
1326
1327   for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next)) {
1328     if (*cp == ocp) {
1329       *cp = ocp->hnum_next;
1330       break;
1331     }
1332   }
1333   /*
1334    * free memory used to hold the various host names and the array
1335    * of alias pointers.
1336    */
1337   MyFree(ocp->he.buf);
1338   MyFree(ocp);
1339   --cachedCount;
1340   ++cainfo.ca_dels;
1341 }
1342
1343 void flush_resolver_cache(void)
1344 {
1345   /*
1346    * stubbed - iterate cache and remove everything that isn't referenced
1347    */
1348 }
1349
1350 /*
1351  * m_dns - dns status query
1352  */
1353 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1354 {
1355 #if !defined(NDEBUG)
1356   struct CacheEntry* cp;
1357   int     i;
1358   struct hostent* hp;
1359
1360   if (parv[1] && *parv[1] == 'l') {
1361     for(cp = cacheTop; cp; cp = cp->list_next) {
1362       hp = &cp->he.h;
1363       sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Ex %d ttl %d host %s(%s)",
1364                     sptr, cp->expireat - CurrentTime, cp->ttl,
1365                     hp->h_name, ircd_ntoa(hp->h_addr));
1366       for (i = 0; hp->h_aliases[i]; i++)
1367         sendcmdto_one(&me, CMD_NOTICE, sptr, "%C : %s = %s (CN)", sptr,
1368                       hp->h_name, hp->h_aliases[i]);
1369       for (i = 1; hp->h_addr_list[i]; i++)
1370         sendcmdto_one(&me, CMD_NOTICE, sptr, "%C : %s = %s (IP)", sptr,
1371                       hp->h_name, ircd_ntoa(hp->h_addr_list[i]));
1372     }
1373     return 0;
1374   }
1375   if (parv[1] && *parv[1] == 'd') {
1376     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :ResolverFileDescriptor = %d", 
1377                   sptr, ResolverFileDescriptor);
1378     return 0;
1379   }
1380   sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Ca %d Cd %d Ce %d Cl %d Ch %d:%d "
1381                 "Cu %d", sptr,
1382                 cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
1383                 cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits, 
1384                 cainfo.ca_updates);
1385   
1386   sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Re %d Rl %d/%d Rp %d Rq %d",
1387                 sptr, reinfo.re_errors, reinfo.re_nu_look,
1388                 reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
1389   sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr,
1390                 reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
1391                 reinfo.re_resends, reinfo.re_timeouts);
1392 #endif
1393   return 0;
1394 }
1395
1396 size_t cres_mem(struct Client* sptr)
1397 {
1398   struct CacheEntry* entry;
1399   struct ResRequest* request;
1400   size_t cache_mem     = 0;
1401   size_t request_mem   = 0;
1402   int    cache_count   = 0;
1403   int    request_count = 0;
1404
1405   for (entry = cacheTop; entry; entry = entry->list_next) {
1406     cache_mem += sizeof(struct CacheEntry);
1407     cache_mem += calc_hostent_buffer_size(&entry->he.h); 
1408     ++cache_count;
1409   }
1410   for (request = requestListHead; request; request = request->next) {
1411     request_mem += sizeof(struct ResRequest);
1412     if (request->name)
1413       request_mem += strlen(request->name) + 1; 
1414     if (request->he.buf)
1415       request_mem += MAXGETHOSTLEN + 1;
1416     ++request_count;
1417   }
1418
1419   if (cachedCount != cache_count) {
1420     send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1421                ":Resolver: cache count mismatch: %d != %d", cachedCount,
1422                cache_count);
1423     assert(cachedCount == cache_count);
1424   }
1425   send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1426              ":Resolver: cache %d(%d) requests %d(%d)", cache_count,
1427              cache_mem, request_count, request_mem);
1428   return cache_mem + request_mem;
1429 }
1430