aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/address.c27
-rw-r--r--src/common/address.h2
-rw-r--r--src/common/address_set.c129
-rw-r--r--src/common/address_set.h35
-rw-r--r--src/common/include.am2
-rw-r--r--src/common/log.c2
-rw-r--r--src/common/torlog.h4
7 files changed, 198 insertions, 3 deletions
diff --git a/src/common/address.c b/src/common/address.c
index 894e15114c..e6b437e9dd 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1183,6 +1183,9 @@ tor_addr_compare_masked(const tor_addr_t *addr1, const tor_addr_t *addr2,
}
}
+/** Input for siphash, to produce some output for an unspec value. */
+static const uint32_t unspec_hash_input[] = { 0x4e4df09f, 0x92985342 };
+
/** Return a hash code based on the address addr. DOCDOC extra */
uint64_t
tor_addr_hash(const tor_addr_t *addr)
@@ -1191,7 +1194,7 @@ tor_addr_hash(const tor_addr_t *addr)
case AF_INET:
return siphash24g(&addr->addr.in_addr.s_addr, 4);
case AF_UNSPEC:
- return 0x4e4d5342;
+ return siphash24g(unspec_hash_input, sizeof(unspec_hash_input));
case AF_INET6:
return siphash24g(&addr->addr.in6_addr.s6_addr, 16);
default:
@@ -1202,6 +1205,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 siphash24(unspec_hash_input, sizeof(unspec_hash_input), key);
+ 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>. */
char *
tor_addr_to_str_dup(const tor_addr_t *addr)
diff --git a/src/common/address.h b/src/common/address.h
index ce85b3d81d..8091f8cd7b 100644
--- a/src/common/address.h
+++ b/src/common/address.h
@@ -229,6 +229,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))
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_internal_(const tor_addr_t *ip, int for_listening,
const char *filename, int lineno);
diff --git a/src/common/address_set.c b/src/common/address_set.c
new file mode 100644
index 0000000000..4924cb65c2
--- /dev/null
+++ b/src/common/address_set.c
@@ -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 output into 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;
+}
+
diff --git a/src/common/address_set.h b/src/common/address_set.h
new file mode 100644
index 0000000000..aedf17fc66
--- /dev/null
+++ b/src/common/address_set.h
@@ -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
+
diff --git a/src/common/include.am b/src/common/include.am
index 1253888815..d12895b107 100644
--- a/src/common/include.am
+++ b/src/common/include.am
@@ -80,6 +80,7 @@ src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS)
LIBOR_A_SRC = \
src/common/address.c \
+ src/common/address_set.c \
src/common/backtrace.c \
src/common/compat.c \
src/common/compat_threads.c \
@@ -146,6 +147,7 @@ src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS)
COMMONHEADERS = \
src/common/address.h \
+ src/common/address_set.h \
src/common/backtrace.h \
src/common/aes.h \
src/common/ciphers.inc \
diff --git a/src/common/log.c b/src/common/log.c
index 6a5819064a..87c260799d 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -1177,7 +1177,7 @@ static const char *domain_list[] = {
"GENERAL", "CRYPTO", "NET", "CONFIG", "FS", "PROTOCOL", "MM",
"HTTP", "APP", "CONTROL", "CIRC", "REND", "BUG", "DIR", "DIRSERV",
"OR", "EDGE", "ACCT", "HIST", "HANDSHAKE", "HEARTBEAT", "CHANNEL",
- "SCHED", "GUARD", "CONSDIFF", NULL
+ "SCHED", "GUARD", "CONSDIFF", "DOS", NULL
};
/** Return a bitmask for the log domain for which <b>domain</b> is the name,
diff --git a/src/common/torlog.h b/src/common/torlog.h
index 6e374b1c11..0149ce9a5b 100644
--- a/src/common/torlog.h
+++ b/src/common/torlog.h
@@ -103,8 +103,10 @@
#define LD_GUARD (1u<<23)
/** Generation and application of consensus diffs. */
#define LD_CONSDIFF (1u<<24)
+/** Denial of Service mitigation. */
+#define LD_DOS (1u<<25)
/** Number of logging domains in the code. */
-#define N_LOGGING_DOMAINS 25
+#define N_LOGGING_DOMAINS 26
/** This log message is not safe to send to a callback-based logger
* immediately. Used as a flag, not a log domain. */