tor  master
Macros | Functions
dns.c File Reference

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>
Include dependency graph for dns.c:

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_tdns_get_cache_entry (cached_resolve_t *query)
 
void dns_insert_cache_entry (cached_resolve_t *new_entry)
 

Detailed Description

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:

  1. To check whether the DNS server is working more or less correctly. This happens via dns_launch_correctness_checks(). The answer is reported in the return value from later calls to dns_seems_to_be_broken().
  2. When a client has asked the relay, in a RELAY_BEGIN cell, to connect to a given server by hostname. This happens via dns_resolve().
  3. When a client has asked the relay, in a RELAY_RESOLVE cell, to look up a given server's IP address(es) by hostname. This also happens via dns_resolve().

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.

Macro Definition Documentation

◆ RESOLVE_MAX_TIMEOUT

#define RESOLVE_MAX_TIMEOUT   300

How long will we wait for an answer from the resolver before we decide that the resolver is wedged?

Function Documentation

◆ assert_all_pending_dns_resolves_ok()

void assert_all_pending_dns_resolves_ok ( void  )

Log an error and abort if any connection waiting for a DNS resolve is corrupted.

Here is the call graph for this function:

◆ assert_connection_edge_not_dns_pending()

void assert_connection_edge_not_dns_pending ( edge_connection_t conn)

Log an error and abort if conn is waiting for a DNS resolve.

◆ connection_dns_remove()

void connection_dns_remove ( edge_connection_t conn)

Remove conn from the list of connections waiting for conn->address.

◆ dns_clip_ttl()

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.

Here is the caller graph for this function:

◆ dns_free_all()

void dns_free_all ( void  )

Free all storage held in the DNS cache and related structures.

◆ dns_init()

int dns_init ( void  )

Initialize the DNS subsystem; called by the OR process.

Here is the caller graph for this function:

◆ dns_launch_correctness_checks()

void dns_launch_correctness_checks ( void  )

If appropriate, start testing whether our DNS servers tend to lie to us.

◆ dns_reset()

int dns_reset ( void  )

Called when DNS-related options change (or may have changed). Returns -1 on failure, 0 on success.

◆ dns_reset_correctness_checks()

void dns_reset_correctness_checks ( void  )

Forget what we've previously learned about our DNS servers' correctness.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dns_resolve()

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.

◆ dns_seems_to_be_broken()

int dns_seems_to_be_broken ( void  )

Return true iff our DNS servers lie to us too much to be trusted.

◆ dns_seems_to_be_broken_for_ipv6()

int dns_seems_to_be_broken_for_ipv6 ( void  )

Return true iff we think that IPv6 hostname lookup is broken

◆ dump_dns_mem_usage()

void dump_dns_mem_usage ( int  severity)

Log memory information about our internal DNS cache at level 'severity'.

◆ has_dns_init_failed()

int has_dns_init_failed ( void  )

Return true iff the most recent attempt to initialize the DNS subsystem failed.

◆ HT_PROTOTYPE()

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() [1/6]

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.

Here is the call graph for this function:

◆ MOCK_IMPL() [2/6]

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.

Here is the call graph for this function:

◆ MOCK_IMPL() [3/6]

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:

  • marking connections on error and clearing their on_circuit
  • linking connections to n_streams/resolving_streams,
  • sending resolved cells if we have an answer/error right away,

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.

Here is the call graph for this function:

◆ MOCK_IMPL() [4/6]

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() [5/6]

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() [6/6]

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."

Here is the call graph for this function: