Change tokenizer to reduce number of lexer states and be
[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/types.h>
42 #include <sys/socket.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <regex.h>
46
47 #include <arpa/nameser.h>
48 #include <resolv.h>
49 #include <netdb.h>
50 #include <arpa/inet.h>
51
52 #include <limits.h>
53 #if (CHAR_BIT != 8)
54 #error this code needs to be able to address individual octets 
55 #endif
56
57 /*
58  * Some systems do not define INADDR_NONE (255.255.255.255)
59  * INADDR_NONE is actually a valid address, but it should never
60  * be returned from any nameserver.
61  * NOTE: The bit pattern for INADDR_NONE and INADDR_ANY (0.0.0.0) should be 
62  * the same on all hosts so we shouldn't need to use htonl or ntohl to
63  * compare or set the values.
64  */ 
65 #ifndef INADDR_NONE
66 #define INADDR_NONE ((unsigned int) 0xffffffff)
67 #endif
68
69 #define MAXPACKET       1024  /* rfc sez 512 but we expand names so ... */
70 #define RES_MAXALIASES  35    /* maximum aliases allowed */
71 #define RES_MAXADDRS    35    /* maximum addresses allowed */
72 /*
73  * OSF1 doesn't have RES_NOALIASES
74  */
75 #ifndef RES_NOALIASES
76 #define RES_NOALIASES 0
77 #endif
78
79 /*
80  * macros used to calulate offsets into fixed query buffer
81  */
82 #define ALIAS_BLEN  ((RES_MAXALIASES + 1) * sizeof(char*))
83 #define ADDRS_BLEN  ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
84
85 #define ADDRS_OFFSET   (ALIAS_BLEN + ADDRS_BLEN)
86 #define ADDRS_DLEN     (RES_MAXADDRS * sizeof(struct in_addr))
87 #define NAMES_OFFSET   (ADDRS_OFFSET + ADDRS_DLEN)
88 #define MAXGETHOSTLEN  (NAMES_OFFSET + MAXPACKET)
89
90 #define AR_TTL          600   /* TTL in seconds for dns cache entries */
91
92 /*
93  * the following values should be prime
94  */
95 #define ARES_CACSIZE    307
96 #define MAXCACHED       17
97 //#define MAXCACHED       281
98
99 /*
100  * Building the Hostent
101  * The Hostent struct is arranged like this:
102  *          +-------------------------------+
103  * Hostent: | struct hostent h              |
104  *          |-------------------------------|
105  *          | char *buf                     |
106  *          +-------------------------------+
107  *
108  * allocated:
109  *
110  *          +-------------------------------+
111  * buf:     | h_aliases pointer array       | Max size: ALIAS_BLEN;
112  *          | NULL                          | contains `char *'s
113  *          |-------------------------------|
114  *          | h_addr_list pointer array     | Max size: ADDRS_BLEN;
115  *          | NULL                          | contains `struct in_addr *'s
116  *          |-------------------------------|
117  *          | h_addr_list addresses         | Max size: ADDRS_DLEN;
118  *          |                               | contains `struct in_addr's
119  *          |-------------------------------|
120  *          | storage for hostname strings  | Max size: ALIAS_DLEN;
121  *          +-------------------------------+ contains `char's
122  *
123  *  For requests the size of the h_aliases, and h_addr_list pointer
124  *  array sizes are set to MAXALISES and MAXADDRS respectively, and
125  *  buf is a fixed size with enough space to hold the largest expected
126  *  reply from a nameserver, see RFC 1034 and RFC 1035.
127  *  For cached entries the sizes are dependent on the actual number
128  *  of aliases and addresses. If new aliases and addresses are found
129  *  for cached entries, the buffer is grown and the new entries are added.
130  *  The hostent struct is filled in with the addresses of the entries in
131  *  the Hostent buf as follows:
132  *  h_name      - contains a pointer to the start of the hostname string area,
133  *                or NULL if none is set.  The h_name is followed by the
134  *                aliases, in the storage for hostname strings area.
135  *  h_aliases   - contains a pointer to the start of h_aliases pointer array.
136  *                This array contains pointers to the storage for hostname
137  *                strings area and is terminated with a NULL.  The first alias
138  *                is stored directly after the h_name.
139  *  h_addr_list - contains a pointer to the start of h_addr_list pointer array.
140  *                This array contains pointers to in_addr structures in the
141  *                h_addr_list addresses area and is terminated with a NULL.
142  *
143  *  Filling the buffer this way allows for proper alignment of the h_addr_list
144  *  addresses.
145  *
146  *  This arrangement allows us to alias a Hostent struct pointer as a
147  *  real struct hostent* without lying. It also allows us to change the
148  *  values contained in the cached entries and requests without changing
149  *  the actual hostent pointer, which is saved in a client struct and can't
150  *  be changed without blowing things up or a lot more fiddling around.
151  *  It also allows for defered allocation of the fixed size buffers until
152  *  they are really needed.
153  *  Nov. 17, 1997 --Bleep
154  */
155
156 struct Hostent {
157   struct hostent h;        /* the hostent struct we are passing around */
158   char           buf[1];   /* buffer for data pointed to from hostent */
159 };
160
161 struct ResRequest {
162   struct ResRequest* next;
163
164   adns_rrtype        type;
165   adns_query         aq;
166
167   struct in_addr     addr;
168   char*              name;
169   struct DNSQuery    query;         /* query callback for this request */
170   struct hostent     he;
171   char*              buf;
172 };
173
174 int ResolverFileDescriptor    = -1;   /* GLOBAL - used in s_bsd.c */
175
176 static struct Socket resSock;           /* Socket describing resolver */
177 static struct Timer  resExpireDNS;      /* Timer for DNS expiration */
178 static adns_state adns = NULL;
179
180 /*
181  * Keep a spare file descriptor open. res_init calls fopen to read the
182  * resolv.conf file. If ircd is hogging all the file descriptors below 256,
183  * on systems with crippled FILE structures this will cause wierd bugs.
184  * This is definitely needed for Solaris which uses an unsigned char to
185  * hold the file descriptor.  --Dianora
186  */ 
187 static int                spare_fd = -1;
188
189 static struct ResRequest* requestListHead;   /* head of resolver request list */
190 static struct ResRequest* requestListTail;   /* tail of resolver request list */
191
192
193 static void     add_request(struct ResRequest* request);
194 static void     rem_request(struct ResRequest* request);
195 static struct ResRequest*   make_request(const struct DNSQuery* query);
196 static time_t   timeout_query_list(time_t now);
197 static void     do_query_name(const struct DNSQuery* query, 
198                               const char* name, 
199                               struct ResRequest* request);
200 static void     do_query_number(const struct DNSQuery* query,
201                                 const struct in_addr*, 
202                                 struct ResRequest* request);
203 static void res_adns_callback(adns_state state, adns_query q, void *context);
204
205 static struct  resinfo {
206   int  re_errors;
207   int  re_nu_look;
208   int  re_na_look;
209   int  re_replies;
210   int  re_requests;
211   int  re_resends;
212   int  re_sent;
213   int  re_timeouts;
214   int  re_shortttl;
215   int  re_unkrep;
216 } reinfo;
217
218
219 /* Socket callback for resolver */
220 static void res_socket_callback(struct Event* ev)
221 {
222   struct timeval tv;
223
224   assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
225
226   tv.tv_sec = CurrentTime;
227   tv.tv_usec = 0;
228   adns_processreadable(adns, ResolverFileDescriptor, &tv);
229 }
230
231 /*
232  * start_resolver - do everything we need to read the resolv.conf file
233  * and initialize the resolver file descriptor if needed
234  */
235 static void start_resolver(void)
236 {
237   int res;
238
239   Debug((DEBUG_DNS, "Resolver: start_resolver"));
240   /*
241    * close the spare file descriptor so res_init can read resolv.conf
242    * successfully. Needed on Solaris
243    */
244   if (spare_fd > -1)
245     close(spare_fd);
246
247   /*
248    * make sure we have a valid file descriptor below 256 so we can
249    * do this again. Needed on Solaris
250    */
251   spare_fd = open("/dev/null",O_RDONLY,0);
252   if ((spare_fd < 0) || (spare_fd > 255)) {
253     char sparemsg[80];
254     ircd_snprintf(0, sparemsg, sizeof(sparemsg), "invalid spare_fd %d",
255                   spare_fd);
256     server_restart(sparemsg);
257   }
258
259   if (adns)
260     return;
261
262   if ((res = adns_init(&adns, adns_if_debug /*| adns_if_noautosys*/, NULL))) {
263     report_error("Resolver: error initializing adns for %s: %s",
264                  cli_name(&me), res);
265     errno = res;
266     return;
267   }
268   errno = 0;
269   
270   ResolverFileDescriptor = adns_get_fd(adns);
271
272   if (!socket_add(&resSock, res_socket_callback, 0, SS_DATAGRAM,
273                   SOCK_EVENT_READABLE, ResolverFileDescriptor))
274     report_error("Resolver: unable to queue resolver file descriptor for %s",
275                  cli_name(&me), ENFILE);
276 }
277
278 /* Call the query timeout function */
279 static void expire_DNS_callback(struct Event* ev)
280 {
281   time_t next;
282
283   next = timeout_query_list(CurrentTime);
284
285   timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
286 }
287
288 /*
289  * init_resolver - initialize resolver and resolver library
290  */
291 int init_resolver(void)
292 {
293   Debug((DEBUG_DNS, "Resolver: init_resolver"));
294 #ifdef  LRAND48
295   srand48(CurrentTime);
296 #endif
297   memset(&reinfo,   0, sizeof(reinfo));
298
299   requestListHead = requestListTail = 0;
300
301   /* initiate the resolver timers */
302   timer_add(timer_init(&resExpireDNS), expire_DNS_callback, 0,
303             TT_RELATIVE, 1);
304
305   errno = h_errno = 0;
306
307   start_resolver();
308   Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s",
309          ResolverFileDescriptor, errno, h_errno, 
310          (strerror(errno)) ? strerror(errno) : "Unknown"));
311   return ResolverFileDescriptor;
312 }
313
314 /*
315  * restart_resolver - flush the cache, reread resolv.conf, reopen socket
316  */
317 void restart_resolver(void)
318 {
319   start_resolver();
320 }
321
322 /*
323  * add_request - place a new request in the request list
324  */
325 static void add_request(struct ResRequest* request)
326 {
327   assert(0 != request);
328   if (!requestListHead)
329     requestListHead = requestListTail = request;
330   else {
331     requestListTail->next = request;
332     requestListTail = request;
333   }
334   request->next = NULL;
335   ++reinfo.re_requests;
336 }
337
338 /*
339  * rem_request - remove a request from the list. 
340  * This must also free any memory that has been allocated for 
341  * temporary storage of DNS results.
342  */
343 static void rem_request(struct ResRequest* request)
344 {
345   struct ResRequest** current;
346   struct ResRequest*  prev = NULL;
347
348   assert(0 != request);
349   for (current = &requestListHead; *current; ) {
350     if (*current == request) {
351       *current = request->next;
352       if (requestListTail == request)
353         requestListTail = prev;
354       break;
355     } 
356     prev    = *current;
357     current = &(*current)->next;
358   }
359   if (request->aq)
360     adns_cancel(request->aq);
361   MyFree(request->buf);
362   MyFree(request->name);
363   MyFree(request);
364 }
365
366 /*
367  * make_request - Create a DNS request record for the server.
368  */
369 static struct ResRequest* make_request(const struct DNSQuery* query)
370 {
371   struct ResRequest* request;
372   assert(0 != query);
373   request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
374   memset(request, 0, sizeof(struct ResRequest));
375
376   request->addr.s_addr    = INADDR_NONE;
377   request->he.h_addrtype  = AF_INET;
378   request->he.h_length    = sizeof(struct in_addr);
379   request->query.vptr     = query->vptr;
380   request->query.callback = query->callback;
381
382   add_request(request);
383   return request;
384 }
385
386 /*
387  * timeout_query_list - Remove queries from the list which have been 
388  * there too long without being resolved.
389  */
390 static time_t timeout_query_list(time_t now)
391 {
392   struct timeval tv, tv_buf, *tv_mod = NULL;
393   time_t next;
394   
395   Debug((DEBUG_DNS, "Resolver: timeout_query_list at %s", myctime(now)));
396
397   tv.tv_sec = now;
398   tv.tv_usec = 0;
399   adns_processtimeouts(adns, &tv);
400   adns_firsttimeout(adns, &tv_mod, &tv_buf, tv);
401   next = tv_mod ? tv_mod->tv_sec : AR_TTL;
402   if (!next)
403     next = 1;
404
405   Debug((DEBUG_DNS, "Resolver: next timeout_query_list in %d seconds", next));
406   return now + next;
407 }
408
409 /*
410  * delete_resolver_queries - cleanup outstanding queries 
411  * for which there no longer exist clients or conf lines.
412  */
413 void delete_resolver_queries(const void* vptr)
414 {
415   struct ResRequest* request;
416   struct ResRequest* next_request;
417
418   for (request = requestListHead; request; request = next_request) {
419     next_request = request->next;
420     if (vptr == request->query.vptr)
421       rem_request(request);
422   }
423 }
424
425 /*
426  * gethost_byname - get host address from name
427  */
428 void gethost_byname(const char* name, const struct DNSQuery* query)
429 {
430   assert(0 != name);
431
432   Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
433   ++reinfo.re_na_look;
434   do_query_name(query, name, NULL);
435 }
436
437 /*
438  * gethost_byaddr - get host name from address
439  */
440 void gethost_byaddr(const char* addr, const struct DNSQuery* query)
441 {
442   assert(0 != addr);
443   Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
444   ++reinfo.re_nu_look;
445   do_query_number(query, (const struct in_addr*) addr, NULL);
446 }
447
448 /*
449  * do_query_name - nameserver lookup name
450  */
451 static void do_query_name(const struct DNSQuery* query, 
452                           const char* name, struct ResRequest* request)
453 {
454   char  hname[HOSTLEN + 1];
455   int   res;
456   assert(0 != name);
457
458   ircd_strncpy(hname, name, HOSTLEN);
459   hname[HOSTLEN] = '\0';
460
461   if (!request) {
462     request       = make_request(query);
463     request->type = adns_r_a;
464     request->name = (char*) MyMalloc(strlen(hname) + 1);
465     strcpy(request->name, hname);
466   }
467   res = adns_submit_callback(adns, hname, adns_r_a, adns_qf_owner,
468                              request, &request->aq, res_adns_callback);
469   assert(!res);
470   timer_chg(&resExpireDNS, TT_RELATIVE, 1);
471 }
472
473 /*
474  * do_query_number - Use this to do reverse IP# lookups.
475  */
476 static void do_query_number(const struct DNSQuery* query, 
477                             const struct in_addr* addr,
478                             struct ResRequest* request)
479 {
480   char  ipbuf[32];
481   const unsigned char* cp;
482   int   res;
483
484   assert(0 != addr);
485   cp = (const unsigned char*) &addr->s_addr;
486   ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
487                 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
488                 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
489
490   if (!request) {
491     request              = make_request(query);
492     request->type        = adns_r_ptr;
493     request->addr.s_addr = addr->s_addr;
494   }
495   res = adns_submit_callback(adns, ipbuf, adns_r_ptr, adns_qf_owner,
496                              request, &request->aq, res_adns_callback);
497   assert(!res);
498   timer_chg(&resExpireDNS, TT_RELATIVE, 1);
499 }
500
501 /*
502  * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
503  * the data we're putting in it.
504  */
505 static struct hostent* dup_hostent(struct hostent* hp)
506 {
507   char*  p;
508   char** ap;
509   char** pp;
510   int    alias_count = 0;
511   int    addr_count = 0;
512   size_t bytes_needed = 0;
513   struct Hostent* new_hp = 0;
514
515   assert(0 != hp);
516
517   /* how much buffer do we need? */
518   bytes_needed += (strlen(hp->h_name) + 1);
519
520   pp = hp->h_aliases;
521   while (*pp) {
522     bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
523     ++alias_count;
524   }
525   pp = hp->h_addr_list;
526   while (*pp++) {
527     bytes_needed += (hp->h_length + sizeof(char*));
528     ++addr_count;
529   }
530   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
531   bytes_needed += (2 * sizeof(char*));
532
533   /* Allocate memory */
534   new_hp = (struct Hostent*) MyMalloc(sizeof(struct Hostent) + bytes_needed);
535
536   new_hp->h.h_addrtype = hp->h_addrtype;
537   new_hp->h.h_length = hp->h_length;
538
539   /* first write the address list */
540   pp = hp->h_addr_list;
541   ap = new_hp->h.h_addr_list =
542       (char**)(new_hp->buf + ((alias_count + 1) * sizeof(char*)));
543   p = (char*)ap + ((addr_count + 1) * sizeof(char*));
544   while (*pp)
545   {
546     *ap++ = p;
547     memcpy(p, *pp++, hp->h_length);
548     p += hp->h_length;
549   }
550   *ap = 0;
551   /* next write the name */
552   new_hp->h.h_name = p;
553   strcpy(p, hp->h_name);
554   p += (strlen(p) + 1);
555
556   /* last write the alias list */
557   pp = hp->h_aliases;
558   ap = new_hp->h.h_aliases = (char**) new_hp->buf;
559   while (*pp) {
560     *ap++ = p;
561     strcpy(p, *pp++);
562     p += (strlen(p) + 1);
563   }
564   *ap = 0;
565   return (struct hostent*) new_hp;
566 }
567
568 static void res_adns_callback(adns_state state, adns_query q, void *context)
569 {
570   struct ResRequest *request = (struct ResRequest *) context;
571   adns_answer *answer = NULL;
572   int res, k;
573   struct hostent* hp;          /* hostent getting filled */
574   char** alias;                /* alias list */
575   char** addr;                 /* address list */
576   char** base_addr;            /* original pointer to address list */
577   char*  name;                 /* pointer to name string */
578   char*  address;              /* pointer to address */
579   char*  base_address;         /* original pointer to address */
580   char*  endp;                 /* end of our buffer */
581   int    addr_count  = 0;      /* number of addresses in hostent */
582   int    alias_count = 0;      /* number of aliases in hostent */
583   
584   assert(request);
585   assert(q);
586   assert(request->aq == q);
587   res = adns_check(adns, &q, &answer, NULL);
588   request->aq = NULL;
589
590   if (res) {
591     /* adns_check returned an error, bail */
592     Debug((DEBUG_DNS, "Resolver: adns_check result %d", res));
593
594     (*request->query.callback)(request->query.vptr, 0);
595     rem_request(request);
596     return;
597   }
598
599   Debug((DEBUG_DNS, "Resolver: adns_check status %d nrrs %d",
600         answer->status, answer->nrrs));
601   
602   /* No error, we have a valid answer structure */
603   if (answer->status != adns_s_ok || !answer->nrrs) {
604     /* Status is not 'ok', or there were no RRs found */
605     ++reinfo.re_errors;
606     (*request->query.callback)(request->query.vptr, 0);
607   } else {
608     ++reinfo.re_replies;
609     hp = &(request->he);    
610     if (!request->buf) {
611       request->buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
612       request->buf[MAXGETHOSTLEN] = '\0';
613       /*
614        * array of alias list pointers starts at beginning of buf
615        */
616       hp->h_aliases = (char**) request->buf;
617       hp->h_aliases[0] = NULL;
618       /*
619        * array of address list pointers starts after alias list pointers
620        * the actual addresses follow the the address list pointers
621        */ 
622       hp->h_addr_list = (char**)(request->buf + ALIAS_BLEN);
623       /*
624        * don't copy the host address to the beginning of h_addr_list
625        */
626       hp->h_addr_list[0] = NULL;
627     }
628
629     hp->h_addrtype = AF_INET;
630
631     endp = request->buf + MAXGETHOSTLEN;
632     /*
633      * find the end of the address list
634      */
635     addr = hp->h_addr_list;
636     while (*addr) {
637       ++addr;
638       ++addr_count;
639     }
640     base_addr = addr;
641     /*
642      * make address point to first available address slot
643      */
644     address = request->buf + ADDRS_OFFSET +
645                       (sizeof(struct in_addr) * addr_count);
646     base_address = address;
647
648     /*
649      * find the end of the alias list
650      */
651     alias = hp->h_aliases;
652     while (*alias) {
653       ++alias;
654       ++alias_count;
655     }
656     /*
657      * make name point to first available space in request->buf
658      */
659     if (alias_count > 0) {
660       name = hp->h_aliases[alias_count - 1];
661       name += (strlen(name) + 1);
662     }
663     else if (hp->h_name)
664       name = hp->h_name + strlen(hp->h_name) + 1;
665     else
666       name = request->buf + ADDRS_OFFSET + ADDRS_DLEN;
667
668     switch (request->type) {
669     case adns_r_a:
670       for (k = 0; k < answer->nrrs; k++) {
671         if (++addr_count < RES_MAXADDRS) {
672           memcpy(address, &answer->rrs.inaddr[k], sizeof(struct in_addr));
673           *addr++ = address;
674           *addr = 0;
675           address += sizeof(struct in_addr);
676         }
677         Debug((DEBUG_DNS, "Resolver: A %s for %s",
678               ircd_ntoa((char*) &answer->rrs.inaddr[k]), answer->owner));
679       }
680       if (!hp->h_name) {
681         strcpy(name, answer->owner);
682         hp->h_name = name;
683         name += strlen(name) + 1;
684       }
685       break;
686     case adns_r_ptr:
687       strcpy(name, answer->rrs.str[0]);
688       hp->h_name = name;
689       name += strlen(name) + 1;
690
691       Debug((DEBUG_DNS, "Resolver: PTR %s for %s", hp->h_name, answer->owner));
692       break;
693     default:
694       /* ignore */
695       break;
696     }
697
698     if (answer->cname) {
699       alias_count++;
700       ircd_strncpy(name, answer->cname, endp - name);
701       *alias++ = name;
702       *alias   = 0;
703       name += strlen(name) + 1;
704       Debug((DEBUG_DNS, "Resolver: CNAME %s for %s",
705             answer->cname, answer->owner));
706     }
707
708     if (request->type == adns_r_ptr) {
709
710       Debug((DEBUG_DNS, "relookup %s <-> %s",
711              request->he.h_name, ircd_ntoa((char*) &request->addr)));
712       /*
713        * Lookup the 'authoritive' name that we were given for the
714        * ip#.  By using this call rather than regenerating the
715        * type we automatically gain the use of the cache with no
716        * extra kludges.
717        */
718       gethost_byname(request->he.h_name, &request->query);
719       /*
720        * If name wasn't found, a request has been queued and it will
721        * be the last one queued.  This is rather nasty way to keep
722        * a host alias with the query. -avalon
723        */
724       MyFree(requestListTail->buf);
725       requestListTail->buf = request->buf;
726       request->buf = 0;
727       memcpy(&requestListTail->he, &request->he, sizeof(struct hostent));
728     } else {
729       /*
730        * got a name and address response, client resolved
731        * XXX - Bug found here by Dianora -
732        * make_cache() occasionally returns a NULL pointer when a
733        * PTR returned a CNAME, cp was not checked before so the
734        * callback was being called with a value of 0x2C != NULL.
735        */
736       struct hostent* he = dup_hostent(&request->he);
737       (*request->query.callback)(request->query.vptr, he);
738     }
739   }
740   
741   rem_request(request);
742   
743   /*
744    * adns doesn't use MyMalloc, so we don't use MyFree
745    */
746   free(answer);
747 }
748
749 /*
750  * m_dns - dns status query
751  */
752 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
753 {
754 #if !defined(NDEBUG)
755   sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Errors %d Lookups %d/%d Replies %d Requests %d",
756                 sptr, reinfo.re_errors, reinfo.re_nu_look,
757                 reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
758   sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Unknown Reply %d Short TTL(<10m) %d Sent %d Resends %d Timeouts %d", sptr,
759                 reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
760                 reinfo.re_resends, reinfo.re_timeouts);
761   sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :ResolverFileDescriptor = %d", 
762                 sptr, ResolverFileDescriptor);
763 #endif
764   return 0;
765 }
766
767 size_t cres_mem(struct Client* sptr)
768 {
769   struct ResRequest* request;
770   size_t request_mem   = 0;
771   int    request_count = 0;
772
773   for (request = requestListHead; request; request = request->next) {
774     request_mem += sizeof(struct ResRequest);
775     if (request->name)
776       request_mem += strlen(request->name) + 1; 
777     if (request->buf)
778       request_mem += MAXGETHOSTLEN + 1;
779     ++request_count;
780   }
781
782   send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
783              ":Resolver: requests %d(%d)", request_count, request_mem);
784   return request_mem;
785 }
786