diff --git a/ChangeLog b/ChangeLog index 45f8c8b429..3ad44ec877 100644 --- a/ChangeLog +++ b/ChangeLog @@ -65,6 +65,7 @@ Changes in version 0.1.2.5-xxxx - 200?-??-?? - Report X-Your-Address-Is correctly from tunneled directory connections; don't report X-Your-Address-Is is when it's an internal address; and never believe reported remote addresses when they're internal. + - Add client-side caching for reverse DNS lookups. o Security bugfixes: - Stop sending the HttpProxyAuthenticator string to directory diff --git a/doc/TODO b/doc/TODO index 0d705f8fad..dd42580a18 100644 --- a/doc/TODO +++ b/doc/TODO @@ -97,7 +97,7 @@ N - DNS improvements . Add client-side interface o SOCKS interface: specify o SOCKS interface: implement -d - Cache answers client-side + o Cache answers client-side o Add to Tor-resolve.py - Add to tor-resolve d - Be a DNS proxy. diff --git a/src/or/connection_edge.c b/src/or/connection_edge.c index 2c6f3205fb..29e3858734 100644 --- a/src/or/connection_edge.c +++ b/src/or/connection_edge.c @@ -664,6 +664,7 @@ addressmap_rewrite(char *address, size_t maxlen) { addressmap_entry_t *ent; int rewrites; + char *cp; for (rewrites = 0; rewrites < 16; rewrites++) { ent = strmap_get(addressmap, address); @@ -671,8 +672,10 @@ addressmap_rewrite(char *address, size_t maxlen) if (!ent || !ent->new_address) return; /* done, no rewrite needed */ + cp = tor_strdup(escaped_safe_str(ent->new_address)); log_info(LD_APP, "Addressmap: rewriting '%s' to '%s'", - safe_str(address), safe_str(ent->new_address)); + escaped_safe_str(address), cp); + tor_free(cp); strlcpy(address, ent->new_address, maxlen); } log_warn(LD_CONFIG, @@ -681,6 +684,28 @@ addressmap_rewrite(char *address, size_t maxlen) /* it's fine to rewrite a rewrite, but don't loop forever */ } +/* DOCDOC */ +static int +addressmap_rewrite_reverse(char *address, size_t maxlen) +{ + size_t len = maxlen + 16; + char *s = tor_malloc(len), *cp; + addressmap_entry_t *ent; + int r = 0; + tor_snprintf(s, len, "REVERSE[%s]", address); + ent = strmap_get(addressmap, s); + if (ent) { + cp = tor_strdup(escaped_safe_str(ent->new_address)); + log_info(LD_APP, "Rewrote reverse lookup '%s' -> '%s'", + escaped_safe_str(s), cp); + tor_free(cp); + strlcpy(address, ent->new_address, maxlen); + r = 1; + } + tor_free(s); + return r; +} + /** Return 1 if address is already registered, else return 0 */ int addressmap_have_mapping(const char *address) @@ -775,6 +800,52 @@ client_dns_clear_failures(const char *address) ent->num_resolve_failures = 0; } +/** Record the fact that address resolved to name. + * We can now use this in subsequent streams via addressmap_rewrite() + * so we can more correctly choose an exit that will allow address. + * + * If exitname is defined, then append the addresses with + * ".exitname.exit" before registering the mapping. + * + * If ttl is nonnegative, the mapping will be valid for + * ttlseconds; otherwise, we use the default. + */ +static void +client_dns_set_addressmap_impl(const char *address, const char *name, + const char *exitname, + int ttl) +{ + /*
..exit\0 or just
\0 */ + char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_VERBOSE_NICKNAME_LEN+10]; + /* 123.123.123.123..exit\0 or just 123.123.123.123\0 */ + char extendedval[INET_NTOA_BUF_LEN+MAX_VERBOSE_NICKNAME_LEN+10]; + + tor_assert(address); + tor_assert(name); + + if (ttl<0) + ttl = DEFAULT_DNS_TTL; + else + ttl = dns_clip_ttl(ttl); + + if (exitname) { + /* XXXX fails to ever get attempts to get an exit address of + * google.com.digest[=~]nickname.exit; we need a syntax for this that + * won't make strict RFC952-compliant applications (like us) barf. */ + tor_snprintf(extendedaddress, sizeof(extendedaddress), + "%s.%s.exit", address, exitname); + tor_snprintf(extendedval, sizeof(extendedval), + "%s.%s.exit", name, exitname); + } else { + tor_snprintf(extendedaddress, sizeof(extendedaddress), + "%s", address); + tor_snprintf(extendedval, sizeof(extendedval), + "%s", name); + } + addressmap_register(extendedaddress, tor_strdup(extendedval), + time(NULL) + ttl); +} + /** Record the fact that address resolved to val. * We can now use this in subsequent streams via addressmap_rewrite() * so we can more correctly choose an exit that will allow address. @@ -791,40 +862,29 @@ client_dns_set_addressmap(const char *address, uint32_t val, int ttl) { struct in_addr in; - /*
..exit\0 or just
\0 */ - char extendedaddress[MAX_SOCKS_ADDR_LEN+MAX_VERBOSE_NICKNAME_LEN+10]; - /* 123.123.123.123..exit\0 or just 123.123.123.123\0 */ - char extendedval[INET_NTOA_BUF_LEN+MAX_VERBOSE_NICKNAME_LEN+10]; char valbuf[INET_NTOA_BUF_LEN]; tor_assert(address); - tor_assert(val); - - if (ttl<0) - ttl = DEFAULT_DNS_TTL; - else - ttl = dns_clip_ttl(ttl); if (tor_inet_aton(address, &in)) return; /* If address was an IP address already, don't add a mapping. */ in.s_addr = htonl(val); tor_inet_ntoa(&in,valbuf,sizeof(valbuf)); - if (exitname) { - /* XXXX fails to ever get attempts to get an exit address of - * google.com.digest[=~]nickname.exit; we need a syntax for this that - * won't make strict RFC952-compliant applications (like us) barf. */ - tor_snprintf(extendedaddress, sizeof(extendedaddress), - "%s.%s.exit", address, exitname); - tor_snprintf(extendedval, sizeof(extendedval), - "%s.%s.exit", valbuf, exitname); - } else { - tor_snprintf(extendedaddress, sizeof(extendedaddress), - "%s", address); - tor_snprintf(extendedval, sizeof(extendedval), - "%s", valbuf); - } - addressmap_register(extendedaddress, tor_strdup(extendedval), - time(NULL) + ttl); + + client_dns_set_addressmap_impl(address, valbuf, exitname, ttl); +} + +/** DOCDOC */ +static void +client_dns_set_reverse_addressmap(const char *address, const char *v, + const char *exitname, + int ttl) +{ + size_t len = strlen(address) + 16; + char *s = tor_malloc(len); + tor_snprintf(s, len, "REVERSE[%s]", address); + client_dns_set_addressmap_impl(s, v, exitname, ttl); + tor_free(s); } /* By default, we hand out 127.192.0.1 through 127.254.254.254. @@ -1103,8 +1163,19 @@ connection_ap_handshake_rewrite_and_attach(edge_connection_t *conn, safe_str(socks->address), socks->port); - /* For address map controls, remap the address */ - addressmap_rewrite(socks->address, sizeof(socks->address)); + if (socks->command == SOCKS_COMMAND_RESOLVE_PTR) { + if (addressmap_rewrite_reverse(socks->address, sizeof(socks->address))) { + connection_ap_handshake_socks_resolved(conn, RESOLVED_TYPE_HOSTNAME, + strlen(socks->address), + socks->address, -1); + connection_mark_unattached_ap(conn, + END_STREAM_REASON_ALREADY_SOCKS_REPLIED); + return 0; + } + } else { + /* For address map controls, remap the address */ + addressmap_rewrite(socks->address, sizeof(socks->address)); + } if (address_is_in_virtual_range(socks->address)) { /* This address was probably handed out by client_dns_get_unmapped_address, @@ -1826,11 +1897,19 @@ connection_ap_handshake_socks_resolved(edge_connection_t *conn, char buf[384]; size_t replylen; - if (answer_type == RESOLVED_TYPE_IPV4) { - uint32_t a = ntohl(get_uint32(answer)); - if (a) - client_dns_set_addressmap(conn->socks_request->address, a, - conn->chosen_exit_name, ttl); + if (ttl >= 0) { + if (answer_type == RESOLVED_TYPE_IPV4 && answer_len == 4) { + uint32_t a = ntohl(get_uint32(answer)); + if (a) + client_dns_set_addressmap(conn->socks_request->address, a, + conn->chosen_exit_name, ttl); + } else if (answer_type == RESOLVED_TYPE_HOSTNAME && answer_len < 256) { + char *cp = tor_strndup(answer, answer_len); + client_dns_set_reverse_addressmap(conn->socks_request->address, + cp, + conn->chosen_exit_name, ttl); + tor_free(cp); + } } if (conn->socks_request->socks_version == 4) {