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