Commit 15efc25f authored by Rasmus Dahlberg's avatar Rasmus Dahlberg Committed by David Goulet
Browse files

dns: Make TTLs fuzzy at exit relays

This change mitigates DNS-based website oracles by making the time that
a domain name is cached uncertain (+- 4 minutes of what's measurable).

Resolves TROVE-2021-009.

Fixes #40674
parent be7afe65
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@
#include "feature/stats/predict_ports.h"
#include "feature/stats/rephist.h"
#include "lib/buf/buffers.h"
#include "lib/crypt_ops/crypto_rand.h"
#include "lib/crypt_ops/crypto_util.h"

#include "core/or/cell_st.h"
@@ -498,6 +499,21 @@ clip_dns_ttl(uint32_t ttl)
    return MAX_DNS_TTL;
}

/** Given a TTL (in seconds), determine what TTL an exit relay should use by
 * first clipping as usual and then adding some randomness which is sampled
 * uniformly at random from [-FUZZY_DNS_TTL, FUZZY_DNS_TTL].  This facilitates
 * fuzzy TTLs, which makes it harder to infer when a website was visited via
 * side-channels like DNS (see "Website Fingerprinting with Website Oracles").
 *
 * Note that this can't underflow because FUZZY_DNS_TTL < MIN_DNS_TTL.
 */
uint32_t
clip_dns_fuzzy_ttl(uint32_t ttl)
{
  return clip_dns_ttl(ttl) +
    crypto_rand_uint(1 + 2*FUZZY_DNS_TTL) - FUZZY_DNS_TTL;
}

/** Send a relay end cell from stream <b>conn</b> down conn's circuit, and
 * remember that we've done so.  If this is not a client connection, set the
 * relay end cell's reason for closing as <b>reason</b>.
+10 −4
Original line number Diff line number Diff line
@@ -188,11 +188,9 @@ void connection_ap_warn_and_unmark_if_pending_circ(
                                             entry_connection_t *entry_conn,
                                             const char *where);

/** Lowest value for DNS ttl that a server should give or a client should
 * believe. */
/** Lowest value for DNS ttl clipping excluding the random addition. */
#define MIN_DNS_TTL (5*60)
/** Highest value for DNS ttl that a server should give or a client should
 * believe. */
/** Highest value for DNS ttl clipping excluding the random addition. */
#define MAX_DNS_TTL (60*60)
/** How long do we keep DNS cache entries before purging them (regardless of
 * their TTL)? */
@@ -200,8 +198,16 @@ void connection_ap_warn_and_unmark_if_pending_circ(
/** How long do we cache/tell clients to cache DNS records when no TTL is
 * known? */
#define DEFAULT_DNS_TTL (30*60)
/** How much should we +- each TTL to make it fuzzy with uniform sampling at
 * exits?  The value 4 minutes was chosen so that the lowest possible clip is
 * 60s.  Such low clips were used in the past for all TTLs due to a bug in Tor,
 * see "The effect of DNS on Tor's Anonymity" by Greschbach et al.  In other
 * words, sampling such low clips is unlikely to cause any breakage at exits.
 */
#define FUZZY_DNS_TTL (4*60)

uint32_t clip_dns_ttl(uint32_t ttl);
uint32_t clip_dns_fuzzy_ttl(uint32_t ttl);

int connection_half_edge_is_valid_data(const smartlist_t *half_conns,
                                       streamid_t stream_id);
+1 −1
Original line number Diff line number Diff line
@@ -1637,7 +1637,7 @@ evdns_callback(int result, char type, int count, int ttl, void *addresses,
  }
  if (result != DNS_ERR_SHUTDOWN)
    dns_found_answer(string_address, orig_query_type,
                     result, &addr, hostname, clip_dns_ttl(ttl));
                     result, &addr, hostname, clip_dns_fuzzy_ttl(ttl));

  tor_free(arg_);
}
+31 −0
Original line number Diff line number Diff line
@@ -90,6 +90,36 @@ test_dns_clip_ttl(void *arg)
  return;
}

static void
test_dns_clip_fuzzy_ttl(void *arg)
{
  (void)arg;

  /* Case 0: check that the fuzzy TTL constant is valid
   */
  tt_int_op(FUZZY_DNS_TTL, OP_LE, MIN_DNS_TTL);
  tt_int_op(FUZZY_DNS_TTL, OP_LE, MAX_DNS_TTL);

  /* Case 1: low clips
   */
  for (int i = 0; i < 1024; i++) {
    int fuzzy_ttl = clip_dns_fuzzy_ttl(MIN_DNS_TTL - 1);
    tt_int_op(fuzzy_ttl, OP_GE, MIN_DNS_TTL-FUZZY_DNS_TTL);
    tt_int_op(fuzzy_ttl, OP_LE, MIN_DNS_TTL+FUZZY_DNS_TTL);
  }

  /* Case 2: high clips
   */
  for (int i = 0; i < 1024; i++) {
    int fuzzy_ttl = clip_dns_fuzzy_ttl(MIN_DNS_TTL);
    tt_int_op(fuzzy_ttl, OP_GE, MAX_DNS_TTL-FUZZY_DNS_TTL);
    tt_int_op(fuzzy_ttl, OP_LE, MAX_DNS_TTL+FUZZY_DNS_TTL);
  }

  done:
  return;
}

static int resolve_retval = 0;
static int resolve_made_conn_pending = 0;
static char *resolved_name = NULL;
@@ -779,6 +809,7 @@ struct testcase_t dns_tests[] = {
     TT_FORK, NULL, NULL },
#endif
   { "clip_ttl", test_dns_clip_ttl, TT_FORK, NULL, NULL },
   { "clip_fuzzy_ttl", test_dns_clip_fuzzy_ttl, TT_FORK, NULL, NULL },
   { "resolve", test_dns_resolve, TT_FORK, NULL, NULL },
   { "impl_addr_is_ip", test_dns_impl_addr_is_ip, TT_FORK, NULL, NULL },
   { "impl_non_exit", test_dns_impl_non_exit, TT_FORK, NULL, NULL },