#define CHANNEL_OBJECT_PRIVATE
#define TOR_TIMERS_PRIVATE
#define CIRCUITPADDING_PRIVATE
#define CIRCUITPADDING_MACHINES_PRIVATE
#define NETWORKSTATUS_PRIVATE
#define CRYPT_PATH_PRIVATE
#define RELAY_PRIVATE
#include "core/or/or.h"
#include "test/test.h"
#include "test/log_test_helpers.h"
#include "lib/testsupport/testsupport.h"
#include "core/or/connection_or.h"
#include "core/or/channel.h"
#include "core/or/channeltls.h"
#include "core/or/crypt_path.h"
#include <event.h>
#include "lib/evloop/compat_libevent.h"
#include "lib/time/compat_time.h"
#include "lib/defs/time.h"
#include "core/or/relay.h"
#include "core/or/circuitlist.h"
#include "core/or/circuitbuild.h"
#include "core/or/circuitpadding.h"
#include "core/or/circuitpadding_machines.h"
#include "core/mainloop/netstatus.h"
#include "core/crypto/relay_crypto.h"
#include "core/or/protover.h"
#include "feature/nodelist/nodelist.h"
#include "app/config/config.h"
#include "feature/nodelist/routerstatus_st.h"
#include "feature/nodelist/networkstatus_st.h"
#include "feature/nodelist/node_st.h"
#include "core/or/cell_st.h"
#include "core/or/crypt_path_st.h"
#include "core/or/or_circuit_st.h"
#include "core/or/origin_circuit_st.h"
#include "test/fakecircs.h"
#include "test/rng_test_helpers.h"
#define MONOTIME_MOCK_START (monotime_absolute_nsec()+\
TOR_NSEC_PER_USEC*TOR_USEC_PER_SEC)
extern smartlist_t *connection_array;
void circuit_expire_old_circuits_clientside(void);
circid_t get_unique_circ_id_by_chan(channel_t *chan);
void helper_create_basic_machine(void);
static void helper_create_conditional_machines(void);
channel_t *new_fake_channel(void);
void test_circuitpadding_negotiation(void *arg);
void test_circuitpadding_wronghop(void *arg);
void test_circuitpadding_conditions(void *arg);
void test_circuitpadding_serialize(void *arg);
void test_circuitpadding_rtt(void *arg);
void test_circuitpadding_tokens(void *arg);
void test_circuitpadding_state_length(void *arg);
static void
simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
int padding);
void free_fake_origin_circuit(origin_circuit_t *circ);
static int deliver_negotiated = 1;
static int64_t curr_mocked_time;
static node_t padding_node;
static node_t non_padding_node;
static channel_t dummy_channel;
static circpad_machine_spec_t circ_client_machine;
static void
timers_advance_and_run(int64_t msec_update)
{
curr_mocked_time += msec_update*TOR_NSEC_PER_MSEC;
monotime_coarse_set_mock_time_nsec(curr_mocked_time);
monotime_set_mock_time_nsec(curr_mocked_time);
timers_run_pending();
}
static void
nodes_init(void)
{
padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
padding_node.rs->pv.supports_hs_setup_padding = 1;
non_padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
non_padding_node.rs->pv.supports_hs_setup_padding = 0;
}
static void
nodes_free(void)
{
tor_free(padding_node.rs);
tor_free(non_padding_node.rs);
}
static const node_t *
node_get_by_id_mock(const char *identity_digest)
{
if (identity_digest[0] == 1) {
return &padding_node;
} else if (identity_digest[0] == 0) {
return &non_padding_node;
}
return NULL;
}
static const node_t *
circuit_get_nth_node_mock(origin_circuit_t *circ, int hop)
{
(void) circ;
(void) hop;
return &padding_node;
}
void
free_fake_origin_circuit(origin_circuit_t *circ)
{
circpad_circuit_free_all_machineinfos(TO_CIRCUIT(circ));
circuit_clear_cpath(circ);
tor_free(circ);
}
void dummy_nop_timer(void);
static circuit_t *client_side;
static circuit_t *relay_side;
static int n_client_cells = 0;
static int n_relay_cells = 0;
static int
circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
crypt_path_t *layer_hint, streamid_t on_stream,
const char *filename, int lineno);
static void
circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction);
static void
circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ,
cell_direction_t direction)
{
(void)cmux;
(void)circ;
(void)direction;
return;
}
static int
circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ,
cell_direction_t cell_direction,
crypt_path_t *layer_hint, streamid_t on_stream,
const char *filename, int lineno)
{
(void)cell; (void)on_stream; (void)filename; (void)lineno;
if (circ == client_side) {
if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) {
circpad_handle_padding_negotiate(relay_side, cell);
} else {
int is_target_hop = circpad_padding_is_from_expected_hop(circ,
layer_hint);
tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_OUT);
tt_int_op(is_target_hop, OP_EQ, 1);
circpad_deliver_recognized_relay_cell_events(relay_side,
cell->payload[0], NULL);
}
n_client_cells++;
} else if (circ == relay_side) {
tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_IN);
if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATED) {
if (deliver_negotiated)
circpad_handle_padding_negotiated(client_side, cell,
TO_ORIGIN_CIRCUIT(client_side)
->cpath->next);
} else if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) {
circpad_handle_padding_negotiate(client_side, cell);
} else {
circpad_deliver_recognized_relay_cell_events(client_side,
cell->payload[0],
TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
}
n_relay_cells++;
}
done:
timers_advance_and_run(1);
return 0;
}
void
test_circuitpadding_serialize(void *arg)
{
(void)arg;
}
static signed_error_t
circpad_send_command_to_hop_mock(origin_circuit_t *circ, uint8_t hopnum,
uint8_t relay_command, const uint8_t *payload,
ssize_t payload_len)
{
(void) circ;
(void) hopnum;
(void) relay_command;
(void) payload;
(void) payload_len;
return 0;
}
void
test_circuitpadding_rtt(void *arg)
{
circpad_delay_t rtt_estimate;
int64_t actual_mocked_monotime_start;
(void)arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
testing_enable_reproducible_rng();
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
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();
circpad_machines_init();
helper_create_basic_machine();
MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock);
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,
0);
relay_side->padding_machine[0] = &circ_client_machine;
relay_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,0);
circpad_cell_event_nonpadding_received(relay_side);
tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0);
timers_advance_and_run(20);
circpad_cell_event_nonpadding_sent(relay_side);
tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 19000);
tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 30000);
tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
OP_EQ,
relay_side->padding_info[0]->rtt_estimate_usec+
circpad_machine_current_state(
relay_side->padding_info[0])->histogram_edges[0]);
circpad_cell_event_nonpadding_received(relay_side);
circpad_cell_event_nonpadding_received(relay_side);
tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0);
timers_advance_and_run(20);
circpad_cell_event_nonpadding_sent(relay_side);
circpad_cell_event_nonpadding_sent(relay_side);
tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 20000);
tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 21000);
tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
OP_EQ,
relay_side->padding_info[0]->rtt_estimate_usec+
circpad_machine_current_state(
relay_side->padding_info[0])->histogram_edges[0]);
tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1);
rtt_estimate = relay_side->padding_info[0]->rtt_estimate_usec;
circpad_cell_event_nonpadding_received(relay_side);
timers_advance_and_run(4);
circpad_cell_event_nonpadding_sent(relay_side);
tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_EQ,
rtt_estimate);
tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1);
tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
OP_EQ,
relay_side->padding_info[0]->rtt_estimate_usec+
circpad_machine_current_state(
relay_side->padding_info[0])->histogram_edges[0]);
circpad_cell_event_nonpadding_received(client_side);
tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
timers_advance_and_run(20);
circpad_cell_event_nonpadding_sent(client_side);
tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
tt_int_op(client_side->padding_info[0]->rtt_estimate_usec, OP_EQ, 0);
tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0),
OP_NE, client_side->padding_info[0]->rtt_estimate_usec);
tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0),
OP_EQ,
circpad_machine_current_state(
client_side->padding_info[0])->histogram_edges[0]);
done:
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
timers_shutdown();
monotime_disable_test_mocking();
UNMOCK(circuit_package_relay_cell);
UNMOCK(circuitmux_attach_circuit);
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
return;
}
void
helper_create_basic_machine(void)
{
circpad_machine_states_init(&circ_client_machine, 2);
circ_client_machine.name = "basic";
circ_client_machine.states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
circ_client_machine.states[CIRCPAD_STATE_START].use_rtt_estimate = 1;
circ_client_machine.states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST;
circ_client_machine.states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
circ_client_machine.states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_NONPADDING_SENT] = CIRCPAD_STATE_CANCEL;
circ_client_machine.states[CIRCPAD_STATE_BURST].token_removal =
CIRCPAD_TOKEN_REMOVAL_HIGHER;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_len = 5;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 500;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 2500;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 5000;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[4] = 20000;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[0] = 1;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[1] = 0;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[2] = 2;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[3] = 2;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[4] = 2;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_total_tokens = 7;
circ_client_machine.states[CIRCPAD_STATE_BURST].use_rtt_estimate = 1;
return;
}
#define BIG_HISTOGRAM_LEN 10
static void
helper_create_machine_with_big_histogram(circpad_removal_t removal_strategy)
{
const int tokens_per_bin = 2;
circpad_machine_states_init(&circ_client_machine, 2);
circpad_state_t *burst_state =
&circ_client_machine.states[CIRCPAD_STATE_BURST];
circ_client_machine.states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
burst_state->next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST;
burst_state->next_state[CIRCPAD_EVENT_NONPADDING_RECV] =CIRCPAD_STATE_BURST;
burst_state->next_state[CIRCPAD_EVENT_NONPADDING_SENT] =CIRCPAD_STATE_CANCEL;
burst_state->token_removal = CIRCPAD_TOKEN_REMOVAL_HIGHER;
burst_state->histogram_len = BIG_HISTOGRAM_LEN;
int n_tokens = 0;
int i;
for (i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
burst_state->histogram[i] = tokens_per_bin;
n_tokens += tokens_per_bin;
}
burst_state->histogram_edges[0] = 0;
burst_state->histogram_edges[1] = 1;
burst_state->histogram_edges[2] = 7;
burst_state->histogram_edges[3] = 15;
burst_state->histogram_edges[4] = 31;
burst_state->histogram_edges[5] = 62;
burst_state->histogram_edges[6] = 125;
burst_state->histogram_edges[7] = 250;
burst_state->histogram_edges[8] = 500;
burst_state->histogram_edges[9] = 1000;
burst_state->histogram_total_tokens = n_tokens;
burst_state->length_dist.type = CIRCPAD_DIST_UNIFORM;
burst_state->length_dist.param1 = n_tokens;
burst_state->length_dist.param2 = n_tokens;
burst_state->max_length = n_tokens;
burst_state->length_includes_nonpadding = 1;
burst_state->use_rtt_estimate = 0;
burst_state->token_removal = removal_strategy;
}
static circpad_decision_t
circpad_machine_schedule_padding_mock(circpad_machine_runtime_t *mi)
{
(void)mi;
return 0;
}
static uint64_t
mock_monotime_absolute_usec(void)
{
return 100;
}
static void
test_circuitpadding_token_removal_higher(void *arg)
{
circpad_machine_runtime_t *mi;
(void)arg;
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
monotime_enable_test_mocking();
helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_HIGHER);
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
mi = client_side->padding_info[0];
tt_assert(mi);
uint64_t current_time = monotime_absolute_usec();
const circpad_delay_t bin_left_bounds[] =
{0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
tt_uint_op(bin_left_bounds[i], OP_EQ,
circpad_histogram_bin_to_usec(mi, i));
}
const circpad_delay_t bin_right_bounds[] =
{0, 6, 14, 30, 61, 124, 249, 499, 999, CIRCPAD_DELAY_INFINITE-1};
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_uint_op(bin_right_bounds[i], OP_EQ,
histogram_get_bin_upper_bound(mi, i));
}
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
const int bin_removal_order[] = {4, 5, 6, 7, 8};
unsigned i;
for (i = 0; i < sizeof(bin_removal_order)/sizeof(int) ; i++) {
int bin_to_remove = bin_removal_order[i];
log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
i, bin_to_remove);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
if (i != BIG_HISTOGRAM_LEN - 2) {
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
}
}
for (i=0; i < 4 ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
mi->padding_scheduled_at_usec = current_time;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[0], OP_EQ, 1);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking();
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
}
static void
test_circuitpadding_token_removal_lower(void *arg)
{
circpad_machine_runtime_t *mi;
(void)arg;
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
monotime_enable_test_mocking();
helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_LOWER);
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
mi = client_side->padding_info[0];
tt_assert(mi);
uint64_t current_time = monotime_absolute_usec();
const circpad_delay_t bin_left_bounds[] =
{0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
tt_uint_op(bin_left_bounds[i], OP_EQ,
circpad_histogram_bin_to_usec(mi, i));
}
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
const int bin_removal_order[] = {4, 3, 2, 1, 0};
unsigned i;
for (i = 0; i < sizeof(bin_removal_order)/sizeof(int) ; i++) {
int bin_to_remove = bin_removal_order[i];
log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
i, bin_to_remove);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
if (i != BIG_HISTOGRAM_LEN - 2) {
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
}
}
for (i = 5; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
circ_client_machine.states[CIRCPAD_STATE_BURST].
histogram_edges[BIG_HISTOGRAM_LEN-2] = 100;
mi->padding_scheduled_at_usec = current_time - 29202;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking();
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
}
static void
test_circuitpadding_closest_token_removal(void *arg)
{
circpad_machine_runtime_t *mi;
(void)arg;
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
monotime_enable_test_mocking();
helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_CLOSEST);
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
mi = client_side->padding_info[0];
tt_assert(mi);
uint64_t current_time = monotime_absolute_usec();
const circpad_delay_t bin_left_bounds[] =
{0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
tt_uint_op(bin_left_bounds[i], OP_EQ,
circpad_histogram_bin_to_usec(mi, i));
}
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
const int bin_removal_order[] = {4, 3, 5, 2, 6, 1, 7, 0, 8, 9};
for (int i = 0; i < BIG_HISTOGRAM_LEN-1 ; i++) {
int bin_to_remove = bin_removal_order[i];
log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
i, bin_to_remove);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
if (i != BIG_HISTOGRAM_LEN - 2) {
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
}
}
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120;
mi->padding_scheduled_at_usec = current_time - 102;
mi->histogram[0] = 0;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[1], OP_EQ, 1);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
mi->padding_scheduled_at_usec = current_time - 29202;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking();
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
}
static void
test_circuitpadding_closest_token_removal_usec(void *arg)
{
circpad_machine_runtime_t *mi;
(void)arg;
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
monotime_enable_test_mocking();
helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC);
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
mi = client_side->padding_info[0];
tt_assert(mi);
uint64_t current_time = monotime_absolute_usec();
const circpad_delay_t bin_left_bounds[] =
{0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
tt_uint_op(bin_left_bounds[i], OP_EQ,
circpad_histogram_bin_to_usec(mi, i));
}
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
const int bin_removal_order[] = {4, 3, 5, 2, 1, 0, 6, 7, 8, 9};
for (int i = 0; i < BIG_HISTOGRAM_LEN-1 ; i++) {
int bin_to_remove = bin_removal_order[i];
log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
i, bin_to_remove);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
if (i != BIG_HISTOGRAM_LEN - 2) {
tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
}
}
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101;
circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120;
mi->padding_scheduled_at_usec = current_time - 102;
mi->histogram[0] = 0;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[1], OP_EQ, 1);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
circ_client_machine.states[CIRCPAD_STATE_BURST].
histogram_edges[BIG_HISTOGRAM_LEN-2] = 100;
mi->padding_scheduled_at_usec = current_time - 29202;
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking();
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
}
static void
test_circuitpadding_token_removal_exact(void *arg)
{
circpad_machine_runtime_t *mi;
(void)arg;
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
monotime_enable_test_mocking();
helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_EXACT);
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
mi = client_side->padding_info[0];
tt_assert(mi);
uint64_t current_time = monotime_absolute_usec();
mi->padding_scheduled_at_usec = current_time - 57;
tt_int_op(mi->histogram[4], OP_EQ, 2);
circpad_cell_event_nonpadding_sent(client_side);
mi->padding_scheduled_at_usec = current_time - 57;
tt_int_op(mi->histogram[4], OP_EQ, 1);
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[4], OP_EQ, 0);
mi->padding_scheduled_at_usec = current_time - 57;
circpad_cell_event_nonpadding_sent(client_side);
for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
if (i != 4) {
tt_int_op(mi->histogram[i], OP_EQ, 2);
}
}
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking();
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
}
#undef BIG_HISTOGRAM_LEN
void
test_circuitpadding_tokens(void *arg)
{
const circpad_state_t *state;
circpad_machine_runtime_t *mi;
int64_t actual_mocked_monotime_start;
(void)arg;
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
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;
note_user_activity(20);
timers_initialize();
helper_create_basic_machine();
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,
0);
mi = client_side->padding_info[0];
circpad_cell_event_nonpadding_received(client_side);
circpad_cell_event_nonpadding_sent(client_side);
circpad_hist_token_t inf_bin = mi->histogram[4];
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_BURST);
state = circpad_machine_current_state(client_side->padding_info[0]);
for (int bin = 0; bin < 2; bin++) {
circpad_delay_t usec =
circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
usec);
tt_int_op(bin, OP_EQ, bin2);
}
for (int bin = 2; bin < state->histogram_len-1; bin++) {
circpad_delay_t usec =
circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
usec);
tt_int_op(bin, OP_EQ, bin2);
bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
usec+3);
tt_int_op(bin, OP_EQ, bin2);
bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
usec-1);
tt_int_op(bin, OP_EQ, bin2+1);
}
for (circpad_delay_t i = 0; i <= state->histogram_edges[0]; i++) {
int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0],
i);
circpad_delay_t usec =
circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
usec);
tt_int_op(bin, OP_EQ, bin2);
tt_int_op(i, OP_LE, usec);
}
for (circpad_delay_t i = state->histogram_edges[0]+1;
i <= state->histogram_edges[0] +
state->histogram_edges[state->histogram_len-2]; i++) {
int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0],
i);
circpad_delay_t usec =
circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
usec);
tt_int_op(bin, OP_EQ, bin2);
tt_int_op(i, OP_GE, usec);
}
{
tt_int_op(mi->histogram[2], OP_EQ, 2);
tt_int_op(mi->histogram[3], OP_EQ, 2);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1);
tt_int_op(mi->histogram[3], OP_EQ, 2);
tt_int_op(mi->histogram[2], OP_EQ, 1);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1);
tt_int_op(mi->histogram[2], OP_EQ, 0);
tt_int_op(mi->histogram[3], OP_EQ, 2);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1);
tt_int_op(mi->histogram[3], OP_EQ, 0);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1);
tt_int_op(mi->histogram[3], OP_EQ, 0);
}
{
tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1);
tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
circpad_machine_remove_higher_token(mi,
circpad_histogram_bin_to_usec(mi, 5)+1000000);
tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
}
{
tt_int_op(mi->histogram[0], OP_EQ, 0);
mi->histogram[0] = 1;
circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2);
tt_int_op(mi->histogram[0], OP_EQ, 0);
}
while (inf_bin != 0) {
tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
circpad_cell_event_nonpadding_received(client_side);
inf_bin--;
}
circpad_cell_event_nonpadding_sent(client_side);
tt_int_op(mi->histogram[4], OP_EQ, 2);
{
tt_int_op(mi->histogram[0], OP_EQ, 1);
circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2);
tt_int_op(mi->histogram[0], OP_EQ, 0);
}
{
tt_int_op(mi->histogram[3], OP_EQ, 2);
circpad_machine_remove_lower_token(mi,
circpad_histogram_bin_to_usec(mi, 3)+1);
circpad_machine_remove_lower_token(mi,
circpad_histogram_bin_to_usec(mi, 3)+1);
tt_int_op(mi->histogram[3], OP_EQ, 0);
tt_int_op(mi->histogram[2], OP_EQ, 2);
circpad_machine_remove_lower_token(mi,
circpad_histogram_bin_to_usec(mi, 3)+1);
circpad_machine_remove_lower_token(mi,
circpad_histogram_bin_to_usec(mi, 3)+1);
circpad_machine_remove_lower_token(mi,
circpad_histogram_bin_to_usec(mi, 3)+1);
tt_int_op(mi->histogram[2], OP_EQ, 0);
}
circpad_machine_setup_tokens(mi);
tt_int_op(mi->histogram[2], OP_EQ, 2);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1, 0);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1, 0);
tt_int_op(mi->histogram[2], OP_EQ, 0);
tt_int_op(mi->histogram[3], OP_EQ, 2);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1, 0);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1, 0);
tt_int_op(mi->histogram[3], OP_EQ, 0);
tt_int_op(mi->histogram[0], OP_EQ, 1);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1, 0);
tt_int_op(mi->histogram[0], OP_EQ, 0);
tt_int_op(mi->histogram[4], OP_EQ, 2);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 2)+1, 0);
tt_int_op(mi->histogram[4], OP_EQ, 2);
circpad_machine_setup_tokens(mi);
tt_int_op(mi->histogram[0], OP_EQ, 1);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 0)/3, 1);
tt_int_op(mi->histogram[0], OP_EQ, 0);
tt_int_op(mi->histogram[2], OP_EQ, 2);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 0)/3, 1);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 0)/3, 1);
tt_int_op(mi->histogram[2], OP_EQ, 0);
tt_int_op(mi->histogram[3], OP_EQ, 2);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 4), 1);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 4), 1);
tt_int_op(mi->histogram[3], OP_EQ, 0);
tt_int_op(mi->histogram[4], OP_EQ, 2);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 4), 1);
circpad_machine_remove_closest_token(mi,
circpad_histogram_bin_to_usec(mi, 4), 1);
tt_int_op(mi->histogram[4], OP_EQ, 2);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
monotime_disable_test_mocking();
tor_free(circ_client_machine.states);
testing_disable_reproducible_rng();
}
void
test_circuitpadding_wronghop(void *arg)
{
(void)arg;
uint32_t read_bw = 0, overhead_bw = 0;
cell_t cell;
signed_error_t ret;
origin_circuit_t *orig_client;
int64_t actual_mocked_monotime_start;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
&dummy_channel));
orig_client = TO_ORIGIN_CIRCUIT(client_side);
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
nodes_init();
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();
circpad_machines_init();
MOCK(node_get_by_id,
node_get_by_id_mock);
MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock);
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
tt_int_op(n_relay_cells, OP_EQ, 1);
tt_int_op(n_client_cells, OP_EQ, 1);
read_bw = orig_client->n_delivered_read_circ_bw;
overhead_bw = orig_client->n_overhead_read_circ_bw;
circpad_deliver_recognized_relay_cell_events(client_side,
RELAY_COMMAND_DROP,
TO_ORIGIN_CIRCUIT(client_side)->cpath);
tt_int_op(read_bw, OP_EQ,
orig_client->n_delivered_read_circ_bw);
tt_int_op(overhead_bw, OP_EQ,
orig_client->n_overhead_read_circ_bw);
circpad_deliver_recognized_relay_cell_events(client_side,
RELAY_COMMAND_DROP,
TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next);
tt_int_op(read_bw, OP_EQ,
orig_client->n_delivered_read_circ_bw);
tt_int_op(overhead_bw, OP_EQ,
orig_client->n_overhead_read_circ_bw);
circpad_deliver_recognized_relay_cell_events(client_side,
RELAY_COMMAND_DROP,
TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
tt_int_op(read_bw, OP_EQ,
orig_client->n_delivered_read_circ_bw);
tt_int_op(overhead_bw, OP_LT,
orig_client->n_overhead_read_circ_bw);
ret = circpad_handle_padding_negotiated(client_side, &cell,
TO_ORIGIN_CIRCUIT(client_side)->cpath);
tt_int_op(ret, OP_EQ, -1);
ret = circpad_handle_padding_negotiated(client_side, &cell,
TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next);
tt_int_op(ret, OP_EQ, -1);
memset(&cell, 255, sizeof(cell));
ret = circpad_handle_padding_negotiated(client_side, &cell,
TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
tt_int_op(ret, OP_EQ, -1);
read_bw = orig_client->n_delivered_read_circ_bw;
overhead_bw = orig_client->n_overhead_read_circ_bw;
relay_send_command_from_edge(0, relay_side,
RELAY_COMMAND_PADDING_NEGOTIATE,
(void*)cell.payload,
(size_t)3, NULL);
tt_int_op(read_bw, OP_EQ,
orig_client->n_delivered_read_circ_bw);
tt_int_op(overhead_bw, OP_EQ,
orig_client->n_overhead_read_circ_bw);
tt_int_op(n_relay_cells, OP_EQ, 2);
tt_int_op(n_client_cells, OP_EQ, 1);
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
255, 2, CIRCPAD_COMMAND_STOP);
tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
tt_int_op(n_relay_cells, OP_EQ, 3);
tt_int_op(n_client_cells, OP_EQ, 2);
ret = circpad_handle_padding_negotiated(relay_side, &cell, NULL);
tt_int_op(ret, OP_EQ, -1);
memset(&cell, 0, sizeof(cell));
ret = circpad_handle_padding_negotiate(relay_side, &cell);
tt_int_op(ret, OP_EQ, -1);
tt_int_op(n_client_cells, OP_EQ, 2);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
&dummy_channel));
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 0);
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
tt_int_op(n_relay_cells, OP_EQ, 3);
tt_int_op(n_client_cells, OP_EQ, 2);
tt_int_op(n_relay_cells, OP_EQ, 3);
tt_int_op(n_client_cells, OP_EQ, 2);
simulate_single_hop_extend(client_side, relay_side, 1);
circpad_padding_negotiated(relay_side,
CIRCPAD_MACHINE_CIRC_SETUP,
CIRCPAD_COMMAND_START,
CIRCPAD_RESPONSE_OK);
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
circpad_padding_negotiated(relay_side,
CIRCPAD_MACHINE_CIRC_SETUP,
CIRCPAD_COMMAND_START,
CIRCPAD_RESPONSE_ERR);
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
monotime_disable_test_mocking();
UNMOCK(node_get_by_id);
UNMOCK(circuit_package_relay_cell);
UNMOCK(circuitmux_attach_circuit);
nodes_free();
testing_disable_reproducible_rng();
}
void
test_circuitpadding_negotiation(void *arg)
{
int64_t actual_mocked_monotime_start;
(void)arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
client_side = TO_CIRCUIT(origin_circuit_new());
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
nodes_init();
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();
circpad_machines_init();
MOCK(node_get_by_id,
node_get_by_id_mock);
MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock);
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
tt_int_op(n_relay_cells, OP_EQ, 1);
tt_int_op(n_client_cells, OP_EQ, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 0);
tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
tt_int_op(n_relay_cells, OP_EQ, 1);
tt_int_op(n_client_cells, OP_EQ, 1);
tt_int_op(n_relay_cells, OP_EQ, 1);
tt_int_op(n_client_cells, OP_EQ, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
CIRCPAD_MACHINE_CIRC_SETUP,
2, CIRCPAD_COMMAND_START);
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
tt_int_op(n_relay_cells, OP_EQ, 1);
tt_int_op(n_client_cells, OP_EQ, 1);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
SMARTLIST_FOREACH(relay_padding_machines,
circpad_machine_spec_t *,
m, tor_free(m->states); tor_free(m));
smartlist_free(relay_padding_machines);
relay_padding_machines = smartlist_new();
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
tt_int_op(n_client_cells, OP_EQ, 2);
tt_int_op(n_relay_cells, OP_EQ, 2);
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_machine[0], OP_EQ, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
monotime_disable_test_mocking();
UNMOCK(node_get_by_id);
UNMOCK(circuit_package_relay_cell);
UNMOCK(circuitmux_attach_circuit);
nodes_free();
}
static void
simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
int padding)
{
char whatevs_key[CPATH_KEY_MATERIAL_LEN];
char digest[DIGEST_LEN];
tor_addr_t addr;
circpad_cell_event_nonpadding_sent(client);
circpad_cell_event_nonpadding_received(mid_relay);
curr_mocked_time += 10 * TOR_NSEC_PER_MSEC;
monotime_coarse_set_mock_time_nsec(curr_mocked_time);
monotime_set_mock_time_nsec(curr_mocked_time);
circpad_cell_event_nonpadding_sent(mid_relay);
circpad_cell_event_nonpadding_received(client);
crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t));
cpath_extend_linked_list(&TO_ORIGIN_CIRCUIT(client)->cpath, hop);
hop->magic = CRYPT_PATH_MAGIC;
hop->state = CPATH_STATE_OPEN;
digest[0] = padding;
hop->extend_info = extend_info_new(
padding ? "padding" : "non-padding",
digest, NULL, NULL, NULL,
&addr, padding);
cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
hop->package_window = circuit_initial_package_window();
hop->deliver_window = CIRCWINDOW_START;
circpad_machine_event_circ_added_hop(TO_ORIGIN_CIRCUIT(client));
}
static circpad_machine_spec_t *
helper_create_length_machine(void)
{
circpad_machine_spec_t *ret =
tor_malloc_zero(sizeof(circpad_machine_spec_t));
circpad_machine_states_init(ret, 2);
ret->states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
ret->states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
ret->states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
ret->states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_BINS_EMPTY] = CIRCPAD_STATE_END;
ret->states[CIRCPAD_STATE_BURST].token_removal =
CIRCPAD_TOKEN_REMOVAL_NONE;
ret->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
ret->states[CIRCPAD_STATE_BURST].length_dist.param1 = 12;
ret->states[CIRCPAD_STATE_BURST].length_dist.param2 = 13;
ret->states[CIRCPAD_STATE_BURST].max_length = 12;
ret->states[CIRCPAD_STATE_BURST].histogram_len = 4;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000000;
ret->states[CIRCPAD_STATE_BURST].histogram[0] = 0;
ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0;
ret->states[CIRCPAD_STATE_BURST].histogram[2] = 6;
ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6;
ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0;
ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 0;
return ret;
}
static circpad_machine_spec_t *
helper_create_conditional_machine(void)
{
circpad_machine_spec_t *ret =
tor_malloc_zero(sizeof(circpad_machine_spec_t));
circpad_machine_states_init(ret, 2);
ret->states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
ret->states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
ret->states[CIRCPAD_STATE_BURST].
next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
ret->states[CIRCPAD_STATE_BURST].token_removal =
CIRCPAD_TOKEN_REMOVAL_EXACT;
ret->states[CIRCPAD_STATE_BURST].histogram_len = 3;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1;
ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000;
ret->states[CIRCPAD_STATE_BURST].histogram[0] = 6;
ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0;
ret->states[CIRCPAD_STATE_BURST].histogram[2] = 0;
ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6;
ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0;
ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1;
return ret;
}
static void
helper_create_conditional_machines(void)
{
circpad_machine_spec_t *add = helper_create_conditional_machine();
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;
add->should_negotiate_end = 1;
add->target_hopnum = 2;
add->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
add->states[CIRCPAD_STATE_BURST].length_dist.param1 = 4;
add->states[CIRCPAD_STATE_BURST].length_dist.param2 = 4;
add->states[CIRCPAD_STATE_BURST].max_length = 4;
add->conditions.requires_vanguards = 0;
add->conditions.min_hops = 2;
add->conditions.state_mask = CIRCPAD_CIRC_BUILDING|
CIRCPAD_CIRC_NO_STREAMS|CIRCPAD_CIRC_HAS_RELAY_EARLY;
add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
circpad_register_padding_machine(add, origin_padding_machines);
add = helper_create_conditional_machine();
add->machine_num = 3;
add->is_origin_side = 1;
add->should_negotiate_end = 1;
add->target_hopnum = 2;
add->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
add->states[CIRCPAD_STATE_BURST].length_dist.param1 = 4;
add->states[CIRCPAD_STATE_BURST].length_dist.param2 = 4;
add->states[CIRCPAD_STATE_BURST].max_length = 4;
add->conditions.requires_vanguards = 1;
add->conditions.min_hops = 3;
add->conditions.state_mask = CIRCPAD_CIRC_OPENED|
CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY;
add->conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
circpad_register_padding_machine(add, origin_padding_machines);
add = helper_create_conditional_machine();
add->machine_num = 2;
circpad_register_padding_machine(add, relay_padding_machines);
add = helper_create_conditional_machine();
add->machine_num = 3;
circpad_register_padding_machine(add, relay_padding_machines);
}
void
test_circuitpadding_state_length(void *arg)
{
int64_t actual_mocked_monotime_start;
(void)arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
nodes_init();
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
&dummy_channel));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
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;
note_user_activity(20);
timers_initialize();
circpad_machine_spec_t *client_machine =
helper_create_length_machine();
MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock);
MOCK(node_get_by_id,
node_get_by_id_mock);
client_side->padding_machine[0] = client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
circpad_machine_runtime_t *mi = client_side->padding_info[0];
circpad_cell_event_padding_sent(client_side);
tt_i64_op(mi->state_length, OP_EQ, 12);
tt_ptr_op(mi->histogram, OP_EQ, NULL);
circpad_cell_event_nonpadding_sent(client_side);
tt_i64_op(mi->state_length, OP_EQ, 12);
for (uint64_t i = mi->state_length-1; i > 0; i--) {
circpad_send_padding_cell_for_callback(mi);
tt_i64_op(mi->state_length, OP_EQ, i);
}
circpad_send_padding_cell_for_callback(mi);
tt_i64_op(mi->state_length, OP_EQ, -1);
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
mi->current_state = CIRCPAD_STATE_START;
client_machine->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1;
circpad_cell_event_padding_sent(client_side);
tt_i64_op(mi->state_length, OP_EQ, 12);
for (uint64_t i = mi->state_length-1; i > 0; i--) {
circpad_cell_event_nonpadding_sent(client_side);
tt_i64_op(mi->state_length, OP_EQ, i);
}
circpad_cell_event_nonpadding_sent(client_side);
tt_i64_op(mi->state_length, OP_EQ, -1);
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
client_machine->states[CIRCPAD_STATE_BURST].token_removal =
CIRCPAD_TOKEN_REMOVAL_EXACT;
mi->current_state = CIRCPAD_STATE_START;
circpad_cell_event_padding_sent(client_side);
tt_i64_op(mi->state_length, OP_EQ, 12);
tt_ptr_op(mi->histogram, OP_NE, NULL);
tt_int_op(mi->chosen_bin, OP_EQ, 2);
for (uint32_t i = mi->histogram[2]-1; i > 0; i--) {
circpad_send_padding_cell_for_callback(mi);
tt_int_op(mi->chosen_bin, OP_EQ, 2);
tt_int_op(mi->histogram[2], OP_EQ, i);
}
tt_i64_op(mi->state_length, OP_EQ, 7);
tt_int_op(mi->histogram[2], OP_EQ, 1);
circpad_send_padding_cell_for_callback(mi);
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
done:
tor_free(client_machine->states);
tor_free(client_machine);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
timers_shutdown();
monotime_disable_test_mocking();
UNMOCK(circuit_package_relay_cell);
UNMOCK(circuitmux_attach_circuit);
UNMOCK(node_get_by_id);
return;
}
void
test_circuitpadding_conditions(void *arg)
{
int64_t actual_mocked_monotime_start;
(void)arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
testing_enable_reproducible_rng();
nodes_init();
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
&dummy_channel));
client_side = TO_CIRCUIT(origin_circuit_new());
relay_side->purpose = CIRCUIT_PURPOSE_OR;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
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;
note_user_activity(20);
timers_initialize();
helper_create_conditional_machines();
MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock);
MOCK(node_get_by_id,
node_get_by_id_mock);
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
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);
circpad_cell_event_padding_sent(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);
simulate_single_hop_extend(client_side, relay_side, 1);
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);
TO_ORIGIN_CIRCUIT(client_side)->p_streams = 0;
circpad_machine_event_circ_has_no_streams(TO_ORIGIN_CIRCUIT(client_side));
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);
TO_ORIGIN_CIRCUIT(client_side)->has_opened = 1;
circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
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);
TO_ORIGIN_CIRCUIT(client_side)->remaining_relay_early_cells = 0;
circpad_machine_event_circ_has_no_relay_early(
TO_ORIGIN_CIRCUIT(client_side));
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);
get_options_mutable()->HSLayer2Nodes = (void*)1;
TO_ORIGIN_CIRCUIT(client_side)->p_streams = (void*)1;
circpad_machine_event_circ_has_streams(TO_ORIGIN_CIRCUIT(client_side));
tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 3);
tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 3);
deliver_negotiated = 0;
circpad_cell_event_padding_sent(client_side);
tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
simulate_single_hop_extend(client_side, relay_side, 1);
tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 3);
tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 3);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
done:
testing_disable_reproducible_rng();
return;
}
#if 0#endif
static void
helper_circpad_circ_distribution_machine_setup(int min, int max)
{
circpad_machine_states_init(&circ_client_machine, 7);
circpad_state_t *zero_st = &circ_client_machine.states[0];
zero_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 1;
zero_st->iat_dist.type = CIRCPAD_DIST_UNIFORM;
zero_st->iat_dist.param1 = min;
zero_st->iat_dist.param2 = max;
zero_st->dist_added_shift_usec = min;
zero_st->dist_max_sample_usec = max;
circpad_state_t *first_st = &circ_client_machine.states[1];
first_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 2;
first_st->iat_dist.type = CIRCPAD_DIST_LOGISTIC;
first_st->iat_dist.param1 = 9;
first_st->iat_dist.param2 = 3;
first_st->dist_added_shift_usec = min;
first_st->dist_max_sample_usec = max;
circpad_state_t *second_st = &circ_client_machine.states[2];
second_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 3;
second_st->iat_dist.type = CIRCPAD_DIST_LOG_LOGISTIC;
second_st->iat_dist.param1 = 1;
second_st->iat_dist.param2 = 0.5;
second_st->dist_added_shift_usec = min;
second_st->dist_max_sample_usec = max;
circpad_state_t *third_st = &circ_client_machine.states[3];
third_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 4;
third_st->iat_dist.type = CIRCPAD_DIST_GEOMETRIC;
third_st->iat_dist.param1 = 0.2;
third_st->dist_added_shift_usec = min;
third_st->dist_max_sample_usec = max;
circpad_state_t *fourth_st = &circ_client_machine.states[4];
fourth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 5;
fourth_st->iat_dist.type = CIRCPAD_DIST_WEIBULL;
fourth_st->iat_dist.param1 = 1.5;
fourth_st->iat_dist.param2 = 1;
fourth_st->dist_added_shift_usec = min;
fourth_st->dist_max_sample_usec = max;
circpad_state_t *fifth_st = &circ_client_machine.states[5];
fifth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 6;
fifth_st->iat_dist.type = CIRCPAD_DIST_PARETO;
fifth_st->iat_dist.param1 = 1;
fifth_st->iat_dist.param2 = 5;
fifth_st->dist_added_shift_usec = min;
fifth_st->dist_max_sample_usec = max;
}
static void
test_circuitpadding_sample_distribution(void *arg)
{
circpad_machine_runtime_t *mi;
int n_samples;
int n_states;
(void) arg;
MOCK(circpad_machine_schedule_padding,
circpad_machine_schedule_padding_mock);
testing_enable_reproducible_rng();
circpad_machines_init();
helper_circpad_circ_distribution_machine_setup(0, 10);
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
mi = client_side->padding_info[0];
for (n_states = 0 ; n_states < 6; n_states++) {
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, n_states);
for (n_samples = 0; n_samples < 100; n_samples++) {
circpad_delay_t delay = circpad_machine_sample_delay(mi);
tt_int_op(delay, OP_GE, 0);
tt_int_op(delay, OP_LE, 10);
}
circpad_cell_event_nonpadding_received(client_side);
}
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
UNMOCK(circpad_machine_schedule_padding);
testing_disable_reproducible_rng();
}
static circpad_decision_t
circpad_machine_spec_transition_mock(circpad_machine_runtime_t *mi,
circpad_event_t event)
{
(void) mi;
(void) event;
return CIRCPAD_STATE_UNCHANGED;
}
static void
test_circuitpadding_machine_rate_limiting(void *arg)
{
(void) arg;
bool retval;
circpad_machine_runtime_t *mi;
int i;
MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
testing_enable_reproducible_rng();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
helper_create_basic_machine();
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
mi = client_side->padding_info[0];
mi->state_length = CIRCPAD_STATE_LENGTH_INFINITE;
circ_client_machine.max_padding_percent = 50;
circ_client_machine.allowed_padding_count = 100;
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 0);
for (i=0;i<99;i++) {
circpad_send_padding_cell_for_callback(mi);
}
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 0);
circpad_send_padding_cell_for_callback(mi);
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 1);
retval = circpad_machine_schedule_padding(mi);
tt_int_op(retval, OP_EQ, CIRCPAD_STATE_UNCHANGED);
for (;i<UINT16_MAX;i++) {
circpad_send_padding_cell_for_callback(mi);
}
tt_int_op(mi->padding_sent, OP_EQ, UINT16_MAX/2+1);
tt_ptr_op(client_side->padding_info[0], OP_EQ, mi);
for (i=0;i<UINT16_MAX;i++) {
circpad_cell_event_nonpadding_sent(client_side);
}
tt_int_op(mi->nonpadding_sent, OP_EQ, UINT16_MAX/2);
tt_int_op(mi->padding_sent, OP_EQ, UINT16_MAX/4+1);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
testing_disable_reproducible_rng();
}
static void
test_circuitpadding_global_rate_limiting(void *arg)
{
(void) arg;
bool retval;
circpad_machine_runtime_t *mi;
int i;
int64_t actual_mocked_monotime_start;
MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
MOCK(circuit_package_relay_cell,
circuit_package_relay_cell_mock);
MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
testing_enable_reproducible_rng();
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();
client_side = TO_CIRCUIT(origin_circuit_new());
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
relay_side->purpose = CIRCUIT_PURPOSE_OR;
helper_create_basic_machine();
relay_side->padding_machine[0] = &circ_client_machine;
relay_side->padding_info[0] =
circpad_circuit_machineinfo_new(relay_side, 0);
mi = relay_side->padding_info[0];
mi->state_length = CIRCPAD_STATE_LENGTH_INFINITE;
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
networkstatus_t vote1;
vote1.net_params = smartlist_new();
smartlist_split_string(vote1.net_params,
"circpad_global_allowed_cells=100 circpad_global_max_padding_pct=50",
NULL, 0, 0);
circpad_new_consensus_params(&vote1);
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 0);
for (i=0;i<99;i++) {
circpad_send_padding_cell_for_callback(mi);
}
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 0);
circpad_send_padding_cell_for_callback(mi);
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 1);
retval = circpad_machine_schedule_padding(mi);
tt_int_op(retval, OP_EQ, CIRCPAD_STATE_UNCHANGED);
for (i=0;i<92;i++) {
circpad_cell_event_nonpadding_sent(relay_side);
}
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 1);
circpad_cell_event_nonpadding_sent(relay_side);
retval = circpad_machine_reached_padding_limit(mi);
tt_int_op(retval, OP_EQ, 0);
done:
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
smartlist_free(vote1.net_params);
testing_disable_reproducible_rng();
}
static void
test_circuitpadding_reduce_disable(void *arg)
{
(void) arg;
int64_t actual_mocked_monotime_start;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
testing_enable_reproducible_rng();
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();
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_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
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);
circpad_cell_event_padding_sent(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);
networkstatus_t vote1;
vote1.net_params = smartlist_new();
smartlist_split_string(vote1.net_params,
"circpad_padding_reduced=1", NULL, 0, 0);
circpad_new_consensus_params(&vote1);
simulate_single_hop_extend(client_side, relay_side, 1);
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);
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);
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);
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);
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);
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);
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);
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(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
testing_disable_reproducible_rng();
}
static void
helper_create_ender_machine(void)
{
circpad_machine_states_init(&circ_client_machine, 2);
circ_client_machine.states[CIRCPAD_STATE_START].
next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_END;
circ_client_machine.conditions.state_mask = CIRCPAD_STATE_ALL;
circ_client_machine.conditions.purpose_mask = CIRCPAD_PURPOSE_ALL;
}
static time_t mocked_timeofday;
static void
mock_tor_gettimeofday(struct timeval *timeval)
{
timeval->tv_sec = mocked_timeofday;
timeval->tv_usec = 0;
}
static void
test_circuitpadding_manage_circuit_lifetime(void *arg)
{
circpad_machine_runtime_t *mi;
(void) arg;
client_side = (circuit_t *)origin_circuit_new();
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
monotime_enable_test_mocking();
MOCK(tor_gettimeofday, mock_tor_gettimeofday);
mocked_timeofday = 23;
helper_create_ender_machine();
circ_client_machine.manage_circ_lifetime = 1;
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
mi = client_side->padding_info[0];
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START);
tt_int_op(client_side->marked_for_close, OP_EQ, 0);
tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
circuit_mark_for_close(client_side,
END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_NONE);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_int_op(client_side->marked_for_close, OP_NE, 0);
tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
client_side->marked_for_close = 0;
circuit_mark_for_close(client_side, END_CIRC_REASON_TORPROTOCOL);
tt_int_op(client_side->marked_for_close, OP_NE, 0);
tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
client_side->marked_for_close = 0;
client_side->purpose = CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT;
circuit_mark_for_close(client_side, END_CIRC_REASON_NONE);
tt_int_op(client_side->marked_for_close, OP_NE, 0);
tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
client_side->marked_for_close = 0;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
circuit_mark_for_close(client_side, END_CIRC_REASON_NONE);
tt_int_op(client_side->marked_for_close, OP_EQ, 0);
tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
client_side->marked_for_close = 0;
circuit_mark_for_close(client_side, 0);
tt_int_op(client_side->marked_for_close, OP_NE, 0);
client_side->marked_for_close = 0;
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
circpad_circuit_free_all_machineinfos(client_side);
tor_free(circ_client_machine.states);
helper_create_ender_machine();
client_side->padding_machine[0] = &circ_client_machine;
client_side->padding_info[0] =
circpad_circuit_machineinfo_new(client_side, 0);
mi = client_side->padding_info[0];
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START);
client_side->timestamp_dirty = 0;
client_side->state = CIRCUIT_STATE_OPEN;
tor_gettimeofday(&client_side->timestamp_began);
TO_ORIGIN_CIRCUIT(client_side)->circuit_idle_timeout = 23;
mocked_timeofday += 24;
circuit_expire_old_circuits_clientside();
circuit_expire_old_circuits_clientside();
circuit_expire_old_circuits_clientside();
tt_int_op(client_side->timestamp_dirty, OP_NE, 0);
tt_int_op(client_side->marked_for_close, OP_EQ, 0);
tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
mocked_timeofday = client_side->timestamp_dirty
+ get_options()->MaxCircuitDirtiness + 2;
client_side->padding_info[0]->last_cell_time_sec =
approx_time()-(CIRCPAD_DELAY_MAX_SECS+10);
circuit_expire_old_circuits_clientside();
tt_int_op(client_side->marked_for_close, OP_NE, 0);
client_side->padding_info[0]->last_cell_time_sec = approx_time();
client_side->marked_for_close = 0;
circuit_expire_old_circuits_clientside();
tt_int_op(client_side->marked_for_close, OP_EQ, 0);
mocked_timeofday = client_side->timestamp_dirty;
circpad_cell_event_nonpadding_received(client_side);
tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
tt_int_op(client_side->marked_for_close, OP_EQ, 0);
mocked_timeofday = client_side->timestamp_dirty;
circuit_expire_old_circuits_clientside();
tt_int_op(client_side->marked_for_close, OP_EQ, 0);
mocked_timeofday = client_side->timestamp_dirty
+ get_options()->MaxCircuitDirtiness + 2;
circuit_expire_old_circuits_clientside();
tt_int_op(client_side->marked_for_close, OP_NE, 0);
done:
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
tor_free(circ_client_machine.states);
monotime_disable_test_mocking();
UNMOCK(tor_gettimeofday);
}
static void
helper_test_hs_machines(bool test_intro_circs)
{
origin_circuit_t *origin_client_side = origin_circuit_new();
client_side = TO_CIRCUIT(origin_client_side);
client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
dummy_channel.cmux = circuitmux_alloc();
relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
relay_side->purpose = CIRCUIT_PURPOSE_OR;
simulate_single_hop_extend(client_side, relay_side, 1);
simulate_single_hop_extend(client_side, relay_side, 1);
origin_client_side->has_opened = 1;
tt_assert(!client_side->padding_machine[0]);
circpad_add_matching_machines(origin_client_side, origin_padding_machines);
tt_assert(!client_side->padding_machine[0]);
client_side->purpose = test_intro_circs ?
CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT : CIRCUIT_PURPOSE_C_REND_JOINED;
circpad_add_matching_machines(origin_client_side, origin_padding_machines);
tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
tt_str_op(client_side->padding_machine[0]->name, OP_EQ,
test_intro_circs ? "client_ip_circ" : "client_rp_circ");
tt_str_op(relay_side->padding_machine[0]->name, OP_EQ,
test_intro_circs ? "relay_ip_circ": "relay_rp_circ");
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
circpad_cell_event_nonpadding_received(client_side);
circpad_cell_event_nonpadding_received(relay_side);
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
circpad_machine_runtime_t *client_machine_runtime =
client_side->padding_info[0];
circpad_machine_runtime_t *relay_machine_runtime =
relay_side->padding_info[0];
if (test_intro_circs) {
tt_i64_op(client_machine_runtime->state_length, OP_EQ, -1);
tt_i64_op(relay_machine_runtime->state_length, OP_GE,
INTRO_MACHINE_MINIMUM_PADDING);
tt_i64_op(relay_machine_runtime->state_length, OP_LT,
INTRO_MACHINE_MAXIMUM_PADDING);
} else {
tt_i64_op(client_machine_runtime->state_length, OP_EQ, 1);
tt_i64_op(relay_machine_runtime->state_length, OP_EQ, 1);
}
if (test_intro_circs) {
int i;
for (i = (int) relay_machine_runtime->state_length ; i > 0 ; i--) {
circpad_send_padding_cell_for_callback(relay_machine_runtime);
}
tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
} else {
int i;
for (i = (int) client_machine_runtime->state_length ; i > 0 ; i--) {
circpad_send_padding_cell_for_callback(client_machine_runtime);
}
tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
CIRCPAD_STATE_END);
}
done:
free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
circuitmux_free(dummy_channel.cmux);
free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
}
static void
test_circuitpadding_hs_machines(void *arg)
{
(void)arg;
MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
MOCK(circuit_package_relay_cell, circuit_package_relay_cell_mock);
MOCK(circuit_get_nth_node, circuit_get_nth_node_mock);
MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
origin_padding_machines = smartlist_new();
relay_padding_machines = smartlist_new();
nodes_init();
monotime_init();
monotime_enable_test_mocking();
monotime_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
monotime_coarse_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
curr_mocked_time = 1*TOR_NSEC_PER_USEC;
timers_initialize();
note_user_activity(20);
circpad_machine_client_hide_intro_circuits(origin_padding_machines);
circpad_machine_client_hide_rend_circuits(origin_padding_machines);
circpad_machine_relay_hide_intro_circuits(relay_padding_machines);
circpad_machine_relay_hide_rend_circuits(relay_padding_machines);
helper_test_hs_machines(true);
helper_test_hs_machines(false);
timers_shutdown();
monotime_disable_test_mocking();
SMARTLIST_FOREACH_BEGIN(origin_padding_machines,
circpad_machine_spec_t *, m) {
machine_spec_free(m);
} SMARTLIST_FOREACH_END(m);
SMARTLIST_FOREACH_BEGIN(relay_padding_machines,
circpad_machine_spec_t *, m) {
machine_spec_free(m);
} SMARTLIST_FOREACH_END(m);
smartlist_free(origin_padding_machines);
smartlist_free(relay_padding_machines);
UNMOCK(circuitmux_attach_circuit);
UNMOCK(circuit_package_relay_cell);
UNMOCK(circuit_get_nth_node);
UNMOCK(circpad_machine_schedule_padding);
}
static void
test_circuitpadding_ignore_non_padding_cells(void *arg)
{
int retval;
relay_header_t rh;
(void) arg;
client_side = (circuit_t *)origin_circuit_new();
client_side->purpose = CIRCUIT_PURPOSE_C_CIRCUIT_PADDING;
rh.command = RELAY_COMMAND_BEGIN;
setup_full_capture_of_logs(LOG_INFO);
retval = handle_relay_cell_command(NULL, client_side, NULL, NULL, &rh, 0);
tt_int_op(retval, OP_EQ, 0);
expect_log_msg_containing("Ignored cell");
done:
;
}
#define TEST_CIRCUITPADDING(name, flags) \
{ #name, test_##name, (flags), NULL, NULL }
struct testcase_t circuitpadding_tests[] = {
TEST_CIRCUITPADDING(circuitpadding_tokens, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_state_length, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_negotiation, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_wronghop, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_conditions, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_rtt, TT_FORK),
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),
TEST_CIRCUITPADDING(circuitpadding_closest_token_removal_usec, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_token_removal_exact, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_manage_circuit_lifetime, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_hs_machines, TT_FORK),
TEST_CIRCUITPADDING(circuitpadding_ignore_non_padding_cells, TT_FORK),
END_OF_TESTCASES
};