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.
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>)
18 #include "ircd_alloc.h"
19 #include "ircd_events.h"
21 #include "ircd_osdep.h"
22 #include "ircd_reply.h"
23 #include "ircd_snprintf.h"
24 #include "ircd_string.h"
40 #include <sys/socket.h>
45 #include <arpa/nameser.h>
48 #include <arpa/inet.h>
52 #error this code needs to be able to address individual octets
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.
64 #define INADDR_NONE ((unsigned int) 0xffffffff)
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 */
71 * OSF1 doesn't have RES_NOALIASES
74 #define RES_NOALIASES 0
78 * macros used to calulate offsets into fixed query buffer
80 #define ALIAS_BLEN ((RES_MAXALIASES + 1) * sizeof(char*))
81 #define ADDRS_BLEN ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
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)
88 #define AR_TTL 600 /* TTL in seconds for dns cache entries */
91 * the following values should be prime
93 #define ARES_CACSIZE 307
97 * RFC 1104/1105 wasn't very helpful about what these fields
98 * should be named, so for now, we'll just name them this way.
99 * we probably should look at what named calls them or something.
104 #define RDLENGTH_SIZE 2
105 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
108 * Building the Hostent
109 * The Hostent struct is arranged like this:
110 * +-------------------------------+
111 * Hostent: | struct hostent h |
112 * |-------------------------------|
114 * +-------------------------------+
118 * +-------------------------------+
119 * buf: | h_aliases pointer array | Max size: ALIAS_BLEN;
120 * | NULL | contains `char *'s
121 * |-------------------------------|
122 * | h_addr_list pointer array | Max size: ADDRS_BLEN;
123 * | NULL | contains `struct in_addr *'s
124 * |-------------------------------|
125 * | h_addr_list addresses | Max size: ADDRS_DLEN;
126 * | | contains `struct in_addr's
127 * |-------------------------------|
128 * | storage for hostname strings | Max size: ALIAS_DLEN;
129 * +-------------------------------+ contains `char's
131 * For requests the size of the h_aliases, and h_addr_list pointer
132 * array sizes are set to MAXALISES and MAXADDRS respectively, and
133 * buf is a fixed size with enough space to hold the largest expected
134 * reply from a nameserver, see RFC 1034 and RFC 1035.
135 * For cached entries the sizes are dependent on the actual number
136 * of aliases and addresses. If new aliases and addresses are found
137 * for cached entries, the buffer is grown and the new entries are added.
138 * The hostent struct is filled in with the addresses of the entries in
139 * the Hostent buf as follows:
140 * h_name - contains a pointer to the start of the hostname string area,
141 * or NULL if none is set. The h_name is followed by the
142 * aliases, in the storage for hostname strings area.
143 * h_aliases - contains a pointer to the start of h_aliases pointer array.
144 * This array contains pointers to the storage for hostname
145 * strings area and is terminated with a NULL. The first alias
146 * is stored directly after the h_name.
147 * h_addr_list - contains a pointer to the start of h_addr_list pointer array.
148 * This array contains pointers to in_addr structures in the
149 * h_addr_list addresses area and is terminated with a NULL.
151 * Filling the buffer this way allows for proper alignment of the h_addr_list
154 * This arrangement allows us to alias a Hostent struct pointer as a
155 * real struct hostent* without lying. It also allows us to change the
156 * values contained in the cached entries and requests without changing
157 * the actual hostent pointer, which is saved in a client struct and can't
158 * be changed without blowing things up or a lot more fiddling around.
159 * It also allows for defered allocation of the fixed size buffers until
160 * they are really needed.
161 * Nov. 17, 1997 --Bleep
165 struct hostent h; /* the hostent struct we are passing around */
166 char* buf; /* buffer for data pointed to from hostent */
170 struct ResRequest* next;
172 int sent; /* number of requests sent */
175 char retries; /* retry counter */
176 char sends; /* number of sends (>1 means resent) */
177 char resend; /* send flag. 0 == dont resend */
182 struct DNSQuery query; /* query callback for this request */
187 struct CacheEntry* hname_next;
188 struct CacheEntry* hnum_next;
189 struct CacheEntry* list_next;
193 struct DNSReply reply;
197 struct CacheEntry* num_list;
198 struct CacheEntry* name_list;
202 int ResolverFileDescriptor = -1; /* GLOBAL - used in s_bsd.c */
204 static struct Socket resSock; /* Socket describing resolver */
205 static struct Timer resExpireDNS; /* Timer for DNS expiration */
206 static struct Timer resExpireCache; /* Timer for cache expiration */
208 static time_t nextDNSCheck = 0;
209 static time_t nextCacheExpire = 1;
212 * Keep a spare file descriptor open. res_init calls fopen to read the
213 * resolv.conf file. If ircd is hogging all the file descriptors below 256,
214 * on systems with crippled FILE structures this will cause wierd bugs.
215 * This is definitely needed for Solaris which uses an unsigned char to
216 * hold the file descriptor. --Dianora
218 static int spare_fd = -1;
220 static int cachedCount = 0;
221 static struct CacheTable hashtable[ARES_CACSIZE];
222 static struct CacheEntry* cacheTop;
223 static struct ResRequest* requestListHead; /* head of resolver request list */
224 static struct ResRequest* requestListTail; /* tail of resolver request list */
227 static void add_request(struct ResRequest* request);
228 static void rem_request(struct ResRequest* request);
229 static struct ResRequest* make_request(const struct DNSQuery* query);
230 static time_t timeout_query_list(time_t now);
231 static time_t expire_cache(time_t now);
232 static void rem_cache(struct CacheEntry*);
233 static void do_query_name(const struct DNSQuery* query,
235 struct ResRequest* request);
236 static void do_query_number(const struct DNSQuery* query,
237 const struct in_addr*,
238 struct ResRequest* request);
239 static void query_name(const char* name,
242 struct ResRequest* request);
243 static void resend_query(struct ResRequest* request);
244 static struct CacheEntry* make_cache(struct ResRequest* request);
245 static struct CacheEntry* find_cache_name(const char* name);
246 static struct CacheEntry* find_cache_number(struct ResRequest* request,
248 static struct ResRequest* find_id(int);
250 static struct cacheinfo {
260 static struct resinfo {
275 * From bind 8.3, these aren't declared in earlier versions of bind
277 extern u_short _getshort(const u_char *);
278 extern u_int _getlong(const u_char *);
281 * res_isourserver(ina)
282 * looks up "ina" in _res.ns_addr_list[]
287 * paul vixie, 29may94
290 res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp)
292 struct sockaddr_in ina;
296 for (ns = 0; ns < statp->nscount; ns++) {
297 const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
299 if (srv->sin_family == ina.sin_family &&
300 srv->sin_port == ina.sin_port &&
301 (srv->sin_addr.s_addr == INADDR_ANY ||
302 srv->sin_addr.s_addr == ina.sin_addr.s_addr))
308 /* Socket callback for resolver */
309 static void res_callback(struct Event* ev)
311 assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
317 * start_resolver - do everything we need to read the resolv.conf file
318 * and initialize the resolver file descriptor if needed
320 static void start_resolver(void)
322 Debug((DEBUG_DNS, "Resolver: start_resolver"));
324 * close the spare file descriptor so res_init can read resolv.conf
325 * successfully. Needed on Solaris
330 res_init(); /* res_init always returns 0 */
332 * make sure we have a valid file descriptor below 256 so we can
333 * do this again. Needed on Solaris
335 spare_fd = open("/dev/null",O_RDONLY,0);
336 if ((spare_fd < 0) || (spare_fd > 255)) {
338 ircd_snprintf(0, sparemsg, sizeof(sparemsg), "invalid spare_fd %d",
340 server_restart(sparemsg);
345 _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
347 _res.options |= RES_NOALIASES;
349 if (ResolverFileDescriptor < 0) {
350 ResolverFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0);
351 if (-1 == ResolverFileDescriptor) {
352 report_error("Resolver: error creating socket for %s: %s",
353 cli_name(&me), errno);
356 if (!os_set_nonblocking(ResolverFileDescriptor))
357 report_error("Resolver: error setting non-blocking for %s: %s",
358 cli_name(&me), errno);
359 if (!socket_add(&resSock, res_callback, 0, SS_DATAGRAM,
360 SOCK_EVENT_READABLE, ResolverFileDescriptor))
361 report_error("Resolver: unable to queue resolver file descriptor for %s",
362 cli_name(&me), ENFILE);
366 /* Call the query timeout function */
367 static void expire_DNS_callback(struct Event* ev)
371 next = timeout_query_list(CurrentTime);
373 timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
376 /* Call the cache expire function */
377 static void expire_cache_callback(struct Event* ev)
381 next = expire_cache(CurrentTime);
383 timer_add(&resExpireCache, expire_cache_callback, 0, TT_ABSOLUTE, next);
387 * init_resolver - initialize resolver and resolver library
389 int init_resolver(void)
391 Debug((DEBUG_DNS, "Resolver: init_resolver"));
393 srand48(CurrentTime);
395 memset(&cainfo, 0, sizeof(cainfo));
396 memset(hashtable, 0, sizeof(hashtable));
397 memset(&reinfo, 0, sizeof(reinfo));
399 requestListHead = requestListTail = 0;
401 /* initiate the resolver timers */
402 timer_add(timer_init(&resExpireDNS), expire_DNS_callback, 0,
404 timer_add(timer_init(&resExpireCache), expire_cache_callback, 0,
410 Debug((DEBUG_DNS, "Resolver: fd %d errno: %d h_errno: %d: %s",
411 ResolverFileDescriptor, errno, h_errno,
412 (strerror(errno)) ? strerror(errno) : "Unknown"));
413 return ResolverFileDescriptor;
417 * restart_resolver - flush the cache, reread resolv.conf, reopen socket
419 void restart_resolver(void)
421 /* flush_cache(); flush the dns cache */
425 static int validate_hostent(const struct hostent* hp)
430 for (name = hp->h_name; name; name = hp->h_aliases[i++]) {
431 if (!string_is_hostname(name))
438 * add_request - place a new request in the request list
440 static void add_request(struct ResRequest* request)
442 assert(0 != request);
443 if (!requestListHead)
444 requestListHead = requestListTail = request;
446 requestListTail->next = request;
447 requestListTail = request;
449 request->next = NULL;
450 ++reinfo.re_requests;
454 * rem_request - remove a request from the list.
455 * This must also free any memory that has been allocated for
456 * temporary storage of DNS results.
458 static void rem_request(struct ResRequest* request)
460 struct ResRequest** current;
461 struct ResRequest* prev = NULL;
463 assert(0 != request);
464 for (current = &requestListHead; *current; ) {
465 if (*current == request) {
466 *current = request->next;
467 if (requestListTail == request)
468 requestListTail = prev;
472 current = &(*current)->next;
474 MyFree(request->he.buf);
475 MyFree(request->name);
480 * make_request - Create a DNS request record for the server.
482 static struct ResRequest* make_request(const struct DNSQuery* query)
484 struct ResRequest* request;
486 request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
487 memset(request, 0, sizeof(struct ResRequest));
489 request->sentat = CurrentTime;
490 request->retries = 3;
492 request->timeout = 5; /* start at 5 per RFC1123 */
493 request->addr.s_addr = INADDR_NONE;
494 request->he.h.h_addrtype = AF_INET;
495 request->he.h.h_length = sizeof(struct in_addr);
496 request->query.vptr = query->vptr;
497 request->query.callback = query->callback;
499 #if defined(NULL_POINTER_NOT_ZERO)
500 request->next = NULL;
501 request->he.buf = NULL;
502 request->he.h.h_name = NULL;
503 request->he.h.h_aliases = NULL;
504 request->he.h.h_addr_list = NULL;
506 add_request(request);
511 * timeout_query_list - Remove queries from the list which have been
512 * there too long without being resolved.
514 static time_t timeout_query_list(time_t now)
516 struct ResRequest* request;
517 struct ResRequest* next_request = 0;
518 time_t next_time = 0;
521 Debug((DEBUG_DNS, "Resolver: timeout_query_list at %s", myctime(now)));
522 for (request = requestListHead; request; request = next_request) {
523 next_request = request->next;
524 timeout = request->sentat + request->timeout;
526 if (--request->retries <= 0) {
527 ++reinfo.re_timeouts;
528 (*request->query.callback)(request->query.vptr, 0);
529 rem_request(request);
533 request->sentat = now;
534 request->timeout += request->timeout;
535 resend_query(request);
538 if (!next_time || timeout < next_time) {
542 return (next_time > now) ? next_time : (now + AR_TTL);
546 * expire_cache - removes entries from the cache which are older
547 * than their expiry times. returns the time at which the server
548 * should next poll the cache.
550 static time_t expire_cache(time_t now)
552 struct CacheEntry* cp;
553 struct CacheEntry* cp_next;
556 Debug((DEBUG_DNS, "Resolver: expire_cache at %s", myctime(now)));
557 for (cp = cacheTop; cp; cp = cp_next) {
558 cp_next = cp->list_next;
559 if (cp->expireat < now) {
563 else if (!expire || expire > cp->expireat)
564 expire = cp->expireat;
566 return (expire > now) ? expire : (now + AR_TTL);
570 * timeout_resolver - check request list and cache for expired entries
572 time_t timeout_resolver(time_t now)
574 if (nextDNSCheck < now)
575 nextDNSCheck = timeout_query_list(now);
576 if (nextCacheExpire < now)
577 nextCacheExpire = expire_cache(now);
578 return IRCD_MIN(nextDNSCheck, nextCacheExpire);
583 * delete_resolver_queries - cleanup outstanding queries
584 * for which there no longer exist clients or conf lines.
586 void delete_resolver_queries(const void* vptr)
588 struct ResRequest* request;
589 struct ResRequest* next_request;
591 for (request = requestListHead; request; request = next_request) {
592 next_request = request->next;
593 if (vptr == request->query.vptr)
594 rem_request(request);
599 * send_res_msg - sends msg to all nameservers found in the "_res" structure.
600 * This should reflect /etc/resolv.conf. We will get responses
601 * which arent needed but is easier than checking to see if nameserver
602 * isnt present. Returns number of messages successfully sent to
603 * nameservers or -1 if no successful sends.
605 static int send_res_msg(const u_char* msg, int len, int rcount)
609 int max_queries = IRCD_MIN(_res.nscount, rcount);
613 * RES_PRIMARY option is not implemented
614 * if (_res.options & RES_PRIMARY || 0 == max_queries)
616 if (0 == max_queries)
619 Debug((DEBUG_DNS, "Resolver: sendto %d", max_queries));
621 for (i = 0; i < max_queries; i++) {
622 if (sendto(ResolverFileDescriptor, msg, len, 0,
623 (struct sockaddr*) &(_res.nsaddr_list[i]),
624 sizeof(struct sockaddr_in)) == len) {
629 log_write(LS_RESOLVER, L_ERROR, 0, "Resolver: send failed %m");
635 * find_id - find a dns request id (id is determined by dn_mkquery)
637 static struct ResRequest* find_id(int id)
639 struct ResRequest* request;
641 for (request = requestListHead; request; request = request->next) {
642 if (request->id == id)
649 * gethost_byname - get host address from name
651 struct DNSReply* gethost_byname(const char* name,
652 const struct DNSQuery* query)
654 struct CacheEntry* cp;
657 Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
659 if ((cp = find_cache_name(name)))
662 do_query_name(query, name, NULL);
668 * gethost_byaddr - get host name from address
670 struct DNSReply* gethost_byaddr(const char* addr,
671 const struct DNSQuery* query)
673 struct CacheEntry *cp;
677 Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
680 if ((cp = find_cache_number(NULL, addr)))
683 do_query_number(query, (const struct in_addr*) addr, NULL);
689 * do_query_name - nameserver lookup name
691 static void do_query_name(const struct DNSQuery* query,
692 const char* name, struct ResRequest* request)
694 char hname[HOSTLEN + 1];
697 ircd_strncpy(hname, name, HOSTLEN);
698 hname[HOSTLEN] = '\0';
701 request = make_request(query);
703 request->name = (char*) MyMalloc(strlen(hname) + 1);
704 strcpy(request->name, hname);
706 query_name(hname, C_IN, T_A, request);
710 * do_query_number - Use this to do reverse IP# lookups.
712 static void do_query_number(const struct DNSQuery* query,
713 const struct in_addr* addr,
714 struct ResRequest* request)
717 const unsigned char* cp;
720 cp = (const unsigned char*) &addr->s_addr;
721 ircd_snprintf(0, ipbuf, sizeof(ipbuf), "%u.%u.%u.%u.in-addr.arpa.",
722 (unsigned int)(cp[3]), (unsigned int)(cp[2]),
723 (unsigned int)(cp[1]), (unsigned int)(cp[0]));
726 request = make_request(query);
727 request->type = T_PTR;
728 request->addr.s_addr = addr->s_addr;
730 query_name(ipbuf, C_IN, T_PTR, request);
734 * query_name - generate a query based on class, type and name.
736 static void query_name(const char* name, int query_class,
737 int type, struct ResRequest* request)
743 assert(0 != request);
745 Debug((DEBUG_DNS, "Resolver: query_name: %s %d %d", name, query_class, type));
746 memset(buf, 0, sizeof(buf));
747 if ((request_len = res_mkquery(QUERY, name, query_class, type,
748 0, 0, 0, (unsigned char*) buf, sizeof(buf))) > 0) {
749 HEADER* header = (HEADER*) buf;
755 * generate a unique id
756 * NOTE: we don't have to worry about converting this to and from
757 * network byte order, the nameserver does not interpret this value
758 * and returns it unchanged
762 header->id = (header->id + lrand48()) & 0xffff;
763 } while (find_id(header->id));
765 gettimeofday(&tv, NULL);
767 header->id = (header->id + k + tv.tv_usec) & 0xffff;
769 } while (find_id(header->id));
771 request->id = header->id;
773 Debug((DEBUG_DNS, "Resolver: query_name %d: %s %d %d", request->id,
774 name, query_class, type));
775 request->sent += send_res_msg((const unsigned char*) buf, request_len, request->sends);
779 static void resend_query(struct ResRequest* request)
781 assert(0 != request);
783 if (request->resend == 0)
786 switch(request->type) {
788 do_query_number(NULL, &request->addr, request);
791 do_query_name(NULL, request->name, request);
799 * proc_answer - process name server reply
800 * build a hostent struct in the passed request
802 static int proc_answer(struct ResRequest* request, HEADER* header,
803 u_char* buf, u_char* eob)
805 char hostbuf[HOSTLEN + 1]; /* working buffer */
806 u_char* current; /* current position in buf */
807 char** alias; /* alias list */
808 char** addr; /* address list */
809 char** base_addr; /* original pointer to address list */
810 char* name; /* pointer to name string */
811 char* address; /* pointer to address */
812 char* base_address; /* original pointer to address */
813 char* endp; /* end of our buffer */
814 int query_class; /* answer class */
815 int type; /* answer type */
816 int rd_length; /* record data length */
817 int answer_count = 0; /* answer counter */
818 int n; /* temp count */
819 int addr_count = 0; /* number of addresses in hostent */
820 int alias_count = 0; /* number of aliases in hostent */
821 int t_ptr_seen = 0; /* Seen a T_PTR in proc_answer? */
822 struct hostent* hp; /* hostent getting filled */
824 assert(0 != request);
829 current = buf + sizeof(HEADER);
830 hp = &(request->he.h);
832 * lazy allocation of request->he.buf, we don't allocate a buffer
833 * unless there is something to put in it.
835 if (!request->he.buf) {
836 request->he.buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
837 request->he.buf[MAXGETHOSTLEN] = '\0';
839 * array of alias list pointers starts at beginning of buf
841 hp->h_aliases = (char**) request->he.buf;
842 hp->h_aliases[0] = NULL;
844 * array of address list pointers starts after alias list pointers
845 * the actual addresses follow the the address list pointers
847 hp->h_addr_list = (char**)(request->he.buf + ALIAS_BLEN);
849 * don't copy the host address to the beginning of h_addr_list
851 hp->h_addr_list[0] = NULL;
853 endp = request->he.buf + MAXGETHOSTLEN;
855 * find the end of the address list
857 addr = hp->h_addr_list;
864 * make address point to first available address slot
866 address = request->he.buf + ADDRS_OFFSET +
867 (sizeof(struct in_addr) * addr_count);
868 base_address = address;
871 * find the end of the alias list
873 alias = hp->h_aliases;
879 * make name point to first available space in request->buf
881 if (alias_count > 0) {
882 name = hp->h_aliases[alias_count - 1];
883 name += (strlen(name) + 1);
886 name = hp->h_name + strlen(hp->h_name) + 1;
888 name = request->he.buf + ADDRS_OFFSET + ADDRS_DLEN;
893 while (header->qdcount-- > 0) {
894 if ((n = dn_skipname(current, eob)) < 0)
896 current += (n + QFIXEDSZ);
899 * process each answer sent to us blech.
901 while (header->ancount-- > 0 && current < eob && name < endp) {
902 n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
905 * no more answers left
909 hostbuf[HOSTLEN] = '\0';
911 * With Address arithmetic you have to be very anal
912 * this code was not working on alpha due to that
913 * (spotted by rodder/jailbird/dianora)
915 current += (size_t) n;
917 if (!((current + ANSWER_FIXED_SIZE) < eob))
920 type = _getshort(current);
921 current += TYPE_SIZE;
923 query_class = _getshort(current);
924 current += CLASS_SIZE;
926 request->ttl = _getlong(current);
929 rd_length = _getshort(current);
930 current += RDLENGTH_SIZE;
933 * Wait to set request->type until we verify this structure
938 * check for invalid rd_length or too many addresses
939 * ignore T_A relies if looking for a T_PTR
943 if (rd_length != sizeof(struct in_addr))
945 if (++addr_count < RES_MAXADDRS) {
946 if (answer_count == 1)
947 hp->h_addrtype = (query_class == C_IN) ? AF_INET : AF_UNSPEC;
949 memcpy(address, current, sizeof(struct in_addr));
952 address += sizeof(struct in_addr);
955 strcpy(name, hostbuf);
957 name += strlen(name) + 1;
959 Debug((DEBUG_DNS, "Resolver: A %s for %s",
960 ircd_ntoa((char*) hp->h_addr_list[addr_count - 1]), hostbuf));
962 current += rd_length;
970 address = base_address;
971 n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
980 * no more answers left
985 * This comment is based on analysis by Shadowfax, Wohali and johan,
986 * not me. (Dianora) I am only commenting it.
988 * dn_expand is guaranteed to not return more than sizeof(hostbuf)
989 * but do all implementations of dn_expand also guarantee
990 * buffer is terminated with null byte? Lets not take chances.
993 hostbuf[HOSTLEN] = '\0';
994 current += (size_t) n;
996 Debug((DEBUG_DNS, "Resolver: PTR %s", hostbuf));
998 * copy the returned hostname into the host name
999 * ignore duplicate ptr records
1002 strcpy(name, hostbuf);
1004 name += strlen(name) + 1;
1009 Debug((DEBUG_DNS, "Resolver: CNAME %s", hostbuf));
1010 if (++alias_count < RES_MAXALIASES) {
1011 ircd_strncpy(name, hostbuf, endp - name);
1014 name += strlen(name) + 1;
1016 current += rd_length;
1020 Debug((DEBUG_DNS,"Resolver: proc_answer type: %d for: %s", type, hostbuf));
1024 return answer_count;
1028 * resolver_read - read a dns reply from the nameserver and process it.
1029 * return 0 if nothing was read from the socket, otherwise return 1
1031 int resolver_read(void)
1033 u_char buf[sizeof(HEADER) + MAXPACKET];
1035 struct ResRequest* request = 0;
1036 struct CacheEntry* cp = 0;
1037 unsigned int rc = 0;
1038 int answer_count = 0;
1039 struct sockaddr_in sin;
1041 Debug((DEBUG_DNS, "Resolver: read"));
1042 if (IO_SUCCESS != os_recvfrom_nonb(ResolverFileDescriptor,
1043 (char*) buf, sizeof(buf), &rc, &sin)) {
1046 if (rc < sizeof(HEADER)) {
1047 Debug((DEBUG_DNS, "Resolver: short reply %d: %s", rc,
1048 (strerror(errno)) ? strerror(errno) : "Unknown"));
1052 * convert DNS reply reader from Network byte order to CPU byte order.
1054 header = (HEADER*) buf;
1055 /* header->id = ntohs(header->id); */
1056 header->ancount = ntohs(header->ancount);
1057 header->qdcount = ntohs(header->qdcount);
1058 header->nscount = ntohs(header->nscount);
1059 header->arcount = ntohs(header->arcount);
1060 ++reinfo.re_replies;
1062 * response for an id which we have already received an answer for
1063 * just ignore this response.
1065 if (0 == (request = find_id(header->id))) {
1066 Debug((DEBUG_DNS, "Resolver: can't find request id: %d", header->id));
1070 * check against possibly fake replies
1072 if (!res_ourserver(&_res, &sin)) {
1073 Debug((DEBUG_DNS, "Resolver: fake reply from: %s", (const char*) &sin.sin_addr));
1078 if ((header->rcode != NOERROR) || (header->ancount == 0)) {
1080 if (SERVFAIL == header->rcode)
1081 resend_query(request);
1084 * If a bad error was returned, we stop here and dont send
1085 * send any more (no retries granted).
1086 * Isomer: Perhaps we should return these error messages back to
1090 switch (header->rcode) {
1092 Debug((DEBUG_DNS, "Fatal DNS error: No Error"));
1095 Debug((DEBUG_DNS, "Fatal DNS error: Format Error"));
1098 Debug((DEBUG_DNS, "Fatal DNS error: Server Failure"));
1101 Debug((DEBUG_DNS, "DNS error: Non Existant Domain"));
1104 Debug((DEBUG_DNS, "Fatal DNS error: Not Implemented"));
1107 Debug((DEBUG_DNS, "Fatal DNS error: Query Refused"));
1110 Debug((DEBUG_DNS, "Unassigned fatal DNS error: %i", header->rcode));
1113 #endif /* DEBUGMODE */
1114 (*request->query.callback)(request->query.vptr, 0);
1115 rem_request(request);
1120 * If this fails there was an error decoding the received packet,
1121 * try it again and hope it works the next time.
1123 answer_count = proc_answer(request, header, buf, buf + rc);
1125 if (T_PTR == request->type) {
1126 struct DNSReply* reply = 0;
1127 if (0 == request->he.h.h_name) {
1129 * got a PTR response with no name, something bogus is happening
1130 * don't bother trying again, the client address doesn't resolve
1132 (*request->query.callback)(request->query.vptr, reply);
1133 rem_request(request);
1136 Debug((DEBUG_DNS, "relookup %s <-> %s",
1137 request->he.h.h_name, ircd_ntoa((char*) &request->addr)));
1139 * Lookup the 'authoritive' name that we were given for the
1140 * ip#. By using this call rather than regenerating the
1141 * type we automatically gain the use of the cache with no
1144 reply = gethost_byname(request->he.h.h_name, &request->query);
1146 (*request->query.callback)(request->query.vptr, reply);
1150 * If name wasn't found, a request has been queued and it will
1151 * be the last one queued. This is rather nasty way to keep
1152 * a host alias with the query. -avalon
1154 MyFree(requestListTail->he.buf);
1155 requestListTail->he.buf = request->he.buf;
1156 request->he.buf = 0;
1157 memcpy(&requestListTail->he.h, &request->he.h, sizeof(struct hostent));
1159 rem_request(request);
1163 * got a name and address response, client resolved
1164 * XXX - Bug found here by Dianora -
1165 * make_cache() occasionally returns a NULL pointer when a
1166 * PTR returned a CNAME, cp was not checked before so the
1167 * callback was being called with a value of 0x2C != NULL.
1169 struct DNSReply* reply = 0;
1170 if (validate_hostent(&request->he.h)) {
1171 if ((cp = make_cache(request)))
1174 (*request->query.callback)(request->query.vptr, reply);
1175 rem_request(request);
1178 else if (!request->sent) {
1180 * XXX - we got a response for a query we didn't send with a valid id?
1181 * this should never happen, bail here and leave the client unresolved
1183 (*request->query.callback)(request->query.vptr, 0);
1184 rem_request(request);
1190 * resolver_read_multiple - process up to count reads
1192 void resolver_read_multiple(int count)
1195 for ( ; i < count; ++i) {
1196 if (0 == resolver_read())
1201 static size_t calc_hostent_buffer_size(const struct hostent* hp)
1210 count += (strlen(hp->h_name) + 1);
1214 for (p = hp->h_aliases; *p; ++p)
1215 count += (strlen(*p) + 1 + sizeof(char*));
1217 * space for addresses
1219 for (p = hp->h_addr_list; *p; ++p)
1220 count += (hp->h_length + sizeof(char*));
1222 * space for 2 nulls to terminate h_aliases and h_addr_list
1224 count += (2 * sizeof(char*));
1230 * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
1231 * the data we're putting in it.
1233 static void dup_hostent(struct Hostent* new_hp, struct hostent* hp)
1238 int alias_count = 0;
1240 size_t bytes_needed = 0;
1242 assert(0 != new_hp);
1245 /* how much buffer do we need? */
1246 bytes_needed += (strlen(hp->h_name) + 1);
1250 bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
1253 pp = hp->h_addr_list;
1255 bytes_needed += (hp->h_length + sizeof(char*));
1258 /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1259 bytes_needed += (2 * sizeof(char*));
1261 /* Allocate memory */
1262 new_hp->buf = (char*) MyMalloc(bytes_needed);
1264 new_hp->h.h_addrtype = hp->h_addrtype;
1265 new_hp->h.h_length = hp->h_length;
1267 /* first write the address list */
1268 pp = hp->h_addr_list;
1269 ap = new_hp->h.h_addr_list =
1270 (char**)(new_hp->buf + ((alias_count + 1) * sizeof(char*)));
1271 p = (char*)ap + ((addr_count + 1) * sizeof(char*));
1275 memcpy(p, *pp++, hp->h_length);
1279 /* next write the name */
1280 new_hp->h.h_name = p;
1281 strcpy(p, hp->h_name);
1282 p += (strlen(p) + 1);
1284 /* last write the alias list */
1286 ap = new_hp->h.h_aliases = (char**) new_hp->buf;
1290 p += (strlen(p) + 1);
1296 * update_hostent - Add records to a Hostent struct in place.
1298 static void update_hostent(struct Hostent* hp, char** addr, char** alias)
1303 int alias_count = 0;
1306 size_t bytes_needed = 0;
1308 if (!hp || !hp->buf)
1311 /* how much buffer do we need? */
1312 bytes_needed = strlen(hp->h.h_name) + 1;
1313 pp = hp->h.h_aliases;
1315 bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
1321 bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
1325 pp = hp->h.h_addr_list;
1327 bytes_needed += (hp->h.h_length + sizeof(char*));
1333 bytes_needed += (hp->h.h_length + sizeof(char*));
1337 /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
1338 bytes_needed += 2 * sizeof(char*);
1340 /* Allocate memory */
1341 buf = (char*) MyMalloc(bytes_needed);
1344 /* first write the address list */
1345 pp = hp->h.h_addr_list;
1346 ap = hp->h.h_addr_list =
1347 (char**)(buf + ((alias_count + 1) * sizeof(char*)));
1348 p = (char*)ap + ((addr_count + 1) * sizeof(char*));
1350 memcpy(p, *pp++, hp->h.h_length);
1352 p += hp->h.h_length;
1356 memcpy(p, *addr++, hp->h.h_length);
1358 p += hp->h.h_length;
1363 /* next write the name */
1364 strcpy(p, hp->h.h_name);
1366 p += (strlen(p) + 1);
1368 /* last write the alias list */
1369 pp = hp->h.h_aliases;
1370 ap = hp->h.h_aliases = (char**) buf;
1374 p += (strlen(p) + 1);
1378 strcpy(p, *alias++);
1380 p += (strlen(p) + 1);
1384 /* release the old buffer */
1391 * hash_number - IP address hash function
1393 static int hash_number(const unsigned char* ip)
1395 /* could use loop but slower */
1397 const u_char* p = (const u_char*) ip;
1402 hashv += hashv + *p++;
1403 hashv += hashv + *p++;
1404 hashv += hashv + *p;
1405 hashv %= ARES_CACSIZE;
1410 * hash_name - hostname hash function
1412 static int hash_name(const char* name)
1414 unsigned int hashv = 0;
1415 const u_char* p = (const u_char*) name;
1419 for (; *p && *p != '.'; ++p)
1421 hashv %= ARES_CACSIZE;
1426 * add_to_cache - Add a new cache item to the queue and hash table.
1428 static struct CacheEntry* add_to_cache(struct CacheEntry* ocp)
1434 ocp->list_next = cacheTop;
1437 hashv = hash_name(ocp->he.h.h_name);
1439 ocp->hname_next = hashtable[hashv].name_list;
1440 hashtable[hashv].name_list = ocp;
1442 hashv = hash_number((const unsigned char*) ocp->he.h.h_addr);
1444 ocp->hnum_next = hashtable[hashv].num_list;
1445 hashtable[hashv].num_list = ocp;
1448 * LRU deletion of excessive cache entries.
1450 if (++cachedCount > MAXCACHED) {
1451 struct CacheEntry* cp;
1452 struct CacheEntry* cp_next;
1453 for (cp = ocp->list_next; cp; cp = cp_next) {
1454 cp_next = cp->list_next;
1463 * update_list - does not alter the cache structure passed. It is assumed that
1464 * it already contains the correct expire time, if it is a new entry. Old
1465 * entries have the expirey time updated.
1467 static void update_list(struct ResRequest* request, struct CacheEntry* cachep)
1469 struct CacheEntry* cp = cachep;
1475 char* addrs[RES_MAXADDRS + 1];
1476 char* aliases[RES_MAXALIASES + 1];
1479 * search for the new cache item in the cache list by hostname.
1480 * If found, move the entry to the top of the list and return.
1482 ++cainfo.ca_updates;
1487 * Compare the cache entry against the new record. Add any
1488 * previously missing names for this entry.
1492 for (i = 0, s = request->he.h.h_name; s; s = request->he.h.h_aliases[i++]) {
1493 for (j = 0, t = cp->he.h.h_name; t; t = cp->he.h.h_aliases[j++]) {
1494 if (0 == ircd_strcmp(t, s))
1503 * Do the same again for IP#'s.
1507 for (i = 0; (s = request->he.h.h_addr_list[i]); i++) {
1508 for (j = 0; (t = cp->he.h.h_addr_list[j]); j++) {
1509 if (!memcmp(t, s, sizeof(struct in_addr)))
1517 if (*addrs || *aliases)
1518 update_hostent(&cp->he, addrs, aliases);
1522 * find_cache_name - find name in nameserver cache
1524 static struct CacheEntry* find_cache_name(const char* name)
1526 struct CacheEntry* cp;
1532 hashv = hash_name(name);
1534 cp = hashtable[hashv].name_list;
1536 for (; cp; cp = cp->hname_next) {
1537 for (i = 0, s = cp->he.h.h_name; s; s = cp->he.h.h_aliases[i++]) {
1538 if (0 == ircd_strcmp(s, name)) {
1539 ++cainfo.ca_na_hits;
1545 for (cp = cacheTop; cp; cp = cp->list_next) {
1547 * if no aliases or the hash value matches, we've already
1548 * done this entry and all possiblilities concerning it.
1550 if (!cp->he.h.h_name || hashv == hash_name(cp->he.h.h_name))
1552 for (i = 0, s = cp->he.h.h_aliases[i]; s; s = cp->he.h.h_aliases[++i]) {
1553 if (0 == ircd_strcmp(name, s)) {
1554 ++cainfo.ca_na_hits;
1563 * find_cache_number - find a cache entry by ip# and update its expire time
1565 static struct CacheEntry* find_cache_number(struct ResRequest* request,
1568 struct CacheEntry* cp;
1573 hashv = hash_number((const unsigned char*) addr);
1574 cp = hashtable[hashv].num_list;
1576 for (; cp; cp = cp->hnum_next) {
1577 for (i = 0; cp->he.h.h_addr_list[i]; ++i) {
1578 if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
1579 ++cainfo.ca_nu_hits;
1584 for (cp = cacheTop; cp; cp = cp->list_next) {
1586 * single address entry...would have been done by hashed
1588 * if the first IP# has the same hashnumber as the IP# we
1589 * are looking for, its been done already.
1591 if (!cp->he.h.h_addr_list[1] ||
1592 hashv == hash_number((const unsigned char*) cp->he.h.h_addr_list[0]))
1594 for (i = 1; cp->he.h.h_addr_list[i]; ++i) {
1595 if (!memcmp(cp->he.h.h_addr_list[i], addr, sizeof(struct in_addr))) {
1596 ++cainfo.ca_nu_hits;
1604 static struct CacheEntry* make_cache(struct ResRequest* request)
1606 struct CacheEntry* cp;
1609 assert(0 != request);
1611 hp = &request->he.h;
1613 * shouldn't happen but it just might...
1615 assert(0 != hp->h_name);
1616 /* assert(0 != hp->h_addr_list[0]); */
1617 if (!hp->h_name || !hp->h_addr_list[0])
1620 * Make cache entry. First check to see if the cache already exists
1621 * and if so, return a pointer to it.
1623 for (i = 0; hp->h_addr_list[i]; ++i) {
1624 if ((cp = find_cache_number(request, hp->h_addr_list[i]))) {
1625 update_list(request, cp);
1630 * a matching entry wasnt found in the cache so go and make one up.
1632 cp = (struct CacheEntry*) MyMalloc(sizeof(struct CacheEntry));
1635 memset(cp, 0, sizeof(struct CacheEntry));
1636 dup_hostent(&cp->he, hp);
1637 cp->reply.hp = &cp->he.h;
1639 * hmmm... we could time out the cache after 10 minutes regardless
1640 * would that be reasonable since we don't save the reply?
1642 if (request->ttl < AR_TTL) {
1643 ++reinfo.re_shortttl;
1647 cp->ttl = request->ttl;
1648 cp->expireat = CurrentTime + cp->ttl;
1649 return add_to_cache(cp);
1653 * rem_cache - delete a cache entry from the cache structures
1654 * and lists and return all memory used for the cache back to the memory pool.
1656 static void rem_cache(struct CacheEntry* ocp)
1658 struct CacheEntry** cp;
1664 if (0 < ocp->reply.ref_count) {
1665 if (ocp->expireat < CurrentTime) {
1666 ocp->expireat = CurrentTime + AR_TTL;
1667 Debug((DEBUG_DNS, "Resolver: referenced cache entry not removed for: %s",
1673 * remove cache entry from linked list
1675 for (cp = &cacheTop; *cp; cp = &((*cp)->list_next)) {
1677 *cp = ocp->list_next;
1683 * remove cache entry from hashed name list
1685 assert(0 != hp->h_name);
1686 hashv = hash_name(hp->h_name);
1688 for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next)) {
1690 *cp = ocp->hname_next;
1695 * remove cache entry from hashed number list
1697 hashv = hash_number((const unsigned char*) hp->h_addr);
1700 for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next)) {
1702 *cp = ocp->hnum_next;
1707 * free memory used to hold the various host names and the array
1708 * of alias pointers.
1710 MyFree(ocp->he.buf);
1716 void flush_resolver_cache(void)
1719 * stubbed - iterate cache and remove everything that isn't referenced
1724 * m_dns - dns status query
1726 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1728 #if !defined(NDEBUG)
1729 struct CacheEntry* cp;
1733 if (parv[1] && *parv[1] == 'l') {
1734 for(cp = cacheTop; cp; cp = cp->list_next) {
1736 sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :Ex %d ttl %d host %s(%s)",
1737 sptr, cp->expireat - CurrentTime, cp->ttl,
1738 hp->h_name, ircd_ntoa(hp->h_addr));
1739 for (i = 0; hp->h_aliases[i]; i++)
1740 sendcmdto_one(&me, CMD_NOTICE, sptr, "%C : %s = %s (CN)", sptr,
1741 hp->h_name, hp->h_aliases[i]);
1742 for (i = 1; hp->h_addr_list[i]; i++)
1743 sendcmdto_one(&me, CMD_NOTICE, sptr, "%C : %s = %s (IP)", sptr,
1744 hp->h_name, ircd_ntoa(hp->h_addr_list[i]));
1748 if (parv[1] && *parv[1] == 'd') {
1749 sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :ResolverFileDescriptor = %d",
1750 sptr, ResolverFileDescriptor);
1753 sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Ca %d Cd %d Ce %d Cl %d Ch %d:%d "
1755 cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires,
1756 cainfo.ca_lookups, cainfo.ca_na_hits, cainfo.ca_nu_hits,
1759 sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Re %d Rl %d/%d Rp %d Rq %d",
1760 sptr, reinfo.re_errors, reinfo.re_nu_look,
1761 reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests);
1762 sendcmdto_one(&me, CMD_NOTICE, sptr,"%C :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr,
1763 reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent,
1764 reinfo.re_resends, reinfo.re_timeouts);
1769 size_t cres_mem(struct Client* sptr)
1771 struct CacheEntry* entry;
1772 struct ResRequest* request;
1773 size_t cache_mem = 0;
1774 size_t request_mem = 0;
1775 int cache_count = 0;
1776 int request_count = 0;
1778 for (entry = cacheTop; entry; entry = entry->list_next) {
1779 cache_mem += sizeof(struct CacheEntry);
1780 cache_mem += calc_hostent_buffer_size(&entry->he.h);
1783 for (request = requestListHead; request; request = request->next) {
1784 request_mem += sizeof(struct ResRequest);
1786 request_mem += strlen(request->name) + 1;
1787 if (request->he.buf)
1788 request_mem += MAXGETHOSTLEN + 1;
1792 if (cachedCount != cache_count) {
1793 send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1794 ":Resolver: cache count mismatch: %d != %d", cachedCount,
1796 assert(cachedCount == cache_count);
1798 send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1799 ":Resolver: cache %d(%d) requests %d(%d)", cache_count,
1800 cache_mem, request_count, request_mem);
1801 return cache_mem + request_mem;