diff --git a/changes/bug6799 b/changes/bug6799 new file mode 100644 index 0000000000..b50762bb0a --- /dev/null +++ b/changes/bug6799 @@ -0,0 +1,13 @@ + o Major features: + + - Increate the base amount of time that a canonical connection + (one that we have made to a known OR) is allowed to stay open + from a 3 minutes to 15 minutes. This leaks less information + about when circuits have closed, and avoids unnecessary overhead + from renegotiating connections. Part of a fix for ticket 6799. + + - Instead of closing connections at a fixed interval after their + last circuit closed, randomly add up to 50% to each connection's + maximum timout. This makes it harder to tell when the last + circuit closed by looking at when a connection closes. Part of a + fix for ticket 6799. diff --git a/src/or/channeltls.c b/src/or/channeltls.c index d5428c1abd..92e51b21a8 100644 --- a/src/or/channeltls.c +++ b/src/or/channeltls.c @@ -1514,7 +1514,7 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan) return; } if (tor_addr_eq(&addr, &(chan->conn->real_addr))) { - chan->conn->is_canonical = 1; + connection_or_set_canonical(chan->conn, 1); break; } cp = next; diff --git a/src/or/connection.c b/src/or/connection.c index 4f74a1d04b..b967eacf2c 100644 --- a/src/or/connection.c +++ b/src/or/connection.c @@ -266,6 +266,8 @@ or_connection_new(int socket_family) or_conn->timestamp_last_added_nonpadding = time(NULL); + connection_or_set_canonical(or_conn, 0); + return or_conn; } diff --git a/src/or/connection_or.c b/src/or/connection_or.c index 8e7cd9ea51..f03b18ddf1 100644 --- a/src/or/connection_or.c +++ b/src/or/connection_or.c @@ -756,6 +756,45 @@ connection_or_update_token_buckets(smartlist_t *conns, }); } +/** How long do we wait before killing non-canonical OR connections with no + * circuits? In Tor versions up to 0.2.1.25 and 0.2.2.12-alpha, we waited 15 + * minutes before cancelling these connections, which caused fast relays to + * accrue many many idle connections. Hopefully 3-4.5 minutes is low enough + * that it kills most idle connections, without being so low that we cause + * clients to bounce on and off. + * + * For canonical connections, the limit is higher, at 15-22.5 minutes. + * + * For each OR connection, we randomly add up to 50% extra to its idle_timeout + * field, to avoid exposing when exactly the last circuit closed. Since we're + * storing idle_timeout in a uint16_t, don't let these values get higher than + * 12 hours or so without revising connection_or_set_canonical and/or expanding + * idle_timeout. + */ +#define IDLE_OR_CONN_TIMEOUT_NONCANONICAL 180 +#define IDLE_OR_CONN_TIMEOUT_CANONICAL 900 + +/* Mark or_conn as canonical if is_canonical is set, and + * non-canonical otherwise. Adjust idle_timeout accordingly. + */ +void +connection_or_set_canonical(or_connection_t *or_conn, + int is_canonical) +{ + const unsigned int timeout_base = is_canonical ? + IDLE_OR_CONN_TIMEOUT_CANONICAL : IDLE_OR_CONN_TIMEOUT_NONCANONICAL; + + if (bool_eq(is_canonical, or_conn->is_canonical) && + or_conn->idle_timeout != 0) { + /* Don't recalculate an existing idle_timeout unless the canonical + * status changed. */ + return; + } + + or_conn->is_canonical = !! is_canonical; /* force to a 1-bit boolean */ + or_conn->idle_timeout = timeout_base + crypto_rand_int(timeout_base / 2); +} + /** If we don't necessarily know the router we're connecting to, but we * have an addr/port/id_digest, then fill in as much as we can. Start * by checking to see if this describes a router we know. @@ -780,7 +819,7 @@ connection_or_init_conn_from_address(or_connection_t *conn, /* XXXX proposal 186 is making this more complex. For now, a conn is canonical when it uses the _preferred_ address. */ if (tor_addr_eq(&conn->base_.addr, &node_ap.addr)) - conn->is_canonical = 1; + connection_or_set_canonical(conn, 1); if (!started_here) { /* Override the addr/port, so our log messages will make sense. * This is dangerous, since if we ever try looking up a conn by diff --git a/src/or/connection_or.h b/src/or/connection_or.h index 85e68f1a33..896556c035 100644 --- a/src/or/connection_or.h +++ b/src/or/connection_or.h @@ -47,6 +47,8 @@ void connection_or_report_broken_states(int severity, int domain); int connection_tls_start_handshake(or_connection_t *conn, int receiving); int connection_tls_continue_handshake(or_connection_t *conn); +void connection_or_set_canonical(or_connection_t *or_conn, + int is_canonical); int connection_init_or_handshake_state(or_connection_t *conn, int started_here); diff --git a/src/or/main.c b/src/or/main.c index bd23141b97..8a653ca40b 100644 --- a/src/or/main.c +++ b/src/or/main.c @@ -993,15 +993,6 @@ directory_info_has_arrived(time_t now, int from_cache) consider_testing_reachability(1, 1); } -/** How long do we wait before killing OR connections with no circuits? - * In Tor versions up to 0.2.1.25 and 0.2.2.12-alpha, we waited 15 minutes - * before cancelling these connections, which caused fast relays to accrue - * many many idle connections. Hopefully 3 minutes is low enough that - * it kills most idle connections, without being so low that we cause - * clients to bounce on and off. - */ -#define IDLE_OR_CONN_TIMEOUT 180 - /** Perform regular maintenance tasks for a single connection. This * function gets run once per second per connection by run_scheduled_events. */ @@ -1088,7 +1079,7 @@ run_connection_housekeeping(int i, time_t now) connection_or_close_normally(TO_OR_CONN(conn), 1); } else if (!connection_or_get_num_circuits(or_conn) && now >= or_conn->timestamp_last_added_nonpadding + - IDLE_OR_CONN_TIMEOUT) { + or_conn->idle_timeout) { log_info(LD_OR,"Expiring non-used OR connection to fd %d (%s:%d) " "[idle %d].", (int)conn->s,conn->address, conn->port, (int)(now - or_conn->timestamp_last_added_nonpadding)); diff --git a/src/or/or.h b/src/or/or.h index 3eaf3447dc..21ee1855cb 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -1424,7 +1424,10 @@ typedef struct or_connection_t { unsigned int wide_circ_ids:1; uint16_t link_proto; /**< What protocol version are we using? 0 for * "none negotiated yet." */ - + uint16_t idle_timeout; /**< How long can this connection sit with no + * circuits on it before we close it? Based on + * IDLE_CIRCUIT_TIMEOUT_{NON,}CANONICAL and + * on is_canonical, randomized. */ or_handshake_state_t *handshake_state; /**< If we are setting this connection * up, state information to do so. */