aboutsummaryrefslogtreecommitdiff
path: root/src/or/dns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/or/dns.c')
-rw-r--r--src/or/dns.c81
1 files changed, 56 insertions, 25 deletions
diff --git a/src/or/dns.c b/src/or/dns.c
index 67972867d5..2e6a7398db 100644
--- a/src/or/dns.c
+++ b/src/or/dns.c
@@ -71,6 +71,7 @@ typedef struct cached_resolve_t {
#define CACHE_STATE_VALID 1
#define CACHE_STATE_FAILED 2
uint32_t expire; /**< Remove items from cache after this time. */
+ uint32_t ttl; /**< What TTL did the nameserver tell us? */
pending_connection_t *pending_connections;
struct cached_resolve_t *next;
} cached_resolve_t;
@@ -79,8 +80,7 @@ static void purge_expired_resolves(uint32_t now);
static void dns_purge_resolve(cached_resolve_t *resolve);
static void dns_found_answer(char *address, uint32_t addr, char outcome,
uint32_t ttl);
-static void send_resolved_cell(connection_t *conn, uint8_t answer_type,
- uint32_t ttl);
+static void send_resolved_cell(connection_t *conn, uint8_t answer_type);
static int assign_to_dnsworker(connection_t *exitconn);
#ifndef USE_EVENTDNS
static int dnsworker_main(void *data);
@@ -130,6 +130,28 @@ dns_init(void)
#endif
}
+uint32_t
+dns_clip_ttl(uint32_t ttl)
+{
+ if (ttl < MIN_DNS_TTL)
+ return MIN_DNS_TTL;
+ else if (ttl > MAX_DNS_TTL)
+ return MAX_DNS_TTL;
+ else
+ return ttl;
+}
+
+static uint32_t
+dns_get_expiry_ttl(uint32_t ttl)
+{
+ if (ttl < MIN_DNS_TTL)
+ return MIN_DNS_TTL;
+ else if (ttl > MAX_DNS_ENTRY_AGE)
+ return MAX_DNS_ENTRY_AGE;
+ else
+ return ttl;
+}
+
/** Helper: free storage held by an entry in the DNS cache. */
static void
_free_cached_resolve(cached_resolve_t *r)
@@ -212,12 +234,14 @@ purge_expired_resolves(uint32_t now)
/** Send a response to the RESOVLE request of a connection. answer_type must
* be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT) */
static void
-send_resolved_cell(connection_t *conn, uint8_t answer_type, uint32_t ttl)
+send_resolved_cell(connection_t *conn, uint8_t answer_type)
{
char buf[RELAY_PAYLOAD_SIZE];
size_t buflen;
+ uint32_t ttl;
buf[0] = answer_type;
+ ttl = dns_clip_ttl(conn->address_ttl);
switch (answer_type)
{
@@ -289,8 +313,9 @@ dns_resolve(connection_t *exitconn)
* know the answer. */
if (tor_inet_aton(exitconn->address, &in) != 0) {
exitconn->addr = ntohl(in.s_addr);
+ exitconn->address_ttl = DEFAULT_DNS_TTL;
if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
- send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4, MAX_DNS_ENTRY_AGE);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
return 1;
}
@@ -305,9 +330,6 @@ dns_resolve(connection_t *exitconn)
strlcpy(search.address, exitconn->address, sizeof(search.address));
resolve = HT_FIND(cache_map, &cache_root, &search);
if (resolve && resolve->expire > now) { /* already there */
- // XXXX Security problem: this leaks a time at which somebody asked for
- // XXXX the address. That's a problem.
- unsigned int ttl = (unsigned int) resolve->expire - now;
switch (resolve->state) {
case CACHE_STATE_PENDING:
/* add us to the pending list */
@@ -323,16 +345,17 @@ dns_resolve(connection_t *exitconn)
return 0;
case CACHE_STATE_VALID:
exitconn->addr = resolve->addr;
+ exitconn->address_ttl = resolve->ttl;
log_debug(LD_EXIT,"Connection (fd %d) found cached answer for %s",
exitconn->s, escaped_safe_str(exitconn->address));
if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
- send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4, ttl);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4);
return 1;
case CACHE_STATE_FAILED:
log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
exitconn->s, escaped_safe_str(exitconn->address));
if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
- send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR, ttl);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
circ = circuit_get_by_edge_conn(exitconn);
if (circ)
circuit_detach_stream(circ, exitconn);
@@ -345,7 +368,7 @@ dns_resolve(connection_t *exitconn)
/* not there, need to add it */
resolve = tor_malloc_zero(sizeof(cached_resolve_t));
resolve->state = CACHE_STATE_PENDING;
- resolve->expire = now + MAX_DNS_ENTRY_AGE;
+ resolve->expire = now + DEFAULT_DNS_TTL; /* this will get replaced. */
strlcpy(resolve->address, exitconn->address, sizeof(resolve->address));
/* add us to the pending list */
@@ -557,7 +580,8 @@ dns_found_answer(char *address, uint32_t addr, char outcome, uint32_t ttl)
resolve->state = (outcome == DNS_RESOLVE_SUCCEEDED) ?
CACHE_STATE_VALID : CACHE_STATE_FAILED;
resolve->addr = addr;
- resolve->expire = time(NULL) + ttl;
+ resolve->expire = time(NULL) + dns_get_expiry_ttl(ttl);
+ resolve->ttl = ttl;
insert_resolve(resolve);
return;
}
@@ -577,7 +601,8 @@ dns_found_answer(char *address, uint32_t addr, char outcome, uint32_t ttl)
/* tor_assert(resolve->state == CACHE_STATE_PENDING); */
resolve->addr = addr;
- resolve->expire = time(NULL) + ttl;
+ resolve->expire = time(NULL) + dns_get_expiry_ttl(ttl);
+ resolve->ttl = ttl;
if (outcome == DNS_RESOLVE_SUCCEEDED)
resolve->state = CACHE_STATE_VALID;
else
@@ -587,6 +612,7 @@ dns_found_answer(char *address, uint32_t addr, char outcome, uint32_t ttl)
pend = resolve->pending_connections;
assert_connection_ok(pend->conn,time(NULL));
pend->conn->addr = resolve->addr;
+ pend->conn->address_ttl = resolve->ttl;
pendconn = pend->conn; /* don't pass complex things to the
connection_mark_for_close macro */
@@ -599,7 +625,7 @@ dns_found_answer(char *address, uint32_t addr, char outcome, uint32_t ttl)
/* This detach must happen after we send the end cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
} else {
- send_resolved_cell(pendconn, RESOLVED_TYPE_ERROR, ttl);
+ send_resolved_cell(pendconn, RESOLVED_TYPE_ERROR);
/* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
}
@@ -623,7 +649,7 @@ dns_found_answer(char *address, uint32_t addr, char outcome, uint32_t ttl)
/* prevent double-remove. This isn't really an accurate state,
* but it does the right thing. */
pendconn->state = EXIT_CONN_STATE_RESOLVEFAILED;
- send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4, ttl);
+ send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4);
circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ);
circuit_detach_stream(circ, pendconn);
@@ -663,7 +689,7 @@ assign_to_dnsworker(connection_t *exitconn)
if (!dnsconn) {
log_warn(LD_EXIT,"no idle dns workers. Failing.");
if (exitconn->purpose == EXIT_PURPOSE_RESOLVE)
- send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT, 0);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
goto err;
}
@@ -1051,28 +1077,30 @@ eventdns_callback(int result, char type, int count, int ttl, void *addresses,
void *arg)
{
char *string_address = arg;
+ int status = DNS_RESOLVE_FAILED_PERMANENT;
+ uint32_t addr = 0;
if (result == DNS_ERR_NONE) {
if (type == DNS_IPv4_A && count) {
uint32_t *addrs = addresses;
- dns_found_answer(string_address, addrs[0], DNS_RESOLVE_SUCCEEDED, ttl);
+ addr = addrs[0];
+ status = DNS_RESOLVE_SUCCEEDED;
} else if (count) {
log_warn(LD_EXIT, "eventdns returned only non-IPv4 answers for %s.",
escaped_safe_str(string_address));
- dns_found_answer(string_address, 0, DNS_RESOLVE_FAILED_PERMANENT, ttl);
} else {
log_warn(LD_BUG, "eventdns returned no addresses or error for %s!",
escaped_safe_str(string_address));
- dns_found_answer(string_address, 0, DNS_RESOLVE_FAILED_PERMANENT, ttl);
}
} else {
- int err = eventdns_err_is_transient(result)
- ? DNS_RESOLVE_FAILED_TRANSIENT : DNS_RESOLVE_FAILED_PERMANENT;
- dns_found_answer(string_address, 0, err, ttl);
+ if (eventdns_err_is_transient(result))
+ status = DNS_RESOLVE_FAILED_TRANSIENT;
}
+ dns_found_answer(string_address, addr, status, ttl);
tor_free(string_address);
}
-static int assign_to_dnsworker(connection_t *exitconn)
+static int
+assign_to_dnsworker(connection_t *exitconn)
{
char *addr = tor_strdup(exitconn->address);
int r = eventdns_resolve(exitconn->address, DNS_QUERY_NO_SEARCH,
@@ -1082,9 +1110,11 @@ static int assign_to_dnsworker(connection_t *exitconn)
escaped_safe_str(addr), r);
if (exitconn->purpose == EXIT_PURPOSE_RESOLVE) {
if (eventdns_err_is_transient(r))
- send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT, 0);
- else
- send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR, MAX_DNS_ENTRY_AGE);
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT);
+ else {
+ exitconn->address_ttl = DEFAULT_DNS_TTL;
+ send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR);
+ }
}
dns_cancel_pending_resolve(addr);/* also sends end and frees */
tor_free(addr);
@@ -1092,3 +1122,4 @@ static int assign_to_dnsworker(connection_t *exitconn)
return r ? -1 : 0;
}
#endif /* USE_EVENTDNS */
+