commit 773bfaf91ebe1ef80f37d473714a11f962e753fb Author: Nick Mathewson nickm@torproject.org Date: Wed Jul 6 17:08:24 2011 -0400
Implement stream isolation
This is the meat of proposal 171: we change circuit_is_acceptable() to require that the connection is compatible with every connection that has been linked to the circuit; we update circuit_is_better to prefer attaching streams to circuits in the way that decreases the circuits' usefulness the least; and we update link_apconn_to_circ() to do the appropriate bookkeeping. --- changes/prop171 | 11 +++++++++++ src/common/util.c | 26 ++++++++++++++++++++++++++ src/common/util.h | 1 + src/or/circuituse.c | 40 +++++++++++++++++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/changes/prop171 b/changes/prop171 index 057556e..91c463f 100644 --- a/changes/prop171 +++ b/changes/prop171 @@ -1,3 +1,14 @@ + o Major features: + - You can now configure Tor so that streams from different + applications are isolated on different circuits, to prevent an + attacker who sees your streams leaving an exit node from linking + your sessions to one another. To do this, choose some way to + distinguish the applications -- have them connect to different + SocksPorts, or have one of them use SOCKS4 while the other uses + SOCKS5, or have them pass different authentication strings to + the SOCKS proxy. Then use the new SocksPort syntax to configure + the degree of isolation you need. This implements Proposal 171. + o Minor features: - There's a new syntax for specifying multiple client ports (such as SOCKSPort, TransPort, DNSPort, NATDPort): you can now just declare diff --git a/src/common/util.c b/src/common/util.c index b95ee3a..bf0bbe0 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -412,6 +412,32 @@ round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) return number; }
+/** Return the number of bits set in <b>v</b>. */ +int +n_bits_set_u8(uint8_t v) +{ + static const int nybble_table[] = { + 0, /* 0000 */ + 1, /* 0001 */ + 1, /* 0010 */ + 2, /* 0011 */ + 1, /* 0100 */ + 2, /* 0101 */ + 2, /* 0110 */ + 3, /* 0111 */ + 1, /* 1000 */ + 2, /* 1001 */ + 2, /* 1010 */ + 3, /* 1011 */ + 2, /* 1100 */ + 3, /* 1101 */ + 3, /* 1110 */ + 4, /* 1111 */ + }; + + return nybble_table[v & 15] + nybble_table[v>>4]; +} + /* ===== * String manipulation * ===== */ diff --git a/src/common/util.h b/src/common/util.h index 6496c42..de06c3c 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -160,6 +160,7 @@ uint64_t round_to_power_of_2(uint64_t u64); unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); +int n_bits_set_u8(uint8_t v);
/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> * and positive <b>b</b>. Works on integer types only. Not defined if a+b can diff --git a/src/or/circuituse.c b/src/or/circuituse.c index 4983b2a..19a6234 100644 --- a/src/or/circuituse.c +++ b/src/or/circuituse.c @@ -143,18 +143,27 @@ circuit_is_acceptable(const origin_circuit_t *origin_circ, return 0; } } + + if (!connection_edge_compatible_with_circuit(conn, origin_circ)) { + /* conn needs to be isolated from other conns that have already used + * origin_circ */ + return 0; + } + return 1; }
/** Return 1 if circuit <b>a</b> is better than circuit <b>b</b> for - * <b>purpose</b>, and return 0 otherwise. Used by circuit_get_best. + * <b>conn</b>, and return 0 otherwise. Used by circuit_get_best. */ static int circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob, - uint8_t purpose) + const edge_connection_t *conn) { const circuit_t *a = TO_CIRCUIT(oa); const circuit_t *b = TO_CIRCUIT(ob); + const uint8_t purpose = conn->_base.purpose; + int a_bits, b_bits;
switch (purpose) { case CIRCUIT_PURPOSE_C_GENERAL: @@ -188,6 +197,29 @@ circuit_is_better(const origin_circuit_t *oa, const origin_circuit_t *ob, return 1; break; } + + /* XXXX023 Maybe this check should get a higher priority to avoid + * using up circuits too rapidly. */ + + a_bits = connection_edge_update_circuit_isolation(conn, + (origin_circuit_t*)oa, 1); + b_bits = connection_edge_update_circuit_isolation(conn, + (origin_circuit_t*)ob, 1); + /* if x_bits < 0, then we have not used x for anything; better not to dirty + * a connection if we can help it. */ + if (a_bits < 0) { + return 0; + } else if (b_bits < 0) { + return 1; + } + a_bits &= ~ oa->isolation_flags_mixed; + a_bits &= ~ ob->isolation_flags_mixed; + if (n_bits_set_u8(a_bits) < n_bits_set_u8(b_bits)) { + /* The fewer new restrictions we need to make on a circuit for stream + * isolation, the better. */ + return 1; + } + return 0; }
@@ -244,7 +276,7 @@ circuit_get_best(const edge_connection_t *conn, /* now this is an acceptable circ to hand back. but that doesn't * mean it's the *best* circ to hand back. try to decide. */ - if (!best || circuit_is_better(origin_circ,best,purpose)) + if (!best || circuit_is_better(origin_circ,best,conn)) best = origin_circ; }
@@ -1476,6 +1508,8 @@ link_apconn_to_circ(edge_connection_t *apconn, origin_circuit_t *circ, tor_assert(circ->cpath->prev->state == CPATH_STATE_OPEN); apconn->cpath_layer = circ->cpath->prev; } + + connection_edge_update_circuit_isolation(apconn, circ, 0); }
/** Return true iff <b>address</b> is matched by one of the entries in
tor-commits@lists.torproject.org