Browse Source

Merge branch 'ticket17857_squashed' into maint-0.3.1

Nick Mathewson 6 years ago
parent
commit
befddf6d2a
5 changed files with 246 additions and 25 deletions
  1. 6 0
      changes/bug17857
  2. 20 5
      src/or/channel.c
  3. 34 0
      src/or/channelpadding.c
  4. 5 0
      src/or/channelpadding.h
  5. 181 20
      src/test/test_channelpadding.c

+ 6 - 0
changes/bug17857

@@ -0,0 +1,6 @@
+  o Minor features (defensive programming):
+    - Create a pair of consensus parameters nf_pad_tor2web and
+      nf_pad_single_onion that allow us to disable netflow padding in the
+      consensus for non-anonymous connections, in case the overhead is high.
+      Closes #17857.
+

+ 20 - 5
src/or/channel.c

@@ -65,6 +65,8 @@
 #include "routerlist.h"
 #include "scheduler.h"
 #include "compat_time.h"
+#include "networkstatus.h"
+#include "rendservice.h"
 
 /* Global lists of channels */
 
@@ -2712,12 +2714,25 @@ channel_do_open_actions(channel_t *chan)
   /* Disable or reduce padding according to user prefs. */
   if (chan->padding_enabled || get_options()->ConnectionPadding == 1) {
     if (!get_options()->ConnectionPadding) {
+      /* Disable if torrc disabled */
       channelpadding_disable_padding_on_channel(chan);
-    }
-
-    /* Padding can be forced and/or reduced by clients, regardless of if
-     * the channel supports it */
-    if (get_options()->ReducedConnectionPadding) {
+    } else if (get_options()->Tor2webMode &&
+            !networkstatus_get_param(NULL,
+                                     CHANNELPADDING_TOR2WEB_PARAM,
+                                     CHANNELPADDING_TOR2WEB_DEFAULT, 0, 1)) {
+      /* Disable if we're using tor2web and the consensus disabled padding
+       * for tor2web */
+      channelpadding_disable_padding_on_channel(chan);
+    } else if (rend_service_allow_non_anonymous_connection(get_options()) &&
+               !networkstatus_get_param(NULL,
+                                        CHANNELPADDING_SOS_PARAM,
+                                        CHANNELPADDING_SOS_DEFAULT, 0, 1)) {
+      /* Disable if we're using RSOS and the consensus disabled padding
+       * for RSOS*/
+      channelpadding_disable_padding_on_channel(chan);
+    } else if (get_options()->ReducedConnectionPadding) {
+      /* Padding can be forced and/or reduced by clients, regardless of if
+       * the channel supports it */
       channelpadding_reduce_padding_on_channel(chan);
     }
   }

+ 34 - 0
src/or/channelpadding.c

@@ -21,6 +21,7 @@
 #include "router.h"
 #include "compat_time.h"
 #include <event2/event.h>
+#include "rendservice.h"
 
 STATIC int channelpadding_get_netflow_inactive_timeout_ms(const channel_t *);
 STATIC int channelpadding_send_disable_command(channel_t *);
@@ -46,6 +47,10 @@ static int consensus_nf_conntimeout_clients;
 static int consensus_nf_pad_before_usage;
 /** Should we pad relay-to-relay connections? */
 static int consensus_nf_pad_relays;
+/** Should we pad tor2web connections? */
+static int consensus_nf_pad_tor2web;
+/** Should we pad rosos connections? */
+static int consensus_nf_pad_single_onion;
 
 #define TOR_MSEC_PER_SEC 1000
 #define TOR_USEC_PER_MSEC 1000
@@ -130,6 +135,16 @@ channelpadding_new_consensus_params(networkstatus_t *ns)
 
   consensus_nf_pad_relays =
     networkstatus_get_param(ns, "nf_pad_relays", 0, 0, 1);
