[tor-commits] [tor/master] Give each or_connection_t a slightly randomized idle_timeout

nickm at torproject.org nickm at torproject.org
Wed Jun 11 16:01:22 UTC 2014


commit 463f6628d316cecdd612b4a78cd5349ab4a824c5
Author: Nick Mathewson <nickm at torproject.org>
Date:   Wed Apr 9 11:13:37 2014 -0400

    Give each or_connection_t a slightly randomized idle_timeout
    
    Instead of killing an or_connection_t that has had no circuits for
    the last 3 minutes, give every or_connection_t a randomized timeout,
    so that an observer can't so easily infer from the connection close
    time the time at which its last circuit closed.
    
    Also, increase the base timeout for canonical connections from 3
    minutes to 15 minutes.
    
    Fix for ticket 6799.
---
 changes/bug6799        |   13 +++++++++++++
 src/or/channeltls.c    |    2 +-
 src/or/connection.c    |    2 ++
 src/or/connection_or.c |   41 ++++++++++++++++++++++++++++++++++++++++-
 src/or/connection_or.h |    2 ++
 src/or/main.c          |   11 +----------
 src/or/or.h            |    5 ++++-
 7 files changed, 63 insertions(+), 13 deletions(-)

diff --git a/changes/bug6799 b/changes/bug6799
new file mode 100644
index 0000000..b50762b
--- /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 d5428c1..92e51b2 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 4f74a1d..b967eac 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 8e7cd9e..f03b18d 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 <b>or_conn</b> as canonical if <b>is_canonical</b> 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 85e68f1..896556c 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 bd23141..8a653ca 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 3eaf344..21ee185 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. */
 





More information about the tor-commits mailing list