Merge branch 'ticket17857_squashed' into maint-0.3.1

This commit is contained in:
Nick Mathewson 2017-09-12 10:29:00 -04:00
commit befddf6d2a
5 changed files with 246 additions and 25 deletions

6
changes/bug17857 Normal file
View File

@ -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.

View File

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

View File

@ -21,6 +21,7 @@
#include "router.h" #include "router.h"
#include "compat_time.h" #include "compat_time.h"
#include <event2/event.h> #include <event2/event.h>
#include "rendservice.h"
STATIC int channelpadding_get_netflow_inactive_timeout_ms(const channel_t *); STATIC int channelpadding_get_netflow_inactive_timeout_ms(const channel_t *);
STATIC int channelpadding_send_disable_command(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; static int consensus_nf_pad_before_usage;
/** Should we pad relay-to-relay connections? */ /** Should we pad relay-to-relay connections? */
static int consensus_nf_pad_relays; 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_MSEC_PER_SEC 1000
#define TOR_USEC_PER_MSEC 1000 #define TOR_USEC_PER_MSEC 1000
@ -130,6 +135,16 @@ channelpadding_new_consensus_params(networkstatus_t *ns)
consensus_nf_pad_relays = consensus_nf_pad_relays =
networkstatus_get_param(ns, "nf_pad_relays", 0, 0, 1); 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; 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)) { if (!chan->has_queued_writes(chan)) {
int is_client_channel = 0; int is_client_channel = 0;

View File

@ -13,6 +13,11 @@
#include "channelpadding_negotiation.h" #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 { typedef enum {
CHANNELPADDING_WONTPAD, CHANNELPADDING_WONTPAD,
CHANNELPADDING_PADLATER, CHANNELPADDING_PADLATER,

View File

@ -26,6 +26,7 @@ void test_channelpadding_timers(void *arg);
void test_channelpadding_consensus(void *arg); void test_channelpadding_consensus(void *arg);
void test_channelpadding_negotiation(void *arg); void test_channelpadding_negotiation(void *arg);
void test_channelpadding_decide_to_pad_channel(void *arg); void test_channelpadding_decide_to_pad_channel(void *arg);
void test_channelpadding_killonehop(void *arg);
void dummy_nop_timer(void); 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); conn->base_.conn_array_index = smartlist_len(connection_array);
smartlist_add(connection_array, conn); smartlist_add(connection_array, conn);
connection_or_set_canonical(conn, 1);
conn->chan = chan; conn->chan = chan;
chan->conn = conn; 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->tls = (tor_tls_t *)((void *)(&fake_tortls));
conn->link_proto = MIN_LINK_PROTO_FOR_CHANNEL_PADDING; conn->link_proto = MIN_LINK_PROTO_FOR_CHANNEL_PADDING;
connection_or_set_canonical(conn, 1);
} }
static channel_tls_t * static channel_tls_t *
@ -166,16 +167,30 @@ free_fake_channeltls(channel_tls_t *chan)
} }
static void static void
setup_mock_network(void) setup_mock_consensus(void)
{ {
routerstatus_t *relay;
connection_array = smartlist_new();
current_md_consensus = current_ns_consensus current_md_consensus = current_ns_consensus
= tor_malloc_zero(sizeof(networkstatus_t)); = tor_malloc_zero(sizeof(networkstatus_t));
current_md_consensus->net_params = smartlist_new(); current_md_consensus->net_params = smartlist_new();
current_md_consensus->routerstatus_list = smartlist_new(); current_md_consensus->routerstatus_list = smartlist_new();
channelpadding_new_consensus_params(current_md_consensus); 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 = (channel_t*)new_fake_channeltls(2);
relay1_relay2->write_cell = mock_channel_write_cell_relay1; 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 = (channel_t*)new_fake_channeltls(3);
client_relay3->write_cell = mock_channel_write_cell_client; client_relay3->write_cell = mock_channel_write_cell_client;
channel_timestamp_active(client_relay3); 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 static void
@ -212,12 +232,7 @@ free_mock_network(void)
free_fake_channeltls((channel_tls_t*)relay3_client); free_fake_channeltls((channel_tls_t*)relay3_client);
free_fake_channeltls((channel_tls_t*)client_relay3); 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); smartlist_free(connection_array);
tor_free(current_ns_consensus);
} }
static void static void
@ -344,6 +359,155 @@ test_channelpadding_timers(void *arg)
return; 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 void
test_channelpadding_consensus(void *arg) test_channelpadding_consensus(void *arg)
{ {
@ -379,11 +543,7 @@ test_channelpadding_consensus(void *arg)
chan = (channel_t*)new_fake_channeltls(0); chan = (channel_t*)new_fake_channeltls(0);
channel_timestamp_active(chan); channel_timestamp_active(chan);
current_md_consensus = current_ns_consensus setup_mock_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);
get_options_mutable()->ORPort_set = 1; get_options_mutable()->ORPort_set = 1;
@ -441,6 +601,7 @@ test_channelpadding_consensus(void *arg)
channelpadding_new_consensus_params(current_md_consensus); channelpadding_new_consensus_params(current_md_consensus);
tried_to_write_cell = 0; tried_to_write_cell = 0;
chan->next_padding_time_ms = monotime_coarse_absolute_msec() + 100;
decision = channelpadding_decide_to_pad_channel(chan); decision = channelpadding_decide_to_pad_channel(chan);
tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED); tt_int_op(decision, OP_EQ, CHANNELPADDING_PADDING_SCHEDULED);
tt_assert(chan->pending_padding_callback); 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); tt_i64_op(val, OP_LE, 24*60*60*2);
done: done:
free_mock_consensus();
free_fake_channeltls((channel_tls_t*)chan); free_fake_channeltls((channel_tls_t*)chan);
smartlist_free(connection_array); 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(); timers_shutdown();
channel_free_all(); channel_free_all();
@ -579,6 +737,7 @@ test_channelpadding_negotiation(void *arg)
*/ */
monotime_init(); monotime_init();
timers_initialize(); timers_initialize();
setup_mock_consensus();
setup_mock_network(); setup_mock_network();
/* Test case #1: Do the right things ignore negotiation? */ /* Test case #1: Do the right things ignore negotiation? */
@ -680,6 +839,7 @@ test_channelpadding_negotiation(void *arg)
done: done:
free_mock_network(); free_mock_network();
free_mock_consensus();
timers_shutdown(); timers_shutdown();
channel_free_all(); channel_free_all();
@ -892,6 +1052,7 @@ struct testcase_t channelpadding_tests[] = {
TEST_CHANNELPADDING(channelpadding_decide_to_pad_channel, TT_FORK), TEST_CHANNELPADDING(channelpadding_decide_to_pad_channel, TT_FORK),
TEST_CHANNELPADDING(channelpadding_negotiation, TT_FORK), TEST_CHANNELPADDING(channelpadding_negotiation, TT_FORK),
TEST_CHANNELPADDING(channelpadding_consensus, TT_FORK), TEST_CHANNELPADDING(channelpadding_consensus, TT_FORK),
TEST_CHANNELPADDING(channelpadding_killonehop, TT_FORK),
TEST_CHANNELPADDING(channelpadding_timers, TT_FORK), TEST_CHANNELPADDING(channelpadding_timers, TT_FORK),
END_OF_TESTCASES END_OF_TESTCASES
}; };