X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=ircd%2Fircd_res.c;h=627e12e826fa813361d0a2737b7e8543aa383ec9;hb=refs%2Fheads%2Fupstream;hp=4946e4beae3d0b19866188c369bd82166f7325cf;hpb=a8461738cd722ccdafa0f6ad127578c84cb57046;p=ircu2.10.12-pk.git diff --git a/ircd/ircd_res.c b/ircd/ircd_res.c index 4946e4b..627e12e 100644 --- a/ircd/ircd_res.c +++ b/ircd/ircd_res.c @@ -1,14 +1,12 @@ /* - * A rewrite of Darren Reeds original res.c As there is nothing - * left of Darrens original code, this is now licensed by the hybrid group. + * A rewrite of Darren Reed's original res.c As there is nothing + * left of Darren's original code, this is now licensed by the hybrid group. * (Well, some of the function names are the same, and bits of the structs..) * You can use it where it is useful, free even. Buy us a beer and stuff. * * The authors takes no responsibility for any damage or loss * of property which results from the use of this software. * - * $Id$ - * * July 1999 - Rewrote a bunch of stuff here. Change hostent builder code, * added callbacks and reference counting of returned hostents. * --Bleep (Thomas Helvey ) @@ -18,6 +16,10 @@ * * Apr 28, 2003 --cryogen and Dianora */ +/** @file + * @brief IRC resolver functions. + * @version $Id$ + */ #include "client.h" #include "ircd_alloc.h" @@ -29,6 +31,7 @@ #include "ircd.h" #include "numeric.h" #include "fileio.h" /* for fbopen / fbclose / fbputs */ +#include "random.h" #include "s_bsd.h" #include "s_debug.h" #include "s_stats.h" @@ -37,7 +40,7 @@ #include "res.h" #include "ircd_reslib.h" -#include +/* #include -- Now using assert in ircd_log.h */ #include #include #include @@ -47,65 +50,87 @@ #error this code needs to be able to address individual octets #endif -static struct Socket res_socket; +/** IPv4 resolver UDP socket. */ +static struct Socket res_socket_v4; +/** IPv6 resolver UDP socket. */ +static struct Socket res_socket_v6; +/** Next DNS lookup timeout. */ static struct Timer res_timeout; - -#define MAXPACKET 1024 /* rfc sez 512 but we expand names so ... */ -#define RES_MAXALIASES 35 /* maximum aliases allowed */ -#define RES_MAXADDRS 35 /* maximum addresses allowed */ -#define AR_TTL 600 /* TTL in seconds for dns cache entries */ +/** Local address for IPv4 DNS lookups. */ +struct irc_sockaddr VirtualHost_dns_v4; +/** Local address for IPv6 DNS lookups. */ +struct irc_sockaddr VirtualHost_dns_v6; +/** Check for whether the resolver has been initialized yet. */ +#define resolver_started() (request_list.next != NULL) + +/** Maximum DNS packet length. + * RFC says 512, but we add extra for expanded names. + */ +#define MAXPACKET 1024 +#define AR_TTL 600 /**< TTL in seconds for dns cache entries */ /* RFC 1104/1105 wasn't very helpful about what these fields * should be named, so for now, we'll just name them this way. * we probably should look at what named calls them or something. */ +/** Size of TYPE field of a DNS RR header. */ #define TYPE_SIZE (size_t)2 +/** Size of CLASS field of a DNS RR header. */ #define CLASS_SIZE (size_t)2 +/** Size of TTL field of a DNS RR header. */ #define TTL_SIZE (size_t)4 +/** Size of RDLENGTH field of a DNS RR header. */ #define RDLENGTH_SIZE (size_t)2 +/** Size of fixed-format part of a DNS RR header. */ #define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE) -typedef enum +/** Current request state. */ +typedef enum { - REQ_IDLE, /* We're doing not much at all */ - REQ_PTR, /* Looking up a PTR */ - REQ_A, /* Looking up an A, possibly because AAAA failed */ - REQ_AAAA, /* Looking up an AAAA */ - REQ_CNAME, /* We got a CNAME in response, we better get a real answer next */ - REQ_INT /* ip6.arpa failed, falling back to ip6.int */ + REQ_IDLE, /**< We're doing not much at all. */ + REQ_PTR, /**< Looking up a PTR. */ + REQ_A, /**< Looking up an A, possibly because AAAA failed. */ + REQ_AAAA, /**< Looking up an AAAA. */ + REQ_CNAME, /**< We got a CNAME in response, we better get a real answer next. */ + REQ_INT /**< ip6.arpa failed, falling back to ip6.int. */ } request_state; +/** Doubly linked list node. */ struct dlink { - struct dlink *prev; - struct dlink *next; + struct dlink *prev; /**< Previous element in list. */ + struct dlink *next; /**< Next element in list. */ }; +/** A single resolver request. + * (Do not be fooled by the "list" in the name.) + */ struct reslist { - struct dlink node; - int id; - int sent; /* number of requests sent */ - request_state state; /* State the resolver machine is in */ - time_t ttl; - char type; - char retries; /* retry counter */ - char sends; /* number of sends (>1 means resent) */ - char resend; /* send flag. 0 == dont resend */ - time_t sentat; - time_t timeout; - struct irc_in_addr addr; - char *name; - struct DNSQuery query; /* query callback for this request */ + struct dlink node; /**< Doubly linked list node. */ + int id; /**< Request ID (from request header). */ + int sent; /**< Number of requests sent. */ + request_state state; /**< State the resolver machine is in. */ + char type; /**< Current request type. */ + char retries; /**< Retry counter. */ + char sends; /**< Number of sends (>1 means resent). */ + char resend; /**< Send flag; 0 == don't resend. */ + time_t sentat; /**< Timestamp we last sent this request. */ + time_t timeout; /**< When this request times out. */ + struct irc_in_addr addr; /**< Address for this request. */ + char *name; /**< Hostname for this request. */ + dns_callback_f callback; /**< Callback function on completion. */ + void *callback_ctx; /**< Context pointer for callback. */ }; +/** Base of request list. */ static struct dlink request_list; static void rem_request(struct reslist *request); -static struct reslist *make_request(const struct DNSQuery *query); -static void do_query_name(const struct DNSQuery *query, +static struct reslist *make_request(dns_callback_f callback, void *ctx); +static void do_query_name(dns_callback_f callback, void *ctx, const char* name, struct reslist *request, int); -static void do_query_number(const struct DNSQuery *query, +static void do_query_number(dns_callback_f callback, void *ctx, const struct irc_in_addr *, struct reslist *request); static void query_name(const char *name, int query_class, int query_type, @@ -114,7 +139,6 @@ static int send_res_msg(const char *buf, int len, int count); static void resend_query(struct reslist *request); static int proc_answer(struct reslist *request, HEADER *header, char *, char *); static struct reslist *find_id(int id); -static struct DNSReply *make_dnsreply(struct reslist *request); static void res_readreply(struct Event *ev); static void timeout_resolver(struct Event *notused); @@ -122,16 +146,19 @@ extern struct irc_sockaddr irc_nsaddr_list[IRCD_MAXNS]; extern int irc_nscount; extern char irc_domain[HOSTLEN]; -/* - * int - * res_ourserver(inp) - * looks up "inp" in irc_nsaddr_list[] - * returns: - * 0 : not found - * >0 : found - * author: - * paul vixie, 29may94 - * revised for ircd, cryogen(stu) may03 +/** Prepare the resolver library to (optionally) accept a list of + * DNS servers through add_dns_server(). + */ +void clear_nameservers(void) +{ + irc_nscount = 0; + memset(&VirtualHost_dns_v4, 0, sizeof(VirtualHost_dns_v4)); + memset(&VirtualHost_dns_v6, 0, sizeof(VirtualHost_dns_v6)); +} + +/** Check whether \a inp is a nameserver we use. + * @param[in] inp Nameserver address. + * @return Non-zero if we trust \a inp; zero if not. */ static int res_ourserver(const struct irc_sockaddr *inp) @@ -146,52 +173,59 @@ res_ourserver(const struct irc_sockaddr *inp) return(0); } -/* - * start_resolver - do everything we need to read the resolv.conf file - * and initialize the resolver file descriptor if needed +/** Start (or re-start) resolver. + * This means read resolv.conf, initialize the list of pending + * requests, open the resolver socket and initialize its timeout. */ -static void -start_resolver(void) +void +restart_resolver(void) { + int need_v4; + int need_v6; + int ns; + irc_res_init(); if (!request_list.next) request_list.next = request_list.prev = &request_list; - if (!s_active(&res_socket)) + /* Check which address family (or families) our nameservers use. */ + for (need_v4 = need_v6 = ns = 0; ns < irc_nscount; ns++) { - int fd; - fd = os_socket(NULL, SOCK_DGRAM, "Resolver UDP socket"); - if (fd < 0) return; - if (!socket_add(&res_socket, res_readreply, NULL, SS_DATAGRAM, - SOCK_EVENT_READABLE, fd)) return; - timer_init(&res_timeout); + if (irc_in_addr_is_ipv4(&irc_nsaddr_list[ns].addr)) + need_v4 = 1; + else + need_v6 = 1; } -} -/* - * init_resolver - initialize resolver and resolver library - */ -int -init_resolver(void) -{ - srand(CurrentTime); - start_resolver(); - return(s_fd(&res_socket)); -} + /* If we need an IPv4 socket, and don't have one, open it. */ + if (need_v4 && !s_active(&res_socket_v4)) + { + int fd = os_socket(&VirtualHost_dns_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET); + if (fd >= 0) + socket_add(&res_socket_v4, res_readreply, NULL, + SS_DATAGRAM, SOCK_EVENT_READABLE, fd); + } -/* - * restart_resolver - reread resolv.conf, reopen socket - */ -void -restart_resolver(void) -{ - start_resolver(); +#ifdef AF_INET6 + /* If we need an IPv6 socket, and don't have one, open it. */ + if (need_v6 && !s_active(&res_socket_v6)) + { + int fd = os_socket(&VirtualHost_dns_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6); + if (fd >= 0) + socket_add(&res_socket_v6, res_readreply, NULL, + SS_DATAGRAM, SOCK_EVENT_READABLE, fd); + } +#endif + + if (s_active(&res_socket_v4) || s_active(&res_socket_v6)) + timer_init(&res_timeout); } -/* - * add_local_domain - Add the domain to hostname, if it is missing - * (as suggested by eps@TOASTER.SFSU.EDU) +/** Append local domain to hostname if needed. + * If \a hname does not contain any '.'s, append #irc_domain to it. + * @param[in,out] hname Hostname to check. + * @param[in] size Length of \a hname buffer. */ void add_local_domain(char* hname, size_t size) @@ -213,8 +247,9 @@ add_local_domain(char* hname, size_t size) } } -/* - * add_dlink - add a link to a doubly linked list +/** Add a node to a doubly linked list. + * @param[in,out] node Node to add to list. + * @param[in,out] next Add \a node before this one. */ static void add_dlink(struct dlink *node, struct dlink *next) @@ -225,10 +260,8 @@ add_dlink(struct dlink *node, struct dlink *next) node->next->prev = node; } -/* - * rem_request - remove a request from the list. - * This must also free any memory that has been allocated for - * temporary storage of DNS results. +/** Remove a request from the list and free it. + * @param[in] request Node to free. */ static void rem_request(struct reslist *request) @@ -241,57 +274,66 @@ rem_request(struct reslist *request) MyFree(request); } -/* - * make_request - Create a DNS request record for the server. +/** Create a DNS request record for the server. + * @param[in] query Callback information for caller. + * @return Newly allocated and linked-in reslist. */ static struct reslist * -make_request(const struct DNSQuery* query) +make_request(dns_callback_f callback, void *ctx) { struct reslist *request; + if (!resolver_started()) + restart_resolver(); + request = (struct reslist *)MyMalloc(sizeof(struct reslist)); memset(request, 0, sizeof(struct reslist)); + request->state = REQ_IDLE; request->sentat = CurrentTime; request->retries = feature_int(FEAT_IRCD_RES_RETRIES); request->resend = 1; request->timeout = feature_int(FEAT_IRCD_RES_TIMEOUT); memset(&request->addr, 0, sizeof(request->addr)); - request->query.vptr = query->vptr; - request->query.callback = query->callback; - request->state = REQ_IDLE; + request->callback = callback; + request->callback_ctx = ctx; add_dlink(&request->node, &request_list); return(request); } -/* - * check_resolver_timeout - Make sure that a timeout event will - * happen by the given time. +/** Make sure that a timeout event will happen by the given time. + * @param[in] when Latest time for timeout to run. */ static void check_resolver_timeout(time_t when) { if (when > CurrentTime + AR_TTL) when = CurrentTime + AR_TTL; - if (!t_active(&res_timeout)) - timer_add(&res_timeout, timeout_resolver, NULL, TT_ABSOLUTE, when); - else if (when < t_expire(&res_timeout)) + /* TODO after 2.10.12: Rewrite the timer API because there should be + * no need for clients to know this kind of implementation detail. */ + if (when > t_expire(&res_timeout)) + /* do nothing */; + else if (t_onqueue(&res_timeout) && !(res_timeout.t_header.gh_flags & GEN_MARKED)) timer_chg(&res_timeout, TT_ABSOLUTE, when); + else + timer_add(&res_timeout, timeout_resolver, NULL, TT_ABSOLUTE, when); } -/* - * timeout_resolver - Remove queries from the list which have been - * there too long without being resolved. +/** Drop pending DNS lookups which have timed out. + * @param[in] ev Timer event data (ignored). */ static void -timeout_resolver(struct Event *notused) +timeout_resolver(struct Event *ev) { struct dlink *ptr, *next_ptr; struct reslist *request; time_t next_time = 0; time_t timeout = 0; + if (ev_type(ev) != ET_EXPIRE) + return; + for (ptr = request_list.next; ptr != &request_list; ptr = next_ptr) { next_ptr = ptr->next; @@ -303,7 +345,7 @@ timeout_resolver(struct Event *notused) if (--request->retries <= 0) { Debug((DEBUG_DNS, "Request %p out of retries; destroying", request)); - (*request->query.callback)(request->query.vptr, 0); + (*request->callback)(request->callback_ctx, NULL, NULL); rem_request(request); continue; } @@ -326,9 +368,10 @@ timeout_resolver(struct Event *notused) check_resolver_timeout(next_time); } -/* - * delete_resolver_queries - cleanup outstanding queries - * for which there no longer exist clients or conf lines. +/** Drop queries that are associated with a particular pointer. + * This is used to clean up lookups for clients or conf blocks + * that went away. + * @param[in] vptr User callback pointer to search for. */ void delete_resolver_queries(const void *vptr) @@ -336,23 +379,24 @@ delete_resolver_queries(const void *vptr) struct dlink *ptr, *next_ptr; struct reslist *request; - for (ptr = request_list.next; ptr != &request_list; ptr = next_ptr) - { - next_ptr = ptr->next; - request = (struct reslist*)ptr; - if (vptr == request->query.vptr) { - Debug((DEBUG_DNS, "Removing request %p with vptr %p", request, vptr)); - rem_request(request); + if (request_list.next) { + for (ptr = request_list.next; ptr != &request_list; ptr = next_ptr) + { + next_ptr = ptr->next; + request = (struct reslist*)ptr; + if (vptr == request->callback_ctx) { + Debug((DEBUG_DNS, "Removing request %p with vptr %p", request, vptr)); + rem_request(request); + } } } } -/* - * send_res_msg - sends msg to all nameservers found in the "_res" structure. - * This should reflect /etc/resolv.conf. We will get responses - * which arent needed but is easier than checking to see if nameserver - * isnt present. Returns number of messages successfully sent to - * nameservers or -1 if no successful sends. +/** Send a message to all of our nameservers. + * @param[in] msg Message to send. + * @param[in] len Length of message. + * @param[in] rcount Maximum number of servers to ask. + * @return Number of servers that were successfully asked. */ static int send_res_msg(const char *msg, int len, int rcount) @@ -367,15 +411,18 @@ send_res_msg(const char *msg, int len, int rcount) if (max_queries == 0) max_queries = 1; - for (i = 0; i < max_queries; i++) - if (os_sendto_nonb(s_fd(&res_socket), msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS) + for (i = 0; i < max_queries; i++) { + int fd = irc_in_addr_is_ipv4(&irc_nsaddr_list[i].addr) ? s_fd(&res_socket_v4) : s_fd(&res_socket_v6); + if (os_sendto_nonb(fd, msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS) ++sent; + } return(sent); } -/* - * find_id - find a dns request id (id is determined by dn_mkquery) +/** Find a DNS request by ID. + * @param[in] id Identifier to find. + * @return Matching DNS request, or NULL if none are found. */ static struct reslist * find_id(int id) @@ -397,29 +444,34 @@ find_id(int id) return(NULL); } -/* - * gethost_byname - wrapper for _type - send T_AAAA first +/** Try to look up address for a hostname, trying IPv6 (T_AAAA) first. + * @param[in] name Hostname to look up. + * @param[in] query Callback information. */ void -gethost_byname(const char *name, const struct DNSQuery *query) +gethost_byname(const char *name, dns_callback_f callback, void *ctx) { - do_query_name(query, name, NULL, T_AAAA); + do_query_name(callback, ctx, name, NULL, T_AAAA); } -/* - * gethost_byaddr - get host name from address +/** Try to look up hostname for an address. + * @param[in] addr Address to look up. + * @param[in] query Callback information. */ void -gethost_byaddr(const struct irc_in_addr *addr, const struct DNSQuery *query) +gethost_byaddr(const struct irc_in_addr *addr, dns_callback_f callback, void *ctx) { - do_query_number(query, addr, NULL); + do_query_number(callback, ctx, addr, NULL); } -/* - * do_query_name - nameserver lookup name +/** Send a query to look up the address for a name. + * @param[in] query Callback information. + * @param[in] name Hostname to look up. + * @param[in] request DNS lookup structure (may be NULL). + * @param[in] type Preferred request type. */ static void -do_query_name(const struct DNSQuery *query, const char *name, +do_query_name(dns_callback_f callback, void *ctx, const char *name, struct reslist *request, int type) { char host_name[HOSTLEN + 1]; @@ -429,10 +481,8 @@ do_query_name(const struct DNSQuery *query, const char *name, if (request == NULL) { - request = make_request(query); - request->name = (char *)MyMalloc(strlen(host_name) + 1); - request->type = type; - strcpy(request->name, host_name); + request = make_request(callback, ctx); + DupString(request->name, host_name); #ifdef IPV6 if (type != T_A) request->state = REQ_AAAA; @@ -446,11 +496,13 @@ do_query_name(const struct DNSQuery *query, const char *name, query_name(host_name, C_IN, type, request); } -/* - * do_query_number - Use this to do reverse IP# lookups. +/** Send a query to look up the name for an address. + * @param[in] query Callback information. + * @param[in] addr Address to look up. + * @param[in] request DNS lookup structure (may be NULL). */ static void -do_query_number(const struct DNSQuery *query, const struct irc_in_addr *addr, +do_query_number(dns_callback_f callback, void *ctx, const struct irc_in_addr *addr, struct reslist *request) { char ipbuf[128]; @@ -495,7 +547,8 @@ do_query_number(const struct DNSQuery *query, const struct irc_in_addr *addr, } if (request == NULL) { - request = make_request(query); + request = make_request(callback, ctx); + request->state= REQ_PTR; request->type = T_PTR; memcpy(&request->addr, addr, sizeof(request->addr)); request->name = (char *)MyMalloc(HOSTLEN + 1); @@ -504,8 +557,11 @@ do_query_number(const struct DNSQuery *query, const struct irc_in_addr *addr, query_name(ipbuf, C_IN, T_PTR, request); } -/* - * query_name - generate a query based on class, type and name. +/** Generate a query based on class, type and name. + * @param[in] name Domain name to look up. + * @param[in] query_class Query class (see RFC 1035). + * @param[in] type Query type (see RFC 1035). + * @param[in] request DNS request structure. */ static void query_name(const char *name, int query_class, int type, @@ -529,7 +585,7 @@ query_name(const char *name, int query_class, int type, */ do { - header->id = (header->id + rand()) & 0xffff; + header->id = (header->id + ircrandom()) & 0xffff; } while (find_id(header->id)); request->id = header->id; ++request->sends; @@ -539,6 +595,9 @@ query_name(const char *name, int query_class, int type, } } +/** Send a failed DNS lookup request again. + * @param[in] request Request to resend. + */ static void resend_query(struct reslist *request) { @@ -548,29 +607,32 @@ resend_query(struct reslist *request) switch(request->type) { case T_PTR: - do_query_number(NULL, &request->addr, request); + do_query_number(NULL, NULL, &request->addr, request); break; case T_A: - do_query_name(NULL, request->name, request, request->type); + do_query_name(NULL, NULL, request->name, request, request->type); break; case T_AAAA: - /* didnt work, try A */ + /* didn't work, try A */ if (request->state == REQ_AAAA) - do_query_name(NULL, request->name, request, T_A); + do_query_name(NULL, NULL, request->name, request, T_A); default: break; } } -/* - * proc_answer - process name server reply +/** Process the answer for a lookup request. + * @param[in] request DNS request that got an answer. + * @param[in] header Header of DNS response. + * @param[in] buf DNS response body. + * @param[in] eob Pointer to end of DNS response. + * @return Number of answers read from \a buf. */ static int proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob) { char hostbuf[HOSTLEN + 100]; /* working buffer */ unsigned char *current; /* current position in buf */ - int query_class; /* answer class */ int type; /* answer type */ int n; /* temp count */ int rd_length; @@ -624,10 +686,8 @@ proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob) type = irc_ns_get16(current); current += TYPE_SIZE; - query_class = irc_ns_get16(current); + /* We do not use the class or TTL values. */ current += CLASS_SIZE; - - request->ttl = irc_ns_get32(current); current += TTL_SIZE; rd_length = irc_ns_get16(current); @@ -673,11 +733,8 @@ proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob) return(1); break; - case T_CNAME: /* first check we already havent started looking + case T_CNAME: /* first check we already haven't started looking into a cname */ - if (request->type != T_PTR) - return(0); - if (request->state == REQ_CNAME) { n = irc_dn_expand((unsigned char *)buf, (unsigned char *)eob, @@ -697,7 +754,13 @@ proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob) * but its possible its just a broken nameserver with still * valid answers. But lets do some rudimentary logging for now... */ - log_write(LS_RESOLVER, L_ERROR, 0, "irc_res.c bogus type %d", type); + log_write(LS_RESOLVER, L_ERROR, 0, "irc_res.c bogus type %d", type); + + if ((char*)current + rd_length >= (char*)current) + current += rd_length; + else + return(0); + break; } } @@ -705,8 +768,8 @@ proc_answer(struct reslist *request, HEADER* header, char* buf, char* eob) return(1); } -/* - * res_readreply - read a dns reply from the nameserver and process it. +/** Read a DNS reply from the nameserver and process it. + * @param[in] ev I/O activity event for resolver socket. */ static void res_readreply(struct Event *ev) @@ -716,17 +779,22 @@ res_readreply(struct Event *ev) char buf[sizeof(HEADER) + MAXPACKET]; HEADER *header; struct reslist *request = NULL; - struct DNSReply *reply = NULL; unsigned int rc; int answer_count; - assert(ev_socket(ev) == &res_socket); + assert((ev_socket(ev) == &res_socket_v4) || (ev_socket(ev) == &res_socket_v6)); sock = ev_socket(ev); if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, sizeof(buf), &rc, &lsin) || (rc <= sizeof(HEADER))) return; + /* + * check against possibly fake replies + */ + if (!res_ourserver(&lsin)) + return; + /* * convert DNS reply reader from Network byte order to CPU byte order. */ @@ -743,20 +811,22 @@ res_readreply(struct Event *ev) if (0 == (request = find_id(header->id))) return; - /* - * check against possibly fake replies - */ - if (!res_ourserver(&lsin)) - return; - if ((header->rcode != NO_ERRORS) || (header->ancount == 0)) { - if (SERVFAIL == header->rcode) - resend_query(request); + if (SERVFAIL == header->rcode || NXDOMAIN == header->rcode) + { + /* + * If a bad error was returned, we stop here and don't send + * send any more (no retries granted). + */ + Debug((DEBUG_DNS, "Request %p has bad response (state %d type %d rcode %d)", request, request->state, request->type, header->rcode)); + (*request->callback)(request->callback_ctx, NULL, NULL); + rem_request(request); + } else { /* - * If we havent already tried this, and we're looking up AAAA, try A + * If we haven't already tried this, and we're looking up AAAA, try A * now */ @@ -772,16 +842,6 @@ res_readreply(struct Event *ev) request->timeout += feature_int(FEAT_IRCD_RES_TIMEOUT); resend_query(request); } - else - { - /* - * If a bad error was returned, we stop here and dont send - * send any more (no retries granted). - */ - Debug((DEBUG_DNS, "Request %p has bad response (state %d type %d)", request, request->state, request->type)); - (*request->query.callback)(request->query.vptr, 0); - rem_request(request); - } } return; @@ -803,7 +863,7 @@ res_readreply(struct Event *ev) * don't bother trying again, the client address doesn't resolve */ Debug((DEBUG_DNS, "Request %p PTR had empty name", request)); - (*request->query.callback)(request->query.vptr, reply); + (*request->callback)(request->callback_ctx, NULL, NULL); rem_request(request); return; } @@ -814,10 +874,10 @@ res_readreply(struct Event *ev) */ #ifdef IPV6 if (!irc_in_addr_is_ipv4(&request->addr)) - do_query_name(&request->query, request->name, NULL, T_AAAA); + do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_AAAA); else #endif - do_query_name(&request->query, request->name, NULL, T_A); + do_query_name(request->callback, request->callback_ctx, request->name, NULL, T_A); Debug((DEBUG_DNS, "Request %p switching to forward resolution", request)); rem_request(request); } @@ -826,8 +886,7 @@ res_readreply(struct Event *ev) /* * got a name and address response, client resolved */ - reply = make_dnsreply(request); - (*request->query.callback)(request->query.vptr, (reply) ? reply : 0); + (*request->callback)(request->callback_ctx, &request->addr, request->name); Debug((DEBUG_DNS, "Request %p got forward resolution", request)); rem_request(request); } @@ -845,19 +904,11 @@ res_readreply(struct Event *ev) } } -static struct DNSReply * -make_dnsreply(struct reslist *request) -{ - struct DNSReply *cp; - assert(request != 0); - - cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply)); - - DupString(cp->h_name, request->name); - memcpy(&cp->addr, &request->addr, sizeof(cp->addr)); - return(cp); -} - +/** Statistics callback to list DNS servers. + * @param[in] source_p Client requesting statistics. + * @param[in] sd Stats descriptor for request (ignored). + * @param[in] param Extra parameter from user (ignored). + */ void report_dns_servers(struct Client *source_p, const struct StatDesc *sd, char *param) { @@ -871,6 +922,10 @@ report_dns_servers(struct Client *source_p, const struct StatDesc *sd, char *par } } +/** Report memory usage to a client. + * @param[in] sptr Client requesting information. + * @return Total memory used by pending requests. + */ size_t cres_mem(struct Client* sptr) { @@ -879,53 +934,17 @@ cres_mem(struct Client* sptr) size_t request_mem = 0; int request_count = 0; - for (dlink = request_list.next; dlink != &request_list; dlink = dlink->next) { - request = (struct reslist*)dlink; - request_mem += sizeof(*request); - if (request->name) - request_mem += strlen(request->name) + 1; - ++request_count; + if (request_list.next) { + for (dlink = request_list.next; dlink != &request_list; dlink = dlink->next) { + request = (struct reslist*)dlink; + request_mem += sizeof(*request); + if (request->name) + request_mem += strlen(request->name) + 1; + ++request_count; + } } send_reply(sptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Resolver: requests %d(%d)", request_count, request_mem); return request_mem; } - -int irc_in_addr_valid(const struct irc_in_addr *addr) -{ - unsigned int ii; - unsigned short val; - - val = addr->in6_16[0]; - if (val != 0 || val != 0xffff) - return 1; - for (ii = 1; ii < 8; ii++) - if (addr->in6_16[ii] != val) - return 1; - return 0; -} - -int irc_in_addr_cmp(const struct irc_in_addr *a, const struct irc_in_addr *b) -{ - if (irc_in_addr_is_ipv4(a)) - return a->in6_16[6] != b->in6_16[6] - || a->in6_16[7] != b->in6_16[7] - || !irc_in_addr_is_ipv4(b); - else - return memcmp(a, b, sizeof(*a)); -} - -int irc_in_addr_is_loopback(const struct irc_in_addr *addr) -{ - if (addr->in6_16[0] != 0 - || addr->in6_16[1] != 0 - || addr->in6_16[2] != 0 - || addr->in6_16[3] != 0 - || addr->in6_16[4] != 0) - return 0; - if ((addr->in6_16[5] == 0xffff) || (addr->in6_16[5] == 0 && addr->in6_16[6] != 0)) - return (ntohs(addr->in6_16[6]) & 0xff00) == 0x7f00; - else - return addr->in6_16[5] == 0 && addr->in6_16[6] == 0 && htons(addr->in6_16[7]) == 1; -}