tor
master
|
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 "or.h"
#include "circuitlist.h"
#include "circuituse.h"
#include "config.h"
#include "connection.h"
#include "connection_edge.h"
#include "control.h"
#include "crypto_rand.h"
#include "dns.h"
#include "main.h"
#include "policies.h"
#include "relay.h"
#include "router.h"
#include "ht.h"
#include "sandbox.h"
#include <event2/event.h>
#include <event2/dns.h>
Macros | |
#define | DNS_PRIVATE |
#define | RESOLVE_MAX_TIMEOUT 300 |
#define | assert_cache_ok() STMT_NIL |
#define | RESOLVED_TYPE_AUTO 0xff |
#define | SET(k, v) evdns_base_set_option(the_evdns_base, (k), (v)) |
#define | N_WILDCARD_CHECKS 2 |
Functions | |
HT_PROTOTYPE (HT_GENERATE2(cache_map, HT_GENERATE2(cached_resolve_t, HT_GENERATE2(node, HT_GENERATE2(cached_resolve_hash, HT_GENERATE2(cached_resolves_eq) | |
int | dns_init (void) |
int | dns_reset (void) |
int | has_dns_init_failed (void) |
uint32_t | dns_clip_ttl (uint32_t ttl) |
void | dns_free_all (void) |
MOCK_IMPL (STATIC void, send_resolved_cell,(edge_connection_t *conn, uint8_t answer_type, const cached_resolve_t *resolved)) | |
MOCK_IMPL (STATIC void, send_resolved_hostname_cell,(edge_connection_t *conn, const char *hostname)) | |
int | dns_resolve (edge_connection_t *exitconn) |
MOCK_IMPL (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)) | |
MOCK_IMPL (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 | assert_all_pending_dns_resolves_ok (void) |
void | connection_dns_remove (edge_connection_t *conn) |
MOCK_IMPL (void, dns_cancel_pending_resolve,(const char *address)) | |
MOCK_IMPL (STATIC int, launch_resolve,(cached_resolve_t *resolve)) | |
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) |
void | dump_dns_mem_usage (int severity) |
cached_resolve_t * | dns_get_cache_entry (cached_resolve_t *query) |
void | dns_insert_cache_entry (cached_resolve_t *new_entry) |
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.
#define RESOLVE_MAX_TIMEOUT 300 |
How long will we wait for an answer from the resolver before we decide that the resolver is wedged?
void assert_all_pending_dns_resolves_ok | ( | void | ) |
Log an error and abort if any connection waiting for a DNS resolve is corrupted.
void assert_connection_edge_not_dns_pending | ( | edge_connection_t * | conn | ) |
Log an error and abort if conn is waiting for a DNS resolve.
void connection_dns_remove | ( | edge_connection_t * | conn | ) |
Remove conn from the list of connections waiting for conn->address.
uint32_t dns_clip_ttl | ( | uint32_t | ttl | ) |
Helper: Given a TTL from a DNS response, determine what TTL to give the OP that asked us to resolve it, and how long to cache that record ourselves.
void dns_free_all | ( | void | ) |
Free all storage held in the DNS cache and related structures.
int dns_init | ( | void | ) |
Initialize the DNS subsystem; called by the OR process.
void dns_launch_correctness_checks | ( | void | ) |
If appropriate, start testing whether our DNS servers tend to lie to us.
int dns_reset | ( | void | ) |
Called when DNS-related options change (or may have changed). Returns -1 on failure, 0 on success.
void dns_reset_correctness_checks | ( | void | ) |
Forget what we've previously learned about our DNS servers' correctness.
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.
int dns_seems_to_be_broken | ( | void | ) |
Return true iff our DNS servers lie to us too much to be trusted.
int dns_seems_to_be_broken_for_ipv6 | ( | void | ) |
Return true iff we think that IPv6 hostname lookup is broken
void dump_dns_mem_usage | ( | int | severity | ) |
Log memory information about our internal DNS cache at level 'severity'.
int has_dns_init_failed | ( | void | ) |
Return true iff the most recent attempt to initialize the DNS subsystem failed.
HT_PROTOTYPE | ( | HT_GENERATE2( | cache_map, |
HT_GENERATE2( | cached_resolve_t, | ||
HT_GENERATE2( | node, | ||
HT_GENERATE2( | cached_resolve_hash, | ||
HT_GENERATE2( | cached_resolves_eq | ||
) |
Initialize the DNS cache.
MOCK_IMPL | ( | 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.
MOCK_IMPL | ( | 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.
MOCK_IMPL | ( | 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.
MOCK_IMPL | ( | 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.
MOCK_IMPL | ( | void | , |
dns_cancel_pending_resolve | , | ||
(const char *address) | |||
) |
Mark all connections waiting for address for close. Then cancel the resolve for address itself, and remove any cached results for address from the cache.
MOCK_IMPL | ( | STATIC | int, |
launch_resolve | , | ||
(cached_resolve_t *resolve) | |||
) |
For eventdns: start resolving as necessary to find the target for exitconn. Returns -1 on error, -2 on transient error, 0 on "resolve launched."