* --Bleep (Thomas Helvey <tomh@inxpress.net>)
*
* This was all needlessly complicated for irc. Simplified. No more hostent
- * All we really care about is the IP -> hostname mappings. Thats all.
+ * All we really care about is the IP -> hostname mappings. Thats all.
*
* Apr 28, 2003 --cryogen and Dianora
*
* removed, various robustness fixes
*
* 2006 --jilles and nenolod
+ *
+ * Resend queries to other servers if the DNS server replies with an error or
+ * an invalid response. Also, avoid servers that return errors or invalid
+ * responses.
+ *
+ * October 2012 --mr_flea
*/
#include "stdinc.h"
#include "ircd_defs.h"
#include "common.h"
#include "ircd.h"
-#include "commio.h"
#include "res.h"
#include "reslib.h"
-#include "tools.h"
-#include "event.h"
-#include "irc_string.h"
-#include "sprintf_irc.h"
+#include "match.h"
#include "numeric.h"
#include "client.h" /* SNO_* */
+#include "s_assert.h"
+#include "logger.h"
+#include "send.h"
#if (CHAR_BIT != 8)
#error this code needs to be able to address individual octets
#define RDLENGTH_SIZE (size_t)2
#define ANSWER_FIXED_SIZE (TYPE_SIZE + CLASS_SIZE + TTL_SIZE + RDLENGTH_SIZE)
-typedef enum
-{
- REQ_IDLE, /* We're doing not much at all */
- REQ_PTR, /* Looking up a PTR */
- REQ_A, /* Looking up an A or AAAA */
- REQ_CNAME /* We got a CNAME in response, we better get a real answer next */
-} request_state;
-
struct reslist
{
- dlink_node node;
+ rb_dlink_node node;
int id;
- int sent; /* number of requests sent */
- request_state state; /* State the resolver machine is in */
time_t ttl;
char type;
- char queryname[128]; /* name currently being queried */
+ char queryname[IRCD_RES_HOSTLEN + 1]; /* name currently being queried */
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_sockaddr_storage addr;
+ unsigned int lastns; /* index of last server sent to */
+ struct rb_sockaddr_storage addr;
char *name;
struct DNSQuery *query; /* query callback for this request */
};
-static int res_fd;
-static dlink_list request_list = { NULL, NULL, 0 };
+static rb_fde_t *res_fd;
+static rb_dlink_list request_list = { NULL, NULL, 0 };
+static int ns_failure_count[IRCD_MAXNS]; /* timeouts and invalid/failed replies */
static void rem_request(struct reslist *request);
static struct reslist *make_request(struct DNSQuery *query);
+static void gethost_byname_type_fqdn(const char *name, struct DNSQuery *query,
+ int type);
static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request, int);
-static void do_query_number(struct DNSQuery *query, const struct irc_sockaddr_storage *,
+static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *,
struct reslist *request);
static void query_name(struct reslist *request);
static int send_res_msg(const char *buf, int len, int count);
static struct reslist *find_id(int id);
static struct DNSReply *make_dnsreply(struct reslist *request);
-extern struct irc_sockaddr_storage irc_nsaddr_list[IRCD_MAXNS];
-extern int irc_nscount;
-extern char irc_domain[HOSTLEN + 1];
-
-
/*
* int
* res_ourserver(inp)
* looks up "inp" in irc_nsaddr_list[]
* returns:
- * 0 : not found
- * >0 : found
+ * server ID or -1 for not found
* author:
* paul vixie, 29may94
* revised for ircd, cryogen(stu) may03
+ * slightly modified for charybdis, mr_flea oct12
*/
-static int res_ourserver(const struct irc_sockaddr_storage *inp)
+static int res_ourserver(const struct rb_sockaddr_storage *inp)
{
-#ifdef IPV6
- struct sockaddr_in6 *v6;
- struct sockaddr_in6 *v6in = (struct sockaddr_in6 *)inp;
+#ifdef RB_IPV6
+ const struct sockaddr_in6 *v6;
+ const struct sockaddr_in6 *v6in = (const struct sockaddr_in6 *)inp;
#endif
- struct sockaddr_in *v4;
- struct sockaddr_in *v4in = (struct sockaddr_in *)inp;
+ const struct sockaddr_in *v4;
+ const struct sockaddr_in *v4in = (const struct sockaddr_in *)inp;
int ns;
for (ns = 0; ns < irc_nscount; ns++)
{
- const struct irc_sockaddr_storage *srv = &irc_nsaddr_list[ns];
-#ifdef IPV6
- v6 = (struct sockaddr_in6 *)srv;
+ const struct rb_sockaddr_storage *srv = &irc_nsaddr_list[ns];
+
+ if (srv->ss_family != inp->ss_family)
+ continue;
+
+#ifdef RB_IPV6
+ v6 = (const struct sockaddr_in6 *)srv;
#endif
- v4 = (struct sockaddr_in *)srv;
+ v4 = (const struct sockaddr_in *)srv;
/* could probably just memcmp(srv, inp, srv.ss_len) here
- * but we'll air on the side of caution - stu
+ * but we'll err on the side of caution - stu
*/
switch (srv->ss_family)
{
-#ifdef IPV6
- case AF_INET6:
- if (srv->ss_family == inp->ss_family)
- if (v6->sin6_port == v6in->sin6_port)
- if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
- sizeof(struct in6_addr)) == 0) ||
- (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
- sizeof(struct in6_addr)) == 0))
- return 1;
- break;
+#ifdef RB_IPV6
+ case AF_INET6:
+ if (v6->sin6_port == v6in->sin6_port)
+ if ((memcmp(&v6->sin6_addr.s6_addr, &v6in->sin6_addr.s6_addr,
+ sizeof(struct in6_addr)) == 0) ||
+ (memcmp(&v6->sin6_addr.s6_addr, &in6addr_any,
+ sizeof(struct in6_addr)) == 0))
+ {
+ return ns;
+ }
+ break;
#endif
- case AF_INET:
- if (srv->ss_family == inp->ss_family)
- if (v4->sin_port == v4in->sin_port)
- if ((v4->sin_addr.s_addr == INADDR_ANY)
- || (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
- return 1;
- break;
- default:
- break;
+ case AF_INET:
+ if (v4->sin_port == v4in->sin_port)
+ if ((v4->sin_addr.s_addr == INADDR_ANY)
+ || (v4->sin_addr.s_addr == v4in->sin_addr.s_addr))
+ {
+ return ns;
+ }
+ break;
+ default:
+ break;
}
}
- return 0;
+ return -1;
}
/*
- * timeout_query_list - Remove queries from the list which have been
+ * timeout_query_list - Remove queries from the list which have been
* there too long without being resolved.
*/
static time_t timeout_query_list(time_t now)
{
- dlink_node *ptr;
- dlink_node *next_ptr;
+ rb_dlink_node *ptr;
+ rb_dlink_node *next_ptr;
struct reslist *request;
time_t next_time = 0;
time_t timeout = 0;
- DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
+ RB_DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
{
request = ptr->data;
timeout = request->sentat + request->timeout;
if (now >= timeout)
{
- if (--request->retries <= 0)
- {
- (*request->query->callback) (request->query->ptr, NULL);
- rem_request(request);
- continue;
- }
- else
- {
- request->sentat = now;
- request->timeout += request->timeout;
- resend_query(request);
- }
+ ns_failure_count[request->lastns]++;
+ request->sentat = now;
+ request->timeout += request->timeout;
+ resend_query(request);
}
if ((next_time == 0) || timeout < next_time)
*/
static void timeout_resolver(void *notused)
{
- timeout_query_list(CurrentTime);
+ timeout_query_list(rb_current_time());
}
+static struct ev_entry *timeout_resolver_ev = NULL;
+
/*
* start_resolver - do everything we need to read the resolv.conf file
* and initialize the resolver file descriptor if needed
*/
static void start_resolver(void)
{
+ int i;
+
irc_res_init();
+ for (i = 0; i < irc_nscount; i++)
+ ns_failure_count[i] = 0;
- if (res_fd <= 0) /* there isn't any such thing as fd 0, that's just a myth. */
+ if (res_fd == NULL)
{
if ((res_fd = rb_socket(irc_nsaddr_list[0].ss_family, SOCK_DGRAM, 0,
- "UDP resolver socket")) == -1)
+ "UDP resolver socket")) == NULL)
return;
/* At the moment, the resolver FD data is global .. */
- rb_setselect(res_fd, FDLIST_NONE, COMM_SELECT_READ, res_readreply, NULL, 0);
- eventAdd("timeout_resolver", timeout_resolver, NULL, 1);
+ rb_setselect(res_fd, RB_SELECT_READ, res_readreply, NULL);
+ timeout_resolver_ev = rb_event_add("timeout_resolver", timeout_resolver, NULL, 1);
}
}
void init_resolver(void)
{
#ifdef HAVE_SRAND48
- srand48(CurrentTime);
+ srand48(rb_current_time());
#endif
start_resolver();
}
void restart_resolver(void)
{
rb_close(res_fd);
- res_fd = -1;
- eventDelete(timeout_resolver, NULL); /* -ddosen */
+ res_fd = NULL;
+ rb_event_delete(timeout_resolver_ev); /* -ddosen */
start_resolver();
}
}
/*
- * rem_request - remove a request from the list.
- * This must also free any memory that has been allocated for
+ * rem_request - remove a request from the list.
+ * This must also free any memory that has been allocated for
* temporary storage of DNS results.
*/
static void rem_request(struct reslist *request)
{
- dlinkDelete(&request->node, &request_list);
- MyFree(request->name);
- MyFree(request);
+ rb_dlinkDelete(&request->node, &request_list);
+ rb_free(request->name);
+ rb_free(request);
}
/*
*/
static struct reslist *make_request(struct DNSQuery *query)
{
- struct reslist *request = MyMalloc(sizeof(struct reslist));
+ struct reslist *request = rb_malloc(sizeof(struct reslist));
- request->sentat = CurrentTime;
+ request->sentat = rb_current_time();
request->retries = 3;
- request->resend = 1;
request->timeout = 4; /* start at 4 and exponential inc. */
request->query = query;
- request->state = REQ_IDLE;
- dlinkAdd(request, &request->node, &request_list);
+ /*
+ * generate a unique id
+ * NOTE: we don't have to worry about converting this to and from
+ * network byte order, the nameserver does not interpret this value
+ * and returns it unchanged
+ *
+ * we generate an id per request now (instead of per send) to allow
+ * late replies to be used.
+ */
+#ifdef HAVE_LRAND48
+ do
+ {
+ request->id = (request->id + lrand48()) & 0xffff;
+ } while (find_id(request->id));
+#else
+ int k = 0;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ do
+ {
+ request->id = (request->id + k + tv.tv_usec) & 0xffff;
+ k++;
+ } while (find_id(request->id));
+#endif /* HAVE_LRAND48 */
+
+ rb_dlinkAdd(request, &request->node, &request_list);
return request;
}
/*
- * delete_resolver_queries - cleanup outstanding queries
+ * delete_resolver_queries - cleanup outstanding queries
* for which there no longer exist clients or conf lines.
*/
void delete_resolver_queries(const struct DNSQuery *query)
{
- dlink_node *ptr;
- dlink_node *next_ptr;
+ rb_dlink_node *ptr;
+ rb_dlink_node *next_ptr;
struct reslist *request;
- DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
+ RB_DLINK_FOREACH_SAFE(ptr, next_ptr, request_list.head)
{
if ((request = ptr->data) != NULL)
{
}
/*
- * 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.
+ * retryfreq - determine how many queries to wait before resending
+ * if there have been that many consecutive timeouts
+ */
+static int retryfreq(int timeouts)
+{
+ switch (timeouts)
+ {
+ case 1:
+ return 3;
+ case 2:
+ return 9;
+ case 3:
+ return 27;
+ case 4:
+ return 81;
+ default:
+ return 243;
+ }
+}
+
+/*
+ * send_res_msg - sends msg to a nameserver.
+ * This should reflect /etc/resolv.conf.
+ * Returns number of nameserver successfully sent to
+ * or -1 if no successful sends.
*/
static int send_res_msg(const char *msg, int len, int rcount)
{
int i;
- int sent = 0;
- int max_queries = IRCD_MIN(irc_nscount, rcount);
+ int ns;
+ static int retrycnt;
- /* RES_PRIMARY option is not implemented
- * if (res.options & RES_PRIMARY || 0 == max_queries)
+ retrycnt++;
+ /* First try a nameserver that seems to work.
+ * Every once in a while, try a possibly broken one to check
+ * if it is working again.
*/
- if (max_queries == 0)
- max_queries = 1;
+ for (i = 0; i < irc_nscount; i++)
+ {
+ ns = (i + rcount - 1) % irc_nscount;
+ if (ns_failure_count[ns] && retrycnt % retryfreq(ns_failure_count[ns]))
+ continue;
+ if (sendto(rb_get_fd(res_fd), msg, len, 0,
+ (struct sockaddr *)&(irc_nsaddr_list[ns]),
+ GET_SS_LEN(&irc_nsaddr_list[ns])) == len)
+ return ns;
+ }
- for (i = 0; sent < max_queries && i < irc_nscount; i++)
+ /* No known working nameservers, try some broken one. */
+ for (i = 0; i < irc_nscount; i++)
{
- if (sendto(res_fd, msg, len, 0,
- (struct sockaddr *)&(irc_nsaddr_list[i]),
- GET_SS_LEN(irc_nsaddr_list[i])) == len)
- ++sent;
+ ns = (i + rcount - 1) % irc_nscount;
+ if (!ns_failure_count[ns])
+ continue;
+ if (sendto(rb_get_fd(res_fd), msg, len, 0,
+ (struct sockaddr *)&(irc_nsaddr_list[ns]),
+ GET_SS_LEN(&irc_nsaddr_list[ns])) == len)
+ return ns;
}
- return (sent);
+ return -1;
}
/*
*/
static struct reslist *find_id(int id)
{
- dlink_node *ptr;
+ rb_dlink_node *ptr;
struct reslist *request;
- DLINK_FOREACH(ptr, request_list.head)
+ RB_DLINK_FOREACH(ptr, request_list.head)
{
request = ptr->data;
return (NULL);
}
-/*
- * gethost_byname_type - get host address from name
- *
+/*
+ * gethost_byname_type - get host address from name, adding domain if needed
*/
void gethost_byname_type(const char *name, struct DNSQuery *query, int type)
+{
+ char fqdn[IRCD_RES_HOSTLEN + 1];
+ assert(name != 0);
+
+ rb_strlcpy(fqdn, name, sizeof fqdn);
+ add_local_domain(fqdn, IRCD_RES_HOSTLEN);
+ gethost_byname_type_fqdn(fqdn, query, type);
+}
+
+/*
+ * gethost_byname_type_fqdn - get host address from fqdn
+ */
+static void gethost_byname_type_fqdn(const char *name, struct DNSQuery *query,
+ int type)
{
assert(name != 0);
do_query_name(query, name, NULL, type);
/*
* gethost_byaddr - get host name from address
*/
-void gethost_byaddr(const struct irc_sockaddr_storage *addr, struct DNSQuery *query)
+void gethost_byaddr(const struct rb_sockaddr_storage *addr, struct DNSQuery *query)
{
do_query_number(query, addr, NULL);
}
static void do_query_name(struct DNSQuery *query, const char *name, struct reslist *request,
int type)
{
- char host_name[HOSTLEN + 1];
-
- strlcpy(host_name, name, HOSTLEN + 1);
- add_local_domain(host_name, HOSTLEN);
-
if (request == NULL)
{
request = make_request(query);
- request->name = (char *)MyMalloc(strlen(host_name) + 1);
- strcpy(request->name, host_name);
- request->state = REQ_A;
+ request->name = rb_strdup(name);
}
- strlcpy(request->queryname, host_name, sizeof(request->queryname));
+ rb_strlcpy(request->queryname, name, sizeof(request->queryname));
request->type = type;
query_name(request);
}
/*
* do_query_number - Use this to do reverse IP# lookups.
*/
-static void do_query_number(struct DNSQuery *query, const struct irc_sockaddr_storage *addr,
+static void do_query_number(struct DNSQuery *query, const struct rb_sockaddr_storage *addr,
struct reslist *request)
{
const unsigned char *cp;
if (request == NULL)
{
request = make_request(query);
- memcpy(&request->addr, addr, sizeof(struct irc_sockaddr_storage));
- request->name = (char *)MyMalloc(HOSTLEN + 1);
+ memcpy(&request->addr, addr, sizeof(struct rb_sockaddr_storage));
+ request->name = (char *)rb_malloc(IRCD_RES_HOSTLEN + 1);
}
if (addr->ss_family == AF_INET)
{
- struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
+ const struct sockaddr_in *v4 = (const struct sockaddr_in *)addr;
cp = (const unsigned char *)&v4->sin_addr.s_addr;
rb_sprintf(request->queryname, "%u.%u.%u.%u.in-addr.arpa", (unsigned int)(cp[3]),
(unsigned int)(cp[2]), (unsigned int)(cp[1]), (unsigned int)(cp[0]));
}
-#ifdef IPV6
+#ifdef RB_IPV6
else if (addr->ss_family == AF_INET6)
{
- struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
+ const struct sockaddr_in6 *v6 = (const struct sockaddr_in6 *)addr;
cp = (const unsigned char *)&v6->sin6_addr.s6_addr;
(void)sprintf(request->queryname, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x."
{
char buf[MAXPACKET];
int request_len = 0;
+ int ns;
memset(buf, 0, sizeof(buf));
irc_res_mkquery(request->queryname, C_IN, request->type, (unsigned char *)buf, sizeof(buf))) > 0)
{
HEADER *header = (HEADER *) buf;
-#ifndef HAVE_LRAND48
- int k = 0;
- struct timeval tv;
-#endif
- /*
- * generate an unique id
- * NOTE: we don't have to worry about converting this to and from
- * network byte order, the nameserver does not interpret this value
- * and returns it unchanged
- */
-#ifdef HAVE_LRAND48
- do
- {
- header->id = (header->id + lrand48()) & 0xffff;
- } while (find_id(header->id));
-#else
- gettimeofday(&tv, NULL);
- do
- {
- header->id = (header->id + k + tv.tv_usec) & 0xffff;
- k++;
- } while (find_id(header->id));
-#endif /* HAVE_LRAND48 */
- request->id = header->id;
+ header->id = request->id;
++request->sends;
- request->sent += send_res_msg(buf, request_len, request->sends);
+ ns = send_res_msg(buf, request_len, request->sends);
+ if (ns != -1)
+ request->lastns = ns;
}
}
static void resend_query(struct reslist *request)
{
- if (request->resend == 0)
+ if (--request->retries <= 0)
+ {
+ (*request->query->callback) (request->query->ptr, NULL);
+ rem_request(request);
return;
+ }
switch (request->type)
{
do_query_number(NULL, &request->addr, request);
break;
case T_A:
-#ifdef IPV6
+#ifdef RB_IPV6
case T_AAAA:
#endif
do_query_name(NULL, request->name, request, request->type);
*/
static int check_question(struct reslist *request, HEADER * header, char *buf, char *eob)
{
- char hostbuf[128]; /* working buffer */
+ char hostbuf[IRCD_RES_HOSTLEN + 1]; /* working buffer */
unsigned char *current; /* current position in buf */
int n; /* temp count */
*/
static int proc_answer(struct reslist *request, HEADER * header, char *buf, char *eob)
{
- char hostbuf[HOSTLEN + 100]; /* working buffer */
+ char hostbuf[IRCD_RES_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;
struct sockaddr_in *v4; /* conversion */
-#ifdef IPV6
+#ifdef RB_IPV6
struct sockaddr_in6 *v6;
#endif
current = (unsigned char *)buf + sizeof(HEADER);
return (0);
}
- hostbuf[HOSTLEN] = '\0';
+ hostbuf[IRCD_RES_HOSTLEN] = '\0';
/* With Address arithmetic you have to be very anal
* this code was not working on alpha due to that
rd_length = irc_ns_get16(current);
current += RDLENGTH_SIZE;
- /*
- * Wait to set request->type until we verify this structure
+ /*
+ * Wait to set request->type until we verify this structure
*/
switch (type)
{
if (rd_length != sizeof(struct in_addr))
return (0);
v4 = (struct sockaddr_in *)&request->addr;
- SET_SS_LEN(request->addr, sizeof(struct sockaddr_in));
+ SET_SS_LEN(&request->addr, sizeof(struct sockaddr_in));
v4->sin_family = AF_INET;
memcpy(&v4->sin_addr, current, sizeof(struct in_addr));
return (1);
break;
-#ifdef IPV6
+#ifdef RB_IPV6
case T_AAAA:
if (request->type != T_AAAA)
return (0);
if (rd_length != sizeof(struct in6_addr))
return (0);
- SET_SS_LEN(request->addr, sizeof(struct sockaddr_in6));
+ SET_SS_LEN(&request->addr, sizeof(struct sockaddr_in6));
v6 = (struct sockaddr_in6 *)&request->addr;
v6->sin6_family = AF_INET6;
memcpy(&v6->sin6_addr, current, sizeof(struct in6_addr));
else if (n == 0)
return (0); /* no more answers left */
- strlcpy(request->name, hostbuf, HOSTLEN + 1);
+ rb_strlcpy(request->name, hostbuf, IRCD_RES_HOSTLEN + 1);
return (1);
break;
- case T_CNAME: /* first check we already havent 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,
- current, hostbuf, sizeof(hostbuf));
-
- if (n < 0)
- return (0);
- return (1);
- }
-
- request->state = REQ_CNAME;
+ case T_CNAME:
+ /* real answer will follow */
current += rd_length;
break;
}
/*
- * res_readreply - read a dns reply from the nameserver and process it.
+ * res_read_single_reply - read a dns reply from the nameserver and process it.
+ * Return value: 1 if a packet was read, 0 otherwise
*/
-static void res_readreply(int fd, void *data)
+static int res_read_single_reply(rb_fde_t *F, void *data)
{
char buf[sizeof(HEADER) + MAXPACKET]
- /* Sparc and alpha need 16bit-alignment for accessing header->id
- * (which is uint16_t). Because of the header = (HEADER*) buf;
+ /* Sparc and alpha need 16bit-alignment for accessing header->id
+ * (which is uint16_t). Because of the header = (HEADER*) buf;
* lateron, this is neeeded. --FaUl
*/
#if defined(__sparc__) || defined(__alpha__)
struct DNSReply *reply = NULL;
int rc;
int answer_count;
- socklen_t len = sizeof(struct irc_sockaddr_storage);
- struct irc_sockaddr_storage lsin;
+ socklen_t len = sizeof(struct rb_sockaddr_storage);
+ struct rb_sockaddr_storage lsin;
+ int ns;
- rc = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
+ rc = recvfrom(rb_get_fd(F), buf, sizeof(buf), 0, (struct sockaddr *)&lsin, &len);
- /* Re-schedule a read *after* recvfrom, or we'll be registering
- * interest where it'll instantly be ready for read :-) -- adrian
- */
- rb_setselect(fd, FDLIST_NONE, COMM_SELECT_READ, res_readreply, NULL, 0);
- /* Better to cast the sizeof instead of rc */
+ /* No packet */
+ if (rc == 0 || rc == -1)
+ return 0;
+
+ /* Too small */
if (rc <= (int)(sizeof(HEADER)))
- return;
+ return 1;
/*
* convert DNS reply reader from Network byte order to CPU byte order.
* just ignore this response.
*/
if (0 == (request = find_id(header->id)))
- return;
+ return 1;
/*
* check against possibly fake replies
*/
- if (!res_ourserver(&lsin))
- return;
+ ns = res_ourserver(&lsin);
+ if (ns == -1)
+ return 1;
+
+ if (ns != request->lastns)
+ {
+ /*
+ * We'll accept the late reply, but penalize it a little more to make
+ * sure a laggy server doesn't end up favored.
+ */
+ ns_failure_count[ns] += 3;
+ }
+
if (!check_question(request, header, buf, buf + rc))
- return;
+ return 1;
if ((header->rcode != NO_ERRORS) || (header->ancount == 0))
{
- if (NXDOMAIN == header->rcode)
+ /*
+ * RFC 2136 states that in the event of a server returning SERVFAIL
+ * or NOTIMP, the request should be resent to the next server.
+ * Additionally, if the server refuses our query, resend it as well.
+ * -- mr_flea
+ */
+ if (SERVFAIL == header->rcode || NOTIMP == header->rcode ||
+ REFUSED == header->rcode)
{
- (*request->query->callback) (request->query->ptr, NULL);
- rem_request(request);
+ ns_failure_count[ns]++;
+ resend_query(request);
}
else
{
/*
- * If a bad error was returned, we stop here and dont send
- * send any more (no retries granted).
+ * Either a fatal error was returned or no answer. Cancel the
+ * request.
*/
+ if (NXDOMAIN == header->rcode)
+ {
+ /* If the rcode is NXDOMAIN, treat it as a good response. */
+ ns_failure_count[ns] /= 4;
+ }
(*request->query->callback) (request->query->ptr, NULL);
rem_request(request);
}
- return;
+ return 1;
}
/*
- * If this fails there was an error decoding the received packet,
- * give up. -- jilles
+ * If this fails there was an error decoding the received packet.
+ * -- jilles
*/
answer_count = proc_answer(request, header, buf, buf + rc);
if (request->name == NULL)
{
/*
- * got a PTR response with no name, something bogus is happening
- * don't bother trying again, the client address doesn't resolve
+ * Got a PTR response with no name, something strange is
+ * happening. Try another DNS server.
*/
- (*request->query->callback) (request->query->ptr, reply);
- rem_request(request);
- return;
+ ns_failure_count[ns]++;
+ resend_query(request);
+ return 1;
}
/*
* Lookup the 'authoritative' name that we were given for the
- * ip#.
- *
+ * ip#.
*/
-#ifdef IPV6
+#ifdef RB_IPV6
if (request->addr.ss_family == AF_INET6)
- gethost_byname_type(request->name, request->query, T_AAAA);
+ gethost_byname_type_fqdn(request->name, request->query, T_AAAA);
else
#endif
- gethost_byname_type(request->name, request->query, T_A);
+ gethost_byname_type_fqdn(request->name, request->query, T_A);
rem_request(request);
}
else
*/
reply = make_dnsreply(request);
(*request->query->callback) (request->query->ptr, reply);
- MyFree(reply);
+ rb_free(reply);
rem_request(request);
}
+
+ ns_failure_count[ns] /= 4;
}
else
{
- /* couldn't decode, give up -- jilles */
- (*request->query->callback) (request->query->ptr, NULL);
- rem_request(request);
+ /* Invalid or corrupt reply - try another resolver. */
+ ns_failure_count[ns]++;
+ resend_query(request);
}
+ return 1;
+}
+
+static void res_readreply(rb_fde_t *F, void *data)
+{
+ while (res_read_single_reply(F, data))
+ ;
+ rb_setselect(F, RB_SELECT_READ, res_readreply, NULL);
}
static struct DNSReply *make_dnsreply(struct reslist *request)
struct DNSReply *cp;
s_assert(request != 0);
- cp = (struct DNSReply *)MyMalloc(sizeof(struct DNSReply));
+ cp = (struct DNSReply *)rb_malloc(sizeof(struct DNSReply));
cp->h_name = request->name;
memcpy(&cp->addr, &request->addr, sizeof(cp->addr));
for (i = 0; i < irc_nscount; i++)
{
- if (!inetntop_sock((struct sockaddr *)&(irc_nsaddr_list[i]),
+ if (!rb_inet_ntop_sock((struct sockaddr *)&(irc_nsaddr_list[i]),
ipaddr, sizeof ipaddr))
- strlcpy(ipaddr, "?", sizeof ipaddr);
+ rb_strlcpy(ipaddr, "?", sizeof ipaddr);
sendto_one_numeric(source_p, RPL_STATSDEBUG,
- "A %s", ipaddr);
+ "A %s %d", ipaddr, ns_failure_count[i]);
}
}