Loading changes/ticket28634 0 → 100644 +10 −0 Original line number Diff line number Diff line o Major features (Circuit padding): - Onion service clients will now add padding cells to the initial portions of their INTRODUCE and RENDEZVOUS circuits, to make those circuits' traffic patterns look more like general purpose Exit traffic. The overhead for this is 2 extra cells in each direction for RENDEZVOUS circuits, and 1 extra upstream cell and 10 downstream cells for INTRODUCE circuits. This will only be enabled if the circuit's middle node supports this feature, too. (Clients may specify fixed middle nodes with the MiddleNodes torrc directive, and may force-disable this feature with the CircuitPadding torrc directive). Closes ticket 28634. scripts/maint/practracker/exceptions.txt +2 −0 Original line number Diff line number Diff line Loading @@ -290,3 +290,5 @@ problem function-size /src/tools/tor-resolve.c:build_socks5_resolve_request() 10 problem function-size /src/tools/tor-resolve.c:do_resolve() 175 problem function-size /src/tools/tor-resolve.c:main() 112 problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 107 problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_relay_hide_intro_circuits() 104 problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_client_hide_rend_circuits() 112 src/app/main/shutdown.c +1 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ tor_free_all(int postfork) dos_free_all(); circuitmux_ewma_free_all(); accounting_free_all(); circpad_free_all(); if (!postfork) { config_free_all(); Loading src/core/include.am +2 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ LIBTOR_APP_A_SOURCES = \ src/core/or/circuitmux.c \ src/core/or/circuitmux_ewma.c \ src/core/or/circuitpadding.c \ src/core/or/circuitpadding_machines.c \ src/core/or/circuitstats.c \ src/core/or/circuituse.c \ src/core/or/crypt_path.c \ Loading Loading @@ -247,6 +248,7 @@ noinst_HEADERS += \ src/core/or/circuitmux_ewma.h \ src/core/or/circuitstats.h \ src/core/or/circuitpadding.h \ src/core/or/circuitpadding_machines.h \ src/core/or/circuituse.h \ src/core/or/command.h \ src/core/or/connection_edge.h \ Loading src/core/or/circuitpadding.c +118 −84 Original line number Diff line number Diff line Loading @@ -37,6 +37,13 @@ * When a padding machine reaches the END state, it gets wiped from the circuit * so that other padding machines can take over if needed (see * circpad_machine_spec_transitioned_to_end()). * **************************** * General notes: * * All used machines should be heap allocated and placed into * origin_padding_machines/relay_padding_machines so that they get correctly * cleaned up by the circpad_free_all() function. **/ #define CIRCUITPADDING_PRIVATE Loading @@ -46,6 +53,7 @@ #include "lib/math/prob_distr.h" #include "core/or/or.h" #include "core/or/circuitpadding.h" #include "core/or/circuitpadding_machines.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/mainloop/netstatus.h" Loading @@ -72,8 +80,6 @@ #include "app/config/config.h" static inline circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose); static inline circpad_circuit_state_t circpad_circuit_state( origin_circuit_t *circ); static void circpad_setup_machine_on_circ(circuit_t *on_circ, Loading Loading @@ -125,34 +131,6 @@ STATIC smartlist_t *relay_padding_machines = NULL; continue; #define FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END } STMT_END ; /** * Return a human-readable description for a circuit padding state. */ static const char * circpad_state_to_string(circpad_statenum_t state) { const char *descr; switch (state) { case CIRCPAD_STATE_START: descr = "START"; break; case CIRCPAD_STATE_BURST: descr = "BURST"; break; case CIRCPAD_STATE_GAP: descr = "GAP"; break; case CIRCPAD_STATE_END: descr = "END"; break; default: descr = "CUSTOM"; // XXX: Just return # in static char buf? } return descr; } /** * Free the machineinfo at an index */ Loading Loading @@ -485,7 +463,10 @@ circpad_machine_setup_tokens(circpad_machine_runtime_t *mi) const circpad_state_t *state = circpad_machine_current_state(mi); /* If this state doesn't exist, or doesn't have token removal, * free any previous state's histogram, and bail */ * free any previous state's runtime histogram, and bail. * * If we don't have a token removal strategy, we also don't need a runtime * histogram and we rely on the immutable one in machine_spec_t. */ if (!state || state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE) { if (mi->histogram) { tor_free(mi->histogram); Loading Loading @@ -525,9 +506,14 @@ circpad_choose_state_length(circpad_machine_runtime_t *mi) length = circpad_distribution_sample(state->length_dist); length = MAX(0, length); length += state->start_length; if (state->max_length) { length = MIN(length, state->max_length); } mi->state_length = clamp_double_to_int64(length); log_info(LD_CIRC, "State length sampled to %"PRIu64".", mi->state_length); } /** Loading Loading @@ -595,6 +581,11 @@ circpad_machine_sample_delay(circpad_machine_runtime_t *mi) histogram_total_tokens = state->histogram_total_tokens; } /* If we are out of tokens, don't schedule padding. */ if (!histogram_total_tokens) { return CIRCPAD_DELAY_INFINITE; } bin_choice = crypto_fast_rng_get_uint64(get_thread_fast_rng(), histogram_total_tokens); Loading Loading @@ -897,7 +888,7 @@ circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi, bin_to_remove = lower; } mi->histogram[bin_to_remove]--; log_debug(LD_GENERAL, "Removing token from bin %d", bin_to_remove); log_debug(LD_CIRC, "Removing token from bin %d", bin_to_remove); return; } else { if (current - lower > higher - current) { Loading Loading @@ -1207,14 +1198,16 @@ circpad_send_padding_cell_for_callback(circpad_machine_runtime_t *mi) circpad_send_command_to_hop(TO_ORIGIN_CIRCUIT(mi->on_circ), CIRCPAD_GET_MACHINE(mi)->target_hopnum, RELAY_COMMAND_DROP, NULL, 0); log_fn(LOG_INFO,LD_CIRC, "Callback: Sending padding to origin circuit %u.", TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier); log_info(LD_CIRC, "Callback: Sending padding to origin circuit %u" " (%d) [length: %"PRIu64"]", TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier, mi->on_circ->purpose, mi->state_length); } else { // If we're a non-origin circ, we can just send from here as if we're the // edge. if (TO_OR_CIRCUIT(circ)->p_chan_cells.n <= circpad_max_circ_queued_cells) { log_fn(LOG_INFO,LD_CIRC, "Callback: Sending padding to non-origin circuit."); log_info(LD_CIRC, "Callback: Sending padding to circuit (%d)" " [length: %"PRIu64"]", mi->on_circ->purpose, mi->state_length); relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, 0, NULL); rep_hist_padding_count_write(PADDING_TYPE_DROP); Loading Loading @@ -1582,9 +1575,8 @@ circpad_machine_spec_transition,(circpad_machine_runtime_t *mi, * a transition to itself. All non-specified events are ignored. */ log_fn(LOG_INFO, LD_CIRC, "Circpad machine %d transitioning from %s to %s", mi->machine_index, circpad_state_to_string(mi->current_state), circpad_state_to_string(s)); "Circpad machine %d transitioning from %u to %u", mi->machine_index, mi->current_state, s); /* If this is not the same state, switch and init tokens, * otherwise just reschedule padding. */ Loading Loading @@ -1734,13 +1726,12 @@ circpad_estimate_circ_rtt_on_send(circuit_t *circ, * to back. Stop estimating RTT in this case. Note that we only * stop RTT update if the circuit is opened, to allow for RTT estimates * of var cells during circ setup. */ mi->stop_rtt_update = 1; if (!mi->rtt_estimate_usec) { if (!mi->rtt_estimate_usec && !mi->stop_rtt_update) { static ratelim_t rtt_lim = RATELIM_INIT(600); log_fn_ratelim(&rtt_lim,LOG_NOTICE,LD_BUG, "Circuit sent two cells back to back before estimating RTT."); } mi->stop_rtt_update = 1; } } Loading Loading @@ -1976,7 +1967,6 @@ circpad_circuit_state(origin_circuit_t *circ) * Convert a normal circuit purpose into a bitmask that we can * use for determining matching circuits. */ static inline circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose) { Loading Loading @@ -2019,7 +2009,8 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ) } /** * Negotiate new machines that would apply to this circuit. * Negotiate new machines that would apply to this circuit, given the machines * inside <b>machines_sl</b>. * * This function checks to see if we have any free machine indexes, * and for each free machine index, it initializes the most recently Loading @@ -2027,14 +2018,15 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ) * index and circuit conditions, and negotiates it with the appropriate * middle relay. */ static void circpad_add_matching_machines(origin_circuit_t *on_circ) STATIC void circpad_add_matching_machines(origin_circuit_t *on_circ, smartlist_t *machines_sl) { circuit_t *circ = TO_CIRCUIT(on_circ); #ifdef TOR_UNIT_TESTS /* Tests don't have to init our padding machines */ if (!origin_padding_machines) if (!machines_sl) return; #endif Loading @@ -2051,7 +2043,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ) /* We have a free machine index. Check the origin padding * machines in reverse order, so that more recently added * machines take priority over older ones. */ SMARTLIST_FOREACH_REVERSE_BEGIN(origin_padding_machines, SMARTLIST_FOREACH_REVERSE_BEGIN(machines_sl, circpad_machine_spec_t *, machine) { /* Machine definitions have a specific target machine index. Loading Loading @@ -2079,6 +2071,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ) if (circpad_negotiate_padding(on_circ, machine->machine_num, machine->target_hopnum, CIRCPAD_COMMAND_START) < 0) { log_info(LD_CIRC, "Padding not negotiated. Cleaning machine"); circpad_circuit_machineinfo_free_idx(circ, i); circ->padding_machine[i] = NULL; on_circ->padding_negotiation_failed = 1; Loading @@ -2102,7 +2095,7 @@ circpad_machine_event_circ_added_hop(origin_circuit_t *on_circ) { /* Since our padding conditions do not specify a max_hops, * all we can do is add machines here */ circpad_add_matching_machines(on_circ); circpad_add_matching_machines(on_circ, origin_padding_machines); } /** Loading @@ -2115,7 +2108,7 @@ void circpad_machine_event_circ_built(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2128,7 +2121,7 @@ void circpad_machine_event_circ_purpose_changed(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2142,7 +2135,7 @@ void circpad_machine_event_circ_has_no_relay_early(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2157,7 +2150,7 @@ void circpad_machine_event_circ_has_streams(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2172,7 +2165,7 @@ void circpad_machine_event_circ_has_no_streams(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading Loading @@ -2253,13 +2246,6 @@ circpad_deliver_recognized_relay_cell_events(circuit_t *circ, uint8_t relay_command, crypt_path_t *layer_hint) { /* Padding negotiate cells are ignored by the state machines * for simplicity. */ if (relay_command == RELAY_COMMAND_PADDING_NEGOTIATE || relay_command == RELAY_COMMAND_PADDING_NEGOTIATED) { return; } if (relay_command == RELAY_COMMAND_DROP) { rep_hist_padding_count_read(PADDING_TYPE_DROP); Loading Loading @@ -2296,16 +2282,12 @@ void circpad_deliver_sent_relay_cell_events(circuit_t *circ, uint8_t relay_command) { /* Padding negotiate cells are ignored by the state machines * for simplicity. */ if (relay_command == RELAY_COMMAND_PADDING_NEGOTIATE || relay_command == RELAY_COMMAND_PADDING_NEGOTIATED) { return; } /* RELAY_COMMAND_DROP is the multi-hop (aka circuit-level) padding cell in * tor. (CELL_PADDING is a channel-level padding cell, which is not relayed * or processed here) */ * or processed here). * * We do generate events for PADDING_NEGOTIATE and PADDING_NEGOTIATED cells. */ if (relay_command == RELAY_COMMAND_DROP) { /* Optimization: The event for RELAY_COMMAND_DROP is sent directly * from circpad_send_padding_cell_for_callback(). This is to avoid Loading Loading @@ -2363,12 +2345,21 @@ circpad_setup_machine_on_circ(circuit_t *on_circ, == NULL); tor_assert_nonfatal(on_circ->padding_info[machine->machine_index] == NULL); /* Log message */ if (CIRCUIT_IS_ORIGIN(on_circ)) { log_info(LD_CIRC, "Registering machine %s to origin circ %u (%d)", machine->name, TO_ORIGIN_CIRCUIT(on_circ)->global_identifier, on_circ->purpose); } else { log_info(LD_CIRC, "Registering machine %s to non-origin circ (%d)", machine->name, on_circ->purpose); } on_circ->padding_info[machine->machine_index] = circpad_circuit_machineinfo_new(on_circ, machine->machine_index); on_circ->padding_machine[machine->machine_index] = machine; } #ifdef TOR_UNIT_TESTS /** Validate a single state of a padding machine */ static bool padding_machine_state_is_valid(const circpad_state_t *state) Loading @@ -2384,7 +2375,7 @@ padding_machine_state_is_valid(const circpad_state_t *state) /* We need at least two bins in a histogram */ if (state->histogram_len < 2) { log_warn(LD_GENERAL, "You can't have a histogram with less than 2 bins"); log_warn(LD_CIRC, "You can't have a histogram with less than 2 bins"); return false; } Loading @@ -2394,7 +2385,7 @@ padding_machine_state_is_valid(const circpad_state_t *state) /* Check that histogram edges are strictly increasing. Ignore the first * edge since it can be zero. */ if (prev_bin_edge >= state->histogram_edges[b] && b > 0) { log_warn(LD_GENERAL, "Histogram edges are not increasing [%u/%u]", log_warn(LD_CIRC, "Histogram edges are not increasing [%u/%u]", prev_bin_edge, state->histogram_edges[b]); return false; } Loading @@ -2406,7 +2397,7 @@ padding_machine_state_is_valid(const circpad_state_t *state) } /* Verify that the total number of tokens is correct */ if (tokens_count != state->histogram_total_tokens) { log_warn(LD_GENERAL, "Histogram token count is wrong [%u/%u]", log_warn(LD_CIRC, "Histogram token count is wrong [%u/%u]", tokens_count, state->histogram_total_tokens); return false; } Loading @@ -2432,12 +2423,12 @@ padding_machine_is_valid(const circpad_machine_spec_t *machine) /* Validate and register <b>machine</b> into <b>machine_list</b>. If * <b>machine_list</b> is NULL, then just validate. */ STATIC void register_padding_machine(circpad_machine_spec_t *machine, void circpad_register_padding_machine(circpad_machine_spec_t *machine, smartlist_t *machine_list) { if (!padding_machine_is_valid(machine)) { log_warn(LD_GENERAL, "Machine #%u is invalid. Ignoring.", log_warn(LD_CIRC, "Machine #%u is invalid. Ignoring.", machine->machine_num); return; } Loading @@ -2447,6 +2438,7 @@ register_padding_machine(circpad_machine_spec_t *machine, } } #ifdef TOR_UNIT_TESTS /* These padding machines are only used for tests pending #28634. */ static void circpad_circ_client_machine_init(void) Loading Loading @@ -2499,7 +2491,8 @@ circpad_circ_client_machine_init(void) circ_client_machine->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 5; circ_client_machine->machine_num = smartlist_len(origin_padding_machines); register_padding_machine(circ_client_machine, origin_padding_machines); circpad_register_padding_machine(circ_client_machine, origin_padding_machines); } static void Loading Loading @@ -2599,7 +2592,8 @@ circpad_circ_responder_machine_init(void) CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC; circ_responder_machine->machine_num = smartlist_len(relay_padding_machines); register_padding_machine(circ_responder_machine, relay_padding_machines); circpad_register_padding_machine(circ_responder_machine, relay_padding_machines); } #endif Loading @@ -2618,6 +2612,14 @@ circpad_machines_init(void) origin_padding_machines = smartlist_new(); relay_padding_machines = smartlist_new(); /* Register machines for hiding client-side intro circuits */ circpad_machine_client_hide_intro_circuits(origin_padding_machines); circpad_machine_relay_hide_intro_circuits(relay_padding_machines); /* Register machines for hiding client-side rendezvous circuits */ circpad_machine_client_hide_rend_circuits(origin_padding_machines); circpad_machine_relay_hide_rend_circuits(relay_padding_machines); // TODO: Parse machines from consensus and torrc #ifdef TOR_UNIT_TESTS circpad_circ_client_machine_init(); Loading Loading @@ -2668,8 +2670,8 @@ circpad_node_supports_padding(const node_t *node) * Returns node_t from the consensus for that hop, if it is opened. * Otherwise returns NULL. */ static const node_t * circuit_get_nth_node(origin_circuit_t *circ, int hop) MOCK_IMPL(STATIC const node_t *, circuit_get_nth_node,(origin_circuit_t *circ, int hop)) { crypt_path_t *iter = circuit_get_cpath_hop(circ, hop); Loading Loading @@ -2732,8 +2734,8 @@ circpad_negotiate_padding(origin_circuit_t *circ, &type)) < 0) return -1; log_fn(LOG_INFO,LD_CIRC, "Negotiating padding on circuit %u", circ->global_identifier); log_fn(LOG_INFO,LD_CIRC, "Negotiating padding on circuit %u (%d)", circ->global_identifier, TO_CIRCUIT(circ)->purpose); return circpad_send_command_to_hop(circ, target_hopnum, RELAY_COMMAND_PADDING_NEGOTIATE, Loading Loading @@ -2818,6 +2820,7 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) const circpad_machine_spec_t *, m) { if (m->machine_num == negotiate->machine_type) { circpad_setup_machine_on_circ(circ, m); circpad_cell_event_nonpadding_received(circ); goto done; } } SMARTLIST_FOREACH_END(m); Loading Loading @@ -2871,6 +2874,7 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, } if (negotiated->command == CIRCPAD_COMMAND_STOP) { log_info(LD_CIRC, "Received STOP command on PADDING_NEGOTIATED"); /* There may not be a padding_info here if we shut down the * machine in circpad_shutdown_old_machines(). Or, if * circpad_add_matching_matchines() added a new machine, Loading @@ -2891,6 +2895,36 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, return 0; } /** Free memory allocated by this machine spec. */ STATIC void machine_spec_free_(circpad_machine_spec_t *m) { if (!m) return; tor_free(m->states); tor_free(m); } /** Free all memory allocated by the circuitpadding subsystem. */ void circpad_free_all(void) { if (origin_padding_machines) { SMARTLIST_FOREACH_BEGIN(origin_padding_machines, circpad_machine_spec_t *, m) { machine_spec_free(m); } SMARTLIST_FOREACH_END(m); smartlist_free(origin_padding_machines); } if (relay_padding_machines) { SMARTLIST_FOREACH_BEGIN(relay_padding_machines, circpad_machine_spec_t *, m) { machine_spec_free(m); } SMARTLIST_FOREACH_END(m); smartlist_free(relay_padding_machines); } } /* Serialization */ // TODO: Should we use keyword=value here? Are there helpers for that? #if 0 Loading Loading
changes/ticket28634 0 → 100644 +10 −0 Original line number Diff line number Diff line o Major features (Circuit padding): - Onion service clients will now add padding cells to the initial portions of their INTRODUCE and RENDEZVOUS circuits, to make those circuits' traffic patterns look more like general purpose Exit traffic. The overhead for this is 2 extra cells in each direction for RENDEZVOUS circuits, and 1 extra upstream cell and 10 downstream cells for INTRODUCE circuits. This will only be enabled if the circuit's middle node supports this feature, too. (Clients may specify fixed middle nodes with the MiddleNodes torrc directive, and may force-disable this feature with the CircuitPadding torrc directive). Closes ticket 28634.
scripts/maint/practracker/exceptions.txt +2 −0 Original line number Diff line number Diff line Loading @@ -290,3 +290,5 @@ problem function-size /src/tools/tor-resolve.c:build_socks5_resolve_request() 10 problem function-size /src/tools/tor-resolve.c:do_resolve() 175 problem function-size /src/tools/tor-resolve.c:main() 112 problem function-size /src/core/or/circuitpadding.c:circpad_machine_schedule_padding() 107 problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_relay_hide_intro_circuits() 104 problem function-size /src/core/or/circuitpadding_machines.c:circpad_machine_client_hide_rend_circuits() 112
src/app/main/shutdown.c +1 −0 Original line number Diff line number Diff line Loading @@ -139,6 +139,7 @@ tor_free_all(int postfork) dos_free_all(); circuitmux_ewma_free_all(); accounting_free_all(); circpad_free_all(); if (!postfork) { config_free_all(); Loading
src/core/include.am +2 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ LIBTOR_APP_A_SOURCES = \ src/core/or/circuitmux.c \ src/core/or/circuitmux_ewma.c \ src/core/or/circuitpadding.c \ src/core/or/circuitpadding_machines.c \ src/core/or/circuitstats.c \ src/core/or/circuituse.c \ src/core/or/crypt_path.c \ Loading Loading @@ -247,6 +248,7 @@ noinst_HEADERS += \ src/core/or/circuitmux_ewma.h \ src/core/or/circuitstats.h \ src/core/or/circuitpadding.h \ src/core/or/circuitpadding_machines.h \ src/core/or/circuituse.h \ src/core/or/command.h \ src/core/or/connection_edge.h \ Loading
src/core/or/circuitpadding.c +118 −84 Original line number Diff line number Diff line Loading @@ -37,6 +37,13 @@ * When a padding machine reaches the END state, it gets wiped from the circuit * so that other padding machines can take over if needed (see * circpad_machine_spec_transitioned_to_end()). * **************************** * General notes: * * All used machines should be heap allocated and placed into * origin_padding_machines/relay_padding_machines so that they get correctly * cleaned up by the circpad_free_all() function. **/ #define CIRCUITPADDING_PRIVATE Loading @@ -46,6 +53,7 @@ #include "lib/math/prob_distr.h" #include "core/or/or.h" #include "core/or/circuitpadding.h" #include "core/or/circuitpadding_machines.h" #include "core/or/circuitlist.h" #include "core/or/circuituse.h" #include "core/mainloop/netstatus.h" Loading @@ -72,8 +80,6 @@ #include "app/config/config.h" static inline circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose); static inline circpad_circuit_state_t circpad_circuit_state( origin_circuit_t *circ); static void circpad_setup_machine_on_circ(circuit_t *on_circ, Loading Loading @@ -125,34 +131,6 @@ STATIC smartlist_t *relay_padding_machines = NULL; continue; #define FOR_EACH_ACTIVE_CIRCUIT_MACHINE_END } STMT_END ; /** * Return a human-readable description for a circuit padding state. */ static const char * circpad_state_to_string(circpad_statenum_t state) { const char *descr; switch (state) { case CIRCPAD_STATE_START: descr = "START"; break; case CIRCPAD_STATE_BURST: descr = "BURST"; break; case CIRCPAD_STATE_GAP: descr = "GAP"; break; case CIRCPAD_STATE_END: descr = "END"; break; default: descr = "CUSTOM"; // XXX: Just return # in static char buf? } return descr; } /** * Free the machineinfo at an index */ Loading Loading @@ -485,7 +463,10 @@ circpad_machine_setup_tokens(circpad_machine_runtime_t *mi) const circpad_state_t *state = circpad_machine_current_state(mi); /* If this state doesn't exist, or doesn't have token removal, * free any previous state's histogram, and bail */ * free any previous state's runtime histogram, and bail. * * If we don't have a token removal strategy, we also don't need a runtime * histogram and we rely on the immutable one in machine_spec_t. */ if (!state || state->token_removal == CIRCPAD_TOKEN_REMOVAL_NONE) { if (mi->histogram) { tor_free(mi->histogram); Loading Loading @@ -525,9 +506,14 @@ circpad_choose_state_length(circpad_machine_runtime_t *mi) length = circpad_distribution_sample(state->length_dist); length = MAX(0, length); length += state->start_length; if (state->max_length) { length = MIN(length, state->max_length); } mi->state_length = clamp_double_to_int64(length); log_info(LD_CIRC, "State length sampled to %"PRIu64".", mi->state_length); } /** Loading Loading @@ -595,6 +581,11 @@ circpad_machine_sample_delay(circpad_machine_runtime_t *mi) histogram_total_tokens = state->histogram_total_tokens; } /* If we are out of tokens, don't schedule padding. */ if (!histogram_total_tokens) { return CIRCPAD_DELAY_INFINITE; } bin_choice = crypto_fast_rng_get_uint64(get_thread_fast_rng(), histogram_total_tokens); Loading Loading @@ -897,7 +888,7 @@ circpad_machine_remove_closest_token(circpad_machine_runtime_t *mi, bin_to_remove = lower; } mi->histogram[bin_to_remove]--; log_debug(LD_GENERAL, "Removing token from bin %d", bin_to_remove); log_debug(LD_CIRC, "Removing token from bin %d", bin_to_remove); return; } else { if (current - lower > higher - current) { Loading Loading @@ -1207,14 +1198,16 @@ circpad_send_padding_cell_for_callback(circpad_machine_runtime_t *mi) circpad_send_command_to_hop(TO_ORIGIN_CIRCUIT(mi->on_circ), CIRCPAD_GET_MACHINE(mi)->target_hopnum, RELAY_COMMAND_DROP, NULL, 0); log_fn(LOG_INFO,LD_CIRC, "Callback: Sending padding to origin circuit %u.", TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier); log_info(LD_CIRC, "Callback: Sending padding to origin circuit %u" " (%d) [length: %"PRIu64"]", TO_ORIGIN_CIRCUIT(mi->on_circ)->global_identifier, mi->on_circ->purpose, mi->state_length); } else { // If we're a non-origin circ, we can just send from here as if we're the // edge. if (TO_OR_CIRCUIT(circ)->p_chan_cells.n <= circpad_max_circ_queued_cells) { log_fn(LOG_INFO,LD_CIRC, "Callback: Sending padding to non-origin circuit."); log_info(LD_CIRC, "Callback: Sending padding to circuit (%d)" " [length: %"PRIu64"]", mi->on_circ->purpose, mi->state_length); relay_send_command_from_edge(0, mi->on_circ, RELAY_COMMAND_DROP, NULL, 0, NULL); rep_hist_padding_count_write(PADDING_TYPE_DROP); Loading Loading @@ -1582,9 +1575,8 @@ circpad_machine_spec_transition,(circpad_machine_runtime_t *mi, * a transition to itself. All non-specified events are ignored. */ log_fn(LOG_INFO, LD_CIRC, "Circpad machine %d transitioning from %s to %s", mi->machine_index, circpad_state_to_string(mi->current_state), circpad_state_to_string(s)); "Circpad machine %d transitioning from %u to %u", mi->machine_index, mi->current_state, s); /* If this is not the same state, switch and init tokens, * otherwise just reschedule padding. */ Loading Loading @@ -1734,13 +1726,12 @@ circpad_estimate_circ_rtt_on_send(circuit_t *circ, * to back. Stop estimating RTT in this case. Note that we only * stop RTT update if the circuit is opened, to allow for RTT estimates * of var cells during circ setup. */ mi->stop_rtt_update = 1; if (!mi->rtt_estimate_usec) { if (!mi->rtt_estimate_usec && !mi->stop_rtt_update) { static ratelim_t rtt_lim = RATELIM_INIT(600); log_fn_ratelim(&rtt_lim,LOG_NOTICE,LD_BUG, "Circuit sent two cells back to back before estimating RTT."); } mi->stop_rtt_update = 1; } } Loading Loading @@ -1976,7 +1967,6 @@ circpad_circuit_state(origin_circuit_t *circ) * Convert a normal circuit purpose into a bitmask that we can * use for determining matching circuits. */ static inline circpad_purpose_mask_t circpad_circ_purpose_to_mask(uint8_t circ_purpose) { Loading Loading @@ -2019,7 +2009,8 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ) } /** * Negotiate new machines that would apply to this circuit. * Negotiate new machines that would apply to this circuit, given the machines * inside <b>machines_sl</b>. * * This function checks to see if we have any free machine indexes, * and for each free machine index, it initializes the most recently Loading @@ -2027,14 +2018,15 @@ circpad_shutdown_old_machines(origin_circuit_t *on_circ) * index and circuit conditions, and negotiates it with the appropriate * middle relay. */ static void circpad_add_matching_machines(origin_circuit_t *on_circ) STATIC void circpad_add_matching_machines(origin_circuit_t *on_circ, smartlist_t *machines_sl) { circuit_t *circ = TO_CIRCUIT(on_circ); #ifdef TOR_UNIT_TESTS /* Tests don't have to init our padding machines */ if (!origin_padding_machines) if (!machines_sl) return; #endif Loading @@ -2051,7 +2043,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ) /* We have a free machine index. Check the origin padding * machines in reverse order, so that more recently added * machines take priority over older ones. */ SMARTLIST_FOREACH_REVERSE_BEGIN(origin_padding_machines, SMARTLIST_FOREACH_REVERSE_BEGIN(machines_sl, circpad_machine_spec_t *, machine) { /* Machine definitions have a specific target machine index. Loading Loading @@ -2079,6 +2071,7 @@ circpad_add_matching_machines(origin_circuit_t *on_circ) if (circpad_negotiate_padding(on_circ, machine->machine_num, machine->target_hopnum, CIRCPAD_COMMAND_START) < 0) { log_info(LD_CIRC, "Padding not negotiated. Cleaning machine"); circpad_circuit_machineinfo_free_idx(circ, i); circ->padding_machine[i] = NULL; on_circ->padding_negotiation_failed = 1; Loading @@ -2102,7 +2095,7 @@ circpad_machine_event_circ_added_hop(origin_circuit_t *on_circ) { /* Since our padding conditions do not specify a max_hops, * all we can do is add machines here */ circpad_add_matching_machines(on_circ); circpad_add_matching_machines(on_circ, origin_padding_machines); } /** Loading @@ -2115,7 +2108,7 @@ void circpad_machine_event_circ_built(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2128,7 +2121,7 @@ void circpad_machine_event_circ_purpose_changed(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2142,7 +2135,7 @@ void circpad_machine_event_circ_has_no_relay_early(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2157,7 +2150,7 @@ void circpad_machine_event_circ_has_streams(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading @@ -2172,7 +2165,7 @@ void circpad_machine_event_circ_has_no_streams(origin_circuit_t *circ) { circpad_shutdown_old_machines(circ); circpad_add_matching_machines(circ); circpad_add_matching_machines(circ, origin_padding_machines); } /** Loading Loading @@ -2253,13 +2246,6 @@ circpad_deliver_recognized_relay_cell_events(circuit_t *circ, uint8_t relay_command, crypt_path_t *layer_hint) { /* Padding negotiate cells are ignored by the state machines * for simplicity. */ if (relay_command == RELAY_COMMAND_PADDING_NEGOTIATE || relay_command == RELAY_COMMAND_PADDING_NEGOTIATED) { return; } if (relay_command == RELAY_COMMAND_DROP) { rep_hist_padding_count_read(PADDING_TYPE_DROP); Loading Loading @@ -2296,16 +2282,12 @@ void circpad_deliver_sent_relay_cell_events(circuit_t *circ, uint8_t relay_command) { /* Padding negotiate cells are ignored by the state machines * for simplicity. */ if (relay_command == RELAY_COMMAND_PADDING_NEGOTIATE || relay_command == RELAY_COMMAND_PADDING_NEGOTIATED) { return; } /* RELAY_COMMAND_DROP is the multi-hop (aka circuit-level) padding cell in * tor. (CELL_PADDING is a channel-level padding cell, which is not relayed * or processed here) */ * or processed here). * * We do generate events for PADDING_NEGOTIATE and PADDING_NEGOTIATED cells. */ if (relay_command == RELAY_COMMAND_DROP) { /* Optimization: The event for RELAY_COMMAND_DROP is sent directly * from circpad_send_padding_cell_for_callback(). This is to avoid Loading Loading @@ -2363,12 +2345,21 @@ circpad_setup_machine_on_circ(circuit_t *on_circ, == NULL); tor_assert_nonfatal(on_circ->padding_info[machine->machine_index] == NULL); /* Log message */ if (CIRCUIT_IS_ORIGIN(on_circ)) { log_info(LD_CIRC, "Registering machine %s to origin circ %u (%d)", machine->name, TO_ORIGIN_CIRCUIT(on_circ)->global_identifier, on_circ->purpose); } else { log_info(LD_CIRC, "Registering machine %s to non-origin circ (%d)", machine->name, on_circ->purpose); } on_circ->padding_info[machine->machine_index] = circpad_circuit_machineinfo_new(on_circ, machine->machine_index); on_circ->padding_machine[machine->machine_index] = machine; } #ifdef TOR_UNIT_TESTS /** Validate a single state of a padding machine */ static bool padding_machine_state_is_valid(const circpad_state_t *state) Loading @@ -2384,7 +2375,7 @@ padding_machine_state_is_valid(const circpad_state_t *state) /* We need at least two bins in a histogram */ if (state->histogram_len < 2) { log_warn(LD_GENERAL, "You can't have a histogram with less than 2 bins"); log_warn(LD_CIRC, "You can't have a histogram with less than 2 bins"); return false; } Loading @@ -2394,7 +2385,7 @@ padding_machine_state_is_valid(const circpad_state_t *state) /* Check that histogram edges are strictly increasing. Ignore the first * edge since it can be zero. */ if (prev_bin_edge >= state->histogram_edges[b] && b > 0) { log_warn(LD_GENERAL, "Histogram edges are not increasing [%u/%u]", log_warn(LD_CIRC, "Histogram edges are not increasing [%u/%u]", prev_bin_edge, state->histogram_edges[b]); return false; } Loading @@ -2406,7 +2397,7 @@ padding_machine_state_is_valid(const circpad_state_t *state) } /* Verify that the total number of tokens is correct */ if (tokens_count != state->histogram_total_tokens) { log_warn(LD_GENERAL, "Histogram token count is wrong [%u/%u]", log_warn(LD_CIRC, "Histogram token count is wrong [%u/%u]", tokens_count, state->histogram_total_tokens); return false; } Loading @@ -2432,12 +2423,12 @@ padding_machine_is_valid(const circpad_machine_spec_t *machine) /* Validate and register <b>machine</b> into <b>machine_list</b>. If * <b>machine_list</b> is NULL, then just validate. */ STATIC void register_padding_machine(circpad_machine_spec_t *machine, void circpad_register_padding_machine(circpad_machine_spec_t *machine, smartlist_t *machine_list) { if (!padding_machine_is_valid(machine)) { log_warn(LD_GENERAL, "Machine #%u is invalid. Ignoring.", log_warn(LD_CIRC, "Machine #%u is invalid. Ignoring.", machine->machine_num); return; } Loading @@ -2447,6 +2438,7 @@ register_padding_machine(circpad_machine_spec_t *machine, } } #ifdef TOR_UNIT_TESTS /* These padding machines are only used for tests pending #28634. */ static void circpad_circ_client_machine_init(void) Loading Loading @@ -2499,7 +2491,8 @@ circpad_circ_client_machine_init(void) circ_client_machine->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 5; circ_client_machine->machine_num = smartlist_len(origin_padding_machines); register_padding_machine(circ_client_machine, origin_padding_machines); circpad_register_padding_machine(circ_client_machine, origin_padding_machines); } static void Loading Loading @@ -2599,7 +2592,8 @@ circpad_circ_responder_machine_init(void) CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC; circ_responder_machine->machine_num = smartlist_len(relay_padding_machines); register_padding_machine(circ_responder_machine, relay_padding_machines); circpad_register_padding_machine(circ_responder_machine, relay_padding_machines); } #endif Loading @@ -2618,6 +2612,14 @@ circpad_machines_init(void) origin_padding_machines = smartlist_new(); relay_padding_machines = smartlist_new(); /* Register machines for hiding client-side intro circuits */ circpad_machine_client_hide_intro_circuits(origin_padding_machines); circpad_machine_relay_hide_intro_circuits(relay_padding_machines); /* Register machines for hiding client-side rendezvous circuits */ circpad_machine_client_hide_rend_circuits(origin_padding_machines); circpad_machine_relay_hide_rend_circuits(relay_padding_machines); // TODO: Parse machines from consensus and torrc #ifdef TOR_UNIT_TESTS circpad_circ_client_machine_init(); Loading Loading @@ -2668,8 +2670,8 @@ circpad_node_supports_padding(const node_t *node) * Returns node_t from the consensus for that hop, if it is opened. * Otherwise returns NULL. */ static const node_t * circuit_get_nth_node(origin_circuit_t *circ, int hop) MOCK_IMPL(STATIC const node_t *, circuit_get_nth_node,(origin_circuit_t *circ, int hop)) { crypt_path_t *iter = circuit_get_cpath_hop(circ, hop); Loading Loading @@ -2732,8 +2734,8 @@ circpad_negotiate_padding(origin_circuit_t *circ, &type)) < 0) return -1; log_fn(LOG_INFO,LD_CIRC, "Negotiating padding on circuit %u", circ->global_identifier); log_fn(LOG_INFO,LD_CIRC, "Negotiating padding on circuit %u (%d)", circ->global_identifier, TO_CIRCUIT(circ)->purpose); return circpad_send_command_to_hop(circ, target_hopnum, RELAY_COMMAND_PADDING_NEGOTIATE, Loading Loading @@ -2818,6 +2820,7 @@ circpad_handle_padding_negotiate(circuit_t *circ, cell_t *cell) const circpad_machine_spec_t *, m) { if (m->machine_num == negotiate->machine_type) { circpad_setup_machine_on_circ(circ, m); circpad_cell_event_nonpadding_received(circ); goto done; } } SMARTLIST_FOREACH_END(m); Loading Loading @@ -2871,6 +2874,7 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, } if (negotiated->command == CIRCPAD_COMMAND_STOP) { log_info(LD_CIRC, "Received STOP command on PADDING_NEGOTIATED"); /* There may not be a padding_info here if we shut down the * machine in circpad_shutdown_old_machines(). Or, if * circpad_add_matching_matchines() added a new machine, Loading @@ -2891,6 +2895,36 @@ circpad_handle_padding_negotiated(circuit_t *circ, cell_t *cell, return 0; } /** Free memory allocated by this machine spec. */ STATIC void machine_spec_free_(circpad_machine_spec_t *m) { if (!m) return; tor_free(m->states); tor_free(m); } /** Free all memory allocated by the circuitpadding subsystem. */ void circpad_free_all(void) { if (origin_padding_machines) { SMARTLIST_FOREACH_BEGIN(origin_padding_machines, circpad_machine_spec_t *, m) { machine_spec_free(m); } SMARTLIST_FOREACH_END(m); smartlist_free(origin_padding_machines); } if (relay_padding_machines) { SMARTLIST_FOREACH_BEGIN(relay_padding_machines, circpad_machine_spec_t *, m) { machine_spec_free(m); } SMARTLIST_FOREACH_END(m); smartlist_free(relay_padding_machines); } } /* Serialization */ // TODO: Should we use keyword=value here? Are there helpers for that? #if 0 Loading