diff options
author | David Goulet <dgoulet@torproject.org> | 2021-01-29 14:54:21 -0500 |
---|---|---|
committer | David Goulet <dgoulet@torproject.org> | 2021-01-29 14:54:21 -0500 |
commit | b2434d30d2c1071f01d9331752fc7d357169332f (patch) | |
tree | fe4b908fc6cfb88c7f0d869f20d4d6a32484c794 /src/core | |
parent | ea380162025d392803a96d331c8dc64bef56f2e7 (diff) | |
parent | 705fd37875c4acd61037da6a2680678ae128e4a4 (diff) | |
download | tor-b2434d30d2c1071f01d9331752fc7d357169332f.tar.gz tor-b2434d30d2c1071f01d9331752fc7d357169332f.zip |
Merge branch 'tor-gitlab/mr/285' into ticket2667_044_01
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/or/address_set.c | 74 | ||||
-rw-r--r-- | src/core/or/address_set.h | 18 | ||||
-rw-r--r-- | src/core/or/connection_edge.c | 25 |
3 files changed, 116 insertions, 1 deletions
diff --git a/src/core/or/address_set.c b/src/core/or/address_set.c index d618ffc3d6..fcddc55e9f 100644 --- a/src/core/or/address_set.c +++ b/src/core/or/address_set.c @@ -69,3 +69,77 @@ address_set_probably_contains(const address_set_t *set, { return bloomfilt_probably_contains(set, addr); } + +/* Length of the item is an address (IPv4 or IPv6) and a 2 byte port. We use + * 16 bytes for the address here (IPv6) since we do not know which family + * the given address in the item thus in the case of IPv4, the extra bytes + * are simply zeroes to accomodate. */ +#define BLOOMFILT_ADDR_PORT_ITEM_LEN (16 + sizeof(uint16_t)) + +/** Build an item for the bloomfilter consisting of an address and port pair. + * + * If the given address is _not_ AF_INET or AF_INET6, then the item is an + * array of 0s. + * + * Return a pointer to a static buffer containing the item. Next call to this + * function invalidates its previous content. */ +static const uint8_t * +build_addr_port_item(const tor_addr_t *addr, const uint16_t port) +{ + static uint8_t data[BLOOMFILT_ADDR_PORT_ITEM_LEN]; + + memset(data, 0, sizeof(data)); + switch (tor_addr_family(addr)) { + case AF_INET: + memcpy(data, &addr->addr.in_addr.s_addr, 4); + break; + case AF_INET6: + memcpy(data, &addr->addr.in6_addr.s6_addr, 16); + break; + case AF_UNSPEC: + /* Leave the 0. */ + break; + default: + /* LCOV_EXCL_START */ + tor_fragile_assert(); + /* LCOV_EXCL_STOP */ + } + + memcpy(data + 16, &port, sizeof(port)); + return data; +} + +/** Return a hash value for the given item that the bloomfilter will use. */ +static uint64_t +bloomfilt_addr_port_hash(const struct sipkey *key, + const void *item) +{ + return siphash24(item, BLOOMFILT_ADDR_PORT_ITEM_LEN, key); +} + +/** Allocate and return an addr_port_set_t, suitable for holding up to + * max_address_guess distinct values. */ +addr_port_set_t * +addr_port_set_new(int max_addresses_guess) +{ + uint8_t k[BLOOMFILT_KEY_LEN]; + crypto_rand((void*)k, sizeof(k)); + return bloomfilt_new(max_addresses_guess, bloomfilt_addr_port_hash, k); +} + +/** Add an address and port pair to the given set. */ +void +addr_port_set_add(addr_port_set_t *set, const tor_addr_t *addr, uint16_t port) +{ + bloomfilt_add(set, build_addr_port_item(addr, port)); +} + +/** Return true if the given address and port pair are in the set. Of course, + * this is a bloomfilter and thus in rare occasion, a false positive happens + * thus the "probably". */ +bool +addr_port_set_probably_contains(const addr_port_set_t *set, + const tor_addr_t *addr, uint16_t port) +{ + return !!bloomfilt_probably_contains(set, build_addr_port_item(addr, port)); +} diff --git a/src/core/or/address_set.h b/src/core/or/address_set.h index 33887a7c9e..2c78ab0576 100644 --- a/src/core/or/address_set.h +++ b/src/core/or/address_set.h @@ -13,13 +13,14 @@ #include "lib/cc/torint.h" #include "lib/container/bloomfilt.h" +struct tor_addr_t; + /** * 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 bloomfilt_t address_set_t; -struct tor_addr_t; address_set_t *address_set_new(int max_addresses_guess); #define address_set_free(set) bloomfilt_free(set) @@ -28,4 +29,19 @@ void address_set_add_ipv4h(address_set_t *set, uint32_t addr); int address_set_probably_contains(const address_set_t *set, const struct tor_addr_t *addr); +/** + * An addr_port_set_t represents a set of tor_addr_t values with a uint16_t + * port value. The implementation is probabilistic: false negatives cannot + * occur but false positives are possible. + */ +typedef struct bloomfilt_t addr_port_set_t; + +addr_port_set_t *addr_port_set_new(int max_addresses_guess); +#define addr_port_set_free(s) bloomfilt_free(s) +void addr_port_set_add(addr_port_set_t *set, + const struct tor_addr_t *addr, uint16_t port); +bool addr_port_set_probably_contains(const addr_port_set_t *set, + const struct tor_addr_t *addr, + uint16_t port); + #endif /* !defined(TOR_ADDRESS_SET_H) */ diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c index 26595003c1..161fd1da47 100644 --- a/src/core/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -4200,6 +4200,31 @@ connection_exit_connect(edge_connection_t *edge_conn) return; } + /* Next, check for attempts to connect back into the Tor network. We don't + * want to allow these for the same reason we don't want to allow + * infinite-length circuits (see "A Practical Congestion Attack on Tor Using + * Long Paths", Usenix Security 2009). See also ticket 2667. + * + * The TORPROTOCOL reason is used instead of EXITPOLICY so client do NOT + * attempt to retry connecting onto another circuit that will also fail + * bringing considerable more load on the network if so. + * + * Since the address+port set here is a bloomfilter, in very rare cases, the + * check will create a false positive meaning that the destination could + * actually be legit and thus being denied exit. However, sending back a + * reason that makes the client retry results in much worst consequences in + * case of an attack so this is a small price to pay. */ + if (!connection_edge_is_rendezvous_stream(edge_conn) && + nodelist_reentry_probably_contains(&conn->addr, conn->port)) { + log_info(LD_EXIT, "%s:%d tried to connect back to a known relay address. " + "Closing.", escaped_safe_str_client(conn->address), + conn->port); + connection_edge_end(edge_conn, END_STREAM_REASON_TORPROTOCOL); + circuit_detach_stream(circuit_get_by_edge_conn(edge_conn), edge_conn); + connection_free(conn); + return; + } + #ifdef HAVE_SYS_UN_H if (conn->socket_family != AF_UNIX) { #else |