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 * 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.
98 #define RDLENGTH_SIZE 2
99 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
102 * Building the Hostent
103 * The Hostent struct is arranged like this:
104 * +-------------------------------+
105 * Hostent: | struct hostent h |
106 * |-------------------------------|
108 * +-------------------------------+
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
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.
145 * Filling the buffer this way allows for proper alignment of the h_addr_list
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
159 struct hostent h; /* the hostent struct we are passing around */
160 char buf[1]; /* buffer for data pointed to from hostent */
164 struct ResRequest* next;
166 int sent; /* number of requests sent */
169 char retries; /* retry counter */
170 char sends; /* number of sends (>1 means resent) */
171 char resend; /* send flag. 0 == dont resend */
176 struct DNSQuery query; /* query callback for this request */
182 int ResolverFileDescriptor = -1; /* GLOBAL - used in s_bsd.c */
184 static struct Socket resSock; /* Socket describing resolver */
185 static struct Timer resExpireDNS; /* Timer for DNS expiration */
187 static time_t nextDNSCheck = 0;
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
196 static int spare_fd = -1;
198 static struct ResRequest* requestListHead; /* head of resolver request list */
199 static struct ResRequest* requestListTail; /* tail of resolver request list */
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,
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,
215 struct ResRequest* request);
216 static void resend_query(struct ResRequest* request);
217 static struct ResRequest* find_id(int);
219 static struct resinfo {
234 * From bind 8.3, these aren't declared in earlier versions of bind
236 extern u_short _getshort(const u_char *);
237 extern u_int _getlong(const u_char *);
240 * res_isourserver(ina)
241 * looks up "ina" in _res.ns_addr_list[]
246 * paul vixie, 29may94
249 res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp)
251 struct sockaddr_in ina;
255 for (ns = 0; ns < statp->nscount; ns++) {
256 const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
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))
267 /* Socket callback for resolver */
268 static void res_callback(struct Event* ev)
270 assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
276 * start_resolver - do everything we need to read the resolv.conf file
277 * and initialize the resolver file descriptor if needed
279 static void start_resolver(void)
281 Debug((DEBUG_DNS, "Resolver: start_resolver"));
283 * close the spare file descriptor so res_init can read resolv.conf
284 * successfully. Needed on Solaris
289 res_init(); /* res_init always returns 0 */
291 * make sure we have a valid file descriptor below 256 so we can
292 * do this again. Needed on Solaris
294 spare_fd = open("/dev/null",O_RDONLY,0);
295 if ((spare_fd < 0) || (spare_fd > 255)) {
297 ircd_snprintf(0, sparemsg, sizeof(sparemsg), "invalid spare_fd %d",
299 server_restart(sparemsg);
304 _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
306 _res.options |= RES_NOALIASES;
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);
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);
325 /* Call the query timeout function */
326 static void expire_DNS_callback(struct Event* ev)
330 next = timeout_query_list(CurrentTime);
332 timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
336 * init_resolver - initialize resolver and resolver library
338 int init_resolver(void)
340 Debug((DEBUG_DNS, "Resolver: init_resolver"));
342 srand48(CurrentTime);
344 memset(&reinfo, 0, sizeof(reinfo));
345 requestListHead = requestListTail = 0;
347 /* initiate the resolver timers */
348 timer_add(timer_init(&resExpireDNS), expire_DNS_callback, 0,
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;
361 * restart_resolver - flush the cache, reread resolv.conf, reopen socket
363 void restart_resolver(void)
365 /* flush_cache(); flush the dns cache */
369 static int validate_hostent(const struct hostent* hp)
374 for (name = hp->h_name; name; name = hp->h_aliases[i++]) {
375 if (!string_is_hostname(name))
382 * add_request - place a new request in the request list
384 static void add_request(struct ResRequest* request)
386 assert(0 != request);
387 if (!requestListHead)
388 requestListHead = requestListTail = request;
390 requestListTail->next = request;
391 requestListTail = request;
393 request->next = NULL;
394 ++reinfo.re_requests;
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.
402 static void rem_request(struct ResRequest* request)
404 struct ResRequest** current;
405 struct ResRequest* prev = NULL;
407 assert(0 != request);
408 for (current = &requestListHead; *current; ) {
409 if (*current == request) {
410 *current = request->next;
411 if (requestListTail == request)
412 requestListTail = prev;
416 current = &(*current)->next;
418 MyFree(request->buf);
419 MyFree(request->name);
424 * make_request - Create a DNS request record for the server.
426 static struct ResRequest* make_request(const struct DNSQuery* query)
428 struct ResRequest* request;
430 request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
431 memset(request, 0, sizeof(struct ResRequest));
433 request->sentat = CurrentTime;
434 request->retries = 3;
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;
443 add_request(request);
448 * timeout_query_list - Remove queries from the list which have been
449 * there too long without being resolved.
451 static time_t timeout_query_list(time_t now)
453 struct ResRequest* request;
454 struct ResRequest* next_request = 0;
455 time_t next_time = 0;
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;
463 if (--request->retries <= 0) {
464 ++reinfo.re_timeouts;
465 (*request->query.callback)(request->query.vptr, 0);
466 rem_request(request);
470 request->sentat = now;
471 request->timeout += request->timeout;
472 resend_query(request);
475 if (!next_time || timeout < next_time) {
479 return (next_time > now) ? next_time : (now + AR_TTL);
483 * timeout_resolver - check request list and cache for expired entries
485 time_t timeout_resolver(time_t now)
487 if (nextDNSCheck < now)
488 nextDNSCheck = timeout_query_list(now);
494 * delete_resolver_queries - cleanup outstanding queries
495 * for which there no longer exist clients or conf lines.
497 void delete_resolver_queries(const void* vptr)
499 struct ResRequest* request;
500 struct ResRequest* next_request;
502 for (request = requestListHead; request; request = next_request) {
503 next_request = request->next;
504 if (vptr == request->query.vptr)
505 rem_request(request);
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.
516 static int send_res_msg(const u_char* msg, int len, int rcount)
520 int max_queries = IRCD_MIN(_res.nscount, rcount);
524 * RES_PRIMARY option is not implemented
525 * if (_res.options & RES_PRIMARY || 0 == max_queries)
527 if (0 == max_queries)
530 Debug((DEBUG_DNS, "Resolver: sendto %d", max_queries));
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) {
540 log_write(LS_RESOLVER, L_ERROR, 0, "Resolver: send failed %m");
546 * find_id - find a dns request id (id is determined by dn_mkquery)
548 static struct ResRequest* find_id(int id)
550 struct ResRequest* request;
552 for (request = requestListHead; request; request = request->next) {
553 if (request->id == id)
560 * gethost_byname - get host address from name
562 void gethost_byname(const char* name, const struct DNSQuery* query)
566 Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
569 if ((cp = find_cache_name(name)))
572 do_query_name(query, name, NULL);
577 * gethost_byaddr - get host name from address
579 void gethost_byaddr(const char* addr, const struct DNSQuery* query)
583 Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
586 do_query_number(query, (const struct in_addr*) addr, NULL);
591 * do_query_name - nameserver lookup name
593 static void do_query_name(const struct DNSQuery* query,
594 const char* name, struct ResRequest* request)
596 char hname[HOSTLEN + 1];
599 ircd_strncpy(hname, name, HOSTLEN);
600 hname[HOSTLEN] = '\0';
603 request = make_request(query);
605 request->name = (char*) MyMalloc(strlen(hname) + 1);
606 strcpy(request->name, hname);
608 query_name(hname, C_IN, T_A, request);
612 * do_query_number - Use this to do reverse IP# lookups.
614 static void do_query_number(const struct DNSQuery* query,
615 const struct in_addr* addr,
616 struct ResRequest* request)
619 const unsigned char* cp;
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]));
628 request = make_request(query);
629 request->type = T_PTR;
630 request->addr.s_addr = addr->s_addr;
632 query_name(ipbuf, C_IN, T_PTR, request);
636 * query_name - generate a query based on class, type and name.
638 static void query_name(const char* name, int query_class,
639 int type, struct ResRequest* request)
641 unsigned char buf[MAXPACKET + 1];
645 assert(0 != request);
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,
651 buf, sizeof(buf) - 1)) > 0) {
652 HEADER* header = (HEADER*) buf;
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
665 header->id = (header->id + lrand48()) & 0xffff;
666 } while (find_id(header->id));
668 gettimeofday(&tv, NULL);
670 header->id = (header->id + k + tv.tv_usec) & 0xffff;
672 } while (find_id(header->id));
674 request->id = header->id;
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);
682 static void resend_query(struct ResRequest* request)
686 if (request->resend == 0)
689 switch(request->type) {
691 do_query_number(NULL, &request->addr, request);
694 do_query_name(NULL, request->name, request);
702 * proc_answer - process name server reply
703 * build a hostent struct in the passed request
705 static int proc_answer(struct ResRequest* request, HEADER* header,
706 u_char* buf, u_char* eob)
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 */
732 current = buf + sizeof(HEADER);
735 * lazy allocation of request->he.buf, we don't allocate a buffer
736 * unless there is something to put in it.
739 request->buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
740 request->buf[MAXGETHOSTLEN] = '\0';
742 * array of alias list pointers starts at beginning of buf
744 hp->h_aliases = (char**) request->buf;
745 hp->h_aliases[0] = NULL;
747 * array of address list pointers starts after alias list pointers
748 * the actual addresses follow the the address list pointers
750 hp->h_addr_list = (char**)(request->buf + ALIAS_BLEN);
752 * don't copy the host address to the beginning of h_addr_list
754 hp->h_addr_list[0] = NULL;
756 endp = request->buf + MAXGETHOSTLEN;
758 * find the end of the address list
760 addr = hp->h_addr_list;
767 * make address point to first available address slot
769 address = request->buf + ADDRS_OFFSET +
770 (sizeof(struct in_addr) * addr_count);
771 base_address = address;
774 * find the end of the alias list
776 alias = hp->h_aliases;
782 * make name point to first available space in request->buf
784 if (alias_count > 0) {
785 name = hp->h_aliases[alias_count - 1];
786 name += (strlen(name) + 1);
789 name = hp->h_name + strlen(hp->h_name) + 1;
791 name = request->buf + ADDRS_OFFSET + ADDRS_DLEN;
796 while (header->qdcount-- > 0) {
797 if ((n = dn_skipname(current, eob)) < 0)
799 current += (n + QFIXEDSZ);
802 * process each answer sent to us blech.
804 while (header->ancount-- > 0 && current < eob && name < endp) {
805 n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
808 * no more answers left
812 hostbuf[HOSTLEN] = '\0';
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)
818 current += (size_t) n;
820 if (!((current + ANSWER_FIXED_SIZE) < eob))
823 type = _getshort(current);
824 current += TYPE_SIZE;
826 query_class = _getshort(current);
827 current += CLASS_SIZE;
829 request->ttl = _getlong(current);
832 rd_length = _getshort(current);
833 current += RDLENGTH_SIZE;
836 * Wait to set request->type until we verify this structure
841 * check for invalid rd_length or too many addresses
842 * ignore T_A relies if looking for a T_PTR
846 if (rd_length != sizeof(struct in_addr))
848 if (++addr_count < RES_MAXADDRS) {
849 if (answer_count == 1)
850 hp->h_addrtype = (query_class == C_IN) ? AF_INET : AF_UNSPEC;
852 memcpy(address, current, sizeof(struct in_addr));
855 address += sizeof(struct in_addr);
858 strcpy(name, hostbuf);
860 name += strlen(name) + 1;
862 Debug((DEBUG_DNS, "Resolver: A %s for %s",
863 ircd_ntoa((char*) hp->h_addr_list[addr_count - 1]), hostbuf));
865 current += rd_length;
873 address = base_address;
874 n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
883 * no more answers left
888 * This comment is based on analysis by Shadowfax, Wohali and johan,
889 * not me. (Dianora) I am only commenting it.
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.
896 hostbuf[HOSTLEN] = '\0';
897 current += (size_t) n;
899 Debug((DEBUG_DNS, "Resolver: PTR %s", hostbuf));
901 * copy the returned hostname into the host name
902 * ignore duplicate ptr records
905 strcpy(name, hostbuf);
907 name += strlen(name) + 1;
912 Debug((DEBUG_DNS, "Resolver: CNAME %s", hostbuf));
913 if (++alias_count < RES_MAXALIASES) {
914 ircd_strncpy(name, hostbuf, endp - name);
917 name += strlen(name) + 1;
919 current += rd_length;
923 Debug((DEBUG_DNS,"Resolver: proc_answer type: %d for: %s", type, hostbuf));
931 * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
932 * the data we're putting in it.
934 static struct hostent* dup_hostent(struct hostent* hp)
941 size_t bytes_needed = 0;
942 struct Hostent* new_hp = 0;
946 /* how much buffer do we need? */
947 bytes_needed += (strlen(hp->h_name) + 1);
951 bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
954 pp = hp->h_addr_list;
956 bytes_needed += (hp->h_length + sizeof(char*));
959 /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
960 bytes_needed += (2 * sizeof(char*));
962 /* Allocate memory */
963 new_hp = (struct Hostent*) MyMalloc(sizeof(struct Hostent) + bytes_needed);
965 new_hp->h.h_addrtype = hp->h_addrtype;
966 new_hp->h.h_length = hp->h_length;
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*));
976 memcpy(p, *pp++, hp->h_length);
980 /* next write the name */
981 new_hp->h.h_name = p;
982 strcpy(p, hp->h_name);
983 p += (strlen(p) + 1);
985 /* last write the alias list */
987 ap = new_hp->h.h_aliases = (char**) new_hp->buf;
991 p += (strlen(p) + 1);
994 return (struct hostent*) new_hp;
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
1001 int resolver_read(void)
1003 unsigned char buf[sizeof(HEADER) + MAXPACKET];
1005 struct ResRequest* request = 0;
1006 unsigned int rc = 0;
1007 int answer_count = 0;
1008 struct sockaddr_in sin;
1010 Debug((DEBUG_DNS, "Resolver: read"));
1011 if (IO_SUCCESS != os_recvfrom_nonb(ResolverFileDescriptor,
1012 (char*) buf, sizeof(buf), &rc, &sin)) {
1015 if (rc < sizeof(HEADER)) {
1016 Debug((DEBUG_DNS, "Resolver: short reply %d: %s", rc,
1017 (strerror(errno)) ? strerror(errno) : "Unknown"));
1021 * convert DNS reply reader from Network byte order to CPU byte order.
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;
1031 * response for an id which we have already received an answer for
1032 * just ignore this response.
1034 if (0 == (request = find_id(header->id))) {
1035 Debug((DEBUG_DNS, "Resolver: can't find request id: %d", header->id));
1039 * check against possibly fake replies
1041 if (!res_ourserver(&_res, &sin)) {
1042 Debug((DEBUG_DNS, "Resolver: fake reply from: %s",
1043 (const char*) &sin.sin_addr));
1048 if ((header->rcode != NOERROR) || (header->ancount == 0)) {
1050 if (SERVFAIL == header->rcode)
1051 resend_query(request);
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
1060 switch (header->rcode) {
1062 Debug((DEBUG_DNS, "Fatal DNS error: No Error"));
1065 Debug((DEBUG_DNS, "Fatal DNS error: Format Error"));
1068 Debug((DEBUG_DNS, "Fatal DNS error: Server Failure"));
1071 Debug((DEBUG_DNS, "DNS error: Non Existant Domain"));
1074 Debug((DEBUG_DNS, "Fatal DNS error: Not Implemented"));
1077 Debug((DEBUG_DNS, "Fatal DNS error: Query Refused"));
1080 Debug((DEBUG_DNS, "Unassigned fatal DNS error: %i", header->rcode));
1083 #endif /* DEBUGMODE */
1084 (*request->query.callback)(request->query.vptr, 0);
1085 rem_request(request);
1090 * If this fails there was an error decoding the received packet,
1091 * try it again and hope it works the next time.
1093 answer_count = proc_answer(request, header, buf, buf + rc);
1095 struct hostent* hp = 0;
1096 if (T_PTR == request->type) {
1097 if (0 == request->he.h_name) {
1099 * got a PTR response with no name, something bogus is happening
1100 * don't bother trying again, the client address doesn't resolve
1102 (*request->query.callback)(request->query.vptr, hp);
1103 rem_request(request);
1106 Debug((DEBUG_DNS, "relookup %s <-> %s",
1107 request->he.h_name, ircd_ntoa((char*) &request->addr)));
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
1114 gethost_byname(request->he.h_name, &request->query);
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
1120 MyFree(requestListTail->buf);
1121 requestListTail->buf = request->buf;
1123 memcpy(&requestListTail->he, &request->he, sizeof(struct hostent));
1124 rem_request(request);
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.
1134 if (validate_hostent(&request->he))
1135 hp = dup_hostent(&request->he);
1136 (*request->query.callback)(request->query.vptr, hp);
1137 rem_request(request);
1140 else if (!request->sent) {
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
1145 (*request->query.callback)(request->query.vptr, 0);
1146 rem_request(request);
1152 * resolver_read_multiple - process up to count reads
1154 void resolver_read_multiple(int count)
1157 for ( ; i < count; ++i) {
1158 if (0 == resolver_read())
1164 * m_dns - dns status query
1166 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1168 #if !defined(NDEBUG)
1169 if (parv[1] && *parv[1] == 'd') {
1170 sendcmdto_one(&me, CMD_NOTICE, sptr, "%C :ResolverFileDescriptor = %d",
1171 sptr, ResolverFileDescriptor);
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);
1185 size_t cres_mem(struct Client* sptr)
1187 struct ResRequest* request;
1188 size_t request_mem = 0;
1189 int request_count = 0;
1191 for (request = requestListHead; request; request = request->next) {
1192 request_mem += sizeof(struct ResRequest);
1194 request_mem += strlen(request->name) + 1;
1196 request_mem += MAXGETHOSTLEN + 1;
1200 send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1201 ":Resolver: requests %d(%d)", request_count, request_mem);