+
+  consensus_nf_pad_tor2web =
+    networkstatus_get_param(ns,
+                            CHANNELPADDING_TOR2WEB_PARAM,
+                            CHANNELPADDING_TOR2WEB_DEFAULT, 0, 1);
+
+  consensus_nf_pad_single_onion =
+    networkstatus_get_param(ns,
+                            CHANNELPADDING_SOS_PARAM,
+                            CHANNELPADDING_SOS_DEFAULT, 0, 1);
 }
 
 /**
@@ -717,6 +732,25 @@ channelpadding_decide_to_pad_channel(channel_t *chan)
     return CHANNELPADDING_WONTPAD;
   }
 
+  if (options->Tor2webMode && !consensus_nf_pad_tor2web) {
+    /* If the consensus just changed values, this channel may still
+     * think padding is enabled. Negotiate it off. */
+    if (chan->padding_enabled)
+      channelpadding_disable_padding_on_channel(chan);
+
+    return CHANNELPADDING_WONTPAD;
+  }
+
+  if (rend_service_allow_non_anonymous_connection(options) &&
+      !consensus_nf_pad_single_onion) {
+    /* If the consensus just changed values, this channel may still
+     * think padding is enabled. Negotiate it off. */
+    if (chan->padding_enabled)
+      channelpadding_disable_padding_on_channel(chan);
+
+    return CHANNELPADDING_WONTPAD;
+  }
+
   if (!chan->has_queued_writes(chan)) {
     int is_client_channel = 0;
 

+ 5 - 0
src/or/channelpadding.h

@@ -13,6 +13,11 @@
 
 #include "channelpadding_negotiation.h"
 
+#define CHANNELPADDING_TOR2WEB_PARAM  "nf_pad_tor2web"
+#define CHANNELPADDING_TOR2WEB_DEFAULT 1
+#define CHANNELPADDING_SOS_PARAM  "nf_pad_single_onion"
+#define CHANNELPADDING_SOS_DEFAULT 1
+
 typedef enum {
   CHANNELPADDING_WONTPAD,
   CHANNELPADDING_PADLATER,

+ 181 - 20
src/test/test_channelpadding.c

@@ -26,6 +26,7 @@ void test_channelpadding_timers(void *arg);
 void test_channelpadding_consensus(void *arg);
 void test_channelpadding_negotiation(void *arg);
 void test_channelpadding_decide_to_pad_channel(void *arg);
+void test_channelpadding_killonehop(void *arg);
 
 void dummy_nop_timer(void);
 
@@ -111,8 +112,6 @@ setup_fake_connection_for_channel(channel_tls_t *chan)
   conn->base_.conn_array_index = smartlist_len(connection_array);
   smartlist_add(connection_array, conn);
 
-  connection_or_set_canonical(conn, 1);
-
   conn->chan = chan;
   chan->conn = conn;
 
@@ -127,6 +126,8 @@ setup_fake_connection_for_channel(channel_tls_t *chan)
   conn->tls = (tor_tls_t *)((void *)(&fake_tortls));
 
   conn->link_proto = MIN_LINK_PROTO_FOR_CHANNEL_PADDING;
+
+  connection_or_set_canonical(conn, 1);
 }
 
 static channel_tls_t *
@@ -166,16 +167,30 @@ free_fake_channeltls(channel_tls_t *chan)
 }
 
 static void
-setup_mock_network(void)
+setup_mock_consensus(void)
 {
-  routerstatus_t *relay;
-  connection_array = smartlist_new();
-
   current_md_consensus = current_ns_consensus
         = tor_malloc_zero(sizeof(networkstatus_t));
   current_md_consensus->net_params = smartlist_new();
   current_md_consensus->routerstatus_list = smartlist_new();
   channelpadding_new_consensus_params(current_md_consensus);
+}
+
+static void
+free_mock_consensus(void)
+{
+  SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
+                    tor_free(r));
+  smartlist_free(current_md_consensus->routerstatus_list);
+  smartlist_free(current_ns_consensus->net_params);
+  tor_free(current_ns_consensus);
+}
+
+static void
+setup_mock_network(void)
+{
+  routerstatus_t *relay;
+  connection_array = smartlist_new();
 
   relay1_relay2 = (channel_t*)new_fake_channeltls(2);
   relay1_relay2->write_cell = mock_channel_write_cell_relay1;
@@ -202,6 +217,11 @@ setup_mock_network(void)
   client_relay3 = (channel_t*)new_fake_channeltls(3);
   client_relay3->write_cell = mock_channel_write_cell_client;
   channel_timestamp_active(client_relay3);
+
+  channel_do_open_actions(relay1_relay2);
+  channel_do_open_actions(relay2_relay1);
+  channel_do_open_actions(relay3_client);
+  channel_do_open_actions(client_relay3);
 }
 
 static void
@@ -212,12 +232,7 @@ free_mock_network(void)
   free_fake_channeltls((channel_tls_t*)relay3_client);
   free_fake_channeltls((channel_tls_t*)client_relay3);
 
-  SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
-                    tor_free(r));
-  smartlist_free(current_md_consensus->routerstatus_list);
-  smartlist_free(current_ns_consensus->net_params);
   smartlist_free(connection_array);
-  tor_free(current_ns_consensus);
 }
 
 static void
@@ -344,6 +359,155 @@ test_channelpadding_timers(void *arg)
   return;
 }
 
+void
+test_channelpadding_killonehop(void *arg)
+{
+  channelpadding_decision_t decision;
+  (void)arg;
+  tor_libevent_postfork();
+
+  routerstatus_t *relay = tor_malloc_zero(sizeof(routerstatus_t));
+  monotime_init();
+  timers_initialize();
+
+  setup_mock_consensus();
+  setup_mock_network();
+
+  /* Do we disable padding if tor2webmode or rsos are enabled, and
+   * the consensus says don't pad?  */
+
+  /* Ensure we can kill tor2web and rsos padding if we want. */
+  // First, test that padding works if either is enabled
+  smartlist_clear(current_md_consensus->net_params);
+  channelpadding_new_consensus_params(current_md_consensus);
+
+  tried_to_write_cell = 0;
+  get_options_mutable()->Tor2webMode = 1;
+  client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+  decision = channelpadding_decide_to_pad_channel(client_relay3);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+  tt_assert(client_relay3->pending_padding_callback);
+  tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+  decision = channelpadding_decide_to_pad_channel(client_relay3);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED);
+
+  // Wait for the timer
+  event_base_loop(tor_libevent_get_base(), 0);
+  tt_int_op(tried_to_write_cell, OP_EQ, 1);
+  tt_assert(!client_relay3->pending_padding_callback);
+
+  // Then test disabling each via consensus param
+  smartlist_add(current_md_consensus->net_params,
+                (void*)"nf_pad_tor2web=0");
+  channelpadding_new_consensus_params(current_md_consensus);
+
+  // Before the client tries to pad, the relay will still pad:
+  tried_to_write_cell = 0;
+  relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+  get_options_mutable()->ORPort_set = 1;
+  get_options_mutable()->Tor2webMode = 0;
+  decision = channelpadding_decide_to_pad_channel(relay3_client);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+  tt_assert(relay3_client->pending_padding_callback);
+
+  // Wait for the timer
+  event_base_loop(tor_libevent_get_base(), 0);
+  tt_int_op(tried_to_write_cell, OP_EQ, 1);
+  tt_assert(!client_relay3->pending_padding_callback);
+
+  // Test client side (it should stop immediately, but send a negotiate)
+  tried_to_write_cell = 0;
+  tt_assert(relay3_client->padding_enabled);
+  tt_assert(client_relay3->padding_enabled);
+  get_options_mutable()->Tor2webMode = 1;
+  /* For the relay to recieve the negotiate: */
+  get_options_mutable()->ORPort_set = 1;
+  decision = channelpadding_decide_to_pad_channel(client_relay3);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+  tt_int_op(tried_to_write_cell, OP_EQ, 1);
+  tt_assert(!client_relay3->pending_padding_callback);
+  tt_assert(!relay3_client->padding_enabled);
+
+  // Test relay side (it should have gotten the negotiation to disable)
+  get_options_mutable()->ORPort_set = 1;
+  get_options_mutable()->Tor2webMode = 0;
+  tt_int_op(channelpadding_decide_to_pad_channel(relay3_client), OP_EQ,
+      CHANNELPADDING_WONTPAD);
+  tt_assert(!relay3_client->padding_enabled);
+
+  /* Repeat for SOS */
+  // First, test that padding works if either is enabled
+  smartlist_clear(current_md_consensus->net_params);
+  channelpadding_new_consensus_params(current_md_consensus);
+
+  relay3_client->padding_enabled = 1;
+  client_relay3->padding_enabled = 1;
+
+  tried_to_write_cell = 0;
+  get_options_mutable()->ORPort_set = 0;
+  get_options_mutable()->HiddenServiceSingleHopMode = 1;
+  get_options_mutable()->HiddenServiceNonAnonymousMode = 1;
+  client_relay3->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+  decision = channelpadding_decide_to_pad_channel(client_relay3);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+  tt_assert(client_relay3->pending_padding_callback);
+  tt_int_op(tried_to_write_cell, OP_EQ, 0);
+
+  decision = channelpadding_decide_to_pad_channel(client_relay3);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_ALREADY_SCHEDULED);
+
+  // Wait for the timer
+  event_base_loop(tor_libevent_get_base(), 0);
+  tt_int_op(tried_to_write_cell, OP_EQ, 1);
+  tt_assert(!client_relay3->pending_padding_callback);
+
+  // Then test disabling each via consensus param
+  smartlist_add(current_md_consensus->net_params,
+                (void*)"nf_pad_single_onion=0");
+  channelpadding_new_consensus_params(current_md_consensus);
+
+  // Before the client tries to pad, the relay will still pad:
+  tried_to_write_cell = 0;
+  relay3_client->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
+  get_options_mutable()->ORPort_set = 1;
+  get_options_mutable()->HiddenServiceSingleHopMode = 0;
+  get_options_mutable()->HiddenServiceNonAnonymousMode = 0;
+  decision = channelpadding_decide_to_pad_channel(relay3_client);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
+  tt_assert(relay3_client->pending_padding_callback);
+
+  // Wait for the timer
+  event_base_loop(tor_libevent_get_base(), 0);
+  tt_int_op(tried_to_write_cell, OP_EQ, 1);
+  tt_assert(!client_relay3->pending_padding_callback);
+
+  // Test client side (it should stop immediately)
+  get_options_mutable()->HiddenServiceSingleHopMode = 1;
+  get_options_mutable()->HiddenServiceNonAnonymousMode = 1;
+  /* For the relay to recieve the negotiate: */
+  get_options_mutable()->ORPort_set = 1;
+  decision = channelpadding_decide_to_pad_channel(client_relay3);
+  tt_int_op(decision, OP_EQ, CHANNELPADDING_WONTPAD);
+  tt_assert(!client_relay3->pending_padding_callback);
+
+  // Test relay side (it should have gotten the negotiation to disable)
+  get_options_mutable()->ORPort_set = 1;
+  get_options_mutable()->HiddenServiceSingleHopMode = 0;
+  get_options_mutable()->HiddenServiceNonAnonymousMode = 0;
+  tt_int_op(channelpadding_decide_to_pad_channel(relay3_client), OP_EQ,
+      CHANNELPADDING_WONTPAD);
+  tt_assert(!relay3_client->padding_enabled);
+
+ done:
+  free_mock_consensus();
+  free_mock_network();
+  tor_free(relay);
+
+  timers_shutdown();
+  channel_free_all();
+}
+
 void
 test_channelpadding_consensus(void *arg)
 {
@@ -379,11 +543,7 @@ test_channelpadding_consensus(void *arg)
   chan = (channel_t*)new_fake_channeltls(0);
   channel_timestamp_active(chan);
 
-  current_md_consensus = current_ns_consensus
-        = tor_malloc_zero(sizeof(networkstatus_t));
-  current_md_consensus->net_params = smartlist_new();
-  current_md_consensus->routerstatus_list = smartlist_new();
-  channelpadding_new_consensus_params(current_md_consensus);
+  setup_mock_consensus();
 
   get_options_mutable()->ORPort_set = 1;
 
@@ -441,6 +601,7 @@ test_channelpadding_consensus(void *arg)
   channelpadding_new_consensus_params(current_md_consensus);
 
   tried_to_write_cell = 0;
+  chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
   decision = channelpadding_decide_to_pad_channel(chan);
   tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
   tt_assert(chan->pending_padding_callback);
@@ -547,12 +708,9 @@ test_channelpadding_consensus(void *arg)
   tt_i64_op(val, OP_LE, 24*60*60*2);
 
  done:
+  free_mock_consensus();
   free_fake_channeltls((channel_tls_t*)chan);
   smartlist_free(connection_array);
-  smartlist_free(current_md_consensus->routerstatus_list);
-  smartlist_free(current_ns_consensus->net_params);
-  tor_free(relay);
-  tor_free(current_ns_consensus);
 
   timers_shutdown();
   channel_free_all();
@@ -579,6 +737,7 @@ test_channelpadding_negotiation(void *arg)
    */
   monotime_init();
   timers_initialize();
+  setup_mock_consensus();
   setup_mock_network();
 
   /* Test case #1: Do the right things ignore negotiation? */
@@ -680,6 +839,7 @@ test_channelpadding_negotiation(void *arg)
 
  done:
   free_mock_network();
+  free_mock_consensus();
 
   timers_shutdown();
   channel_free_all();
@@ -892,6 +1052,7 @@ struct testcase_t channelpadding_tests[] = {
   TEST_CHANNELPADDING(channelpadding_decide_to_pad_channel, TT_FORK),
   TEST_CHANNELPADDING(channelpadding_negotiation, TT_FORK),
   TEST_CHANNELPADDING(channelpadding_consensus, TT_FORK),
+  TEST_CHANNELPADDING(channelpadding_killonehop, TT_FORK),
   TEST_CHANNELPADDING(channelpadding_timers, TT_FORK),
   END_OF_TESTCASES
 };