Commit 965a73dc authored by Roger Dingledine's avatar Roger Dingledine
Browse files

bugfix: we were caching transient dns failures


svn:r1266
parent 45a3f6b9
...@@ -16,16 +16,13 @@ ...@@ -16,16 +16,13 @@
#define MIN_DNSWORKERS 3 #define MIN_DNSWORKERS 3
#define MAX_IDLE_DNSWORKERS 10 #define MAX_IDLE_DNSWORKERS 10
#define DNS_RESOLVE_FAILED_TRANSIENT 1
#define DNS_RESOLVE_FAILED_PERMANENT 2
#define DNS_RESOLVE_SUCCEEDED 3
int num_dnsworkers=0; int num_dnsworkers=0;
int num_dnsworkers_busy=0; int num_dnsworkers_busy=0;
static void purge_expired_resolves(uint32_t now);
static int assign_to_dnsworker(connection_t *exitconn);
static void dns_found_answer(char *address, uint32_t addr);
int dnsworker_main(void *data);
static int spawn_dnsworker(void);
static void spawn_enough_dnsworkers(void);
struct pending_connection_t { struct pending_connection_t {
struct connection_t *conn; struct connection_t *conn;
struct pending_connection_t *next; struct pending_connection_t *next;
...@@ -44,6 +41,14 @@ struct cached_resolve { ...@@ -44,6 +41,14 @@ struct cached_resolve {
struct cached_resolve *next; struct cached_resolve *next;
}; };
static void purge_expired_resolves(uint32_t now);
static int assign_to_dnsworker(connection_t *exitconn);
static void dns_purge_resolve(struct cached_resolve *resolve);
static void dns_found_answer(char *address, uint32_t addr, char outcome);
int dnsworker_main(void *data);
static int spawn_dnsworker(void);
static void spawn_enough_dnsworkers(void);
static SPLAY_HEAD(cache_tree, cached_resolve) cache_root; static SPLAY_HEAD(cache_tree, cached_resolve) cache_root;
static int compare_cached_resolves(struct cached_resolve *a, static int compare_cached_resolves(struct cached_resolve *a,
...@@ -238,7 +243,7 @@ void connection_dns_remove(connection_t *conn) ...@@ -238,7 +243,7 @@ void connection_dns_remove(connection_t *conn)
void dns_cancel_pending_resolve(char *address) { void dns_cancel_pending_resolve(char *address) {
struct pending_connection_t *pend; struct pending_connection_t *pend;
struct cached_resolve search; struct cached_resolve search;
struct cached_resolve *resolve, *tmp; struct cached_resolve *resolve;
connection_t *pendconn; connection_t *pendconn;
strncpy(search.address, address, MAX_ADDRESSLEN); strncpy(search.address, address, MAX_ADDRESSLEN);
...@@ -266,6 +271,12 @@ void dns_cancel_pending_resolve(char *address) { ...@@ -266,6 +271,12 @@ void dns_cancel_pending_resolve(char *address) {
tor_free(pend); tor_free(pend);
} }
dns_purge_resolve(resolve);
}
static void dns_purge_resolve(struct cached_resolve *resolve) {
struct cached_resolve *tmp;
/* remove resolve from the linked list */ /* remove resolve from the linked list */
if(resolve == oldest_cached_resolve) { if(resolve == oldest_cached_resolve) {
oldest_cached_resolve = resolve->next; oldest_cached_resolve = resolve->next;
...@@ -287,7 +298,7 @@ void dns_cancel_pending_resolve(char *address) { ...@@ -287,7 +298,7 @@ void dns_cancel_pending_resolve(char *address) {
tor_free(resolve); tor_free(resolve);
} }
static void dns_found_answer(char *address, uint32_t addr) { static void dns_found_answer(char *address, uint32_t addr, char outcome) {
struct pending_connection_t *pend; struct pending_connection_t *pend;
struct cached_resolve search; struct cached_resolve search;
struct cached_resolve *resolve; struct cached_resolve *resolve;
...@@ -316,7 +327,7 @@ static void dns_found_answer(char *address, uint32_t addr) { ...@@ -316,7 +327,7 @@ static void dns_found_answer(char *address, uint32_t addr) {
/* assert(resolve->state == CACHE_STATE_PENDING); */ /* assert(resolve->state == CACHE_STATE_PENDING); */
resolve->addr = ntohl(addr); resolve->addr = ntohl(addr);
if(resolve->addr) if(outcome == DNS_RESOLVE_SUCCEEDED)
resolve->state = CACHE_STATE_VALID; resolve->state = CACHE_STATE_VALID;
else else
resolve->state = CACHE_STATE_FAILED; resolve->state = CACHE_STATE_FAILED;
...@@ -337,6 +348,10 @@ static void dns_found_answer(char *address, uint32_t addr) { ...@@ -337,6 +348,10 @@ static void dns_found_answer(char *address, uint32_t addr) {
resolve->pending_connections = pend->next; resolve->pending_connections = pend->next;
tor_free(pend); tor_free(pend);
} }
if(outcome == DNS_RESOLVE_FAILED_TRANSIENT) { /* remove from cache */
dns_purge_resolve(resolve);
}
} }
/******************************************************************/ /******************************************************************/
...@@ -348,6 +363,7 @@ int connection_dns_finished_flushing(connection_t *conn) { ...@@ -348,6 +363,7 @@ int connection_dns_finished_flushing(connection_t *conn) {
} }
int connection_dns_process_inbuf(connection_t *conn) { int connection_dns_process_inbuf(connection_t *conn) {
char answer[5];
uint32_t addr; uint32_t addr;
assert(conn && conn->type == CONN_TYPE_DNSWORKER); assert(conn && conn->type == CONN_TYPE_DNSWORKER);
...@@ -364,16 +380,19 @@ int connection_dns_process_inbuf(connection_t *conn) { ...@@ -364,16 +380,19 @@ int connection_dns_process_inbuf(connection_t *conn) {
} }
assert(conn->state == DNSWORKER_STATE_BUSY); assert(conn->state == DNSWORKER_STATE_BUSY);
if(buf_datalen(conn->inbuf) < 4) /* entire answer available? */ if(buf_datalen(conn->inbuf) < 5) /* entire answer available? */
return 0; /* not yet */ return 0; /* not yet */
assert(buf_datalen(conn->inbuf) == 4); assert(buf_datalen(conn->inbuf) == 5);
connection_fetch_from_buf((char*)&addr,sizeof(addr),conn); connection_fetch_from_buf(answer,sizeof(answer),conn);
addr = *(uint32_t*)(answer+1);
log_fn(LOG_DEBUG, "DNSWorker (fd %d) returned answer for '%s'", log_fn(LOG_DEBUG, "DNSWorker (fd %d) returned answer for '%s'",
conn->s, conn->address); conn->s, conn->address);
dns_found_answer(conn->address, addr); assert(answer[0] >= DNS_RESOLVE_FAILED_TRANSIENT);
assert(answer[0] <= DNS_RESOLVE_SUCCEEDED);
dns_found_answer(conn->address, addr, answer[0]);
tor_free(conn->address); tor_free(conn->address);
conn->address = tor_strdup("<idle>"); conn->address = tor_strdup("<idle>");
...@@ -386,6 +405,7 @@ int connection_dns_process_inbuf(connection_t *conn) { ...@@ -386,6 +405,7 @@ int connection_dns_process_inbuf(connection_t *conn) {
int dnsworker_main(void *data) { int dnsworker_main(void *data) {
char address[MAX_ADDRESSLEN]; char address[MAX_ADDRESSLEN];
unsigned char address_len; unsigned char address_len;
char answer[5];
struct hostent *rent; struct hostent *rent;
int *fdarray = data; int *fdarray = data;
int fd; int fd;
...@@ -398,7 +418,6 @@ int dnsworker_main(void *data) { ...@@ -398,7 +418,6 @@ int dnsworker_main(void *data) {
for(;;) { for(;;) {
if(recv(fd, &address_len, 1, 0) != 1) { if(recv(fd, &address_len, 1, 0) != 1) {
// log_fn(LOG_INFO,"read length failed. Child exiting.");
log_fn(LOG_INFO,"dnsworker exiting because tor process died."); log_fn(LOG_INFO,"dnsworker exiting because tor process died.");
spawn_exit(); spawn_exit();
} }
...@@ -412,19 +431,24 @@ int dnsworker_main(void *data) { ...@@ -412,19 +431,24 @@ int dnsworker_main(void *data) {
rent = gethostbyname(address); rent = gethostbyname(address);
if (!rent) { if (!rent) {
log_fn(LOG_INFO,"Could not resolve dest addr %s. Returning nulls.",address); if(h_errno == TRY_AGAIN) { /* transient error -- don't cache it */
if(write_all(fd, "\0\0\0\0", 4, 1) != 4) { log_fn(LOG_INFO,"Could not resolve dest addr %s (transient).",address);
log_fn(LOG_ERR,"writing nulls failed. Child exiting."); answer[0] = DNS_RESOLVE_FAILED_TRANSIENT;
spawn_exit(); } else { /* permanent error, can be cached */
log_fn(LOG_INFO,"Could not resolve dest addr %s (permanent).",address);
answer[0] = DNS_RESOLVE_FAILED_PERMANENT;
} }
memset(answer+1,0,4);
} else { } else {
assert(rent->h_length == 4); /* break to remind us if we move away from ipv4 */ assert(rent->h_length == 4); /* break to remind us if we move away from ipv4 */
if(write_all(fd, rent->h_addr, 4, 1) != 4) { answer[0] = DNS_RESOLVE_SUCCEEDED;
log_fn(LOG_INFO,"writing answer failed. Child exiting."); memcpy(answer+1, rent->h_addr, 4);
spawn_exit();
}
log_fn(LOG_INFO,"Resolved address '%s'.",address); log_fn(LOG_INFO,"Resolved address '%s'.",address);
} }
if(write_all(fd, answer, 5, 1) != 5) {
log_fn(LOG_ERR,"writing answer failed. Child exiting.");
spawn_exit();
}
} }
return 0; /* windows wants this function to return an int */ return 0; /* windows wants this function to return an int */
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment