Commit d3af1f21 authored by Nick Mathewson's avatar Nick Mathewson 🥄
Browse files

Backport candidate: Fix a long-standing server-side DNS bug. When a

client asks us to resolve (not connect to) an address, and we have a
cached answer, give them the cached answer.  Previously, we would give
them no answer at all.



svn:r8478
parent a951c015
...@@ -24,6 +24,11 @@ Changes in version 0.1.2.2-alpha - 2006-??-?? ...@@ -24,6 +24,11 @@ Changes in version 0.1.2.2-alpha - 2006-??-??
descriptor for a named server with that name, we might return an old descriptor for a named server with that name, we might return an old
one. one.
o Major bugfixes
- When a client asks us to resolve (not connect to) an address,
and we have a cached answer, give them the cached answer.
Previously, we would give them no answer at all.
o Minor Bugfixes o Minor Bugfixes
- Small performance improvements on parsing descriptors (x2). - Small performance improvements on parsing descriptors (x2).
- Major performance descriptor on inserting descriptors; change - Major performance descriptor on inserting descriptors; change
......
...@@ -111,7 +111,7 @@ d - Special-case localhost? ...@@ -111,7 +111,7 @@ d - Special-case localhost?
o Connect to resolve cells, server-side. o Connect to resolve cells, server-side.
o Add element to routerinfo to note routers that aren't using eventdns, o Add element to routerinfo to note routers that aren't using eventdns,
so we can avoid sending them reverse DNS etc. so we can avoid sending them reverse DNS etc.
- Fix the bug with server-side caching, whatever is causing it. o Fix the bug with server-side caching, whatever is causing it.
. Add client-side interface . Add client-side interface
o SOCKS interface: specify o SOCKS interface: specify
o SOCKS interface: implement o SOCKS interface: implement
......
...@@ -1899,7 +1899,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) ...@@ -1899,7 +1899,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
log_debug(LD_EXIT,"about to start the dns_resolve()."); log_debug(LD_EXIT,"about to start the dns_resolve().");
/* send it off to the gethostbyname farm */ /* send it off to the gethostbyname farm */
switch (dns_resolve(n_stream)) { switch (dns_resolve(n_stream, NULL)) {
case 1: /* resolve worked */ case 1: /* resolve worked */
/* add it into the linked list of n_streams on this circuit */ /* add it into the linked list of n_streams on this circuit */
...@@ -1912,6 +1912,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ) ...@@ -1912,6 +1912,7 @@ connection_exit_begin_conn(cell_t *cell, circuit_t *circ)
connection_exit_connect(n_stream); connection_exit_connect(n_stream);
return 0; return 0;
case -1: /* resolve failed */ case -1: /* resolve failed */
/* XXXX send back indication of failure for connect case? -NM*/
/* n_stream got freed. don't touch it. */ /* n_stream got freed. don't touch it. */
break; break;
case 0: /* resolve added to pending list */ case 0: /* resolve added to pending list */
...@@ -1954,7 +1955,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ) ...@@ -1954,7 +1955,7 @@ connection_exit_begin_resolve(cell_t *cell, or_circuit_t *circ)
dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE; dummy_conn->_base.purpose = EXIT_PURPOSE_RESOLVE;
/* send it off to the gethostbyname farm */ /* send it off to the gethostbyname farm */
switch (dns_resolve(dummy_conn)) { switch (dns_resolve(dummy_conn, circ)) {
case -1: /* Impossible to resolve; a resolved cell was sent. */ case -1: /* Impossible to resolve; a resolved cell was sent. */
/* Connection freed; don't touch it. */ /* Connection freed; don't touch it. */
return 0; return 0;
......
...@@ -113,8 +113,9 @@ static void purge_expired_resolves(time_t now); ...@@ -113,8 +113,9 @@ static void purge_expired_resolves(time_t now);
static void dns_found_answer(const char *address, int is_reverse, static void dns_found_answer(const char *address, int is_reverse,
uint32_t addr, const char *hostname, char outcome, uint32_t addr, const char *hostname, char outcome,
uint32_t ttl); uint32_t ttl);
static void send_resolved_cell(edge_connection_t *conn, uint8_t answer_type); static void send_resolved_cell(edge_connection_t *conn, or_circuit_t *circ,
static int launch_resolve(edge_connection_t *exitconn); uint8_t answer_type);
static int launch_resolve(edge_connection_t *exitconn, or_circuit_t *circ);
#ifndef USE_EVENTDNS #ifndef USE_EVENTDNS
static void dnsworkers_rotate(void); static void dnsworkers_rotate(void);
static void dnsworker_main(void *data); static void dnsworker_main(void *data);
...@@ -385,9 +386,15 @@ purge_expired_resolves(time_t now) ...@@ -385,9 +386,15 @@ purge_expired_resolves(time_t now)
} }
/** Send a response to the RESOLVE request of a connection. answer_type must /** Send a response to the RESOLVE request of a connection. answer_type must
* be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT) */ * be one of RESOLVED_TYPE_(IPV4|ERROR|ERROR_TRANSIENT)
*
* If <b>circ</b> is provided, and we have a cached answer, send the
* answer back along circ; otherwise, send the answer back along *
* <b>exitconn</b>'s attached circuit.
*/
static void static void
send_resolved_cell(edge_connection_t *conn, uint8_t answer_type) send_resolved_cell(edge_connection_t *conn, or_circuit_t *circ,
uint8_t answer_type)
{ {
char buf[RELAY_PAYLOAD_SIZE]; char buf[RELAY_PAYLOAD_SIZE];
size_t buflen; size_t buflen;
...@@ -421,7 +428,14 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type) ...@@ -421,7 +428,14 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
return; return;
} }
// log_notice(LD_EXIT, "Sending a regular RESOLVED reply: "); // log_notice(LD_EXIT, "Sending a regular RESOLVED reply: ");
connection_edge_send_command(conn, circuit_get_by_edge_conn(conn),
if (!circ) {
circuit_t *tmp = circuit_get_by_edge_conn(conn);
if (! CIRCUIT_IS_ORIGIN(tmp))
circ = TO_OR_CIRCUIT(tmp);
}
connection_edge_send_command(conn, TO_CIRCUIT(circ),
RELAY_COMMAND_RESOLVED, buf, buflen, RELAY_COMMAND_RESOLVED, buf, buflen,
conn->cpath_layer); conn->cpath_layer);
} }
...@@ -429,9 +443,14 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type) ...@@ -429,9 +443,14 @@ send_resolved_cell(edge_connection_t *conn, uint8_t answer_type)
/** Send a response to the RESOLVE request of a connection for an in-addr.arpa /** Send a response to the RESOLVE request of a connection for an in-addr.arpa
* address on connection <b>conn</b> which yielded the result <b>hostname</b>. * address on connection <b>conn</b> which yielded the result <b>hostname</b>.
* The answer type will be RESOLVED_HOSTNAME. * The answer type will be RESOLVED_HOSTNAME.
*
* If <b>circ</b> is provided, and we have a cached answer, send the
* answer back along circ; otherwise, send the answer back along
* <b>exitconn</b>'s attached circuit.
*/ */
static void static void
send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname) send_resolved_hostname_cell(edge_connection_t *conn, or_circuit_t *circ,
const char *hostname)
{ {
char buf[RELAY_PAYLOAD_SIZE]; char buf[RELAY_PAYLOAD_SIZE];
size_t buflen; size_t buflen;
...@@ -447,8 +466,14 @@ send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname) ...@@ -447,8 +466,14 @@ send_resolved_hostname_cell(edge_connection_t *conn, const char *hostname)
set_uint32(buf+2+namelen, htonl(ttl)); set_uint32(buf+2+namelen, htonl(ttl));
buflen = 2+namelen+4; buflen = 2+namelen+4;
if (!circ) {
circuit_t *tmp = circuit_get_by_edge_conn(conn);
if (! CIRCUIT_IS_ORIGIN(tmp))
circ = TO_OR_CIRCUIT(tmp);
}
// log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname); // log_notice(LD_EXIT, "Sending a reply RESOLVED reply: %s", hostname);
connection_edge_send_command(conn, circuit_get_by_edge_conn(conn), connection_edge_send_command(conn, TO_CIRCUIT(circ),
RELAY_COMMAND_RESOLVED, buf, buflen, RELAY_COMMAND_RESOLVED, buf, buflen,
conn->cpath_layer); conn->cpath_layer);
// log_notice(LD_EXIT, "Sent"); // log_notice(LD_EXIT, "Sent");
...@@ -500,6 +525,10 @@ parse_inaddr_arpa_address(const char *address, struct in_addr *in) ...@@ -500,6 +525,10 @@ parse_inaddr_arpa_address(const char *address, struct in_addr *in)
* if resolve valid, put it into <b>exitconn</b>-\>addr and return 1. * if resolve valid, put it into <b>exitconn</b>-\>addr and return 1.
* If resolve failed, unlink exitconn if needed, free it, and return -1. * If resolve failed, unlink exitconn if needed, free it, and return -1.
* *
* If <b>circ</b> is provided, and this is a resolve request, we have
* a cached answer, send the answer back along circ; otherwise, send
* the answer back along <b>exitconn</b>'s attached circuit.
*
* Else, if seen before and pending, add conn to the pending list, * Else, if seen before and pending, add conn to the pending list,
* and return 0. * and return 0.
* *
...@@ -507,7 +536,7 @@ parse_inaddr_arpa_address(const char *address, struct in_addr *in) ...@@ -507,7 +536,7 @@ parse_inaddr_arpa_address(const char *address, struct in_addr *in)
* dns farm, and return 0. * dns farm, and return 0.
*/ */
int int
dns_resolve(edge_connection_t *exitconn) dns_resolve(edge_connection_t *exitconn, or_circuit_t *oncirc)
{ {
cached_resolve_t *resolve; cached_resolve_t *resolve;
cached_resolve_t search; cached_resolve_t search;
...@@ -529,7 +558,7 @@ dns_resolve(edge_connection_t *exitconn) ...@@ -529,7 +558,7 @@ dns_resolve(edge_connection_t *exitconn)
exitconn->_base.addr = ntohl(in.s_addr); exitconn->_base.addr = ntohl(in.s_addr);
exitconn->address_ttl = DEFAULT_DNS_TTL; exitconn->address_ttl = DEFAULT_DNS_TTL;
if (is_resolve) if (is_resolve)
send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4); send_resolved_cell(exitconn, oncirc, RESOLVED_TYPE_IPV4);
return 1; return 1;
} }
...@@ -566,7 +595,7 @@ dns_resolve(edge_connection_t *exitconn) ...@@ -566,7 +595,7 @@ dns_resolve(edge_connection_t *exitconn)
#endif #endif
if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE) if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR); send_resolved_cell(exitconn, oncirc, RESOLVED_TYPE_ERROR);
circ = circuit_get_by_edge_conn(exitconn); circ = circuit_get_by_edge_conn(exitconn);
if (circ) if (circ)
circuit_detach_stream(circ, exitconn); circuit_detach_stream(circ, exitconn);
...@@ -602,19 +631,21 @@ dns_resolve(edge_connection_t *exitconn) ...@@ -602,19 +631,21 @@ dns_resolve(edge_connection_t *exitconn)
exitconn->address_ttl = resolve->ttl; exitconn->address_ttl = resolve->ttl;
if (resolve->is_reverse) { if (resolve->is_reverse) {
tor_assert(is_resolve); tor_assert(is_resolve);
send_resolved_hostname_cell(exitconn, resolve->result.hostname); send_resolved_hostname_cell(exitconn, oncirc,
resolve->result.hostname);
} else { } else {
exitconn->_base.addr = resolve->result.addr; exitconn->_base.addr = resolve->result.addr;
if (is_resolve) if (is_resolve)
send_resolved_cell(exitconn, RESOLVED_TYPE_IPV4); send_resolved_cell(exitconn, oncirc, RESOLVED_TYPE_IPV4);
} }
return 1; return 1;
case CACHE_STATE_CACHED_FAILED: case CACHE_STATE_CACHED_FAILED:
log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s", log_debug(LD_EXIT,"Connection (fd %d) found cached error for %s",
exitconn->_base.s, exitconn->_base.s,
escaped_safe_str(exitconn->_base.address)); escaped_safe_str(exitconn->_base.address));
/* XXXX send back indication of failure for connect case? -NM*/
if (is_resolve) if (is_resolve)
send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR); send_resolved_cell(exitconn, oncirc, RESOLVED_TYPE_ERROR);
circ = circuit_get_by_edge_conn(exitconn); circ = circuit_get_by_edge_conn(exitconn);
if (circ) if (circ)
circuit_detach_stream(circ, exitconn); circuit_detach_stream(circ, exitconn);
...@@ -647,7 +678,7 @@ dns_resolve(edge_connection_t *exitconn) ...@@ -647,7 +678,7 @@ dns_resolve(edge_connection_t *exitconn)
log_debug(LD_EXIT,"Launching %s.", log_debug(LD_EXIT,"Launching %s.",
escaped_safe_str(exitconn->_base.address)); escaped_safe_str(exitconn->_base.address));
assert_cache_ok(); assert_cache_ok();
return launch_resolve(exitconn); return launch_resolve(exitconn, oncirc);
} }
/** Log an error and abort if conn is waiting for a DNS resolve. /** Log an error and abort if conn is waiting for a DNS resolve.
...@@ -903,7 +934,7 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr, ...@@ -903,7 +934,7 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr,
/* This detach must happen after we send the end cell. */ /* This detach must happen after we send the end cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
} else { } else {
send_resolved_cell(pendconn, RESOLVED_TYPE_ERROR); send_resolved_cell(pendconn, NULL, RESOLVED_TYPE_ERROR);
/* This detach must happen after we send the resolved cell. */ /* This detach must happen after we send the resolved cell. */
circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn); circuit_detach_stream(circuit_get_by_edge_conn(pendconn), pendconn);
} }
...@@ -930,9 +961,9 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr, ...@@ -930,9 +961,9 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr,
* but it does the right thing. */ * but it does the right thing. */
pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED; pendconn->_base.state = EXIT_CONN_STATE_RESOLVEFAILED;
if (is_reverse) if (is_reverse)
send_resolved_hostname_cell(pendconn, hostname); send_resolved_hostname_cell(pendconn, NULL, hostname);
else else
send_resolved_cell(pendconn, RESOLVED_TYPE_IPV4); send_resolved_cell(pendconn, NULL, RESOLVED_TYPE_IPV4);
circ = circuit_get_by_edge_conn(pendconn); circ = circuit_get_by_edge_conn(pendconn);
tor_assert(circ); tor_assert(circ);
circuit_detach_stream(circ, pendconn); circuit_detach_stream(circ, pendconn);
...@@ -963,7 +994,7 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr, ...@@ -963,7 +994,7 @@ dns_found_answer(const char *address, int is_reverse, uint32_t addr,
* <b>exitconn</b>-\>address; tell that dns worker to begin resolving. * <b>exitconn</b>-\>address; tell that dns worker to begin resolving.
*/ */
static int static int
launch_resolve(edge_connection_t *exitconn) launch_resolve(edge_connection_t *exitconn, or_circuit_t *circ)
{ {
connection_t *dnsconn; connection_t *dnsconn;
unsigned char len; unsigned char len;
...@@ -983,7 +1014,7 @@ launch_resolve(edge_connection_t *exitconn) ...@@ -983,7 +1014,7 @@ launch_resolve(edge_connection_t *exitconn)
if (!dnsconn) { if (!dnsconn) {
log_warn(LD_EXIT,"no idle dns workers. Failing."); log_warn(LD_EXIT,"no idle dns workers. Failing.");
if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE) if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE)
send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT); send_resolved_cell(exitconn, circ, RESOLVED_TYPE_ERROR_TRANSIENT);
goto err; goto err;
} }
...@@ -1533,7 +1564,7 @@ eventdns_callback(int result, char type, int count, int ttl, void *addresses, ...@@ -1533,7 +1564,7 @@ eventdns_callback(int result, char type, int count, int ttl, void *addresses,
/** For eventdns: start resolving as necessary to find the target for /** For eventdns: start resolving as necessary to find the target for
* <b>exitconn</b> */ * <b>exitconn</b> */
static int static int
launch_resolve(edge_connection_t *exitconn) launch_resolve(edge_connection_t *exitconn, or_circuit_t *circ)
{ {
char *addr = tor_strdup(exitconn->_base.address); char *addr = tor_strdup(exitconn->_base.address);
struct in_addr in; struct in_addr in;
...@@ -1568,10 +1599,10 @@ launch_resolve(edge_connection_t *exitconn) ...@@ -1568,10 +1599,10 @@ launch_resolve(edge_connection_t *exitconn)
escaped_safe_str(addr), r); escaped_safe_str(addr), r);
if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE) { if (exitconn->_base.purpose == EXIT_PURPOSE_RESOLVE) {
if (eventdns_err_is_transient(r)) if (eventdns_err_is_transient(r))
send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR_TRANSIENT); send_resolved_cell(exitconn, circ, RESOLVED_TYPE_ERROR_TRANSIENT);
else { else {
exitconn->address_ttl = DEFAULT_DNS_TTL; exitconn->address_ttl = DEFAULT_DNS_TTL;
send_resolved_cell(exitconn, RESOLVED_TYPE_ERROR); send_resolved_cell(exitconn, circ, RESOLVED_TYPE_ERROR);
} }
} }
dns_cancel_pending_resolve(addr); /* also sends end and frees */ dns_cancel_pending_resolve(addr); /* also sends end and frees */
......
...@@ -2160,7 +2160,7 @@ void connection_dns_remove(edge_connection_t *conn); ...@@ -2160,7 +2160,7 @@ void connection_dns_remove(edge_connection_t *conn);
void assert_connection_edge_not_dns_pending(edge_connection_t *conn); void assert_connection_edge_not_dns_pending(edge_connection_t *conn);
void assert_all_pending_dns_resolves_ok(void); void assert_all_pending_dns_resolves_ok(void);
void dns_cancel_pending_resolve(const char *question); void dns_cancel_pending_resolve(const char *question);
int dns_resolve(edge_connection_t *exitconn); int dns_resolve(edge_connection_t *exitconn, or_circuit_t *circ);
void dns_launch_wildcard_checks(void); void dns_launch_wildcard_checks(void);
/********************************* hibernate.c **********************/ /********************************* hibernate.c **********************/
......
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