mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-27 22:03:31 +01:00
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.
This commit is contained in:
parent
1d3c8c1f74
commit
773bfaf91e
@ -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
|
||||
|
@ -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
|
||||
* ===== */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user