mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-24 14:51:11 +01:00
Merge remote-tracking branch 'dgoulet/ticket24902_029_05'
This commit is contained in:
commit
abdf2a6f7f
13 changed files with 560 additions and 0 deletions
|
@ -1204,6 +1204,28 @@ tor_addr_hash(const tor_addr_t *addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** As tor_addr_hash, but use a particular siphash key. */
|
||||||
|
uint64_t
|
||||||
|
tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr)
|
||||||
|
{
|
||||||
|
/* This is duplicate code with tor_addr_hash, since this function needs to
|
||||||
|
* be backportable all the way to 0.2.9. */
|
||||||
|
|
||||||
|
switch (tor_addr_family(addr)) {
|
||||||
|
case AF_INET:
|
||||||
|
return siphash24(&addr->addr.in_addr.s_addr, 4, key);
|
||||||
|
case AF_UNSPEC:
|
||||||
|
return 0x4e4d5342;
|
||||||
|
case AF_INET6:
|
||||||
|
return siphash24(&addr->addr.in6_addr.s6_addr, 16, key);
|
||||||
|
default:
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
|
tor_fragile_assert();
|
||||||
|
return 0;
|
||||||
|
/* LCOV_EXCL_END */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Return a newly allocated string with a representation of <b>addr</b>. */
|
/** Return a newly allocated string with a representation of <b>addr</b>. */
|
||||||
char *
|
char *
|
||||||
tor_addr_to_str_dup(const tor_addr_t *addr)
|
tor_addr_to_str_dup(const tor_addr_t *addr)
|
||||||
|
|
|
@ -231,6 +231,8 @@ int tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
|
||||||
#define tor_addr_eq(a,b) (0==tor_addr_compare((a),(b),CMP_EXACT))
|
#define tor_addr_eq(a,b) (0==tor_addr_compare((a),(b),CMP_EXACT))
|
||||||
|
|
||||||
uint64_t tor_addr_hash(const tor_addr_t *addr);
|
uint64_t tor_addr_hash(const tor_addr_t *addr);
|
||||||
|
struct sipkey;
|
||||||
|
uint64_t tor_addr_keyed_hash(const struct sipkey *key, const tor_addr_t *addr);
|
||||||
int tor_addr_is_v4(const tor_addr_t *addr);
|
int tor_addr_is_v4(const tor_addr_t *addr);
|
||||||
int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
|
int tor_addr_is_internal_(const tor_addr_t *ip, int for_listening,
|
||||||
const char *filename, int lineno);
|
const char *filename, int lineno);
|
||||||
|
|
129
src/common/address_set.c
Normal file
129
src/common/address_set.c
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/* Copyright (c) 2018, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file address_set.c
|
||||||
|
* \brief Implementation for a set of addresses.
|
||||||
|
*
|
||||||
|
* This module was first written on a semi-emergency basis to improve the
|
||||||
|
* robustness of the anti-DoS module. As such, it's written in a pretty
|
||||||
|
* conservative way, and should be susceptible to improvement later on.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "address_set.h"
|
||||||
|
#include "address.h"
|
||||||
|
#include "compat.h"
|
||||||
|
#include "container.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "siphash.h"
|
||||||
|
|
||||||
|
/** How many 64-bit siphash values to extract per address */
|
||||||
|
#define N_HASHES 2
|
||||||
|
/** How many bloom-filter bits we set per address. This is twice the N_HASHES
|
||||||
|
* value, since we split the siphash outcome two 32-bit values. */
|
||||||
|
#define N_BITS_PER_ITEM (N_HASHES * 2)
|
||||||
|
|
||||||
|
/* XXXX This code is largely duplicated with digestset_t. We should merge
|
||||||
|
* them together into a common bloom-filter implementation. I'm keeping
|
||||||
|
* them separate for now, though, since this module needs to be backported
|
||||||
|
* all the way to 0.2.9.
|
||||||
|
*
|
||||||
|
* The main difference between digestset_t and this code is that we use
|
||||||
|
* independent siphashes rather than messing around with bit-shifts. The
|
||||||
|
* approach here is probably more sound, and we should prefer it if&when we
|
||||||
|
* unify the implementations.
|
||||||
|
**/
|
||||||
|
|
||||||
|
struct address_set_t {
|
||||||
|
/** siphash keys to make N_HASHES independent hashes for each address. */
|
||||||
|
struct sipkey key[N_HASHES];
|
||||||
|
int mask; /**< One less than the number of bits in <b>ba</b>; always one less
|
||||||
|
* than a power of two. */
|
||||||
|
bitarray_t *ba; /**< A bit array to implement the Bloom filter. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate and return an address_set, suitable for holding up to
|
||||||
|
* <b>max_address_guess</b> distinct values.
|
||||||
|
*/
|
||||||
|
address_set_t *
|
||||||
|
address_set_new(int max_addresses_guess)
|
||||||
|
{
|
||||||
|
/* See digestset_new() for rationale on this equation. */
|
||||||
|
int n_bits = 1u << (tor_log2(max_addresses_guess)+5);
|
||||||
|
|
||||||
|
address_set_t *set = tor_malloc_zero(sizeof(address_set_t));
|
||||||
|
set->mask = n_bits - 1;
|
||||||
|
set->ba = bitarray_init_zero(n_bits);
|
||||||
|
crypto_rand((char*) set->key, sizeof(set->key));
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release all storage associated with <b>set</b>
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
address_set_free(address_set_t *set)
|
||||||
|
{
|
||||||
|
if (! set)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bitarray_free(set->ba);
|
||||||
|
tor_free(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Yield the bit index corresponding to 'val' for set. */
|
||||||
|
#define BIT(set, val) ((val) & (set)->mask)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add <b>addr</b> to <b>set</b>.
|
||||||
|
*
|
||||||
|
* All future queries for <b>addr</b> in set will return true. Removing
|
||||||
|
* items is not possible.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
address_set_add(address_set_t *set, const struct tor_addr_t *addr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < N_HASHES; ++i) {
|
||||||
|
uint64_t h = tor_addr_keyed_hash(&set->key[i], addr);
|
||||||
|
uint32_t high_bits = (uint32_t)(h >> 32);
|
||||||
|
uint32_t low_bits = (uint32_t)(h);
|
||||||
|
bitarray_set(set->ba, BIT(set, high_bits));
|
||||||
|
bitarray_set(set->ba, BIT(set, low_bits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** As address_set_add(), but take an ipv4 address in host order. */
|
||||||
|
void
|
||||||
|
address_set_add_ipv4h(address_set_t *set, uint32_t addr)
|
||||||
|
{
|
||||||
|
tor_addr_t a;
|
||||||
|
tor_addr_from_ipv4h(&a, addr);
|
||||||
|
address_set_add(set, &a);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if <b>addr</b> if a member of <b>set</b>. (And probably,
|
||||||
|
* return false if <b>addr</b> is not a member of set.)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
address_set_probably_contains(address_set_t *set,
|
||||||
|
const struct tor_addr_t *addr)
|
||||||
|
{
|
||||||
|
int i, matches = 0;
|
||||||
|
for (i = 0; i < N_HASHES; ++i) {
|
||||||
|
uint64_t h = tor_addr_keyed_hash(&set->key[i], addr);
|
||||||
|
uint32_t high_bits = (uint32_t)(h >> 32);
|
||||||
|
uint32_t low_bits = (uint32_t)(h);
|
||||||
|
// Note that !! is necessary here, since bitarray_is_set does not
|
||||||
|
// necessarily return 1 on true.
|
||||||
|
matches += !! bitarray_is_set(set->ba, BIT(set, high_bits));
|
||||||
|
matches += !! bitarray_is_set(set->ba, BIT(set, low_bits));
|
||||||
|
}
|
||||||
|
return matches == N_BITS_PER_ITEM;
|
||||||
|
}
|
||||||
|
|
35
src/common/address_set.h
Normal file
35
src/common/address_set.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* Copyright (c) 2018, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file addressset.h
|
||||||
|
* \brief Types to handle sets of addresses.
|
||||||
|
*
|
||||||
|
* This module was first written on a semi-emergency basis to improve the
|
||||||
|
* robustness of the anti-DoS module. As such, it's written in a pretty
|
||||||
|
* conservative way, and should be susceptible to improvement later on.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef TOR_ADDRESS_SET_H
|
||||||
|
#define TOR_ADDRESS_SET_H
|
||||||
|
|
||||||
|
#include "orconfig.h"
|
||||||
|
#include "torint.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An address_set_t represents a set of tor_addr_t values. The implementation
|
||||||
|
* is probabilistic: false negatives cannot occur but false positives are
|
||||||
|
* possible.
|
||||||
|
*/
|
||||||
|
typedef struct address_set_t address_set_t;
|
||||||
|
struct tor_addr_t;
|
||||||
|
|
||||||
|
address_set_t *address_set_new(int max_addresses_guess);
|
||||||
|
void address_set_free(address_set_t *set);
|
||||||
|
void address_set_add(address_set_t *set, const struct tor_addr_t *addr);
|
||||||
|
void address_set_add_ipv4h(address_set_t *set, uint32_t addr);
|
||||||
|
int address_set_probably_contains(address_set_t *set,
|
||||||
|
const struct tor_addr_t *addr);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -80,6 +80,7 @@ src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS)
|
||||||
|
|
||||||
LIBOR_A_SRC = \
|
LIBOR_A_SRC = \
|
||||||
src/common/address.c \
|
src/common/address.c \
|
||||||
|
src/common/address_set.c \
|
||||||
src/common/backtrace.c \
|
src/common/backtrace.c \
|
||||||
src/common/buffers.c \
|
src/common/buffers.c \
|
||||||
src/common/compat.c \
|
src/common/compat.c \
|
||||||
|
@ -145,6 +146,7 @@ src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
|
||||||
|
|
||||||
COMMONHEADERS = \
|
COMMONHEADERS = \
|
||||||
src/common/address.h \
|
src/common/address.h \
|
||||||
|
src/common/address_set.h \
|
||||||
src/common/backtrace.h \
|
src/common/backtrace.h \
|
||||||
src/common/buffers.h \
|
src/common/buffers.h \
|
||||||
src/common/buffers_tls.h \
|
src/common/buffers_tls.h \
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "geoip.h"
|
#include "geoip.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "networkstatus.h"
|
#include "networkstatus.h"
|
||||||
|
#include "nodelist.h"
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
|
|
||||||
#include "dos.h"
|
#include "dos.h"
|
||||||
|
@ -664,6 +665,14 @@ dos_new_client_conn(or_connection_t *or_conn)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We ignore any known address meaning an address of a known relay. The
|
||||||
|
* reason to do so is because network reentry is possible where a client
|
||||||
|
* connection comes from an Exit node. Even when we'll fix reentry, this is
|
||||||
|
* a robust defense to keep in place. */
|
||||||
|
if (nodelist_probably_contains_address(&or_conn->real_addr)) {
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* We are only interested in client connection from the geoip cache. */
|
/* We are only interested in client connection from the geoip cache. */
|
||||||
entry = geoip_lookup_client(&or_conn->real_addr, NULL,
|
entry = geoip_lookup_client(&or_conn->real_addr, NULL,
|
||||||
GEOIP_CLIENT_CONNECT);
|
GEOIP_CLIENT_CONNECT);
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
|
|
||||||
#include "or.h"
|
#include "or.h"
|
||||||
#include "address.h"
|
#include "address.h"
|
||||||
|
#include "address_set.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "control.h"
|
#include "control.h"
|
||||||
#include "dirserv.h"
|
#include "dirserv.h"
|
||||||
|
@ -87,6 +88,7 @@ static void count_usable_descriptors(int *num_present,
|
||||||
static void update_router_have_minimum_dir_info(void);
|
static void update_router_have_minimum_dir_info(void);
|
||||||
static double get_frac_paths_needed_for_circs(const or_options_t *options,
|
static double get_frac_paths_needed_for_circs(const or_options_t *options,
|
||||||
const networkstatus_t *ns);
|
const networkstatus_t *ns);
|
||||||
|
static void node_add_to_address_set(const node_t *node);
|
||||||
|
|
||||||
/** A nodelist_t holds a node_t object for every router we're "willing to use
|
/** A nodelist_t holds a node_t object for every router we're "willing to use
|
||||||
* for something". Specifically, it should hold a node_t for every node that
|
* for something". Specifically, it should hold a node_t for every node that
|
||||||
|
@ -105,6 +107,9 @@ typedef struct nodelist_t {
|
||||||
* you should add it to this map with node_add_to_ed25519_map().
|
* you should add it to this map with node_add_to_ed25519_map().
|
||||||
*/
|
*/
|
||||||
HT_HEAD(nodelist_ed_map, node_t) nodes_by_ed_id;
|
HT_HEAD(nodelist_ed_map, node_t) nodes_by_ed_id;
|
||||||
|
|
||||||
|
/* Set of addresses that belong to nodes we believe in. */
|
||||||
|
address_set_t *node_addrs;
|
||||||
} nodelist_t;
|
} nodelist_t;
|
||||||
|
|
||||||
static inline unsigned int
|
static inline unsigned int
|
||||||
|
@ -381,6 +386,50 @@ node_addrs_changed(node_t *node)
|
||||||
node->country = -1;
|
node->country = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add all address information about <b>node</b> to the current address
|
||||||
|
* set (if there is one).
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
node_add_to_address_set(const node_t *node)
|
||||||
|
{
|
||||||
|
if (!the_nodelist || !the_nodelist->node_addrs)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* These various address sources can be redundant, but it's likely faster
|
||||||
|
* to add them all than to compare them all for equality. */
|
||||||
|
|
||||||
|
if (node->rs) {
|
||||||
|
if (node->rs->addr)
|
||||||
|
address_set_add_ipv4h(the_nodelist->node_addrs, node->rs->addr);
|
||||||
|
if (!tor_addr_is_null(&node->rs->ipv6_addr))
|
||||||
|
address_set_add(the_nodelist->node_addrs, &node->rs->ipv6_addr);
|
||||||
|
}
|
||||||
|
if (node->ri) {
|
||||||
|
if (node->ri->addr)
|
||||||
|
address_set_add_ipv4h(the_nodelist->node_addrs, node->ri->addr);
|
||||||
|
if (!tor_addr_is_null(&node->ri->ipv6_addr))
|
||||||
|
address_set_add(the_nodelist->node_addrs, &node->ri->ipv6_addr);
|
||||||
|
}
|
||||||
|
if (node->md) {
|
||||||
|
if (!tor_addr_is_null(&node->md->ipv6_addr))
|
||||||
|
address_set_add(the_nodelist->node_addrs, &node->md->ipv6_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Return true if <b>addr</b> is the address of some node in the nodelist.
|
||||||
|
* If not, probably return false. */
|
||||||
|
int
|
||||||
|
nodelist_probably_contains_address(const tor_addr_t *addr)
|
||||||
|
{
|
||||||
|
if (BUG(!addr))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!the_nodelist || !the_nodelist->node_addrs)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return address_set_probably_contains(the_nodelist->node_addrs, addr);
|
||||||
|
}
|
||||||
|
|
||||||
/** Add <b>ri</b> to an appropriate node in the nodelist. If we replace an
|
/** Add <b>ri</b> to an appropriate node in the nodelist. If we replace an
|
||||||
* old routerinfo, and <b>ri_old_out</b> is not NULL, set *<b>ri_old_out</b>
|
* old routerinfo, and <b>ri_old_out</b> is not NULL, set *<b>ri_old_out</b>
|
||||||
* to the previous routerinfo.
|
* to the previous routerinfo.
|
||||||
|
@ -431,6 +480,8 @@ nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out)
|
||||||
networkstatus_get_latest_consensus());
|
networkstatus_get_latest_consensus());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_add_to_address_set(node);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,9 +523,22 @@ nodelist_add_microdesc(microdesc_t *md)
|
||||||
node_add_to_ed25519_map(node);
|
node_add_to_ed25519_map(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node_add_to_address_set(node);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Default value. */
|
||||||
|
#define ESTIMATED_ADDRESS_PER_NODE 2
|
||||||
|
|
||||||
|
/* Return the estimated number of address per node_t. This is used for the
|
||||||
|
* size of the bloom filter in the nodelist (node_addrs). */
|
||||||
|
MOCK_IMPL(int,
|
||||||
|
get_estimated_address_per_node, (void))
|
||||||
|
{
|
||||||
|
return ESTIMATED_ADDRESS_PER_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
/** Tell the nodelist that the current usable consensus is <b>ns</b>.
|
/** Tell the nodelist that the current usable consensus is <b>ns</b>.
|
||||||
* This makes the nodelist change all of the routerstatus entries for
|
* This makes the nodelist change all of the routerstatus entries for
|
||||||
* the nodes, drop nodes that no longer have enough info to get used,
|
* the nodes, drop nodes that no longer have enough info to get used,
|
||||||
|
@ -493,6 +557,12 @@ nodelist_set_consensus(networkstatus_t *ns)
|
||||||
SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
|
SMARTLIST_FOREACH(the_nodelist->nodes, node_t *, node,
|
||||||
node->rs = NULL);
|
node->rs = NULL);
|
||||||
|
|
||||||
|
/* Conservatively estimate that every node will have 2 addresses. */
|
||||||
|
const int estimated_addresses = smartlist_len(ns->routerstatus_list) *
|
||||||
|
get_estimated_address_per_node();
|
||||||
|
address_set_free(the_nodelist->node_addrs);
|
||||||
|
the_nodelist->node_addrs = address_set_new(estimated_addresses);
|
||||||
|
|
||||||
SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
|
SMARTLIST_FOREACH_BEGIN(ns->routerstatus_list, routerstatus_t *, rs) {
|
||||||
node_t *node = node_get_or_create(rs->identity_digest);
|
node_t *node = node_get_or_create(rs->identity_digest);
|
||||||
node->rs = rs;
|
node->rs = rs;
|
||||||
|
@ -536,6 +606,11 @@ nodelist_set_consensus(networkstatus_t *ns)
|
||||||
|
|
||||||
nodelist_purge();
|
nodelist_purge();
|
||||||
|
|
||||||
|
/* Now add all the nodes we have to the address set. */
|
||||||
|
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
||||||
|
node_add_to_address_set(node);
|
||||||
|
} SMARTLIST_FOREACH_END(node);
|
||||||
|
|
||||||
if (! authdir) {
|
if (! authdir) {
|
||||||
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
SMARTLIST_FOREACH_BEGIN(the_nodelist->nodes, node_t *, node) {
|
||||||
/* We have no routerstatus for this router. Clear flags so we can skip
|
/* We have no routerstatus for this router. Clear flags so we can skip
|
||||||
|
@ -694,6 +769,9 @@ nodelist_free_all(void)
|
||||||
|
|
||||||
smartlist_free(the_nodelist->nodes);
|
smartlist_free(the_nodelist->nodes);
|
||||||
|
|
||||||
|
address_set_free(the_nodelist->node_addrs);
|
||||||
|
the_nodelist->node_addrs = NULL;
|
||||||
|
|
||||||
tor_free(the_nodelist);
|
tor_free(the_nodelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ const node_t *node_get_by_hex_id(const char *identity_digest,
|
||||||
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
|
node_t *nodelist_set_routerinfo(routerinfo_t *ri, routerinfo_t **ri_old_out);
|
||||||
node_t *nodelist_add_microdesc(microdesc_t *md);
|
node_t *nodelist_add_microdesc(microdesc_t *md);
|
||||||
void nodelist_set_consensus(networkstatus_t *ns);
|
void nodelist_set_consensus(networkstatus_t *ns);
|
||||||
|
int nodelist_probably_contains_address(const tor_addr_t *addr);
|
||||||
|
|
||||||
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
|
void nodelist_remove_microdesc(const char *identity_digest, microdesc_t *md);
|
||||||
void nodelist_remove_routerinfo(routerinfo_t *ri);
|
void nodelist_remove_routerinfo(routerinfo_t *ri);
|
||||||
|
@ -154,5 +155,7 @@ node_set_hsdir_index(node_t *node, const networkstatus_t *ns);
|
||||||
|
|
||||||
#endif /* defined(NODELIST_PRIVATE) */
|
#endif /* defined(NODELIST_PRIVATE) */
|
||||||
|
|
||||||
|
MOCK_DECL(int, get_estimated_address_per_node, (void));
|
||||||
|
|
||||||
#endif /* !defined(TOR_NODELIST_H) */
|
#endif /* !defined(TOR_NODELIST_H) */
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,7 @@ src_test_test_SOURCES = \
|
||||||
src/test/test_accounting.c \
|
src/test/test_accounting.c \
|
||||||
src/test/test_addr.c \
|
src/test/test_addr.c \
|
||||||
src/test/test_address.c \
|
src/test/test_address.c \
|
||||||
|
src/test/test_address_set.c \
|
||||||
src/test/test_buffers.c \
|
src/test/test_buffers.c \
|
||||||
src/test/test_cell_formats.c \
|
src/test/test_cell_formats.c \
|
||||||
src/test/test_cell_queue.c \
|
src/test/test_cell_queue.c \
|
||||||
|
|
|
@ -1185,6 +1185,7 @@ struct testgroup_t testgroups[] = {
|
||||||
{ "accounting/", accounting_tests },
|
{ "accounting/", accounting_tests },
|
||||||
{ "addr/", addr_tests },
|
{ "addr/", addr_tests },
|
||||||
{ "address/", address_tests },
|
{ "address/", address_tests },
|
||||||
|
{ "address_set/", address_set_tests },
|
||||||
{ "buffer/", buffer_tests },
|
{ "buffer/", buffer_tests },
|
||||||
{ "cellfmt/", cell_format_tests },
|
{ "cellfmt/", cell_format_tests },
|
||||||
{ "cellqueue/", cell_queue_tests },
|
{ "cellqueue/", cell_queue_tests },
|
||||||
|
|
|
@ -177,6 +177,7 @@ extern const struct testcase_setup_t ed25519_test_setup;
|
||||||
extern struct testcase_t accounting_tests[];
|
extern struct testcase_t accounting_tests[];
|
||||||
extern struct testcase_t addr_tests[];
|
extern struct testcase_t addr_tests[];
|
||||||
extern struct testcase_t address_tests[];
|
extern struct testcase_t address_tests[];
|
||||||
|
extern struct testcase_t address_set_tests[];
|
||||||
extern struct testcase_t buffer_tests[];
|
extern struct testcase_t buffer_tests[];
|
||||||
extern struct testcase_t cell_format_tests[];
|
extern struct testcase_t cell_format_tests[];
|
||||||
extern struct testcase_t cell_queue_tests[];
|
extern struct testcase_t cell_queue_tests[];
|
||||||
|
|
174
src/test/test_address_set.c
Normal file
174
src/test/test_address_set.c
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/* Copyright (c) 2017, The Tor Project, Inc. */
|
||||||
|
/* See LICENSE for licensing information */
|
||||||
|
|
||||||
|
#include "or.h"
|
||||||
|
#include "address_set.h"
|
||||||
|
#include "microdesc.h"
|
||||||
|
#include "networkstatus.h"
|
||||||
|
#include "nodelist.h"
|
||||||
|
#include "routerlist.h"
|
||||||
|
#include "torcert.h"
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
static networkstatus_t *dummy_ns = NULL;
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_networkstatus_get_latest_consensus(void)
|
||||||
|
{
|
||||||
|
return dummy_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
|
||||||
|
{
|
||||||
|
tor_assert(f == FLAV_MICRODESC);
|
||||||
|
return dummy_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of address a single node_t can have. Default to the production
|
||||||
|
* value. This is to control the size of the bloom filter. */
|
||||||
|
static int addr_per_node = 2;
|
||||||
|
static int
|
||||||
|
mock_get_estimated_address_per_node(void)
|
||||||
|
{
|
||||||
|
return addr_per_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_contains(void *arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
address_set_t *set = NULL;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
/* Setup an IPv4 and IPv6 addresses. */
|
||||||
|
tor_addr_t addr_v6;
|
||||||
|
tor_addr_parse(&addr_v6, "1:2:3:4::");
|
||||||
|
tor_addr_t addr_v4;
|
||||||
|
tor_addr_parse(&addr_v4, "42.42.42.42");
|
||||||
|
uint32_t ipv4h = tor_addr_to_ipv4h(&addr_v4);
|
||||||
|
|
||||||
|
/* Make it very big so the chance of failing the contain test will be
|
||||||
|
* extremely rare. */
|
||||||
|
set = address_set_new(1024);
|
||||||
|
tt_assert(set);
|
||||||
|
|
||||||
|
/* Add and lookup IPv6. */
|
||||||
|
address_set_add(set, &addr_v6);
|
||||||
|
ret = address_set_probably_contains(set, &addr_v6);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
|
||||||
|
/* Add and lookup IPv4. */
|
||||||
|
address_set_add_ipv4h(set, ipv4h);
|
||||||
|
ret = address_set_probably_contains(set, &addr_v4);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
|
||||||
|
/* Try a lookup of rubbish. */
|
||||||
|
tor_addr_t dummy_addr;
|
||||||
|
memset(&dummy_addr, 'A', sizeof(dummy_addr));
|
||||||
|
dummy_addr.family = AF_INET;
|
||||||
|
ret = address_set_probably_contains(set, &dummy_addr);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
dummy_addr.family = AF_INET6;
|
||||||
|
ret = address_set_probably_contains(set, &dummy_addr);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
done:
|
||||||
|
address_set_free(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_nodelist(void *arg)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
MOCK(networkstatus_get_latest_consensus,
|
||||||
|
mock_networkstatus_get_latest_consensus);
|
||||||
|
MOCK(networkstatus_get_latest_consensus_by_flavor,
|
||||||
|
mock_networkstatus_get_latest_consensus_by_flavor);
|
||||||
|
MOCK(get_estimated_address_per_node,
|
||||||
|
mock_get_estimated_address_per_node);
|
||||||
|
|
||||||
|
dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
|
||||||
|
dummy_ns->flavor = FLAV_MICRODESC;
|
||||||
|
dummy_ns->routerstatus_list = smartlist_new();
|
||||||
|
|
||||||
|
tor_addr_t addr_v4, addr_v6, dummy_addr;
|
||||||
|
tor_addr_parse(&addr_v4, "42.42.42.42");
|
||||||
|
uint32_t ipv4h = tor_addr_to_ipv4h(&addr_v4);
|
||||||
|
tor_addr_parse(&addr_v6, "1:2:3:4::");
|
||||||
|
memset(&dummy_addr, 'A', sizeof(dummy_addr));
|
||||||
|
|
||||||
|
/* This will make the nodelist bloom filter very large
|
||||||
|
* (the_nodelist->node_addrs) so we will fail the contain test rarely. */
|
||||||
|
addr_per_node = 1024;
|
||||||
|
|
||||||
|
/* No node no nothing. The lookups should be empty. */
|
||||||
|
nodelist_set_consensus(dummy_ns);
|
||||||
|
|
||||||
|
/* The address set should be empty. */
|
||||||
|
ret = nodelist_probably_contains_address(&addr_v4);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
ret = nodelist_probably_contains_address(&addr_v6);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
dummy_addr.family = AF_INET;
|
||||||
|
ret = nodelist_probably_contains_address(&dummy_addr);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
dummy_addr.family = AF_INET6;
|
||||||
|
ret = nodelist_probably_contains_address(&dummy_addr);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
md = tor_malloc_zero(sizeof(*md));
|
||||||
|
ri = tor_malloc_zero(sizeof(*ri));
|
||||||
|
rs = tor_malloc_zero(sizeof(*rs));
|
||||||
|
crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
|
||||||
|
crypto_rand(md->digest, sizeof(md->digest));
|
||||||
|
memcpy(rs->descriptor_digest, md->digest, DIGEST256_LEN);
|
||||||
|
|
||||||
|
/* Setup the rs, ri and md addresses. */
|
||||||
|
rs->addr = ipv4h;
|
||||||
|
tor_addr_parse(&rs->ipv6_addr, "1:2:3:4::");
|
||||||
|
ri->addr = ipv4h;
|
||||||
|
tor_addr_parse(&ri->ipv6_addr, "1:2:3:4::");
|
||||||
|
tor_addr_parse(&md->ipv6_addr, "1:2:3:4::");
|
||||||
|
|
||||||
|
/* Add the rs to the consensus becoming a node_t. */
|
||||||
|
smartlist_add(dummy_ns->routerstatus_list, rs);
|
||||||
|
nodelist_set_consensus(dummy_ns);
|
||||||
|
|
||||||
|
/* At this point, the address set should be initialized in the nodelist and
|
||||||
|
* we should be able to lookup. */
|
||||||
|
ret = nodelist_probably_contains_address(&addr_v4);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
ret = nodelist_probably_contains_address(&addr_v6);
|
||||||
|
tt_int_op(ret, OP_EQ, 1);
|
||||||
|
/* Lookup unknown address. */
|
||||||
|
dummy_addr.family = AF_INET;
|
||||||
|
ret = nodelist_probably_contains_address(&dummy_addr);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
dummy_addr.family = AF_INET6;
|
||||||
|
ret = nodelist_probably_contains_address(&dummy_addr);
|
||||||
|
tt_int_op(ret, OP_EQ, 0);
|
||||||
|
|
||||||
|
done:
|
||||||
|
routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
|
||||||
|
smartlist_clear(dummy_ns->routerstatus_list);
|
||||||
|
networkstatus_vote_free(dummy_ns);
|
||||||
|
UNMOCK(networkstatus_get_latest_consensus);
|
||||||
|
UNMOCK(networkstatus_get_latest_consensus_by_flavor);
|
||||||
|
UNMOCK(get_estimated_address_per_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct testcase_t address_set_tests[] = {
|
||||||
|
{ "contains", test_contains, TT_FORK,
|
||||||
|
NULL, NULL },
|
||||||
|
{ "nodelist", test_nodelist, TT_FORK,
|
||||||
|
NULL, NULL },
|
||||||
|
|
||||||
|
END_OF_TESTCASES
|
||||||
|
};
|
||||||
|
|
|
@ -10,9 +10,36 @@
|
||||||
#include "circuitlist.h"
|
#include "circuitlist.h"
|
||||||
#include "geoip.h"
|
#include "geoip.h"
|
||||||
#include "channel.h"
|
#include "channel.h"
|
||||||
|
#include "microdesc.h"
|
||||||
|
#include "networkstatus.h"
|
||||||
|
#include "nodelist.h"
|
||||||
|
#include "routerlist.h"
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "log_test_helpers.h"
|
#include "log_test_helpers.h"
|
||||||
|
|
||||||
|
static networkstatus_t *dummy_ns = NULL;
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_networkstatus_get_latest_consensus(void)
|
||||||
|
{
|
||||||
|
return dummy_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
static networkstatus_t *
|
||||||
|
mock_networkstatus_get_latest_consensus_by_flavor(consensus_flavor_t f)
|
||||||
|
{
|
||||||
|
tor_assert(f == FLAV_MICRODESC);
|
||||||
|
return dummy_ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of address a single node_t can have. Default to the production
|
||||||
|
* value. This is to control the size of the bloom filter. */
|
||||||
|
static int addr_per_node = 2;
|
||||||
|
static int
|
||||||
|
mock_get_estimated_address_per_node(void)
|
||||||
|
{
|
||||||
|
return addr_per_node;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
mock_enable_dos_protection(const networkstatus_t *ns)
|
mock_enable_dos_protection(const networkstatus_t *ns)
|
||||||
{
|
{
|
||||||
|
@ -385,10 +412,86 @@ test_dos_bucket_refill(void *arg)
|
||||||
dos_free_all();
|
dos_free_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test if we avoid counting a known relay. */
|
||||||
|
static void
|
||||||
|
test_known_relay(void *arg)
|
||||||
|
{
|
||||||
|
clientmap_entry_t *entry = NULL;
|
||||||
|
routerstatus_t *rs = NULL; microdesc_t *md = NULL; routerinfo_t *ri = NULL;
|
||||||
|
|
||||||
|
(void) arg;
|
||||||
|
|
||||||
|
MOCK(networkstatus_get_latest_consensus,
|
||||||
|
mock_networkstatus_get_latest_consensus);
|
||||||
|
MOCK(networkstatus_get_latest_consensus_by_flavor,
|
||||||
|
mock_networkstatus_get_latest_consensus_by_flavor);
|
||||||
|
MOCK(get_estimated_address_per_node,
|
||||||
|
mock_get_estimated_address_per_node);
|
||||||
|
MOCK(get_param_cc_enabled, mock_enable_dos_protection);
|
||||||
|
|
||||||
|
dos_init();
|
||||||
|
|
||||||
|
dummy_ns = tor_malloc_zero(sizeof(*dummy_ns));
|
||||||
|
dummy_ns->flavor = FLAV_MICRODESC;
|
||||||
|
dummy_ns->routerstatus_list = smartlist_new();
|
||||||
|
|
||||||
|
/* Setup an OR conn so we can pass it to the DoS subsystem. */
|
||||||
|
or_connection_t or_conn;
|
||||||
|
tor_addr_parse(&or_conn.real_addr, "42.42.42.42");
|
||||||
|
|
||||||
|
rs = tor_malloc_zero(sizeof(*rs));
|
||||||
|
rs->addr = tor_addr_to_ipv4h(&or_conn.real_addr);
|
||||||
|
crypto_rand(rs->identity_digest, sizeof(rs->identity_digest));
|
||||||
|
smartlist_add(dummy_ns->routerstatus_list, rs);
|
||||||
|
|
||||||
|
/* This will make the nodelist bloom filter very large
|
||||||
|
* (the_nodelist->node_addrs) so we will fail the contain test rarely. */
|
||||||
|
addr_per_node = 1024;
|
||||||
|
nodelist_set_consensus(dummy_ns);
|
||||||
|
|
||||||
|
/* We have now a node in our list so we'll make sure we don't count it as a
|
||||||
|
* client connection. */
|
||||||
|
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
|
||||||
|
/* Suppose we have 5 connections in rapid succession, the counter should
|
||||||
|
* always be 0 because we should ignore this. */
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
|
||||||
|
tt_assert(entry);
|
||||||
|
/* We should have a count of 0. */
|
||||||
|
tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 0);
|
||||||
|
|
||||||
|
/* To make sure that his is working properly, make a unknown client
|
||||||
|
* connection and see if we do get it. */
|
||||||
|
tor_addr_parse(&or_conn.real_addr, "42.42.42.43");
|
||||||
|
geoip_note_client_seen(GEOIP_CLIENT_CONNECT, &or_conn.real_addr, NULL, 0);
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
dos_new_client_conn(&or_conn);
|
||||||
|
entry = geoip_lookup_client(&or_conn.real_addr, NULL, GEOIP_CLIENT_CONNECT);
|
||||||
|
tt_assert(entry);
|
||||||
|
/* We should have a count of 2. */
|
||||||
|
tt_uint_op(entry->dos_stats.concurrent_count, OP_EQ, 2);
|
||||||
|
|
||||||
|
done:
|
||||||
|
routerstatus_free(rs); routerinfo_free(ri); microdesc_free(md);
|
||||||
|
smartlist_clear(dummy_ns->routerstatus_list);
|
||||||
|
networkstatus_vote_free(dummy_ns);
|
||||||
|
dos_free_all();
|
||||||
|
UNMOCK(networkstatus_get_latest_consensus);
|
||||||
|
UNMOCK(networkstatus_get_latest_consensus_by_flavor);
|
||||||
|
UNMOCK(get_estimated_address_per_node);
|
||||||
|
UNMOCK(get_param_cc_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
struct testcase_t dos_tests[] = {
|
struct testcase_t dos_tests[] = {
|
||||||
{ "conn_creation", test_dos_conn_creation, TT_FORK, NULL, NULL },
|
{ "conn_creation", test_dos_conn_creation, TT_FORK, NULL, NULL },
|
||||||
{ "circuit_creation", test_dos_circuit_creation, TT_FORK, NULL, NULL },
|
{ "circuit_creation", test_dos_circuit_creation, TT_FORK, NULL, NULL },
|
||||||
{ "bucket_refill", test_dos_bucket_refill, TT_FORK, NULL, NULL },
|
{ "bucket_refill", test_dos_bucket_refill, TT_FORK, NULL, NULL },
|
||||||
|
{ "known_relay" , test_known_relay, TT_FORK,
|
||||||
|
NULL, NULL },
|
||||||
END_OF_TESTCASES
|
END_OF_TESTCASES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue