diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/app/config/config.c | 10 | ||||
-rw-r--r-- | src/app/config/or_options_st.h | 11 | ||||
-rw-r--r-- | src/core/or/circuitpadding.c | 59 | ||||
-rw-r--r-- | src/core/or/circuitpadding.h | 11 | ||||
-rw-r--r-- | src/test/test_circuitpadding.c | 157 | ||||
-rw-r--r-- | src/test/test_options.c | 1 |
6 files changed, 245 insertions, 4 deletions
diff --git a/src/app/config/config.c b/src/app/config/config.c index 26a3061a26..e601bb2ecd 100644 --- a/src/app/config/config.c +++ b/src/app/config/config.c @@ -597,6 +597,8 @@ static config_var_t option_vars_[] = { V(ReducedConnectionPadding, BOOL, "0"), V(ConnectionPadding, AUTOBOOL, "auto"), V(RefuseUnknownExits, AUTOBOOL, "auto"), + V(CircuitPadding, BOOL, "1"), + V(ReducedCircuitPadding, BOOL, "0"), V(RejectPlaintextPorts, CSV, ""), V(RelayBandwidthBurst, MEMUNIT, "0"), V(RelayBandwidthRate, MEMUNIT, "0"), @@ -3744,6 +3746,14 @@ options_validate(or_options_t *old_options, or_options_t *options, REJECT("Relays cannot set ReducedConnectionPadding. "); } + if (server_mode(options) && options->CircuitPadding == 0) { + REJECT("Relays cannot set CircuitPadding to 0. "); + } + + if (server_mode(options) && options->ReducedCircuitPadding == 1) { + REJECT("Relays cannot set ReducedCircuitPadding. "); + } + if (options->BridgeDistribution) { if (!options->BridgeRelay) { REJECT("You set BridgeDistribution, but you didn't set BridgeRelay!"); diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h index bd707fd193..4e03bec7fa 100644 --- a/src/app/config/or_options_st.h +++ b/src/app/config/or_options_st.h @@ -248,6 +248,17 @@ struct or_options_t { * pad to the server regardless of server support. */ int ConnectionPadding; + /** Boolean: if true, then circuit padding will be negotiated by client + * and server, subject to consenus limits (default). If 0, it will be fully + * disabled. */ + int CircuitPadding; + + /** Boolean: if true, then this client will only use circuit padding + * algorithms that are known to use a low amount of overhead. If false, + * we will use all available circuit padding algorithms. + */ + int ReducedCircuitPadding; + /** To what authority types do we publish our descriptor? Choices are * "v1", "v2", "v3", "bridge", or "". */ struct smartlist_t *PublishServerDescriptor; diff --git a/src/core/or/circuitpadding.c b/src/core/or/circuitpadding.c index 9253c9e282..f21cf113cc 100644 --- a/src/core/or/circuitpadding.c +++ b/src/core/or/circuitpadding.c @@ -81,6 +81,8 @@ static void circpad_setup_machine_on_circ(circuit_t *on_circ, static double circpad_distribution_sample(circpad_distribution_t dist); /** Cached consensus params */ +static uint8_t circpad_padding_disabled; +static uint8_t circpad_padding_reduced; static uint8_t circpad_global_max_padding_percent; static uint16_t circpad_global_allowed_cells; static uint16_t circpad_max_circ_queued_cells; @@ -1081,6 +1083,14 @@ circpad_send_padding_callback(tor_timer_t *timer, void *args, void circpad_new_consensus_params(const networkstatus_t *ns) { + circpad_padding_disabled = + networkstatus_get_param(ns, "circpad_padding_disabled", + 0, 0, 1); + + circpad_padding_reduced = + networkstatus_get_param(ns, "circpad_padding_reduced", + 0, 0, 1); + circpad_global_allowed_cells = networkstatus_get_param(ns, "circpad_global_allowed_cells", 0, 0, UINT16_MAX-1); @@ -1095,6 +1105,24 @@ circpad_new_consensus_params(const networkstatus_t *ns) } /** + * Return true if padding is allowed by torrc and consensus. + */ +STATIC bool +circpad_is_padding_allowed(void) +{ + /* If padding has been disabled in the consensus, don't send any more + * padding. Technically the machine should be shut down when the next + * machine condition check happens, but machine checks only happen on + * certain circuit events, and if padding is disabled due to some + * network overload or DoS condition, we really want to stop ASAP. */ + if (circpad_padding_disabled || !get_options()->CircuitPadding) { + return 0; + } + + return 1; +} + +/** * Check this machine against its padding limits, as well as global * consensus limits. * @@ -1115,7 +1143,7 @@ circpad_machine_reached_padding_limit(circpad_machine_runtime_t *mi) /* If machine_padding_pct is non-zero, and we've sent more * than the allowed count of padding cells, then check our * percent limits for this machine. */ - if (machine->max_padding_percent && + if (machine->max_padding_percent && mi->padding_sent >= machine->allowed_padding_count) { uint32_t total_cells = mi->padding_sent + mi->nonpadding_sent; @@ -1162,6 +1190,18 @@ circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi)) struct timeval timeout; tor_assert(mi); + /* Don't schedule padding if it is disabled */ + if (!circpad_is_padding_allowed()) { + static ratelim_t padding_lim = RATELIM_INIT(600); + log_fn_ratelim(&padding_lim,LOG_INFO,LD_CIRC, + "Padding has been disabled, but machine still on circuit %"PRIu64 + ", %d", + mi->on_circ->n_chan ? mi->on_circ->n_chan->global_identifier : 0, + mi->on_circ->n_circ_id); + + return CIRCPAD_STATE_UNCHANGED; + } + /* Don't schedule padding if we are currently in dormant mode. */ if (!is_participating_on_network()) { log_info(LD_CIRC, "Not scheduling padding because we are dormant."); @@ -1182,7 +1222,8 @@ circpad_machine_schedule_padding,(circpad_machine_runtime_t *mi)) "Padding machine has reached padding limit on circuit %u", TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier); } else { - log_fn(LOG_INFO, LD_CIRC, + static ratelim_t padding_lim = RATELIM_INIT(600); + log_fn_ratelim(&padding_lim,LOG_INFO,LD_CIRC, "Padding machine has reached padding limit on circuit %"PRIu64 ", %d", mi->on_circ->n_chan ? mi->on_circ->n_chan->global_identifier : 0, @@ -1621,6 +1662,19 @@ static inline bool circpad_machine_conditions_met(origin_circuit_t *circ, const circpad_machine_spec_t *machine) { + /* If padding is disabled, no machines should match/apply. This has + * the effect of shutting down all machines, and not adding any more. */ + if (circpad_padding_disabled || !get_options()->CircuitPadding) + return 0; + + /* If the consensus or our torrc has selected reduced connection padding, + * then only allow this machine if it is flagged as acceptable under + * reduced padding conditions */ + if (circpad_padding_reduced || get_options()->ReducedCircuitPadding) { + if (!machine->conditions.reduced_padding_ok) + return 0; + } + if (!(circpad_circ_purpose_to_mask(TO_CIRCUIT(circ)->purpose) & machine->conditions.purpose_mask)) return 0; @@ -2166,6 +2220,7 @@ circpad_circ_client_machine_init(void) circ_client_machine->conditions.state_mask = CIRCPAD_CIRC_BUILDING|CIRCPAD_CIRC_OPENED|CIRCPAD_CIRC_HAS_RELAY_EARLY; circ_client_machine->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL; + circ_client_machine->conditions.reduced_padding_ok = 1; circ_client_machine->target_hopnum = 2; circ_client_machine->is_origin_side = 1; diff --git a/src/core/or/circuitpadding.h b/src/core/or/circuitpadding.h index bc2522c210..f00369eb0a 100644 --- a/src/core/or/circuitpadding.h +++ b/src/core/or/circuitpadding.h @@ -152,6 +152,17 @@ typedef struct circpad_machine_conditions_t { /** Only apply the machine *if* vanguards are enabled */ unsigned requires_vanguards : 1; + /** + * This machine is ok to use if reduced padding is set in consensus + * or torrc. This machine will still be applied even if reduced padding + * is not set; this flag only acts to exclude machines that don't have + * it set when reduced padding is requested. Therefore, reduced padding + * machines should appear at the lowest priority in the padding machine + * lists (aka first in the list), so that non-reduced padding machines + * for the same purpose are given a chance to apply when reduced padding + * is not requested. */ + unsigned reduced_padding_ok : 1; + /** Only apply the machine *if* the circuit's state matches any of * the bits set in this bitmask. */ circpad_circuit_state_t state_mask; diff --git a/src/test/test_circuitpadding.c b/src/test/test_circuitpadding.c index 914bcb97d7..db175fecee 100644 --- a/src/test/test_circuitpadding.c +++ b/src/test/test_circuitpadding.c @@ -1685,8 +1685,11 @@ static void helper_create_conditional_machines(void) { circpad_machine_spec_t *add = helper_create_conditional_machine(); - origin_padding_machines = smartlist_new(); - relay_padding_machines = smartlist_new(); + + if (!origin_padding_machines) + origin_padding_machines = smartlist_new(); + if (!relay_padding_machines) + relay_padding_machines = smartlist_new(); add->machine_num = 2; add->is_origin_side = 1; @@ -2398,6 +2401,155 @@ test_circuitpadding_global_rate_limiting(void *arg) smartlist_free(vote1.net_params); } +/* Test reduced and disabled padding */ +static void +test_circuitpadding_reduce_disable(void *arg) +{ + (void) arg; + int64_t actual_mocked_monotime_start; + + MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock); + + nodes_init(); + dummy_channel.cmux = circuitmux_alloc(); + relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel, + &dummy_channel); + client_side = (circuit_t *)origin_circuit_new(); + relay_side->purpose = CIRCUIT_PURPOSE_OR; + client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL; + + circpad_machines_init(); + helper_create_conditional_machines(); + + monotime_init(); + monotime_enable_test_mocking(); + actual_mocked_monotime_start = MONOTIME_MOCK_START; + monotime_set_mock_time_nsec(actual_mocked_monotime_start); + monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start); + curr_mocked_time = actual_mocked_monotime_start; + timers_initialize(); + + /* This is needed so that we are not considered to be dormant */ + note_user_activity(20); + + MOCK(circuit_package_relay_cell, + circuit_package_relay_cell_mock); + MOCK(node_get_by_id, + node_get_by_id_mock); + + /* Simulate extend. This should result in the original machine getting + * added, since the circuit is not built */ + simulate_single_hop_extend(client_side, relay_side, 1); + simulate_single_hop_extend(client_side, relay_side, 1); + + /* Verify that machine #2 is added */ + tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2); + tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2); + + /* Deliver a padding cell to the client, to trigger burst state */ + circpad_cell_event_padding_sent(client_side); + + /* This should have trigger length shutdown condition on client.. */ + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + + /* Verify machine is gone from both sides */ + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + /* Now test the reduced padding machine by setting up the consensus */ + networkstatus_t vote1; + vote1.net_params = smartlist_new(); + smartlist_split_string(vote1.net_params, + "circpad_padding_reduced=1", NULL, 0, 0); + + /* Register reduced padding machine with the padding subsystem */ + circpad_new_consensus_params(&vote1); + + simulate_single_hop_extend(client_side, relay_side, 1); + + /* Verify that machine #0 is added */ + tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 0); + tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 0); + + tt_int_op( + circpad_machine_reached_padding_limit(client_side->padding_info[0]), + OP_EQ, 0); + tt_int_op( + circpad_machine_reached_padding_limit(relay_side->padding_info[0]), + OP_EQ, 0); + + /* Test that machines get torn down when padding is disabled */ + SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); + smartlist_free(vote1.net_params); + vote1.net_params = smartlist_new(); + smartlist_split_string(vote1.net_params, + "circpad_padding_disabled=1", NULL, 0, 0); + + /* Register reduced padding machine with the padding subsystem */ + circpad_new_consensus_params(&vote1); + + tt_int_op( + circpad_machine_schedule_padding(client_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + tt_int_op( + circpad_machine_schedule_padding(relay_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + + /* Signal that circuit is built: this event causes us to re-evaluate + * machine conditions (which don't apply because padding is disabled). */ + circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side)); + + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp)); + smartlist_free(vote1.net_params); + vote1.net_params = NULL; + circpad_new_consensus_params(&vote1); + + get_options_mutable()->ReducedCircuitPadding = 1; + + simulate_single_hop_extend(client_side, relay_side, 1); + + /* Verify that machine #0 is added */ + tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 0); + tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 0); + + tt_int_op( + circpad_machine_reached_padding_limit(client_side->padding_info[0]), + OP_EQ, 0); + tt_int_op( + circpad_machine_reached_padding_limit(relay_side->padding_info[0]), + OP_EQ, 0); + + get_options_mutable()->CircuitPadding = 0; + + tt_int_op( + circpad_machine_schedule_padding(client_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + tt_int_op( + circpad_machine_schedule_padding(relay_side->padding_info[0]), + OP_EQ, CIRCPAD_STATE_UNCHANGED); + + /* Signal that circuit is built: this event causes us to re-evaluate + * machine conditions (which don't apply because padding is disabled). */ + + circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side)); + + tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL); + tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL); + + done: + free_fake_orcirc(relay_side); + circuitmux_detach_all_circuits(dummy_channel.cmux, NULL); + circuitmux_free(dummy_channel.cmux); +} + #define TEST_CIRCUITPADDING(name, flags) \ { #name, test_##name, (flags), NULL, NULL } @@ -2412,6 +2564,7 @@ struct testcase_t circuitpadding_tests[] = { TEST_CIRCUITPADDING(circuitpadding_sample_distribution, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_machine_rate_limiting, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_global_rate_limiting, TT_FORK), + TEST_CIRCUITPADDING(circuitpadding_reduce_disable, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_token_removal_lower, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_token_removal_higher, TT_FORK), TEST_CIRCUITPADDING(circuitpadding_closest_token_removal, TT_FORK), diff --git a/src/test/test_options.c b/src/test/test_options.c index f12e6b6763..396be6b18d 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -430,6 +430,7 @@ get_options_test_data(const char *conf) // 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. + result->opt->CircuitPadding = 1; // default must be "1" rv = config_get_lines(conf, &cl, 1); tt_int_op(rv, OP_EQ, 0); |