44010293356d1b6f5b7f61cd765e9af78abbc571
[ircu2.10.12-pk.git] / ircd / res_libresolv.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 "res.h"
16 #include "client.h"
17 #include "ircd.h"
18 #include "ircd_alloc.h"
19 #include "ircd_events.h"
20 #include "ircd_log.h"
21 #include "ircd_osdep.h"
22 #include "ircd_reply.h"
23 #include "ircd_snprintf.h"
24 #include "ircd_string.h"
25 #include "msg.h"
26 #include "numeric.h"
27 #include "s_bsd.h"
28 #include "s_debug.h"
29 #include "s_misc.h"
30 #include "send.h"
31 #include "struct.h"
32 #include "support.h"
33 #include "sys.h"
34
35 #include <assert.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <sys/time.h>
40 #include <sys/socket.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <regex.h>
44
45 #include <arpa/nameser.h>
46 #include <resolv.h>
47 #include <netdb.h>
48 #include <arpa/inet.h>
49
50 #include <limits.h>
51 #if (CHAR_BIT != 8)
52 #error this code needs to be able to address individual octets 
53 #endif
54
55 /*
56  * Some systems do not define INADDR_NONE (255.255.255.255)
57  * INADDR_NONE is actually a valid address, but it should never
58  * be returned from any nameserver.
59  * NOTE: The bit pattern for INADDR_NONE and INADDR_ANY (0.0.0.0) should be 
60  * the same on all hosts so we shouldn't need to use htonl or ntohl to
61  * compare or set the values.
62  */ 
63 #ifndef INADDR_NONE
64 #define INADDR_NONE ((unsigned int) 0xffffffff)
65 #endif
66
67 #define MAXPACKET       1024  /* rfc sez 512 but we expand names so ... */
68 #define RES_MAXALIASES  35    /* maximum aliases allowed */
69 #define RES_MAXADDRS    35    /* maximum addresses allowed */
70 /*
71  * OSF1 doesn't have RES_NOALIASES
72  */
73 #ifndef RES_NOALIASES
74 #define RES_NOALIASES 0
75 #endif
76
77 /*
78  * macros used to calulate offsets into fixed query buffer
79  */
80 #define ALIAS_BLEN  ((RES_MAXALIASES + 1) * sizeof(char*))
81 #define ADDRS_BLEN  ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
82
83 #define ADDRS_OFFSET   (ALIAS_BLEN + ADDRS_BLEN)
84 #define ADDRS_DLEN     (RES_MAXADDRS * sizeof(struct in_addr))
85 #define NAMES_OFFSET   (ADDRS_OFFSET + ADDRS_DLEN)
86 #define MAXGETHOSTLEN  (NAMES_OFFSET + MAXPACKET)
87
88 #define AR_TTL          600   /* TTL in seconds for dns cache entries */
89
90 /*
91  * RFC 1104/1105 wasn't very helpful about what these fields
92  * should be named, so for now, we'll just name them this way.
93  * we probably should look at what named calls them or something.
94  */
95 #define TYPE_SIZE       2
96 #define CLASS_SIZE      2
97 #define TTL_SIZE        4
98 #define RDLENGTH_SIZE   2
99 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
100
101 /*
102  * Building the Hostent
103  * The Hostent struct is arranged like this:
104  *          +-------------------------------+
105  * Hostent: | struct hostent h              |
106  *          |-------------------------------|
107  *          | char *buf                     |
108  *          +-------------------------------+
109  *
110  * allocated:
111  *
112  *          +-------------------------------+
113  * buf:     | h_aliases pointer array       | Max size: ALIAS_BLEN;
114  *          | NULL                          | contains `char *'s
115  *          |-------------------------------|
116  *          | h_addr_list pointer array     | Max size: ADDRS_BLEN;
117  *          | NULL                          | contains `struct in_addr *'s
118  *          |-------------------------------|
119  *          | h_addr_list addresses         | Max size: ADDRS_DLEN;
120  *          |                               | contains `struct in_addr's
121  *          |-------------------------------|
122  *          | storage for hostname strings  | Max size: ALIAS_DLEN;
123  *          +-------------------------------+ contains `char's
124  *
125  *  For requests the size of the h_aliases, and h_addr_list pointer
126  *  array sizes are set to MAXALISES and MAXADDRS respectively, and
127  *  buf is a fixed size with enough space to hold the largest expected
128  *  reply from a nameserver, see RFC 1034 and RFC 1035.
129  *  For cached entries the sizes are dependent on the actual number
130  *  of aliases and addresses. If new aliases and addresses are found
131  *  for cached entries, the buffer is grown and the new entries are added.
132  *  The hostent struct is filled in with the addresses of the entries in
133  *  the Hostent buf as follows:
134  *  h_name      - contains a pointer to the start of the hostname string area,
135  *                or NULL if none is set.  The h_name is followed by the
136  *                aliases, in the storage for hostname strings area.
137  *  h_aliases   - contains a pointer to the start of h_aliases pointer array.
138  *                This array contains pointers to the storage for hostname
139  *                strings area and is terminated with a NULL.  The first alias
140  *                is stored directly after the h_name.
141  *  h_addr_list - contains a pointer to the start of h_addr_list pointer array.
142  *                This array contains pointers to in_addr structures in the
143  *                h_addr_list addresses area and is terminated with a NULL.
144  *
145  *  Filling the buffer this way allows for proper alignment of the h_addr_list
146  *  addresses.
147  *
148  *  This arrangement allows us to alias a Hostent struct pointer as a
149  *  real struct hostent* without lying. It also allows us to change the
150  *  values contained in the cached entries and requests without changing
151  *  the actual hostent pointer, which is saved in a client struct and can't
152  *  be changed without blowing things up or a lot more fiddling around.
153  *  It also allows for defered allocation of the fixed size buffers until
154  *  they are really needed.
155  *  Nov. 17, 1997 --Bleep
156  */
157
158 struct Hostent {
159   struct hostent h;       /* the hostent struct we are passing around */
160   char           buf[1];  /* buffer for data pointed to from hostent */
161 };
162
163 struct ResRequest {
164   struct ResRequest* next;
165   int                id;
166   int                sent;          /* number of requests sent */
167   time_t             ttl;
168   char               type;
169   char               retries;       /* retry counter */
170   char               sends;         /* number of sends (>1 means resent) */
171   char               resend;        /* send flag. 0 == dont resend */
172   time_t             sentat;
173   time_t             timeout;
174   struct in_addr     addr;
175   char*              name;
176   struct DNSQuery    query;         /* query callback for this request */
177   struct hostent     he;
178   char*              buf;
179 };
180
181
182 int ResolverFileDescriptor    = -1;   /* GLOBAL - used in s_bsd.c */
183
184 static struct Socket resSock;           /* Socket describing resolver */
185 static struct Timer  resExpireDNS;      /* Timer for DNS expiration */
186
187 static time_t nextDNSCheck    = 0;
188
189 /*
190  * Keep a spare file descriptor open. res_init calls fopen to read the
191  * resolv.conf file. If ircd is hogging all the file descriptors below 256,
192  * on systems with crippled FILE structures this will cause wierd bugs.
193  * This is definitely needed for Solaris which uses an unsigned char to
194  * hold the file descriptor.  --Dianora
195  */ 
196 static int                spare_fd = -1;
197
198 static struct ResRequest* requestListHead;   /* head of resolver request list */
199 static struct ResRequest* requestListTail;   /* tail of resolver request list */
200
201
202 static void     add_request(struct ResRequest* request);
203 static void     rem_request(struct ResRequest* request);
204 static struct ResRequest*   make_request(const struct DNSQuery* query);
205 static time_t   timeout_query_list(time_t now);
206 static void     do_query_name(const struct DNSQuery* query, 
207                               const char* name, 
208                               struct ResRequest* request);
209 static void     do_query_number(const struct DNSQuery* query,
210                                 const struct in_addr*, 
211                                 struct ResRequest* request);
212 static void     query_name(const char* name, 
213                            int query_class, 
214                            int query_type, 
215                            struct ResRequest* request);
216 static void     resend_query(struct ResRequest* request);
217 static struct ResRequest*   find_id(int);
218
219 static  struct  resinfo {
220   int  re_errors;
221   int  re_nu_look;
222   int  re_na_look;
223   int  re_replies;
224   int  re_requests;
225   int  re_resends;
226   int  re_sent;
227   int  re_timeouts;
228   int  re_shortttl;
229   int  re_unkrep;
230 } reinfo;
231
232
233 /*
234  * From bind 8.3, these aren't declared in earlier versions of bind
235  */
236 extern u_short  _getshort(const u_char *);
237 extern u_int    _getlong(const u_char *);
238 /*
239  * int
240  * res_isourserver(ina)
241  *      looks up "ina" in _res.ns_addr_list[]
242  * returns:
243  *      0  : not found
244  *      >0 : found
245  * author:
246  *      paul vixie, 29may94
247  */
248 static int
249 res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp) 
250 {
251   struct sockaddr_in ina;
252   int ns;
253
254   ina = *inp;
255   for (ns = 0;  ns < statp->nscount;  ns++) {
256     const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
257
258     if (srv->sin_family == ina.sin_family &&
259          srv->sin_port == ina.sin_port &&
260          (srv->sin_addr.s_addr == INADDR_ANY ||
261           srv->sin_addr.s_addr == ina.sin_addr.s_addr))
262              return (1);
263   }
264   return (0);
265 }
266
267 /* Socket callback for resolver */
268 static void res_callback(struct Event* ev)
269 {
270   assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
271
272   resolver_read();
273 }
274
275 /*
276  * start_resolver - do everything we need to read the resolv.conf file
277  * and initialize the resolver file descriptor if needed
278  */
279 static void start_resolver(void)
280 {
281   Debug((DEBUG_DNS, "Resolver: start_resolver"));
282   /*
283    * close the spare file descriptor so res_init can read resolv.conf
284    * successfully. Needed on Solaris
285    */
286   if (spare_fd > -1)
287     close(spare_fd);
288
289   res_init();      /* res_init always returns 0 */
290   /*
291    * make sure we have a valid file descriptor below 256 so we can
292    * do this again. Needed on Solaris
293    */
294   spare_fd = open("/dev/null",O_RDONLY,0);
295   if ((spare_fd < 0) || (spare_fd > 255)) {
296     char sparemsg[80];
297     ircd_snprintf(0, sparemsg, sizeof(sparemsg), "invalid spare_fd %d",
298                   spare_fd);
299     server_restart(sparemsg);
300   }
301
302   if (!_res.nscount) {
303     _res.nscount = 1;
304     _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
305   }
306   _res.options |= RES_NOALIASES;
307
308   if (ResolverFileDescriptor < 0) {
309     ResolverFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
310     if (-1 == ResolverFileDescriptor) {
311       report_error("Resolver: error creating socket for %s: %s", 
312                    cli_name(&me), errno);
313       return;
314     }
315     if (!os_set_nonblocking(ResolverFileDescriptor))
316       report_error("Resolver: error setting non-blocking for %s: %s", 
317                    cli_name(&me), errno);
318     if (!socket_add(&resSock, res_callback, 0, SS_DATAGRAM,
319                     SOCK_EVENT_READABLE, ResolverFileDescriptor))
320       report_error("Resolver: unable to queue resolver file descriptor for %s",
321                    cli_name(&me), ENFILE);
322   }
323 }
324
325 /* Call the query timeout function */
326 static void expire_DNS_callback(struct Event* ev)
327 {
328   time_t next;
329
330   next = timeout_query_list(CurrentTime);
331
332   timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
333 }
334
335 /*
336  * init_resolver - initialize resolver and resolver library
337  */
338 int init_resolver(void)
339 {
340   Debug((DEBUG_DNS, "Resolver: init_resolver"));
341 #ifdef  LRAND48
342   srand48(CurrentTime);
343 #endif
344   memset(&reinfo, 0, sizeof(reinfo));
345   requestListHead = requestListTail = 0;
346
347   /* initiate the resolver timers */
348   timer_add(timer_init(&resExpireDNS), expire_DNS_callback, 0,
349             TT_RELATIVE, 1);
350
351   errno = h_errno = 0;
352
353   start_resolver();
354   Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s",
355          ResolverFileDescriptor, errno, h_errno, 
356          (strerror(errno)) ? strerror(errno) : "Unknown"));
357   return ResolverFileDescriptor;
358 }
359
360 /*
361  * restart_resolver - flush the cache, reread resolv.conf, reopen socket
362  */
363 void restart_resolver(void)
364 {
365   /* flush_cache();  flush the dns cache */
366   start_resolver();
367 }
368
369 static int validate_hostent(const struct hostent* hp)
370 {
371   const char* name;
372   int  i = 0;
373   assert(0 != hp);
374   for (name = hp->h_name; name; name = hp->h_aliases[i++]) {
375     if (!string_is_hostname(name))
376       return 0;
377   }
378   return 1;
379 }
380
381 /*
382  * add_request - place a new request in the request list
383  */
384 static void add_request(struct ResRequest* request)
385 {
386   assert(0 != request);
387   if (!requestListHead)
388     requestListHead = requestListTail = request;
389   else {
390     requestListTail->next = request;
391     requestListTail = request;
392   }
393   request->next = NULL;
394   ++reinfo.re_requests;
395 }
396
397 /*
398  * rem_request - remove a request from the list. 
399  * This must also free any memory that has been allocated for 
400  * temporary storage of DNS results.
401  */
402 static void rem_request(struct ResRequest* request)
403 {
404   struct ResRequest** current;
405   struct ResRequest*  prev = NULL;
406
407   assert(0 != request);
408   for (current = &requestListHead; *current; ) {
409     if (*current == request) {
410       *current = request->next;
411       if (requestListTail == request)
412         requestListTail = prev;
413       break;
414     } 
415     prev    = *current;
416     current = &(*current)->next;
417   }
418   MyFree(request->buf);
419   MyFree(request->name);
420   MyFree(request);
421 }
422
423 /*
424  * make_request - Create a DNS request record for the server.
425  */
426 static struct ResRequest* make_request(const struct DNSQuery* query)
427 {
428   struct ResRequest* request;
429   assert(0 != query);
430   request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
431   memset(request, 0, sizeof(struct ResRequest));
432
433   request->sentat           = CurrentTime;
434   request->retries          = 3;
435   request->resend           = 1;
436   request->timeout          = 5;    /* start at 5 per RFC1123 */
437   request->addr.s_addr      = INADDR_NONE;
438   request->he.h_addrtype    = AF_INET;
439   request->he.h_length      = sizeof(struct in_addr);
440   request->query.vptr       = query->vptr;
441   request->query.callback   = query->callback;
442
443   add_request(request);
444   return request;
445 }
446
447 /*
448  * timeout_query_list - Remove queries from the list which have been 
449  * there too long without being resolved.
450  */
451 static time_t timeout_query_list(time_t now)
452 {
453   struct ResRequest* request;
454   struct ResRequest* next_request = 0;
455   time_t             next_time    = 0;
456   time_t             timeout      = 0;
457
458   Debug((DEBUG_DNS, "Resolver: timeout_query_list at %s", myctime(now)));
459   for (request = requestListHead; request; request = next_request) {
460     next_request = request->next;
461     timeout = request->sentat + request->timeout;
462     if (timeout < now) {
463       if (--request->retries <= 0) {
464         ++reinfo.re_timeouts;
465         (*request->query.callback)(request->query.vptr, 0);
466         rem_request(request);
467         continue;
468       }
469       else {
470         request->sentat = now;
471         request->timeout += request->timeout;
472         resend_query(request);
473       }
474     }
475     if (!next_time || timeout < next_time) {
476       next_time = timeout;
477     }
478   }
479   return (next_time > now) ? next_time : (now + AR_TTL);
480 }
481
482 /*
483  * timeout_resolver - check request list and cache for expired entries
484  */
485 time_t timeout_resolver(time_t now)
486 {
487   if (nextDNSCheck < now)
488     nextDNSCheck = timeout_query_list(now);
489   return nextDNSCheck;
490 }
491
492
493 /*
494  * delete_resolver_queries - cleanup outstanding queries 
495  * for which there no longer exist clients or conf lines.
496  */
497 void delete_resolver_queries(const void* vptr)
498 {
499   struct ResRequest* request;
500   struct ResRequest* next_request;
501
502   for (request = requestListHead; request; request = next_request) {
503     next_request = request->next;
504     if (vptr == request->query.vptr)
505       rem_request(request);
506   }
507 }
508
509 /*
510  * send_res_msg - sends msg to all nameservers found in the "_res" structure.
511  * This should reflect /etc/resolv.conf. We will get responses
512  * which arent needed but is easier than checking to see if nameserver
513  * isnt present. Returns number of messages successfully sent to 
514  * nameservers or -1 if no successful sends.
515  */
516 static int send_res_msg(const u_char* msg, int len, int rcount)
517 {
518   int i;
519   int sent = 0;
520   int max_queries = IRCD_MIN(_res.nscount, rcount);
521
522   assert(0 != msg);
523   /*
524    * RES_PRIMARY option is not implemented
525    * if (_res.options & RES_PRIMARY || 0 == max_queries)
526    */
527   if (0 == max_queries)
528     max_queries = 1;
529
530   Debug((DEBUG_DNS, "Resolver: sendto %d", max_queries));
531
532   for (i = 0; i < max_queries; i++) {
533     if (sendto(ResolverFileDescriptor, msg, len, 0, 
534                (struct sockaddr*) &(_res.nsaddr_list[i]),
535                sizeof(struct sockaddr_in)) == len) {
536       ++reinfo.re_sent;
537       ++sent;
538     }
539     else
540       log_write(LS_RESOLVER, L_ERROR, 0, "Resolver: send failed %m");
541   }
542   return sent;
543 }
544
545 /*
546  * find_id - find a dns request id (id is determined by dn_mkquery)
547  */
548 static struct ResRequest* find_id(int id)
549 {
550   struct ResRequest* request;
551
552   for (request = requestListHead; request; request = request->next) {
553     if (request->id == id)
554       return request;
555   }
556   return NULL;
557 }
558
559 /*
560  * gethost_byname - get host address from name
561  */
562 void gethost_byname(const char* name, const struct DNSQuery* query)
563 {
564   assert(0 != name);
565
566   Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
567   ++reinfo.re_na_look;
568 #if 0
569   if ((cp = find_cache_name(name)))
570     return &(cp->reply);
571 #endif
572   do_query_name(query, name, NULL);
573   nextDNSCheck = 1;
574 }
575
576 /*
577  * gethost_byaddr - get host name from address
578  */
579 void gethost_byaddr(const char* addr, const struct DNSQuery* query)
580 {
581   assert(0 != addr);
582
583   Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
584
585   ++reinfo.re_nu_look;
586   do_query_number(query, (const struct in_addr*) addr, NULL);
587   nextDNSCheck = 1;
588 }
589
590 /*
591  * do_query_name - nameserver lookup name
592  */
593 static void do_query_name(const struct DNSQuery* query, 
594                           const char* name, struct ResRequest* request)
595 {
596   char  hname[HOSTLEN + 1];
597   assert(0 != name);
598
599   ircd_strncpy(hname, name, HOSTLEN);
600   hname[HOSTLEN] = '\0';
601
602   if (!request) {
603     request       = make_request(query);
604     request->type = T_A;
605     request->name = (char*) MyMalloc(strlen(hname) + 1);
606     strcpy(request->name, hname);
607   }
608   query_name(hname, C_IN, T_A, request);
609 }
610
611 /*
612  * do_query_number - Use this to do reverse IP# lookups.
613  */
614 static void do_query_number(const struct DNSQuery* query, 
615                             const struct in_addr* addr,
616                             struct ResRequest* request)
617 {
618   char  ipbuf[32];
619   const unsigned char* cp;
620
621   assert(0 != addr);
622   cp = (const unsigned char*) &addr->s_addr;
623   ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
624                 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
625                 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
626
627   if (!request) {
628     request              = make_request(query);
629     request->type        = T_PTR;
630     request->addr.s_addr = addr->s_addr;
631   }
632   query_name(ipbuf, C_IN, T_PTR, request);
633 }
634
635 /*
636  * query_name - generate a query based on class, type and name.
637  */
638 static void query_name(const char* name, int query_class,
639                        int type, struct ResRequest* request)
640 {
641   unsigned char buf[MAXPACKET + 1];
642   int  request_len = 0;
643
644   assert(0 != name);
645   assert(0 != request);
646
647   Debug((DEBUG_DNS, "Resolver: query_name: %s %d %d", name, query_class, type));
648   memset(buf, 0, sizeof(buf));
649   if ((request_len = res_mkquery(QUERY, name, query_class, type, 
650                                  0, 0, 0,
651                                  buf, sizeof(buf) - 1)) > 0) {
652     HEADER* header = (HEADER*) buf;
653 #ifndef LRAND48
654     int            k = 0;
655     struct timeval tv;
656 #endif
657     /*
658      * generate a unique id
659      * NOTE: we don't have to worry about converting this to and from
660      * network byte order, the nameserver does not interpret this value
661      * and returns it unchanged
662      */
663 #ifdef LRAND48
664     do {
665       header->id = (header->id + lrand48()) & 0xffff;
666     } while (find_id(header->id));
667 #else
668     gettimeofday(&tv, NULL);
669     do {
670       header->id = (header->id + k + tv.tv_usec) & 0xffff;
671       ++k;
672     } while (find_id(header->id));
673 #endif /* LRAND48 */
674     request->id = header->id;
675     ++request->sends;
676     Debug((DEBUG_DNS, "Resolver: query_name %d: %s %d %d", request->id, 
677           name, query_class, type));
678     request->sent += send_res_msg(buf, request_len, request->sends);
679   }
680 }
681
682 static void resend_query(struct ResRequest* request)
683 {
684   assert(request);
685
686   if (request->resend == 0)
687     return;
688   ++reinfo.re_resends;
689   switch(request->type) {
690   case T_PTR:
691     do_query_number(NULL, &request->addr, request);
692     break;
693   case T_A:
694     do_query_name(NULL, request->name, request);
695     break;
696   default:
697     break;
698   }
699 }
700
701 /*
702  * proc_answer - process name server reply
703  * build a hostent struct in the passed request
704  */
705 static int proc_answer(struct ResRequest* request, HEADER* header,
706                        u_char* buf, u_char* eob)
707 {
708   char   hostbuf[HOSTLEN + 1]; /* working buffer */
709   u_char* current;             /* current position in buf */
710   char** alias;                /* alias list */
711   char** addr;                 /* address list */
712   char** base_addr;            /* original pointer to address list */
713   char*  name;                 /* pointer to name string */
714   char*  address;              /* pointer to address */
715   char*  base_address;         /* original pointer to address */
716   char*  endp;                 /* end of our buffer */
717   int    query_class;          /* answer class */
718   int    type;                 /* answer type */
719   int    rd_length;            /* record data length */
720   int    answer_count = 0;     /* answer counter */
721   int    n;                    /* temp count */
722   int    addr_count  = 0;      /* number of addresses in hostent */
723   int    alias_count = 0;      /* number of aliases in hostent */
724   int    t_ptr_seen = 0;       /* Seen a T_PTR in proc_answer? */
725   struct hostent* hp;          /* hostent getting filled */
726
727   assert(request);
728   assert(header);
729   assert(buf);
730   assert(eob);
731   
732   current = buf + sizeof(HEADER);
733   hp = &(request->he);
734   /*
735    * lazy allocation of request->he.buf, we don't allocate a buffer
736    * unless there is something to put in it.
737    */
738   if (!request->buf) {
739     request->buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
740     request->buf[MAXGETHOSTLEN] = '\0';
741     /*
742      * array of alias list pointers starts at beginning of buf
743      */
744     hp->h_aliases = (char**) request->buf;
745     hp->h_aliases[0] = NULL;
746     /*
747      * array of address list pointers starts after alias list pointers
748      * the actual addresses follow the the address list pointers
749      */ 
750     hp->h_addr_list = (char**)(request->buf + ALIAS_BLEN);
751     /*
752      * don't copy the host address to the beginning of h_addr_list
753      */
754     hp->h_addr_list[0] = NULL;
755   }
756   endp = request->buf + MAXGETHOSTLEN;
757   /*
758    * find the end of the address list
759    */
760   addr = hp->h_addr_list;
761   while (*addr) {
762     ++addr;
763     ++addr_count;
764   }
765   base_addr = addr;
766   /*
767    * make address point to first available address slot
768    */
769   address = request->buf + ADDRS_OFFSET +
770                     (sizeof(struct in_addr) * addr_count);
771   base_address = address;
772
773   /*
774    * find the end of the alias list
775    */
776   alias = hp->h_aliases;
777   while (*alias) {
778     ++alias;
779     ++alias_count;
780   }
781   /*
782    * make name point to first available space in request->buf
783    */
784   if (alias_count > 0) {
785     name = hp->h_aliases[alias_count - 1];
786     name += (strlen(name) + 1);
787   }
788   else if (hp->h_name)
789     name = hp->h_name + strlen(hp->h_name) + 1;
790   else
791     name = request->buf + ADDRS_OFFSET + ADDRS_DLEN;
792  
793   /*
794    * skip past queries
795    */ 
796   while (header->qdcount-- > 0) {
797     if ((n = dn_skipname(current, eob)) < 0)
798       break;
799     current += (n + QFIXEDSZ);
800   }
801   /*
802    * process each answer sent to us blech.
803    */
804   while (header->ancount-- > 0 && current < eob && name < endp) {
805     n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
806     if (n <= 0) {
807       /*
808        * no more answers left
809        */
810       return answer_count;
811     }
812     hostbuf[HOSTLEN] = '\0';
813     /* 
814      * With Address arithmetic you have to be very anal
815      * this code was not working on alpha due to that
816      * (spotted by rodder/jailbird/dianora)
817      */
818     current += (size_t) n;
819
820     if (!((current + ANSWER_FIXED_SIZE) < eob))
821       break;
822
823     type = _getshort(current);
824     current += TYPE_SIZE;
825
826     query_class = _getshort(current);
827     current += CLASS_SIZE;
828
829     request->ttl = _getlong(current);
830     current += TTL_SIZE;
831
832     rd_length = _getshort(current);
833     current += RDLENGTH_SIZE;
834
835     /* 
836      * Wait to set request->type until we verify this structure 
837      */
838     switch(type) {
839     case T_A:
840       /*
841        * check for invalid rd_length or too many addresses
842        * ignore T_A relies if looking for a T_PTR
843        */
844       if (t_ptr_seen)
845         return answer_count;
846       if (rd_length != sizeof(struct in_addr))
847         return answer_count;
848       if (++addr_count < RES_MAXADDRS) {
849         if (answer_count == 1)
850           hp->h_addrtype = (query_class == C_IN) ?  AF_INET : AF_UNSPEC;
851
852         memcpy(address, current, sizeof(struct in_addr));
853         *addr++ = address;
854         *addr = 0;
855         address += sizeof(struct in_addr);
856
857         if (!hp->h_name) {
858           strcpy(name, hostbuf);
859           hp->h_name = name;
860           name += strlen(name) + 1;
861         }
862         Debug((DEBUG_DNS, "Resolver: A %s for %s", 
863                ircd_ntoa((char*) hp->h_addr_list[addr_count - 1]), hostbuf));
864       }
865       current += rd_length;
866       ++answer_count;
867       break;
868     case T_PTR:
869       t_ptr_seen = 1;
870       addr_count = 0;
871       addr = base_addr;
872       *addr = 0;
873       address = base_address;
874       n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
875       if (n < 0) {
876         /*
877          * broken message
878          */
879         return 0;
880       }
881       else if (n == 0) {
882         /*
883          * no more answers left
884          */
885         return answer_count;
886       }
887       /*
888        * This comment is based on analysis by Shadowfax, Wohali and johan, 
889        * not me.  (Dianora) I am only commenting it.
890        *
891        * dn_expand is guaranteed to not return more than sizeof(hostbuf)
892        * but do all implementations of dn_expand also guarantee
893        * buffer is terminated with null byte? Lets not take chances.
894        *  -Dianora
895        */
896       hostbuf[HOSTLEN] = '\0';
897       current += (size_t) n;
898
899       Debug((DEBUG_DNS, "Resolver: PTR %s", hostbuf));
900       /*
901        * copy the returned hostname into the host name
902        * ignore duplicate ptr records
903        */
904       if (!hp->h_name) {
905         strcpy(name, hostbuf);
906         hp->h_name = name;
907         name += strlen(name) + 1;
908       }
909       ++answer_count;
910       break;
911     case T_CNAME:
912       Debug((DEBUG_DNS, "Resolver: CNAME %s", hostbuf));
913       if (++alias_count < RES_MAXALIASES) {
914         ircd_strncpy(name, hostbuf, endp - name);
915         *alias++ = name;
916         *alias   = 0;
917         name += strlen(name) + 1;
918       }
919       current += rd_length;
920       ++answer_count;
921       break;
922     default :
923       Debug((DEBUG_DNS,"Resolver: proc_answer type: %d for: %s", type, hostbuf));
924       break;
925     }
926   }
927   return answer_count;
928 }
929
930 /*
931  * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
932  * the data we're putting in it.
933  */
934 static struct hostent* dup_hostent(struct hostent* hp)
935 {
936   char*  p;
937   char** ap;
938   char** pp;
939   int    alias_count = 0;
940   int    addr_count = 0;
941   size_t bytes_needed = 0;
942   struct Hostent* new_hp = 0;
943
944   assert(0 != hp);
945
946   /* how much buffer do we need? */
947   bytes_needed += (strlen(hp->h_name) + 1);
948
949   pp = hp->h_aliases;
950   while (*pp) {
951     bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
952     ++alias_count;
953   }
954   pp = hp->h_addr_list;
955   while (*pp++) {
956     bytes_needed += (hp->h_length + sizeof(char*));
957     ++addr_count;
958   }
959   /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
960   bytes_needed += (2 * sizeof(char*));
961
962   /* Allocate memory */
963   new_hp = (struct Hostent*) MyMalloc(sizeof(struct Hostent) + bytes_needed);
964
965   new_hp->h.h_addrtype = hp->h_addrtype;
966   new_hp->h.h_length = hp->h_length;
967
968   /* first write the address list */
969   pp = hp->h_addr_list;
970   ap = new_hp->h.h_addr_list =
971       (char**)(new_hp->buf + ((alias_count + 1) * sizeof(char*)));
972   p = (char*)ap + ((addr_count + 1) * sizeof(char*));
973   while (*pp)
974   {
975     *ap++ = p;
976     memcpy(p, *pp++, hp->h_length);
977     p += hp->h_length;
978   }
979   *ap = 0;
980   /* next write the name */
981   new_hp->h.h_name = p;
982   strcpy(p, hp->h_name);
983   p += (strlen(p) + 1);
984
985   /* last write the alias list */
986   pp = hp->h_aliases;
987   ap = new_hp->h.h_aliases = (char**) new_hp->buf;
988   while (*pp) {
989     *ap++ = p;
990     strcpy(p, *pp++);
991     p += (strlen(p) + 1);
992   }
993   *ap = 0;
994   return (struct hostent*) new_hp;
995 }
996
997 /*
998  * resolver_read - read a dns reply from the nameserver and process it.
999  * return 0 if nothing was read from the socket, otherwise return 1
1000  */
1001 int resolver_read(void)
1002 {
1003   unsigned char      buf[sizeof(HEADER) + MAXPACKET];
1004   HEADER*            header       = 0;
1005   struct ResRequest* request      = 0;
1006   unsigned int       rc           = 0;
1007   int                answer_count = 0;
1008   struct sockaddr_in sin;
1009
1010   Debug((DEBUG_DNS, "Resolver: read"));
1011   if (IO_SUCCESS != os_recvfrom_nonb(ResolverFileDescriptor,
1012                                      (char*) buf, sizeof(buf), &rc, &sin)) {
1013     return 0;
1014   }
1015   if (rc < sizeof(HEADER)) {
1016     Debug((DEBUG_DNS, "Resolver: short reply %d: %s", rc, 
1017            (strerror(errno)) ? strerror(errno) : "Unknown"));
1018     return 0;
1019   }
1020   /*
1021    * convert DNS reply reader from Network byte order to CPU byte order.
1022    */
1023   header = (HEADER*) buf;
1024   /* header->id = ntohs(header->id); */
1025   header->ancount = ntohs(header->ancount);
1026   header->qdcount = ntohs(header->qdcount);
1027   header->nscount = ntohs(header->nscount);
1028   header->arcount = ntohs(header->arcount);
1029   ++reinfo.re_replies;
1030   /*
1031    * response for an id which we have already received an answer for
1032    * just ignore this response.
1033    */
1034   if (0 == (request = find_id(header->id))) {
1035     Debug((DEBUG_DNS, "Resolver: can't find request id: %d", header->id));
1036     return 1;
1037   }
1038   /*
1039    * check against possibly fake replies
1040    */
1041   if (!res_ourserver(&_res, &sin)) {
1042     Debug((DEBUG_DNS, "Resolver: fake reply from: %s",
1043            (const char*) &sin.sin_addr));
1044     ++reinfo.re_unkrep;
1045     return 1;
1046   }
1047
1048   if ((header->rcode != NOERROR) || (header->ancount == 0)) {
1049     ++reinfo.re_errors;
1050     if (SERVFAIL == header->rcode)
1051       resend_query(request);
1052     else {
1053       /*
1054        * If a bad error was returned, we stop here and dont send
1055        * send any more (no retries granted).
1056        * Isomer: Perhaps we should return these error messages back to
1057        *         the client?
1058        */
1059 #ifdef DEBUGMODE
1060       switch (header->rcode) {
1061         case NOERROR:
1062           Debug((DEBUG_DNS, "Fatal DNS error: No Error"));
1063           break;
1064         case FORMERR:
1065           Debug((DEBUG_DNS, "Fatal DNS error: Format Error"));
1066           break;
1067         case SERVFAIL:
1068           Debug((DEBUG_DNS, "Fatal DNS error: Server Failure"));
1069           break;
1070         case NXDOMAIN:
1071           Debug((DEBUG_DNS, "DNS error: Non Existant Domain"));
1072           break;
1073         case NOTIMP:
1074           Debug((DEBUG_DNS, "Fatal DNS error: Not Implemented"));
1075           break;
1076         case REFUSED:
1077           Debug((DEBUG_DNS, "Fatal DNS error: Query Refused"));
1078           break;
1079         default:
1080           Debug((DEBUG_DNS, "Unassigned fatal DNS error: %i", header->rcode));
1081           break;
1082       }
1083 #endif /* DEBUGMODE */
1084       (*request->query.callback)(request->query.vptr, 0);
1085       rem_request(request);
1086     } 
1087     return 1;
1088   }
1089   /*
1090    * If this fails there was an error decoding the received packet, 
1091    * try it again and hope it works the next time.
1092    */
1093   answer_count = proc_answer(request, header, buf, buf + rc);
1094   if (answer_count) {
1095     struct hostent* hp = 0;
1096     if (T_PTR == request->type) {
1097       if (0 == request->he.h_name) {
1098         /*
1099          * got a PTR response with no name, something bogus is happening
1100          * don't bother trying again, the client address doesn't resolve 
1101          */
1102         (*request->query.callback)(request->query.vptr, hp);
1103         rem_request(request); 
1104         return 1;
1105       }
1106       Debug((DEBUG_DNS, "relookup %s <-> %s",
1107              request->he.h_name, ircd_ntoa((char*) &request->addr)));
1108       /*
1109        * Lookup the 'authoritive' name that we were given for the
1110        * ip#.  By using this call rather than regenerating the
1111        * type we automatically gain the use of the cache with no
1112        * extra kludges.
1113        */
1114       gethost_byname(request->he.h_name, &request->query);
1115       /*
1116        * If name wasn't found, a request has been queued and it will
1117        * be the last one queued.  This is rather nasty way to keep
1118        * a host alias with the query. -avalon
1119        */
1120       MyFree(requestListTail->buf);
1121       requestListTail->buf = request->buf;
1122       request->buf = 0;
1123       memcpy(&requestListTail->he, &request->he, sizeof(struct hostent));
1124       rem_request(request);
1125     }
1126     else {
1127       /*
1128        * got a name and address response, client resolved
1129        * XXX - Bug found here by Dianora -
1130        * make_cache() occasionally returns a NULL pointer when a
1131        * PTR returned a CNAME, cp was not checked before so the
1132        * callback was being called with a value of 0x2C != NULL.
1133        */
1134       if (validate_hostent(&request->he))
1135         hp = dup_hostent(&request->he);
1136       (*request->query.callback)(request->query.vptr, hp);
1137       rem_request(request);
1138     }
1139   }
1140   else if (!request->sent) {
1141     /*
1142      * XXX - we got a response for a query we didn't send with a valid id?
1143      * this should never happen, bail here and leave the client unresolved
1144      */
1145     (*request->query.callback)(request->query.vptr, 0);
1146     rem_request(request);
1147   }
1148   return 1;
1149 }
1150
1151 /*
1152  * resolver_read_multiple - process up to count reads
1153  */
1154 void resolver_read_multiple(int count)
1155 {
1156   int i = 0;
1157   for ( ; i < count; ++i) {
1158     if (0 == resolver_read())
1159       return;
1160   }
1161 }
1162
1163 /*
1164  * m_dns - dns status query
1165  */
1166 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1167 {
1168 #if !defined(NDEBUG)
1169   if (parv[1] && *parv[1] == 'd') {
1170     sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :ResolverFileDescriptor = %d", 
1171                   sptr, ResolverFileDescriptor);
1172     return 0;
1173   }
1174   
1175   sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Re %d Rl %d/%d Rp %d Rq %d",
1176                 sptr, reinfo.re_errors, reinfo.re_nu_look,
1177                 reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
1178   sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr,
1179                 reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
1180                 reinfo.re_resends, reinfo.re_timeouts);
1181 #endif
1182   return 0;
1183 }
1184
1185 size_t cres_mem(struct Client* sptr)
1186 {
1187   struct ResRequest* request;
1188   size_t request_mem   = 0;
1189   int    request_count = 0;
1190
1191   for (request = requestListHead; request; request = request->next) {
1192     request_mem += sizeof(struct ResRequest);
1193     if (request->name)
1194       request_mem += strlen(request->name) + 1; 
1195     if (request->buf)
1196       request_mem += MAXGETHOSTLEN + 1;
1197     ++request_count;
1198   }
1199
1200   send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1201              ":Resolver: requests %d(%d)", request_count, request_mem);
1202   return request_mem;
1203 }
1204