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"
20 #include "ircd_features.h"
22 #include "ircd_osdep.h"
23 #include "ircd_reply.h"
24 #include "ircd_snprintf.h"
25 #include "ircd_string.h"
41 #include <sys/socket.h>
46 #include <arpa/nameser.h>
49 #include <arpa/inet.h>
53 #error this code needs to be able to address individual octets
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.
65 #define INADDR_NONE ((unsigned int) 0xffffffff)
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 */
72 * OSF1 doesn't have RES_NOALIASES
75 #define RES_NOALIASES 0
79 * macros used to calulate offsets into fixed query buffer
81 #define ALIAS_BLEN ((RES_MAXALIASES + 1) * sizeof(char*))
82 #define ADDRS_BLEN ((RES_MAXADDRS + 1) * sizeof(struct in_addr*))
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)
89 #define AR_TTL 600 /* TTL in seconds for dns cache entries */
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.
99 #define RDLENGTH_SIZE 2
100 #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
103 * Building the Hostent
104 * The Hostent struct is arranged like this:
105 * +-------------------------------+
106 * Hostent: | struct hostent h |
107 * |-------------------------------|
109 * +-------------------------------+
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
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.
146 * Filling the buffer this way allows for proper alignment of the h_addr_list
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
160 struct hostent h; /* the hostent struct we are passing around */
161 char buf[1]; /* buffer for data pointed to from hostent */
165 struct ResRequest* next;
167 int sent; /* number of requests sent */
170 char retries; /* retry counter */
171 char sends; /* number of sends (>1 means resent) */
172 char resend; /* send flag. 0 == dont resend */
177 struct DNSQuery query; /* query callback for this request */
183 int ResolverFileDescriptor = -1; /* GLOBAL - used in s_bsd.c */
185 static struct Socket resSock; /* Socket describing resolver */
186 static struct Timer resExpireDNS; /* Timer for DNS expiration */
188 static time_t nextDNSCheck = 0;
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
197 static int spare_fd = -1;
199 static struct ResRequest* requestListHead; /* head of resolver request list */
200 static struct ResRequest* requestListTail; /* tail of resolver request list */
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,
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,
216 struct ResRequest* request);
217 static void resend_query(struct ResRequest* request);
218 static struct ResRequest* find_id(int);
220 static struct resinfo {
235 * From bind 8.3, these aren't declared in earlier versions of bind
237 extern u_short _getshort(const u_char *);
238 extern u_int _getlong(const u_char *);
241 * res_isourserver(ina)
242 * looks up "ina" in _res.ns_addr_list[]
247 * paul vixie, 29may94
250 res_ourserver(const struct __res_state* statp, const struct sockaddr_in* inp)
252 struct sockaddr_in ina;
256 for (ns = 0; ns < statp->nscount; ns++) {
257 const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
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))
268 /* Socket callback for resolver */
269 static void res_callback(struct Event* ev)
271 assert(ev_type(ev) == ET_READ || ev_type(ev) == ET_ERROR);
277 * start_resolver - do everything we need to read the resolv.conf file
278 * and initialize the resolver file descriptor if needed
280 static void start_resolver(void)
282 Debug((DEBUG_DNS, "Resolver: start_resolver"));
284 * close the spare file descriptor so res_init can read resolv.conf
285 * successfully. Needed on Solaris
290 res_init(); /* res_init always returns 0 */
292 * make sure we have a valid file descriptor below 256 so we can
293 * do this again. Needed on Solaris
295 spare_fd = open("/dev/null",O_RDONLY,0);
296 if ((spare_fd < 0) || (spare_fd > 255)) {
298 ircd_snprintf(0, sparemsg, sizeof(sparemsg), "invalid spare_fd %d",
300 server_restart(sparemsg);
305 _res.nsaddr_list[0].sin_addr.s_addr = inet_addr("127.0.0.1");
307 _res.options |= RES_NOALIASES;
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);
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);
326 /* Call the query timeout function */
327 static void expire_DNS_callback(struct Event* ev)
331 next = timeout_query_list(CurrentTime);
333 timer_add(&resExpireDNS, expire_DNS_callback, 0, TT_ABSOLUTE, next);
337 * init_resolver - initialize resolver and resolver library
339 int init_resolver(void)
341 Debug((DEBUG_DNS, "Resolver: init_resolver"));
343 srand48(CurrentTime);
345 memset(&reinfo, 0, sizeof(reinfo));
346 requestListHead = requestListTail = 0;
348 /* initiate the resolver timers */
349 timer_add(timer_init(&resExpireDNS), expire_DNS_callback, 0,
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;
362 * restart_resolver - flush the cache, reread resolv.conf, reopen socket
364 void restart_resolver(void)
366 /* flush_cache(); flush the dns cache */
370 static int validate_hostent(const struct hostent* hp)
375 for (name = hp->h_name; name; name = hp->h_aliases[i++]) {
376 if (!string_is_hostname(name))
383 * add_request - place a new request in the request list
385 static void add_request(struct ResRequest* request)
387 assert(0 != request);
388 if (!requestListHead)
389 requestListHead = requestListTail = request;
391 requestListTail->next = request;
392 requestListTail = request;
394 request->next = NULL;
395 ++reinfo.re_requests;
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.
403 static void rem_request(struct ResRequest* request)
405 struct ResRequest** current;
406 struct ResRequest* prev = NULL;
408 assert(0 != request);
409 for (current = &requestListHead; *current; ) {
410 if (*current == request) {
411 *current = request->next;
412 if (requestListTail == request)
413 requestListTail = prev;
417 current = &(*current)->next;
419 MyFree(request->buf);
420 MyFree(request->name);
425 * make_request - Create a DNS request record for the server.
427 static struct ResRequest* make_request(const struct DNSQuery* query)
429 struct ResRequest* request;
431 request = (struct ResRequest*) MyMalloc(sizeof(struct ResRequest));
432 memset(request, 0, sizeof(struct ResRequest));
434 request->sentat = CurrentTime;
435 request->retries = feature_int(FEAT_IRCD_RES_RETRIES);
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;
444 add_request(request);
449 * timeout_query_list - Remove queries from the list which have been
450 * there too long without being resolved.
452 static time_t timeout_query_list(time_t now)
454 struct ResRequest* request;
455 struct ResRequest* next_request = 0;
456 time_t next_time = 0;
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;
464 if (--request->retries <= 0) {
465 ++reinfo.re_timeouts;
466 (*request->query.callback)(request->query.vptr, 0);
467 rem_request(request);
471 request->sentat = now;
472 request->timeout += request->timeout;
473 resend_query(request);
476 if (!next_time || timeout < next_time) {
480 return (next_time > now) ? next_time : (now + AR_TTL);
484 * timeout_resolver - check request list and cache for expired entries
486 time_t timeout_resolver(time_t now)
488 if (nextDNSCheck < now)
489 nextDNSCheck = timeout_query_list(now);
495 * delete_resolver_queries - cleanup outstanding queries
496 * for which there no longer exist clients or conf lines.
498 void delete_resolver_queries(const void* vptr)
500 struct ResRequest* request;
501 struct ResRequest* next_request;
503 for (request = requestListHead; request; request = next_request) {
504 next_request = request->next;
505 if (vptr == request->query.vptr)
506 rem_request(request);
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.
517 static int send_res_msg(const u_char* msg, int len, int rcount)
521 int max_queries = IRCD_MIN(_res.nscount, rcount);
525 * RES_PRIMARY option is not implemented
526 * if (_res.options & RES_PRIMARY || 0 == max_queries)
528 if (0 == max_queries)
531 Debug((DEBUG_DNS, "Resolver: sendto %d", max_queries));
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) {
541 log_write(LS_RESOLVER, L_ERROR, 0, "Resolver: send failed %m");
547 * find_id - find a dns request id (id is determined by dn_mkquery)
549 static struct ResRequest* find_id(int id)
551 struct ResRequest* request;
553 for (request = requestListHead; request; request = request->next) {
554 if (request->id == id)
561 * gethost_byname - get host address from name
563 void gethost_byname(const char* name, const struct DNSQuery* query)
567 Debug((DEBUG_DNS, "Resolver: gethost_byname %s", name));
570 if ((cp = find_cache_name(name)))
573 do_query_name(query, name, NULL);
578 * gethost_byaddr - get host name from address
580 void gethost_byaddr(const char* addr, const struct DNSQuery* query)
584 Debug((DEBUG_DNS, "Resolver: gethost_byaddr %s", ircd_ntoa(addr)));
587 do_query_number(query, (const struct in_addr*) addr, NULL);
592 * do_query_name - nameserver lookup name
594 static void do_query_name(const struct DNSQuery* query,
595 const char* name, struct ResRequest* request)
597 char hname[HOSTLEN + 1];
600 ircd_strncpy(hname, name, HOSTLEN);
601 hname[HOSTLEN] = '\0';
604 request = make_request(query);
606 request->name = (char*) MyMalloc(strlen(hname) + 1);
607 strcpy(request->name, hname);
609 query_name(hname, C_IN, T_A, request);
613 * do_query_number - Use this to do reverse IP# lookups.
615 static void do_query_number(const struct DNSQuery* query,
616 const struct in_addr* addr,
617 struct ResRequest* request)
620 const unsigned char* cp;
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]));
629 request = make_request(query);
630 request->type = T_PTR;
631 request->addr.s_addr = addr->s_addr;
633 query_name(ipbuf, C_IN, T_PTR, request);
637 * query_name - generate a query based on class, type and name.
639 static void query_name(const char* name, int query_class,
640 int type, struct ResRequest* request)
642 unsigned char buf[MAXPACKET + 1];
646 assert(0 != request);
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,
652 buf, sizeof(buf) - 1)) > 0) {
653 HEADER* header = (HEADER*) buf;
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
666 header->id = (header->id + lrand48()) & 0xffff;
667 } while (find_id(header->id));
669 gettimeofday(&tv, NULL);
671 header->id = (header->id + k + tv.tv_usec) & 0xffff;
673 } while (find_id(header->id));
675 request->id = header->id;
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);
683 static void resend_query(struct ResRequest* request)
687 if (request->resend == 0)
690 switch(request->type) {
692 do_query_number(NULL, &request->addr, request);
695 do_query_name(NULL, request->name, request);
703 * proc_answer - process name server reply
704 * build a hostent struct in the passed request
706 static int proc_answer(struct ResRequest* request, HEADER* header,
707 u_char* buf, u_char* eob)
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 */
733 current = buf + sizeof(HEADER);
736 * lazy allocation of request->he.buf, we don't allocate a buffer
737 * unless there is something to put in it.
740 request->buf = (char*) MyMalloc(MAXGETHOSTLEN + 1);
741 request->buf[MAXGETHOSTLEN] = '\0';
743 * array of alias list pointers starts at beginning of buf
745 hp->h_aliases = (char**) request->buf;
746 hp->h_aliases[0] = NULL;
748 * array of address list pointers starts after alias list pointers
749 * the actual addresses follow the the address list pointers
751 hp->h_addr_list = (char**)(request->buf + ALIAS_BLEN);
753 * don't copy the host address to the beginning of h_addr_list
755 hp->h_addr_list[0] = NULL;
757 endp = request->buf + MAXGETHOSTLEN;
759 * find the end of the address list
761 addr = hp->h_addr_list;
768 * make address point to first available address slot
770 address = request->buf + ADDRS_OFFSET +
771 (sizeof(struct in_addr) * addr_count);
772 base_address = address;
775 * find the end of the alias list
777 alias = hp->h_aliases;
783 * make name point to first available space in request->buf
785 if (alias_count > 0) {
786 name = hp->h_aliases[alias_count - 1];
787 name += (strlen(name) + 1);
790 name = hp->h_name + strlen(hp->h_name) + 1;
792 name = request->buf + ADDRS_OFFSET + ADDRS_DLEN;
797 while (header->qdcount-- > 0) {
798 if ((n = dn_skipname(current, eob)) < 0)
800 current += (n + QFIXEDSZ);
803 * process each answer sent to us blech.
805 while (header->ancount-- > 0 && current < eob && name < endp) {
806 n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
809 * no more answers left
813 hostbuf[HOSTLEN] = '\0';
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)
819 current += (size_t) n;
821 if (!((current + ANSWER_FIXED_SIZE) < eob))
824 type = _getshort(current);
825 current += TYPE_SIZE;
827 query_class = _getshort(current);
828 current += CLASS_SIZE;
830 request->ttl = _getlong(current);
833 rd_length = _getshort(current);
834 current += RDLENGTH_SIZE;
837 * Wait to set request->type until we verify this structure
842 * check for invalid rd_length or too many addresses
843 * ignore T_A relies if looking for a T_PTR
847 if (rd_length != sizeof(struct in_addr))
849 if (++addr_count < RES_MAXADDRS) {
850 if (answer_count == 1)
851 hp->h_addrtype = (query_class == C_IN) ? AF_INET : AF_UNSPEC;
853 memcpy(address, current, sizeof(struct in_addr));
856 address += sizeof(struct in_addr);
859 strcpy(name, hostbuf);
861 name += strlen(name) + 1;
863 Debug((DEBUG_DNS, "Resolver: A %s for %s",
864 ircd_ntoa((char*) hp->h_addr_list[addr_count - 1]), hostbuf));
866 current += rd_length;
874 address = base_address;
875 n = dn_expand(buf, eob, current, hostbuf, sizeof(hostbuf));
884 * no more answers left
889 * This comment is based on analysis by Shadowfax, Wohali and johan,
890 * not me. (Dianora) I am only commenting it.
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.
897 hostbuf[HOSTLEN] = '\0';
898 current += (size_t) n;
900 Debug((DEBUG_DNS, "Resolver: PTR %s", hostbuf));
902 * copy the returned hostname into the host name
903 * ignore duplicate ptr records
906 strcpy(name, hostbuf);
908 name += strlen(name) + 1;
913 Debug((DEBUG_DNS, "Resolver: CNAME %s", hostbuf));
914 if (++alias_count < RES_MAXALIASES) {
915 ircd_strncpy(name, hostbuf, endp - name);
918 name += strlen(name) + 1;
920 current += rd_length;
924 Debug((DEBUG_DNS,"Resolver: proc_answer type: %d for: %s", type, hostbuf));
932 * dup_hostent - Duplicate a hostent struct, allocate only enough memory for
933 * the data we're putting in it.
935 static struct hostent* dup_hostent(struct hostent* hp)
942 size_t bytes_needed = 0;
943 struct Hostent* new_hp = 0;
947 /* how much buffer do we need? */
948 bytes_needed += (strlen(hp->h_name) + 1);
952 bytes_needed += (strlen(*pp++) + 1 + sizeof(char*));
955 pp = hp->h_addr_list;
957 bytes_needed += (hp->h_length + sizeof(char*));
960 /* Reserve space for 2 nulls to terminate h_aliases and h_addr_list */
961 bytes_needed += (2 * sizeof(char*));
963 /* Allocate memory */
964 new_hp = (struct Hostent*) MyMalloc(sizeof(struct Hostent) + bytes_needed);
966 new_hp->h.h_addrtype = hp->h_addrtype;
967 new_hp->h.h_length = hp->h_length;
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*));
977 memcpy(p, *pp++, hp->h_length);
981 /* next write the name */
982 new_hp->h.h_name = p;
983 strcpy(p, hp->h_name);
984 p += (strlen(p) + 1);
986 /* last write the alias list */
988 ap = new_hp->h.h_aliases = (char**) new_hp->buf;
992 p += (strlen(p) + 1);
995 return (struct hostent*) new_hp;
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
1002 int resolver_read(void)
1004 unsigned char buf[sizeof(HEADER) + MAXPACKET];
1006 struct ResRequest* request = 0;
1007 unsigned int rc = 0;
1008 int answer_count = 0;
1009 struct sockaddr_in sin;
1011 Debug((DEBUG_DNS, "Resolver: read"));
1012 if (IO_SUCCESS != os_recvfrom_nonb(ResolverFileDescriptor,
1013 (char*) buf, sizeof(buf), &rc, &sin)) {
1016 if (rc < sizeof(HEADER)) {
1017 Debug((DEBUG_DNS, "Resolver: short reply %d: %s", rc,
1018 (strerror(errno)) ? strerror(errno) : "Unknown"));
1022 * convert DNS reply reader from Network byte order to CPU byte order.
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;
1032 * response for an id which we have already received an answer for
1033 * just ignore this response.
1035 if (0 == (request = find_id(header->id))) {
1036 Debug((DEBUG_DNS, "Resolver: can't find request id: %d", header->id));
1040 * check against possibly fake replies
1042 if (!res_ourserver(&_res, &sin)) {
1043 Debug((DEBUG_DNS, "Resolver: fake reply from: %s",
1044 (const char*) &sin.sin_addr));
1049 if ((header->rcode != NOERROR) || (header->ancount == 0)) {
1051 if (SERVFAIL == header->rcode)
1052 resend_query(request);
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
1061 switch (header->rcode) {
1063 Debug((DEBUG_DNS, "Fatal DNS error: No Error"));
1066 Debug((DEBUG_DNS, "Fatal DNS error: Format Error"));
1069 Debug((DEBUG_DNS, "Fatal DNS error: Server Failure"));
1072 Debug((DEBUG_DNS, "DNS error: Non Existant Domain"));
1075 Debug((DEBUG_DNS, "Fatal DNS error: Not Implemented"));
1078 Debug((DEBUG_DNS, "Fatal DNS error: Query Refused"));
1081 Debug((DEBUG_DNS, "Unassigned fatal DNS error: %i", header->rcode));
1084 #endif /* DEBUGMODE */
1085 (*request->query.callback)(request->query.vptr, 0);
1086 rem_request(request);
1091 * If this fails there was an error decoding the received packet,
1092 * try it again and hope it works the next time.
1094 answer_count = proc_answer(request, header, buf, buf + rc);
1096 struct hostent* hp = 0;
1097 if (T_PTR == request->type) {
1098 if (0 == request->he.h_name) {
1100 * got a PTR response with no name, something bogus is happening
1101 * don't bother trying again, the client address doesn't resolve
1103 (*request->query.callback)(request->query.vptr, hp);
1104 rem_request(request);
1107 Debug((DEBUG_DNS, "relookup %s <-> %s",
1108 request->he.h_name, ircd_ntoa((char*) &request->addr)));
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
1115 gethost_byname(request->he.h_name, &request->query);
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
1121 MyFree(requestListTail->buf);
1122 requestListTail->buf = request->buf;
1124 memcpy(&requestListTail->he, &request->he, sizeof(struct hostent));
1125 rem_request(request);
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.
1135 if (validate_hostent(&request->he))
1136 hp = dup_hostent(&request->he);
1137 (*request->query.callback)(request->query.vptr, hp);
1138 rem_request(request);
1141 else if (!request->sent) {
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
1146 (*request->query.callback)(request->query.vptr, 0);
1147 rem_request(request);
1153 * resolver_read_multiple - process up to count reads
1155 void resolver_read_multiple(int count)
1158 for ( ; i < count; ++i) {
1159 if (0 == resolver_read())
1165 * m_dns - dns status query
1167 int m_dns(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
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);
1182 size_t cres_mem(struct Client* sptr)
1184 struct ResRequest* request;
1185 size_t request_mem = 0;
1186 int request_count = 0;
1188 for (request = requestListHead; request; request = request->next) {
1189 request_mem += sizeof(struct ResRequest);
1191 request_mem += strlen(request->name) + 1;
1193 request_mem += MAXGETHOSTLEN + 1;
1197 send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG,
1198 ":Resolver: requests %d(%d)", request_count, request_mem);