[tor-commits] [tor/master] Add options to control dormant-client feature.

nickm at torproject.org nickm at torproject.org
Mon Nov 26 21:36:44 UTC 2018


commit 3743f7969587079a2f2bb03d0b7e5038557fd64a
Author: Nick Mathewson <nickm at torproject.org>
Date:   Thu Nov 15 13:16:58 2018 -0500

    Add options to control dormant-client feature.
    
    The DormantClientTimeout option controls how long Tor will wait before
    going dormant.  It also provides a way to disable the feature by setting
    DormantClientTimeout to e.g. "50 years".
    
    The DormantTimeoutDisabledByIdleStreams option controls whether open but
    inactive streams count as "client activity".  To implement it, I had to
    make it so that reading or writing on a client stream *always* counts as
    activity.
    
    Closes ticket 28429.
---
 doc/tor.1.txt                  | 13 +++++++++++++
 src/app/config/config.c        |  6 ++++++
 src/app/config/or_options_st.h | 10 ++++++++++
 src/core/mainloop/mainloop.c   | 19 ++++++++++---------
 src/core/or/connection_edge.c  | 11 +++++++++++
 src/test/test_options.c        |  1 +
 6 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/doc/tor.1.txt b/doc/tor.1.txt
index b147ad68a..47bddea09 100644
--- a/doc/tor.1.txt
+++ b/doc/tor.1.txt
@@ -1789,6 +1789,19 @@ The following options are useful only for clients (that is, if
     Try this many simultaneous connections to download a consensus before
     waiting for one to complete, timeout, or error out. (Default: 3)
 
+[[DormantClientTimeout]] **DormantClientTimeout**  __N__ **minutes**|**hours**|**days**|**weeks**::
+    If Tor spends this much time without any client activity,
+    enter a dormant state where automatic circuits are not built, and
+    directory information is not fetched.
+    Does not affect servers or onion services. Must be at least 10 minutes.
+    (Default: 24 hours)
+
+[[DormantTimeoutDisabledByIdleStreams]] **DormantTimeoutDisabledByIdleStreams  **0**|**1**::
+    If true, then any open client stream (even one not reading or writing)
+    counts as client activity for the purpose of DormantClientTimeout.
+    If false, then only network activity counts. (Default: 1)
+
+
 SERVER OPTIONS
 --------------
 
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 8aa0c1f4b..90eae50fd 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -389,6 +389,8 @@ static config_var_t option_vars_[] = {
   OBSOLETE("DynamicDHGroups"),
   VPORT(DNSPort),
   OBSOLETE("DNSListenAddress"),
+  V(DormantClientTimeout,         INTERVAL, "24 hours"),
+  V(DormantTimeoutDisabledByIdleStreams, BOOL,     "1"),
   /* DoS circuit creation options. */
   V(DoSCircuitCreationEnabled,   AUTOBOOL, "auto"),
   V(DoSCircuitCreationMinConnections,      UINT, "0"),
@@ -3836,6 +3838,10 @@ options_validate(or_options_t *old_options, or_options_t *options,
            "default.");
   }
 
+  if (options->DormantClientTimeout < 10*60 && !options->TestingTorNetwork) {
+    REJECT("DormantClientTimeout is too low. It must be at least 10 minutes.");
+  }
+
   if (options->PathBiasNoticeRate > 1.0) {
     tor_asprintf(msg,
               "PathBiasNoticeRate is too high. "
diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h
index 3524b99b5..6cbc86ec1 100644
--- a/src/app/config/or_options_st.h
+++ b/src/app/config/or_options_st.h
@@ -1072,6 +1072,16 @@ struct or_options_t {
 
   /** Autobool: Do we refuse single hop client rendezvous? */
   int DoSRefuseSingleHopClientRendezvous;
+
+  /** Interval: how long without activity does it take for a client
+   * to become dormant?
+   **/
+  int DormantClientTimeout;
+
+  /** Boolean: true if having an idle stream is sufficient to prevent a client
+   * from becoming dormant.
+   **/
+  int DormantTimeoutDisabledByIdleStreams;
 };
 
 #endif
diff --git a/src/core/mainloop/mainloop.c b/src/core/mainloop/mainloop.c
index 2d12e2648..1bd186d85 100644
--- a/src/core/mainloop/mainloop.c
+++ b/src/core/mainloop/mainloop.c
@@ -2018,24 +2018,25 @@ check_network_participation_callback(time_t now, const or_options_t *options)
     goto found_activity;
   }
 
-  /* XXXX Add an option to never become dormant. */
-
   /* If we have any currently open entry streams other than "linked"
    * connections used for directory requests, those count as user activity.
    */
-  /* XXXX make this configurable? */
-  if (connection_get_by_type_nonlinked(CONN_TYPE_AP) != NULL) {
-    goto found_activity;
+  if (options->DormantTimeoutDisabledByIdleStreams) {
+    if (connection_get_by_type_nonlinked(CONN_TYPE_AP) != NULL) {
+      goto found_activity;
+    }
   }
 
   /* XXXX Make this configurable? */
 /** How often do we check whether we have had network activity? */
 #define CHECK_PARTICIPATION_INTERVAL (5*60)
 
-  /** Become dormant if there has been no user activity in this long. */
-  /* XXXX make this configurable! */
-#define BECOME_DORMANT_AFTER_INACTIVITY (24*60*60)
-  if (get_last_user_activity_time() + BECOME_DORMANT_AFTER_INACTIVITY >= now) {
+  /* Become dormant if there has been no user activity in a long time.
+   * (The funny checks below are in order to prevent overflow.) */
+  time_t time_since_last_activity = 0;
+  if (get_last_user_activity_time() < now)
+    time_since_last_activity = now - get_last_user_activity_time();
+  if (time_since_last_activity >= options->DormantClientTimeout) {
     log_notice(LD_GENERAL, "No user activity in a long time: becoming"
                " dormant.");
     set_network_participation(false);
diff --git a/src/core/or/connection_edge.c b/src/core/or/connection_edge.c
index 58aefcf8f..7b51313e8 100644
--- a/src/core/or/connection_edge.c
+++ b/src/core/or/connection_edge.c
@@ -62,6 +62,7 @@
 #include "app/config/config.h"
 #include "core/mainloop/connection.h"
 #include "core/mainloop/mainloop.h"
+#include "core/mainloop/netstatus.h"
 #include "core/or/channel.h"
 #include "core/or/circuitbuild.h"
 #include "core/or/circuitlist.h"
@@ -297,6 +298,11 @@ connection_edge_process_inbuf(edge_connection_t *conn, int package_partial)
       }
       return 0;
     case AP_CONN_STATE_OPEN:
+      if (! conn->base_.linked) {
+        note_user_activity(approx_time());
+      }
+
+      /* falls through. */
     case EXIT_CONN_STATE_OPEN:
       if (connection_edge_package_raw_inbuf(conn, package_partial, NULL) < 0) {
         /* (We already sent an end cell if possible) */
@@ -751,6 +757,11 @@ connection_edge_flushed_some(edge_connection_t *conn)
 {
   switch (conn->base_.state) {
     case AP_CONN_STATE_OPEN:
+      if (! conn->base_.linked) {
+        note_user_activity(approx_time());
+      }
+
+      /* falls through. */
     case EXIT_CONN_STATE_OPEN:
       connection_edge_consider_sending_sendme(conn);
       break;
diff --git a/src/test/test_options.c b/src/test/test_options.c
index f14e620ee..376d77626 100644
--- a/src/test/test_options.c
+++ b/src/test/test_options.c
@@ -425,6 +425,7 @@ get_options_test_data(const char *conf)
   // with options_init(), but about a dozen tests break when I do that.
   // Being kinda lame and just fixing the immedate breakage for now..
   result->opt->ConnectionPadding = -1; // default must be "auto"
+  result->opt->DormantClientTimeout = 1800; // must be over 600.
 
   rv = config_get_lines(conf, &cl, 1);
   tt_int_op(rv, OP_EQ, 0);





More information about the tor-commits mailing list