Tor 0.4.9.0-alpha-dev
|
Implements a local cache for DNS results for Tor servers. This is implemented as a wrapper around Adam Langley's eventdns.c code. (We can't just use gethostbyname() and friends because we really need to be nonblocking.) More...
#include "core/or/or.h"
#include "app/config/config.h"
#include "core/mainloop/connection.h"
#include "core/mainloop/mainloop.h"
#include "core/mainloop/netstatus.h"
#include "core/or/circuitlist.h"
#include "core/or/circuituse.h"
#include "core/or/connection_edge.h"
#include "core/or/policies.h"
#include "core/or/relay.h"
#include "feature/control/control_events.h"
#include "feature/relay/dns.h"
#include "feature/nodelist/networkstatus.h"
#include "feature/relay/router.h"
#include "feature/relay/routermode.h"
#include "feature/stats/rephist.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/evloop/compat_libevent.h"
#include "lib/sandbox/sandbox.h"
#include "core/or/edge_connection_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/conflux_util.h"
#include "ht.h"
#include <event2/event.h>
#include <event2/dns.h>
Go to the source code of this file.
Macros | |
#define | DNS_PRIVATE |
#define | RESOLVE_MAX_TIMEOUT 300 |
#define | assert_cache_ok() STMT_NIL |
#define | RESOLVED_TYPE_AUTO 0xff |
#define | EXIT_DNS_TIMEOUT_DEFAULT (1000) |
#define | EXIT_DNS_TIMEOUT_MIN (1) |
#define | EXIT_DNS_TIMEOUT_MAX (120000) |
#define | EXIT_DNS_NUM_ATTEMPTS_DEFAULT (2) |
#define | EXIT_DNS_NUM_ATTEMPTS_MIN (0) |
#define | EXIT_DNS_NUM_ATTEMPTS_MAX (255) |
#define | SET(k, v) evdns_base_set_option(the_evdns_base, (k), (v)) |
#define | N_WILDCARD_CHECKS 2 |
Functions | |
static void | purge_expired_resolves (time_t now) |
static void | dns_found_answer (const char *address, uint8_t query_type, int dns_answer, const tor_addr_t *addr, const char *hostname, uint32_t ttl) |
static void | add_wildcarded_test_address (const char *address) |
static int | configure_nameservers (int force) |
static int | answer_is_wildcarded (const char *ip) |
static int | evdns_err_is_transient (int err) |
static void | inform_pending_connections (cached_resolve_t *resolve) |
static void | make_pending_resolve_cached (cached_resolve_t *cached) |
static void | configure_libevent_options (void) |
static void | assert_resolve_ok (cached_resolve_t *resolve) |
static | HT_HEAD (cache_map, cached_resolve_t) |
static unsigned int | cached_resolve_hash (cached_resolve_t *a) |
HT_PROTOTYPE (cache_map, cached_resolve_t, node, cached_resolve_hash, cached_resolves_eq) | |
HT_GENERATE2 (cache_map, cached_resolve_t, node, cached_resolve_hash, cached_resolves_eq, 0.6, tor_reallocarray_, tor_free_) | |
static void | init_cache_map (void) |
static void | evdns_log_cb (int warn, const char *msg) |
void | dns_new_consensus_params (const networkstatus_t *ns) |
int | dns_init (void) |
int | dns_reset (void) |
int | has_dns_init_failed (void) |
static void | free_cached_resolve_ (cached_resolve_t *r) |
static int | compare_cached_resolves_by_expiry_ (const void *_a, const void *_b) |
static void | cached_resolve_add_answer (cached_resolve_t *resolve, int query_type, int dns_result, const tor_addr_t *answer_addr, const char *answer_hostname, uint32_t ttl) |
static int | cached_resolve_have_all_answers (const cached_resolve_t *resolve) |
static void | set_expiry (cached_resolve_t *resolve, time_t expires) |
void | dns_free_all (void) |
STATIC void | send_resolved_cell (edge_connection_t *conn, uint8_t answer_type, const cached_resolve_t *resolved) |
void | dns_send_resolved_error_cell (edge_connection_t *conn, uint8_t answer_type) |
STATIC void | send_resolved_hostname_cell (edge_connection_t *conn, const char *hostname) |
int | dns_resolve (edge_connection_t *exitconn) |
STATIC int | dns_resolve_impl (edge_connection_t *exitconn, int is_resolve, or_circuit_t *oncirc, char **hostname_out, int *made_connection_pending_out, cached_resolve_t **resolve_out) |
STATIC int | set_exitconn_info_from_resolve (edge_connection_t *exitconn, const cached_resolve_t *resolve, char **hostname_out) |
void | assert_connection_edge_not_dns_pending (edge_connection_t *conn) |
void | connection_dns_remove (edge_connection_t *conn) |
STATIC void | dns_cancel_pending_resolve (const char *address) |
static int | is_test_address (const char *address) |
size_t | number_of_configured_nameservers (void) |
static const char * | get_consensus_param_exit_dns_timeout (void) |
static const char * | get_consensus_param_exit_dns_attempts (void) |
static void | evdns_callback (int result, char type, int count, int ttl, void *addresses, void *arg) |
static int | launch_one_resolve (const char *address, uint8_t query_type, const tor_addr_t *ptr_address) |
STATIC int | launch_resolve (cached_resolve_t *resolve) |
static void | wildcard_increment_answer (const char *id) |
static void | evdns_wildcard_check_callback (int result, char type, int count, int ttl, void *addresses, void *arg) |
static void | launch_wildcard_check (int min_len, int max_len, int is_ipv6, const char *suffix) |
static void | launch_test_addresses (evutil_socket_t fd, short event, void *args) |
static void | dns_launch_wildcard_checks (void) |
void | dns_launch_correctness_checks (void) |
int | dns_seems_to_be_broken (void) |
int | dns_seems_to_be_broken_for_ipv6 (void) |
void | dns_reset_correctness_checks (void) |
static int | dns_cache_entry_count (void) |
size_t | dns_cache_total_allocation (void) |
void | dump_dns_mem_usage (int severity) |
size_t | dns_cache_handle_oom (time_t now, size_t min_remove_bytes) |
cached_resolve_t * | dns_get_cache_entry (cached_resolve_t *query) |
void | dns_insert_cache_entry (cached_resolve_t *new_entry) |
Variables | |
static struct evdns_base * | the_evdns_base = NULL |
static int | nameservers_configured = 0 |
static int | nameserver_config_failed = 0 |
static char * | resolv_conf_fname = NULL |
static time_t | resolv_conf_mtime = 0 |
static smartlist_t * | cached_resolve_pqueue = NULL |
static int | n_wildcard_requests = 0 |
static strmap_t * | dns_wildcard_response_count = NULL |
static smartlist_t * | dns_wildcard_list = NULL |
static int | dns_wildcard_one_notice_given = 0 |
static int | dns_wildcard_notice_given = 0 |
static smartlist_t * | dns_wildcarded_test_address_list = NULL |
static int | dns_wildcarded_test_address_notice_given = 0 |
static int | dns_is_completely_invalid = 0 |
Implements a local cache for DNS results for Tor servers. This is implemented as a wrapper around Adam Langley's eventdns.c code. (We can't just use gethostbyname() and friends because we really need to be nonblocking.)
There are three main cases when a Tor relay uses dns.c to launch a DNS request:
Each of these gets handled a little differently.
To check for correctness, we look up some hostname we expect to exist and have real entries, some hostnames which we expect to definitely not exist, and some hostnames that we expect to probably not exist. If too many of the hostnames that shouldn't exist do exist, that's a DNS hijacking attempt. If too many of the hostnames that should exist have the same addresses as the ones that shouldn't exist, that's a very bad DNS hijacking attempt, or a very naughty captive portal. And if the hostnames that should exist simply don't exist, we probably have a broken nameserver.
To handle client requests, we first check our cache for answers. If there isn't something up-to-date, we've got to launch A or AAAA requests as appropriate. How we handle responses to those in particular is a bit complex; see dns_lookup() and set_exitconn_info_from_resolve().
When a lookup is finally complete, the inform_pending_connections() function will tell all of the streams that have been waiting for the resolve, by calling connection_exit_connect() if the client sent a RELAY_BEGIN cell, and by calling send_resolved_cell() or send_hostname_cell() if the client sent a RELAY_RESOLVE cell.
Definition in file dns.c.
#define RESOLVE_MAX_TIMEOUT 300 |
|
static |
|
static |
void assert_connection_edge_not_dns_pending | ( | edge_connection_t * | conn | ) |
Log an error and abort if conn is waiting for a DNS resolve.
Definition at line 966 of file dns.c.
Referenced by connection_unlink().
|
static |
|
static |
|
inlinestatic |
|
static |
|
static |
Compare two cached_resolve_t pointers by expiry time, and return less-than-zero, zero, or greater-than-zero as appropriate. Used for the priority queue implementation.
Definition at line 300 of file dns.c.
Referenced by set_expiry().
|
static |
Configure the libevent options. This can safely be called after initialization or even if the evdns base is not set.
Definition at line 1432 of file dns.c.
Referenced by dns_new_consensus_params().
|
static |
Configure eventdns nameservers if force is true, or if the configuration has changed since the last time we called this function, or if we failed on our last attempt. On Unix, this reads from /etc/resolv.conf or options->ServerDNSResolvConfFile; on Windows, this reads from options->ServerDNSResolvConfFile or the registry. Return 0 on success or -1 on failure.
Definition at line 1493 of file dns.c.
Referenced by dns_init().
void connection_dns_remove | ( | edge_connection_t * | conn | ) |
Remove conn from the list of connections waiting for conn->address.
Definition at line 993 of file dns.c.
Referenced by connection_exit_about_to_close().
|
static |
Return the number of DNS cache entries as an int
Definition at line 2210 of file dns.c.
Referenced by dump_dns_mem_usage().
size_t dns_cache_handle_oom | ( | time_t | now, |
size_t | min_remove_bytes | ||
) |
STATIC void dns_cancel_pending_resolve | ( | const char * | address | ) |
|
static |
Called on the OR side when the eventdns library tells us the outcome of a single DNS resolve: remember the answer, and tell all pending connections about the result of the lookup if the lookup is now done. (address is a NUL-terminated string containing the address to look up; query_type is one of DNS_{IPv4_A,IPv6_AAAA,PTR}; dns_answer is DNS_OK or one of DNS_ERR_*, addr is an IPv4 or IPv6 address if we got one; hostname is a hostname fora PTR request if we got one, and ttl is the time-to-live of this answer, in seconds.)
void dns_free_all | ( | void | ) |
cached_resolve_t * dns_get_cache_entry | ( | cached_resolve_t * | query | ) |
int dns_init | ( | void | ) |
Initialize the DNS subsystem; called by the OR process.
Definition at line 233 of file dns.c.
Referenced by retry_dns_callback().
void dns_insert_cache_entry | ( | cached_resolve_t * | new_entry | ) |
void dns_launch_correctness_checks | ( | void | ) |
|
static |
Launch DNS requests for a few nonexistent hostnames and a few well-known hostnames, and see if we can catch our nameserver trying to hijack them and map them to a stupid "I couldn't find ggoogle.com but maybe you'd like to buy these lovely encyclopedias" page.
Definition at line 2086 of file dns.c.
Referenced by dns_launch_correctness_checks().
void dns_new_consensus_params | ( | const networkstatus_t * | ns | ) |
int dns_reset | ( | void | ) |
void dns_reset_correctness_checks | ( | void | ) |
Forget what we've previously learned about our DNS servers' correctness.
Definition at line 2153 of file dns.c.
Referenced by dns_servers_relaunch_checks().
int dns_resolve | ( | edge_connection_t * | exitconn | ) |
See if we have a cache entry for exitconn->address. If so, if resolve valid, put it into exitconn->addr and return 1. If resolve failed, free exitconn and return -1.
(For EXIT_PURPOSE_RESOLVE connections, send back a RESOLVED error cell on returning -1. For EXIT_PURPOSE_CONNECT connections, there's no need to send back an END cell, since connection_exit_begin_conn will do that for us.)
If we have a cached answer, send the answer back along exitconn's circuit.
Else, if seen before and pending, add conn to the pending list, and return 0.
Else, if not seen before, add conn to pending list, hand to dns farm, and return 0.
Exitconn's on_circuit field must be set, but exitconn should not yet be linked onto the n_streams/resolving_streams list of that circuit. On success, link the connection to n_streams if it's an exit connection. On "pending", link the connection to resolving streams. Otherwise, clear its on_circuit field.
STATIC int dns_resolve_impl | ( | edge_connection_t * | exitconn, |
int | is_resolve, | ||
or_circuit_t * | oncirc, | ||
char ** | hostname_out, | ||
int * | made_connection_pending_out, | ||
cached_resolve_t ** | resolve_out | ||
) |
Helper function for dns_resolve: same functionality, but does not handle:
Return -2 on a transient error. If it's a reverse resolve and it's successful, sets *hostname_out to a newly allocated string holding the cached reverse DNS value.
Set *made_connection_pending_out to true if we have placed exitconn on the list of pending connections for some resolve; set it to false otherwise.
Set *resolve_out to a cached resolve, if we found one.
Definition at line 719 of file dns.c.
Referenced by dns_resolve().
int dns_seems_to_be_broken | ( | void | ) |
int dns_seems_to_be_broken_for_ipv6 | ( | void | ) |
void dns_send_resolved_error_cell | ( | edge_connection_t * | conn, |
uint8_t | answer_type | ||
) |
void dump_dns_mem_usage | ( | int | severity | ) |
Log memory information about our internal DNS cache at level 'severity'.
Definition at line 2225 of file dns.c.
Referenced by dumpmemusage().
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
|
static |
int has_dns_init_failed | ( | void | ) |
Return true iff the most recent attempt to initialize the DNS subsystem failed.
Definition at line 274 of file dns.c.
Referenced by retry_dns_callback().
|
static |
|
static |
Given a pending cached_resolve_t that we just finished resolving, inform every connection that was waiting for the outcome of that resolution.
Do this by sending a RELAY_RESOLVED cell (if the pending stream had sent us a RELAY_RESOLVE cell), or by launching an exit connection (if the pending stream had sent us a RELAY_BEGIN cell).
|
static |
|
inlinestatic |
|
static |
STATIC int launch_resolve | ( | cached_resolve_t * | resolve | ) |
|
static |
|
static |
|
static |
Remove a pending cached_resolve_t from the hashtable, and add a corresponding cached cached_resolve_t.
This function is only necessary because of the perversity of our cache timeout code; see inline comment for ideas on eliminating it.
size_t number_of_configured_nameservers | ( | void | ) |
|
static |
STATIC void send_resolved_cell | ( | edge_connection_t * | conn, |
uint8_t | answer_type, | ||
const cached_resolve_t * | resolved | ||
) |
Send a response to the RESOLVE request of a connection. answer_type must be one of RESOLVED_TYPE_(AUTO|ERROR|ERROR_TRANSIENT|).
If circ is provided, and we have a cached answer, send the answer back along circ; otherwise, send the answer back along conn's attached circuit.
Definition at line 509 of file dns.c.
Referenced by dns_resolve().
STATIC void send_resolved_hostname_cell | ( | edge_connection_t * | conn, |
const char * | hostname | ||
) |
Send a response to the RESOLVE request of a connection for an in-addr.arpa address on connection conn which yielded the result hostname. The answer type will be RESOLVED_HOSTNAME.
If circ is provided, and we have a cached answer, send the answer back along circ; otherwise, send the answer back along conn's attached circuit.
Definition at line 582 of file dns.c.
Referenced by dns_resolve().
STATIC int set_exitconn_info_from_resolve | ( | edge_connection_t * | exitconn, |
const cached_resolve_t * | resolve, | ||
char ** | hostname_out | ||
) |
Given an exit connection exitconn, and a cached_resolve_t resolve whose DNS lookups have all either succeeded or failed, update the appropriate fields (address_ttl and addr) of exitconn.
The logic can be complicated here, since we might have launched both an A lookup and an AAAA lookup, and since either of those might have succeeded or failed, and since we want to answer a RESOLVE cell with a full answer but answer a BEGIN cell with whatever answer the client would accept and we could still connect to.
If this is a reverse lookup, set *hostname_out to a newly allocated copy of the name resulting hostname.
Return -2 on a transient error, -1 on a permenent error, and 1 on a successful lookup.
Definition at line 871 of file dns.c.
Referenced by inform_pending_connections().
|
static |
Set an expiry time for a cached_resolve_t, and add it to the expiry priority queue
|
static |
|
static |
Priority queue of cached_resolve_t objects to let us know when they will expire.
Definition at line 313 of file dns.c.
Referenced by set_expiry().
|
static |
True iff all addresses seem to be getting wildcarded.
Definition at line 1892 of file dns.c.
Referenced by dns_seems_to_be_broken().
|
static |
If present, a list of dotted-quad IP addresses that we are pretty sure our nameserver wants to return in response to requests for nonexistent domains.
Definition at line 1878 of file dns.c.
Referenced by answer_is_wildcarded().
|
static |
|
static |
|
static |
Map from dotted-quad IP address in response to an int holding how many times we've seen it for a randomly generated (hopefully bogus) address. It would be easier to use definitely-invalid addresses (as specified by RFC2606), but see comment in dns_launch_wildcard_checks().
Definition at line 1873 of file dns.c.
Referenced by wildcard_increment_answer().
|
static |
List of supposedly good addresses that are getting wildcarded to the same addresses as nonexistent addresses.
Definition at line 1888 of file dns.c.
Referenced by add_wildcarded_test_address().
|
static |
|
static |
|
static |
Did our most recent attempt to configure nameservers with eventdns fail?
Definition at line 95 of file dns.c.
Referenced by has_dns_init_failed().
|
static |
Have we currently configured nameservers with eventdns?
Definition at line 93 of file dns.c.
Referenced by launch_resolve().
|
static |
|
static |
|
static |
Our evdns_base; this structure handles all our name lookups.
Definition at line 90 of file dns.c.
Referenced by configure_libevent_options(), configure_nameservers(), dns_reset(), and number_of_configured_nameservers().