TOR_VEGAS: Implement Prop#324 TOR_VEGAS.
[tor.git] / src / test / test_circuitpadding.c
blob6ced3f4111610b03db776012ff120aacce1668cd
1 #define CHANNEL_OBJECT_PRIVATE
2 #define TOR_TIMERS_PRIVATE
3 #define CIRCUITPADDING_PRIVATE
4 #define CIRCUITPADDING_MACHINES_PRIVATE
5 #define NETWORKSTATUS_PRIVATE
6 #define CRYPT_PATH_PRIVATE
7 #define RELAY_PRIVATE
9 #include "core/or/or.h"
10 #include "test/test.h"
11 #include "test/log_test_helpers.h"
12 #include "lib/testsupport/testsupport.h"
13 #include "core/or/connection_or.h"
14 #include "core/or/channel.h"
15 #include "core/or/channeltls.h"
16 #include "core/or/crypt_path.h"
17 #include <event.h>
18 #include "lib/evloop/compat_libevent.h"
19 #include "lib/time/compat_time.h"
20 #include "lib/defs/time.h"
21 #include "core/or/relay.h"
22 #include "core/or/circuitlist.h"
23 #include "core/or/circuitbuild.h"
24 #include "core/or/circuitpadding.h"
25 #include "core/or/circuitpadding_machines.h"
26 #include "core/or/extendinfo.h"
27 #include "core/mainloop/netstatus.h"
28 #include "core/crypto/relay_crypto.h"
29 #include "core/or/protover.h"
30 #include "feature/nodelist/nodelist.h"
31 #include "app/config/config.h"
33 #include "feature/nodelist/routerstatus_st.h"
34 #include "feature/nodelist/networkstatus_st.h"
35 #include "feature/nodelist/node_st.h"
36 #include "core/or/cell_st.h"
37 #include "core/or/crypt_path_st.h"
38 #include "core/or/or_circuit_st.h"
39 #include "core/or/origin_circuit_st.h"
41 #include "test/fakecircs.h"
42 #include "test/rng_test_helpers.h"
44 /* Start our monotime mocking at 1 second past whatever monotime_init()
45 * thought the actual wall clock time was, for platforms with bad resolution
46 * and weird timevalues during monotime_init() before mocking. */
47 #define MONOTIME_MOCK_START (monotime_absolute_nsec()+\
48 TOR_NSEC_PER_USEC*TOR_USEC_PER_SEC)
50 extern smartlist_t *connection_array;
51 void circuit_expire_old_circuits_clientside(void);
53 circid_t get_unique_circ_id_by_chan(channel_t *chan);
54 void helper_create_basic_machine(void);
55 static void helper_create_conditional_machines(void);
57 channel_t *new_fake_channel(void);
58 void test_circuitpadding_negotiation(void *arg);
59 void test_circuitpadding_wronghop(void *arg);
60 void test_circuitpadding_conditions(void *arg);
62 void test_circuitpadding_serialize(void *arg);
63 void test_circuitpadding_rtt(void *arg);
64 void test_circuitpadding_tokens(void *arg);
65 void test_circuitpadding_state_length(void *arg);
67 static void
68 simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
69 int padding);
70 void free_fake_origin_circuit(origin_circuit_t *circ);
72 static int deliver_negotiated = 1;
73 static int64_t curr_mocked_time;
75 static node_t padding_node;
76 static node_t non_padding_node;
78 static channel_t dummy_channel;
79 static circpad_machine_spec_t circ_client_machine;
81 static void
82 timers_advance_and_run(int64_t msec_update)
84 curr_mocked_time += msec_update*TOR_NSEC_PER_MSEC;
85 monotime_coarse_set_mock_time_nsec(curr_mocked_time);
86 monotime_set_mock_time_nsec(curr_mocked_time);
87 timers_run_pending();
90 static void
91 nodes_init(void)
93 padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
94 padding_node.rs->pv.supports_hs_setup_padding = 1;
96 non_padding_node.rs = tor_malloc_zero(sizeof(routerstatus_t));
97 non_padding_node.rs->pv.supports_hs_setup_padding = 0;
100 static void
101 nodes_free(void)
103 tor_free(padding_node.rs);
105 tor_free(non_padding_node.rs);
108 static const node_t *
109 node_get_by_id_mock(const char *identity_digest)
111 if (identity_digest[0] == 1) {
112 return &padding_node;
113 } else if (identity_digest[0] == 0) {
114 return &non_padding_node;
117 return NULL;
120 static const node_t *
121 circuit_get_nth_node_mock(origin_circuit_t *circ, int hop)
123 (void) circ;
124 (void) hop;
126 return &padding_node;
129 void
130 free_fake_origin_circuit(origin_circuit_t *circ)
132 circpad_circuit_free_all_machineinfos(TO_CIRCUIT(circ));
133 circuit_clear_cpath(circ);
134 tor_free(circ);
137 void dummy_nop_timer(void);
139 //static int dont_stop_libevent = 0;
141 static circuit_t *client_side;
142 static circuit_t *relay_side;
144 static int n_client_cells = 0;
145 static int n_relay_cells = 0;
147 static int
148 circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ,
149 cell_direction_t cell_direction,
150 crypt_path_t *layer_hint, streamid_t on_stream,
151 const char *filename, int lineno);
153 static void
154 circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ,
155 cell_direction_t direction);
157 static void
158 circuitmux_attach_circuit_mock(circuitmux_t *cmux, circuit_t *circ,
159 cell_direction_t direction)
161 (void)cmux;
162 (void)circ;
163 (void)direction;
165 return;
168 static int
169 circuit_package_relay_cell_mock(cell_t *cell, circuit_t *circ,
170 cell_direction_t cell_direction,
171 crypt_path_t *layer_hint, streamid_t on_stream,
172 const char *filename, int lineno)
174 (void)cell; (void)on_stream; (void)filename; (void)lineno;
176 if (circ == client_side) {
177 if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) {
178 // Deliver to relay
179 circpad_handle_padding_negotiate(relay_side, cell);
180 } else {
182 int is_target_hop = circpad_padding_is_from_expected_hop(circ,
183 layer_hint);
184 tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_OUT);
185 tt_int_op(is_target_hop, OP_EQ, 1);
187 // No need to pretend a padding cell was sent: This event is
188 // now emitted internally when the circuitpadding code sends them.
189 //circpad_cell_event_padding_sent(client_side);
191 // Receive padding cell at middle
192 circpad_deliver_recognized_relay_cell_events(relay_side,
193 cell->payload[0], NULL);
195 n_client_cells++;
196 } else if (circ == relay_side) {
197 tt_int_op(cell_direction, OP_EQ, CELL_DIRECTION_IN);
199 if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATED) {
200 // XXX: blah need right layer_hint..
201 if (deliver_negotiated)
202 circpad_handle_padding_negotiated(client_side, cell,
203 TO_ORIGIN_CIRCUIT(client_side)
204 ->cpath->next);
205 } else if (cell->payload[0] == RELAY_COMMAND_PADDING_NEGOTIATE) {
206 circpad_handle_padding_negotiate(client_side, cell);
207 } else {
208 // No need to pretend a padding cell was sent: This event is
209 // now emitted internally when the circuitpadding code sends them.
210 //circpad_cell_event_padding_sent(relay_side);
212 // Receive padding cell at client
213 circpad_deliver_recognized_relay_cell_events(client_side,
214 cell->payload[0],
215 TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
218 n_relay_cells++;
221 done:
222 timers_advance_and_run(1);
223 return 0;
226 // Test reading and writing padding to strings (or options_t + consensus)
227 void
228 test_circuitpadding_serialize(void *arg)
230 (void)arg;
233 static signed_error_t
234 circpad_send_command_to_hop_mock(origin_circuit_t *circ, uint8_t hopnum,
235 uint8_t relay_command, const uint8_t *payload,
236 ssize_t payload_len)
238 (void) circ;
239 (void) hopnum;
240 (void) relay_command;
241 (void) payload;
242 (void) payload_len;
243 return 0;
246 void
247 test_circuitpadding_rtt(void *arg)
249 /* Test Plan:
251 * 1. Test RTT measurement server side
252 * a. test usage of measured RTT
253 * 2. Test termination of RTT measurement
254 * a. test non-update of RTT
255 * 3. Test client side circuit and non-application of RTT..
257 circpad_delay_t rtt_estimate;
258 int64_t actual_mocked_monotime_start;
259 (void)arg;
261 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
262 MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
263 testing_enable_reproducible_rng();
265 dummy_channel.cmux = circuitmux_alloc();
266 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
267 client_side = TO_CIRCUIT(origin_circuit_new());
268 relay_side->purpose = CIRCUIT_PURPOSE_OR;
269 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
271 monotime_init();
272 monotime_enable_test_mocking();
273 actual_mocked_monotime_start = MONOTIME_MOCK_START;
274 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
275 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
276 curr_mocked_time = actual_mocked_monotime_start;
278 timers_initialize();
279 circpad_machines_init();
280 helper_create_basic_machine();
282 MOCK(circuit_package_relay_cell,
283 circuit_package_relay_cell_mock);
285 client_side->padding_machine[0] = &circ_client_machine;
286 client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,
289 relay_side->padding_machine[0] = &circ_client_machine;
290 relay_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,0);
292 /* Test 1: Test measuring RTT */
293 circpad_cell_event_nonpadding_received(relay_side);
294 tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0);
296 timers_advance_and_run(20);
298 circpad_cell_event_nonpadding_sent(relay_side);
299 tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
301 tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 19000);
302 tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 30000);
303 tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
304 OP_EQ,
305 relay_side->padding_info[0]->rtt_estimate_usec+
306 circpad_machine_current_state(
307 relay_side->padding_info[0])->histogram_edges[0]);
309 circpad_cell_event_nonpadding_received(relay_side);
310 circpad_cell_event_nonpadding_received(relay_side);
311 tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_NE, 0);
312 timers_advance_and_run(20);
313 circpad_cell_event_nonpadding_sent(relay_side);
314 circpad_cell_event_nonpadding_sent(relay_side);
315 tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
317 tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_GE, 20000);
318 tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_LE, 21000);
319 tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
320 OP_EQ,
321 relay_side->padding_info[0]->rtt_estimate_usec+
322 circpad_machine_current_state(
323 relay_side->padding_info[0])->histogram_edges[0]);
325 /* Test 2: Termination of RTT measurement (from the previous test) */
326 tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1);
327 rtt_estimate = relay_side->padding_info[0]->rtt_estimate_usec;
329 circpad_cell_event_nonpadding_received(relay_side);
330 timers_advance_and_run(4);
331 circpad_cell_event_nonpadding_sent(relay_side);
333 tt_int_op(relay_side->padding_info[0]->rtt_estimate_usec, OP_EQ,
334 rtt_estimate);
335 tt_u64_op(relay_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
336 tt_int_op(relay_side->padding_info[0]->stop_rtt_update, OP_EQ, 1);
337 tt_int_op(circpad_histogram_bin_to_usec(relay_side->padding_info[0], 0),
338 OP_EQ,
339 relay_side->padding_info[0]->rtt_estimate_usec+
340 circpad_machine_current_state(
341 relay_side->padding_info[0])->histogram_edges[0]);
343 /* Test 3: Make sure client side machine properly ignores RTT */
344 circpad_cell_event_nonpadding_received(client_side);
345 tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
347 timers_advance_and_run(20);
348 circpad_cell_event_nonpadding_sent(client_side);
349 tt_u64_op(client_side->padding_info[0]->last_received_time_usec, OP_EQ, 0);
351 tt_int_op(client_side->padding_info[0]->rtt_estimate_usec, OP_EQ, 0);
352 tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0),
353 OP_NE, client_side->padding_info[0]->rtt_estimate_usec);
354 tt_int_op(circpad_histogram_bin_to_usec(client_side->padding_info[0], 0),
355 OP_EQ,
356 circpad_machine_current_state(
357 client_side->padding_info[0])->histogram_edges[0]);
358 done:
359 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
360 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
361 circuitmux_free(dummy_channel.cmux);
362 timers_shutdown();
363 monotime_disable_test_mocking();
364 UNMOCK(circuit_package_relay_cell);
365 UNMOCK(circuitmux_attach_circuit);
366 tor_free(circ_client_machine.states);
367 testing_disable_reproducible_rng();
369 return;
372 void
373 helper_create_basic_machine(void)
375 /* Start, burst */
376 circpad_machine_states_init(&circ_client_machine, 2);
378 circ_client_machine.name = "basic";
380 circ_client_machine.states[CIRCPAD_STATE_START].
381 next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
382 circ_client_machine.states[CIRCPAD_STATE_START].use_rtt_estimate = 1;
384 circ_client_machine.states[CIRCPAD_STATE_BURST].
385 next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST;
386 circ_client_machine.states[CIRCPAD_STATE_BURST].
387 next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
389 circ_client_machine.states[CIRCPAD_STATE_BURST].
390 next_state[CIRCPAD_EVENT_NONPADDING_SENT] = CIRCPAD_STATE_CANCEL;
392 circ_client_machine.states[CIRCPAD_STATE_BURST].token_removal =
393 CIRCPAD_TOKEN_REMOVAL_HIGHER;
395 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_len = 5;
397 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 500;
398 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 2500;
399 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 5000;
400 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000;
401 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[4] = 20000;
403 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[0] = 1;
404 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[1] = 0;
405 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[2] = 2;
406 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[3] = 2;
407 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram[4] = 2;
409 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_total_tokens = 7;
410 circ_client_machine.states[CIRCPAD_STATE_BURST].use_rtt_estimate = 1;
412 return;
415 #define BIG_HISTOGRAM_LEN 10
417 /** Setup a machine with a big histogram */
418 static void
419 helper_create_machine_with_big_histogram(circpad_removal_t removal_strategy)
421 const int tokens_per_bin = 2;
423 /* Start, burst */
424 circpad_machine_states_init(&circ_client_machine, 2);
426 circpad_state_t *burst_state =
427 &circ_client_machine.states[CIRCPAD_STATE_BURST];
429 circ_client_machine.states[CIRCPAD_STATE_START].
430 next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_BURST;
432 burst_state->next_state[CIRCPAD_EVENT_PADDING_RECV] = CIRCPAD_STATE_BURST;
433 burst_state->next_state[CIRCPAD_EVENT_NONPADDING_RECV] =CIRCPAD_STATE_BURST;
435 burst_state->next_state[CIRCPAD_EVENT_NONPADDING_SENT] =CIRCPAD_STATE_CANCEL;
437 burst_state->token_removal = CIRCPAD_TOKEN_REMOVAL_HIGHER;
439 burst_state->histogram_len = BIG_HISTOGRAM_LEN;
441 int n_tokens = 0;
442 int i;
443 for (i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
444 burst_state->histogram[i] = tokens_per_bin;
445 n_tokens += tokens_per_bin;
448 burst_state->histogram_edges[0] = 0;
449 burst_state->histogram_edges[1] = 1;
450 burst_state->histogram_edges[2] = 7;
451 burst_state->histogram_edges[3] = 15;
452 burst_state->histogram_edges[4] = 31;
453 burst_state->histogram_edges[5] = 62;
454 burst_state->histogram_edges[6] = 125;
455 burst_state->histogram_edges[7] = 250;
456 burst_state->histogram_edges[8] = 500;
457 burst_state->histogram_edges[9] = 1000;
459 burst_state->histogram_total_tokens = n_tokens;
460 burst_state->length_dist.type = CIRCPAD_DIST_UNIFORM;
461 burst_state->length_dist.param1 = n_tokens;
462 burst_state->length_dist.param2 = n_tokens;
463 burst_state->max_length = n_tokens;
464 burst_state->length_includes_nonpadding = 1;
465 burst_state->use_rtt_estimate = 0;
466 burst_state->token_removal = removal_strategy;
469 static circpad_decision_t
470 circpad_machine_schedule_padding_mock(circpad_machine_runtime_t *mi)
472 (void)mi;
473 return 0;
476 static uint64_t
477 mock_monotime_absolute_usec(void)
479 return 100;
482 /** Test higher token removal strategy by bin */
483 static void
484 test_circuitpadding_token_removal_higher(void *arg)
486 circpad_machine_runtime_t *mi;
487 (void)arg;
489 /* Mock it up */
490 MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
491 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
492 testing_enable_reproducible_rng();
494 /* Setup test environment (time etc.) */
495 client_side = TO_CIRCUIT(origin_circuit_new());
496 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
497 monotime_enable_test_mocking();
499 /* Create test machine */
500 helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_HIGHER);
501 client_side->padding_machine[0] = &circ_client_machine;
502 client_side->padding_info[0] =
503 circpad_circuit_machineinfo_new(client_side, 0);
505 /* move the machine to the right state */
506 circpad_cell_event_nonpadding_received(client_side);
507 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
508 CIRCPAD_STATE_BURST);
510 /* Get the machine and setup tokens */
511 mi = client_side->padding_info[0];
512 tt_assert(mi);
514 /*************************************************************************/
516 uint64_t current_time = monotime_absolute_usec();
518 /* Test left boundaries of each histogram bin: */
519 const circpad_delay_t bin_left_bounds[] =
520 {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
521 for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
522 tt_uint_op(bin_left_bounds[i], OP_EQ,
523 circpad_histogram_bin_to_usec(mi, i));
526 /* Test right boundaries of each histogram bin: */
527 const circpad_delay_t bin_right_bounds[] =
528 {0, 6, 14, 30, 61, 124, 249, 499, 999, CIRCPAD_DELAY_INFINITE-1};
529 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
530 tt_uint_op(bin_right_bounds[i], OP_EQ,
531 histogram_get_bin_upper_bound(mi, i));
534 /* Check that all bins have two tokens right now */
535 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
536 tt_int_op(mi->histogram[i], OP_EQ, 2);
539 /* This is the right order to remove tokens from this histogram. That is, we
540 * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
541 * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
542 * the same reason, then from the 5th, etc. */
543 const int bin_removal_order[] = {4, 5, 6, 7, 8};
544 unsigned i;
546 /* Remove all tokens from all bins apart from the infinity bin */
547 for (i = 0; i < sizeof(bin_removal_order)/sizeof(int) ; i++) {
548 int bin_to_remove = bin_removal_order[i];
549 log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
550 i, bin_to_remove);
552 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
554 mi->padding_scheduled_at_usec = current_time - 57;
555 circpad_cell_event_nonpadding_sent(client_side);
557 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
559 mi->padding_scheduled_at_usec = current_time - 57;
560 circpad_cell_event_nonpadding_sent(client_side);
562 /* Test that we cleaned out this bin. Don't do this in the case of the last
563 bin since the tokens will get refilled */
564 if (i != BIG_HISTOGRAM_LEN - 2) {
565 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
569 /* Check that all lower bins are not touched */
570 for (i=0; i < 4 ; i++) {
571 tt_int_op(mi->histogram[i], OP_EQ, 2);
574 /* Test below the lowest bin, for coverage */
575 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
576 CIRCPAD_STATE_BURST);
577 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
578 mi->padding_scheduled_at_usec = current_time;
579 circpad_cell_event_nonpadding_sent(client_side);
580 tt_int_op(mi->histogram[0], OP_EQ, 1);
582 done:
583 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
584 monotime_disable_test_mocking();
585 tor_free(circ_client_machine.states);
586 testing_disable_reproducible_rng();
589 /** Test lower token removal strategy by bin */
590 static void
591 test_circuitpadding_token_removal_lower(void *arg)
593 circpad_machine_runtime_t *mi;
594 (void)arg;
596 /* Mock it up */
597 MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
598 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
599 testing_enable_reproducible_rng();
601 /* Setup test environment (time etc.) */
602 client_side = TO_CIRCUIT(origin_circuit_new());
603 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
604 monotime_enable_test_mocking();
606 /* Create test machine */
607 helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_LOWER);
608 client_side->padding_machine[0] = &circ_client_machine;
609 client_side->padding_info[0] =
610 circpad_circuit_machineinfo_new(client_side, 0);
612 /* move the machine to the right state */
613 circpad_cell_event_nonpadding_received(client_side);
614 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
615 CIRCPAD_STATE_BURST);
617 /* Get the machine and setup tokens */
618 mi = client_side->padding_info[0];
619 tt_assert(mi);
621 /*************************************************************************/
623 uint64_t current_time = monotime_absolute_usec();
625 /* Test left boundaries of each histogram bin: */
626 const circpad_delay_t bin_left_bounds[] =
627 {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
628 for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
629 tt_uint_op(bin_left_bounds[i], OP_EQ,
630 circpad_histogram_bin_to_usec(mi, i));
633 /* Check that all bins have two tokens right now */
634 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
635 tt_int_op(mi->histogram[i], OP_EQ, 2);
638 /* This is the right order to remove tokens from this histogram. That is, we
639 * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
640 * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
641 * the same reason, then from the 5th, etc. */
642 const int bin_removal_order[] = {4, 3, 2, 1, 0};
643 unsigned i;
645 /* Remove all tokens from all bins apart from the infinity bin */
646 for (i = 0; i < sizeof(bin_removal_order)/sizeof(int) ; i++) {
647 int bin_to_remove = bin_removal_order[i];
648 log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
649 i, bin_to_remove);
651 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
653 mi->padding_scheduled_at_usec = current_time - 57;
654 circpad_cell_event_nonpadding_sent(client_side);
656 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
658 mi->padding_scheduled_at_usec = current_time - 57;
659 circpad_cell_event_nonpadding_sent(client_side);
661 /* Test that we cleaned out this bin. Don't do this in the case of the last
662 bin since the tokens will get refilled */
663 if (i != BIG_HISTOGRAM_LEN - 2) {
664 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
668 /* Check that all higher bins are untouched */
669 for (i = 5; i < BIG_HISTOGRAM_LEN ; i++) {
670 tt_int_op(mi->histogram[i], OP_EQ, 2);
673 /* Test above the highest bin, for coverage */
674 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
675 CIRCPAD_STATE_BURST);
676 circ_client_machine.states[CIRCPAD_STATE_BURST].
677 histogram_edges[BIG_HISTOGRAM_LEN-2] = 100;
678 mi->padding_scheduled_at_usec = current_time - 29202;
679 circpad_cell_event_nonpadding_sent(client_side);
680 tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
682 done:
683 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
684 monotime_disable_test_mocking();
685 tor_free(circ_client_machine.states);
686 testing_disable_reproducible_rng();
689 /** Test closest token removal strategy by bin */
690 static void
691 test_circuitpadding_closest_token_removal(void *arg)
693 circpad_machine_runtime_t *mi;
694 (void)arg;
696 /* Mock it up */
697 MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
698 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
699 testing_enable_reproducible_rng();
701 /* Setup test environment (time etc.) */
702 client_side = TO_CIRCUIT(origin_circuit_new());
703 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
704 monotime_enable_test_mocking();
706 /* Create test machine */
707 helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_CLOSEST);
708 client_side->padding_machine[0] = &circ_client_machine;
709 client_side->padding_info[0] =
710 circpad_circuit_machineinfo_new(client_side, 0);
712 /* move the machine to the right state */
713 circpad_cell_event_nonpadding_received(client_side);
714 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
715 CIRCPAD_STATE_BURST);
717 /* Get the machine and setup tokens */
718 mi = client_side->padding_info[0];
719 tt_assert(mi);
721 /*************************************************************************/
723 uint64_t current_time = monotime_absolute_usec();
725 /* Test left boundaries of each histogram bin: */
726 const circpad_delay_t bin_left_bounds[] =
727 {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
728 for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
729 tt_uint_op(bin_left_bounds[i], OP_EQ,
730 circpad_histogram_bin_to_usec(mi, i));
733 /* Check that all bins have two tokens right now */
734 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
735 tt_int_op(mi->histogram[i], OP_EQ, 2);
738 /* This is the right order to remove tokens from this histogram. That is, we
739 * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
740 * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
741 * the same reason, then from the 5th, etc. */
742 const int bin_removal_order[] = {4, 3, 5, 2, 6, 1, 7, 0, 8, 9};
744 /* Remove all tokens from all bins apart from the infinity bin */
745 for (int i = 0; i < BIG_HISTOGRAM_LEN-1 ; i++) {
746 int bin_to_remove = bin_removal_order[i];
747 log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
748 i, bin_to_remove);
750 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
752 mi->padding_scheduled_at_usec = current_time - 57;
753 circpad_cell_event_nonpadding_sent(client_side);
755 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
757 mi->padding_scheduled_at_usec = current_time - 57;
758 circpad_cell_event_nonpadding_sent(client_side);
760 /* Test that we cleaned out this bin. Don't do this in the case of the last
761 bin since the tokens will get refilled */
762 if (i != BIG_HISTOGRAM_LEN - 2) {
763 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
767 /* Check that all bins have been refilled */
768 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
769 tt_int_op(mi->histogram[i], OP_EQ, 2);
772 /* Test below the lowest bin, for coverage */
773 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
774 CIRCPAD_STATE_BURST);
775 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
776 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101;
777 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120;
778 mi->padding_scheduled_at_usec = current_time - 102;
779 mi->histogram[0] = 0;
780 circpad_cell_event_nonpadding_sent(client_side);
781 tt_int_op(mi->histogram[1], OP_EQ, 1);
783 /* Test above the highest bin, for coverage */
784 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
785 CIRCPAD_STATE_BURST);
786 mi->padding_scheduled_at_usec = current_time - 29202;
787 circpad_cell_event_nonpadding_sent(client_side);
788 tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
790 done:
791 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
792 monotime_disable_test_mocking();
793 tor_free(circ_client_machine.states);
794 testing_disable_reproducible_rng();
797 /** Test closest token removal strategy with usec */
798 static void
799 test_circuitpadding_closest_token_removal_usec(void *arg)
801 circpad_machine_runtime_t *mi;
802 (void)arg;
804 /* Mock it up */
805 MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
806 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
807 testing_enable_reproducible_rng();
809 /* Setup test environment (time etc.) */
810 client_side = TO_CIRCUIT(origin_circuit_new());
811 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
812 monotime_enable_test_mocking();
814 /* Create test machine */
815 helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_CLOSEST_USEC);
816 client_side->padding_machine[0] = &circ_client_machine;
817 client_side->padding_info[0] =
818 circpad_circuit_machineinfo_new(client_side, 0);
820 /* move the machine to the right state */
821 circpad_cell_event_nonpadding_received(client_side);
822 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
823 CIRCPAD_STATE_BURST);
825 /* Get the machine and setup tokens */
826 mi = client_side->padding_info[0];
827 tt_assert(mi);
829 /*************************************************************************/
831 uint64_t current_time = monotime_absolute_usec();
833 /* Test left boundaries of each histogram bin: */
834 const circpad_delay_t bin_left_bounds[] =
835 {0, 1, 7, 15, 31, 62, 125, 250, 500, 1000, CIRCPAD_DELAY_INFINITE};
836 for (int i = 0; i <= BIG_HISTOGRAM_LEN ; i++) {
837 tt_uint_op(bin_left_bounds[i], OP_EQ,
838 circpad_histogram_bin_to_usec(mi, i));
841 /* XXX we want to test remove_token_exact and
842 circpad_machine_remove_closest_token() with usec */
844 /* Check that all bins have two tokens right now */
845 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
846 tt_int_op(mi->histogram[i], OP_EQ, 2);
849 /* This is the right order to remove tokens from this histogram. That is, we
850 * first remove tokens from the 4th bin since 57 usec is nearest to the 4th
851 * bin midpoint (31 + (62-31)/2 == 46). Then we remove from the 3rd bin for
852 * the same reason, then from the 5th, etc. */
853 const int bin_removal_order[] = {4, 3, 5, 2, 1, 0, 6, 7, 8, 9};
855 /* Remove all tokens from all bins apart from the infinity bin */
856 for (int i = 0; i < BIG_HISTOGRAM_LEN-1 ; i++) {
857 int bin_to_remove = bin_removal_order[i];
858 log_debug(LD_GENERAL, "Testing that %d attempt removes %d bin",
859 i, bin_to_remove);
861 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 2);
863 mi->padding_scheduled_at_usec = current_time - 57;
864 circpad_cell_event_nonpadding_sent(client_side);
866 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 1);
868 mi->padding_scheduled_at_usec = current_time - 57;
869 circpad_cell_event_nonpadding_sent(client_side);
871 /* Test that we cleaned out this bin. Don't do this in the case of the last
872 bin since the tokens will get refilled */
873 if (i != BIG_HISTOGRAM_LEN - 2) {
874 tt_int_op(mi->histogram[bin_to_remove], OP_EQ, 0);
878 /* Check that all bins have been refilled */
879 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
880 tt_int_op(mi->histogram[i], OP_EQ, 2);
883 /* Test below the lowest bin, for coverage */
884 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
885 CIRCPAD_STATE_BURST);
886 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[0] = 100;
887 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[1] = 101;
888 circ_client_machine.states[CIRCPAD_STATE_BURST].histogram_edges[2] = 120;
889 mi->padding_scheduled_at_usec = current_time - 102;
890 mi->histogram[0] = 0;
891 circpad_cell_event_nonpadding_sent(client_side);
892 tt_int_op(mi->histogram[1], OP_EQ, 1);
894 /* Test above the highest bin, for coverage */
895 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
896 CIRCPAD_STATE_BURST);
897 circ_client_machine.states[CIRCPAD_STATE_BURST].
898 histogram_edges[BIG_HISTOGRAM_LEN-2] = 100;
899 mi->padding_scheduled_at_usec = current_time - 29202;
900 circpad_cell_event_nonpadding_sent(client_side);
901 tt_int_op(mi->histogram[BIG_HISTOGRAM_LEN-2], OP_EQ, 1);
903 done:
904 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
905 monotime_disable_test_mocking();
906 tor_free(circ_client_machine.states);
907 testing_disable_reproducible_rng();
910 /** Test closest token removal strategy with usec */
911 static void
912 test_circuitpadding_token_removal_exact(void *arg)
914 circpad_machine_runtime_t *mi;
915 (void)arg;
917 /* Mock it up */
918 MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
919 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
920 testing_enable_reproducible_rng();
922 /* Setup test environment (time etc.) */
923 client_side = TO_CIRCUIT(origin_circuit_new());
924 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
925 monotime_enable_test_mocking();
927 /* Create test machine */
928 helper_create_machine_with_big_histogram(CIRCPAD_TOKEN_REMOVAL_EXACT);
929 client_side->padding_machine[0] = &circ_client_machine;
930 client_side->padding_info[0] =
931 circpad_circuit_machineinfo_new(client_side, 0);
933 /* move the machine to the right state */
934 circpad_cell_event_nonpadding_received(client_side);
935 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
936 CIRCPAD_STATE_BURST);
938 /* Get the machine and setup tokens */
939 mi = client_side->padding_info[0];
940 tt_assert(mi);
942 /**********************************************************************/
943 uint64_t current_time = monotime_absolute_usec();
945 /* Ensure that we will clear out bin #4 with this usec */
946 mi->padding_scheduled_at_usec = current_time - 57;
947 tt_int_op(mi->histogram[4], OP_EQ, 2);
948 circpad_cell_event_nonpadding_sent(client_side);
949 mi->padding_scheduled_at_usec = current_time - 57;
950 tt_int_op(mi->histogram[4], OP_EQ, 1);
951 circpad_cell_event_nonpadding_sent(client_side);
952 tt_int_op(mi->histogram[4], OP_EQ, 0);
954 /* Ensure that we will not remove any other tokens even tho we try to, since
955 * this is what the exact strategy dictates */
956 mi->padding_scheduled_at_usec = current_time - 57;
957 circpad_cell_event_nonpadding_sent(client_side);
958 for (int i = 0; i < BIG_HISTOGRAM_LEN ; i++) {
959 if (i != 4) {
960 tt_int_op(mi->histogram[i], OP_EQ, 2);
964 done:
965 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
966 monotime_disable_test_mocking();
967 tor_free(circ_client_machine.states);
968 testing_disable_reproducible_rng();
971 #undef BIG_HISTOGRAM_LEN
973 void
974 test_circuitpadding_tokens(void *arg)
976 const circpad_state_t *state;
977 circpad_machine_runtime_t *mi;
978 int64_t actual_mocked_monotime_start;
979 (void)arg;
981 testing_enable_reproducible_rng();
983 /** Test plan:
985 * 1. Test symmetry between bin_to_usec and usec_to_bin
986 * a. Test conversion
987 * b. Test edge transitions (lower, upper)
988 * 2. Test remove higher on an empty bin
989 * a. Normal bin
990 * b. Infinity bin
991 * c. Bin 0
992 * d. No higher
993 * 3. Test remove lower
994 * a. Normal bin
995 * b. Bin 0
996 * c. No lower
997 * 4. Test remove closest
998 * a. Closest lower
999 * b. Closest higher
1000 * c. Closest 0
1001 * d. Closest Infinity
1003 client_side = TO_CIRCUIT(origin_circuit_new());
1004 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1006 monotime_init();
1007 monotime_enable_test_mocking();
1008 actual_mocked_monotime_start = MONOTIME_MOCK_START;
1009 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
1010 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
1011 curr_mocked_time = actual_mocked_monotime_start;
1013 /* This is needed so that we are not considered to be dormant */
1014 note_user_activity(20);
1016 timers_initialize();
1018 helper_create_basic_machine();
1019 client_side->padding_machine[0] = &circ_client_machine;
1020 client_side->padding_info[0] = circpad_circuit_machineinfo_new(client_side,
1023 mi = client_side->padding_info[0];
1025 // Pretend a non-padding cell was sent
1026 circpad_cell_event_nonpadding_received(client_side);
1027 circpad_cell_event_nonpadding_sent(client_side);
1028 /* We have to save the infinity bin because one inf delay
1029 * could have been chosen when we transition to burst */
1030 circpad_hist_token_t inf_bin = mi->histogram[4];
1032 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
1033 CIRCPAD_STATE_BURST);
1035 state = circpad_machine_current_state(client_side->padding_info[0]);
1037 // Test 0: convert bin->usec->bin
1038 // Bin 0+1 have different semantics
1039 for (int bin = 0; bin < 2; bin++) {
1040 circpad_delay_t usec =
1041 circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
1042 int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1043 usec);
1044 tt_int_op(bin, OP_EQ, bin2);
1046 for (int bin = 2; bin < state->histogram_len-1; bin++) {
1047 circpad_delay_t usec =
1048 circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
1049 int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1050 usec);
1051 tt_int_op(bin, OP_EQ, bin2);
1052 /* Verify we round down */
1053 bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1054 usec+3);
1055 tt_int_op(bin, OP_EQ, bin2);
1057 bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1058 usec-1);
1059 tt_int_op(bin, OP_EQ, bin2+1);
1062 // Test 1: converting usec->bin->usec->bin
1063 // Bin 0+1 have different semantics.
1064 for (circpad_delay_t i = 0; i <= state->histogram_edges[0]; i++) {
1065 int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1067 circpad_delay_t usec =
1068 circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
1069 int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1070 usec);
1071 tt_int_op(bin, OP_EQ, bin2);
1072 tt_int_op(i, OP_LE, usec);
1074 for (circpad_delay_t i = state->histogram_edges[0]+1;
1075 i <= state->histogram_edges[0] +
1076 state->histogram_edges[state->histogram_len-2]; i++) {
1077 int bin = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1079 circpad_delay_t usec =
1080 circpad_histogram_bin_to_usec(client_side->padding_info[0], bin);
1081 int bin2 = circpad_histogram_usec_to_bin(client_side->padding_info[0],
1082 usec);
1083 tt_int_op(bin, OP_EQ, bin2);
1084 tt_int_op(i, OP_GE, usec);
1087 /* 2.a. Normal higher bin */
1089 tt_int_op(mi->histogram[2], OP_EQ, 2);
1090 tt_int_op(mi->histogram[3], OP_EQ, 2);
1091 circpad_machine_remove_higher_token(mi,
1092 circpad_histogram_bin_to_usec(mi, 2)+1);
1093 tt_int_op(mi->histogram[3], OP_EQ, 2);
1094 tt_int_op(mi->histogram[2], OP_EQ, 1);
1096 circpad_machine_remove_higher_token(mi,
1097 circpad_histogram_bin_to_usec(mi, 2)+1);
1098 tt_int_op(mi->histogram[2], OP_EQ, 0);
1100 tt_int_op(mi->histogram[3], OP_EQ, 2);
1101 circpad_machine_remove_higher_token(mi,
1102 circpad_histogram_bin_to_usec(mi, 2)+1);
1103 circpad_machine_remove_higher_token(mi,
1104 circpad_histogram_bin_to_usec(mi, 2)+1);
1105 tt_int_op(mi->histogram[3], OP_EQ, 0);
1106 circpad_machine_remove_higher_token(mi,
1107 circpad_histogram_bin_to_usec(mi, 2)+1);
1108 tt_int_op(mi->histogram[3], OP_EQ, 0);
1111 /* 2.b. Higher Infinity bin */
1113 tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
1114 circpad_machine_remove_higher_token(mi,
1115 circpad_histogram_bin_to_usec(mi, 2)+1);
1116 tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
1118 /* Test past the infinity bin */
1119 circpad_machine_remove_higher_token(mi,
1120 circpad_histogram_bin_to_usec(mi, 5)+1000000);
1122 tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
1125 /* 2.c. Bin 0 */
1127 tt_int_op(mi->histogram[0], OP_EQ, 0);
1128 mi->histogram[0] = 1;
1129 circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2);
1130 tt_int_op(mi->histogram[0], OP_EQ, 0);
1133 /* Drain the infinity bin and cause a refill */
1134 while (inf_bin != 0) {
1135 tt_int_op(mi->histogram[4], OP_EQ, inf_bin);
1136 circpad_cell_event_nonpadding_received(client_side);
1137 inf_bin--;
1140 circpad_cell_event_nonpadding_sent(client_side);
1142 // We should have refilled here.
1143 tt_int_op(mi->histogram[4], OP_EQ, 2);
1145 /* 3.a. Bin 0 */
1147 tt_int_op(mi->histogram[0], OP_EQ, 1);
1148 circpad_machine_remove_higher_token(mi, state->histogram_edges[0]/2);
1149 tt_int_op(mi->histogram[0], OP_EQ, 0);
1152 /* 3.b. Test remove lower normal bin */
1154 tt_int_op(mi->histogram[3], OP_EQ, 2);
1155 circpad_machine_remove_lower_token(mi,
1156 circpad_histogram_bin_to_usec(mi, 3)+1);
1157 circpad_machine_remove_lower_token(mi,
1158 circpad_histogram_bin_to_usec(mi, 3)+1);
1159 tt_int_op(mi->histogram[3], OP_EQ, 0);
1160 tt_int_op(mi->histogram[2], OP_EQ, 2);
1161 circpad_machine_remove_lower_token(mi,
1162 circpad_histogram_bin_to_usec(mi, 3)+1);
1163 circpad_machine_remove_lower_token(mi,
1164 circpad_histogram_bin_to_usec(mi, 3)+1);
1165 /* 3.c. No lower */
1166 circpad_machine_remove_lower_token(mi,
1167 circpad_histogram_bin_to_usec(mi, 3)+1);
1168 tt_int_op(mi->histogram[2], OP_EQ, 0);
1171 /* 4. Test remove closest
1172 * a. Closest lower
1173 * b. Closest higher
1174 * c. Closest 0
1175 * d. Closest Infinity
1177 circpad_machine_setup_tokens(mi);
1178 tt_int_op(mi->histogram[2], OP_EQ, 2);
1179 circpad_machine_remove_closest_token(mi,
1180 circpad_histogram_bin_to_usec(mi, 2)+1, 0);
1181 circpad_machine_remove_closest_token(mi,
1182 circpad_histogram_bin_to_usec(mi, 2)+1, 0);
1183 tt_int_op(mi->histogram[2], OP_EQ, 0);
1184 tt_int_op(mi->histogram[3], OP_EQ, 2);
1185 circpad_machine_remove_closest_token(mi,
1186 circpad_histogram_bin_to_usec(mi, 2)+1, 0);
1187 circpad_machine_remove_closest_token(mi,
1188 circpad_histogram_bin_to_usec(mi, 2)+1, 0);
1189 tt_int_op(mi->histogram[3], OP_EQ, 0);
1190 tt_int_op(mi->histogram[0], OP_EQ, 1);
1191 circpad_machine_remove_closest_token(mi,
1192 circpad_histogram_bin_to_usec(mi, 2)+1, 0);
1193 tt_int_op(mi->histogram[0], OP_EQ, 0);
1194 tt_int_op(mi->histogram[4], OP_EQ, 2);
1195 circpad_machine_remove_closest_token(mi,
1196 circpad_histogram_bin_to_usec(mi, 2)+1, 0);
1197 tt_int_op(mi->histogram[4], OP_EQ, 2);
1199 /* 5. Test remove closest usec
1200 * a. Closest 0
1201 * b. Closest lower (below midpoint)
1202 * c. Closest higher (above midpoint)
1203 * d. Closest Infinity
1205 circpad_machine_setup_tokens(mi);
1207 tt_int_op(mi->histogram[0], OP_EQ, 1);
1208 circpad_machine_remove_closest_token(mi,
1209 circpad_histogram_bin_to_usec(mi, 0)/3, 1);
1210 tt_int_op(mi->histogram[0], OP_EQ, 0);
1211 tt_int_op(mi->histogram[2], OP_EQ, 2);
1212 circpad_machine_remove_closest_token(mi,
1213 circpad_histogram_bin_to_usec(mi, 0)/3, 1);
1214 circpad_machine_remove_closest_token(mi,
1215 circpad_histogram_bin_to_usec(mi, 0)/3, 1);
1216 tt_int_op(mi->histogram[2], OP_EQ, 0);
1217 tt_int_op(mi->histogram[3], OP_EQ, 2);
1218 circpad_machine_remove_closest_token(mi,
1219 circpad_histogram_bin_to_usec(mi, 4), 1);
1220 circpad_machine_remove_closest_token(mi,
1221 circpad_histogram_bin_to_usec(mi, 4), 1);
1222 tt_int_op(mi->histogram[3], OP_EQ, 0);
1223 tt_int_op(mi->histogram[4], OP_EQ, 2);
1224 circpad_machine_remove_closest_token(mi,
1225 circpad_histogram_bin_to_usec(mi, 4), 1);
1226 circpad_machine_remove_closest_token(mi,
1227 circpad_histogram_bin_to_usec(mi, 4), 1);
1228 tt_int_op(mi->histogram[4], OP_EQ, 2);
1230 // XXX: Need more coverage of the actual usec branches
1232 done:
1233 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1234 monotime_disable_test_mocking();
1235 tor_free(circ_client_machine.states);
1236 testing_disable_reproducible_rng();
1239 void
1240 test_circuitpadding_wronghop(void *arg)
1243 * Test plan:
1244 * 1. Padding sent from hop 1 and 3 to client
1245 * 2. Send negotiated from hop 1 and 3 to client
1246 * 3. Garbled negotiated cell
1247 * 4. Padding negotiate sent to client
1248 * 5. Send negotiate stop command for unknown machine
1249 * 6. Send negotiated to relay
1250 * 7. Garbled padding negotiate cell
1252 (void)arg;
1253 uint32_t read_bw = 0, overhead_bw = 0;
1254 cell_t cell;
1255 signed_error_t ret;
1256 origin_circuit_t *orig_client;
1257 int64_t actual_mocked_monotime_start;
1259 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
1261 /* Mock this function so that our cell counting tests don't get confused by
1262 * padding that gets sent by scheduled timers. */
1263 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
1264 testing_enable_reproducible_rng();
1266 client_side = TO_CIRCUIT(origin_circuit_new());
1267 dummy_channel.cmux = circuitmux_alloc();
1268 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
1269 &dummy_channel));
1270 orig_client = TO_ORIGIN_CIRCUIT(client_side);
1272 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1273 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1274 nodes_init();
1276 monotime_init();
1277 monotime_enable_test_mocking();
1278 actual_mocked_monotime_start = MONOTIME_MOCK_START;
1279 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
1280 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
1281 curr_mocked_time = actual_mocked_monotime_start;
1283 timers_initialize();
1284 circpad_machines_init();
1286 MOCK(node_get_by_id,
1287 node_get_by_id_mock);
1289 MOCK(circuit_package_relay_cell,
1290 circuit_package_relay_cell_mock);
1292 /* Build three hops */
1293 simulate_single_hop_extend(client_side, relay_side, 1);
1294 simulate_single_hop_extend(client_side, relay_side, 1);
1295 simulate_single_hop_extend(client_side, relay_side, 1);
1297 /* verify padding was negotiated */
1298 tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
1299 tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
1301 /* verify echo was sent */
1302 tt_int_op(n_relay_cells, OP_EQ, 1);
1303 tt_int_op(n_client_cells, OP_EQ, 1);
1305 read_bw = orig_client->n_delivered_read_circ_bw;
1306 overhead_bw = orig_client->n_overhead_read_circ_bw;
1308 /* 1. Test padding from first and third hop */
1309 circpad_deliver_recognized_relay_cell_events(client_side,
1310 RELAY_COMMAND_DROP,
1311 TO_ORIGIN_CIRCUIT(client_side)->cpath);
1312 tt_int_op(read_bw, OP_EQ,
1313 orig_client->n_delivered_read_circ_bw);
1314 tt_int_op(overhead_bw, OP_EQ,
1315 orig_client->n_overhead_read_circ_bw);
1317 circpad_deliver_recognized_relay_cell_events(client_side,
1318 RELAY_COMMAND_DROP,
1319 TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next);
1320 tt_int_op(read_bw, OP_EQ,
1321 orig_client->n_delivered_read_circ_bw);
1322 tt_int_op(overhead_bw, OP_EQ,
1323 orig_client->n_overhead_read_circ_bw);
1325 circpad_deliver_recognized_relay_cell_events(client_side,
1326 RELAY_COMMAND_DROP,
1327 TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
1328 tt_int_op(read_bw, OP_EQ,
1329 orig_client->n_delivered_read_circ_bw);
1330 tt_int_op(overhead_bw, OP_LT,
1331 orig_client->n_overhead_read_circ_bw);
1333 /* 2. Test padding negotiated not handled from hops 1,3 */
1334 ret = circpad_handle_padding_negotiated(client_side, &cell,
1335 TO_ORIGIN_CIRCUIT(client_side)->cpath);
1336 tt_int_op(ret, OP_EQ, -1);
1338 ret = circpad_handle_padding_negotiated(client_side, &cell,
1339 TO_ORIGIN_CIRCUIT(client_side)->cpath->next->next);
1340 tt_int_op(ret, OP_EQ, -1);
1342 /* 3. Garbled negotiated cell */
1343 memset(&cell, 255, sizeof(cell));
1344 ret = circpad_handle_padding_negotiated(client_side, &cell,
1345 TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
1346 tt_int_op(ret, OP_EQ, -1);
1348 /* 4. Test that negotiate is dropped at origin */
1349 read_bw = orig_client->n_delivered_read_circ_bw;
1350 overhead_bw = orig_client->n_overhead_read_circ_bw;
1351 relay_send_command_from_edge(0, relay_side,
1352 RELAY_COMMAND_PADDING_NEGOTIATE,
1353 (void*)cell.payload,
1354 (size_t)3, NULL);
1355 tt_int_op(read_bw, OP_EQ,
1356 orig_client->n_delivered_read_circ_bw);
1357 tt_int_op(overhead_bw, OP_EQ,
1358 orig_client->n_overhead_read_circ_bw);
1360 tt_int_op(n_relay_cells, OP_EQ, 2);
1361 tt_int_op(n_client_cells, OP_EQ, 1);
1363 /* 5. Test that asking to stop the wrong machine does nothing */
1364 circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
1365 255, 2, CIRCPAD_COMMAND_STOP, 0);
1366 tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
1367 tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
1368 tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
1369 tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
1370 tt_int_op(n_relay_cells, OP_EQ, 2);
1371 tt_int_op(n_client_cells, OP_EQ, 2);
1373 /* 6. Sending negotiated command to relay does nothing */
1374 ret = circpad_handle_padding_negotiated(relay_side, &cell, NULL);
1375 tt_int_op(ret, OP_EQ, -1);
1377 /* 7. Test garbled negotiated cell (bad command 255) */
1378 memset(&cell, 0, sizeof(cell));
1379 ret = circpad_handle_padding_negotiate(relay_side, &cell);
1380 tt_int_op(ret, OP_EQ, -1);
1381 tt_int_op(n_client_cells, OP_EQ, 2);
1383 /* Test 2: Test no padding */
1384 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1385 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
1387 client_side = TO_CIRCUIT(origin_circuit_new());
1388 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
1389 &dummy_channel));
1390 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1391 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1393 simulate_single_hop_extend(client_side, relay_side, 1);
1394 simulate_single_hop_extend(client_side, relay_side, 0);
1396 /* verify no padding was negotiated */
1397 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1398 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1400 /* verify no echo was sent */
1401 tt_int_op(n_relay_cells, OP_EQ, 2);
1402 tt_int_op(n_client_cells, OP_EQ, 2);
1404 /* Finish circuit */
1405 simulate_single_hop_extend(client_side, relay_side, 1);
1407 /* Spoof padding negotiated on circuit with no padding */
1408 circpad_padding_negotiated(relay_side,
1409 CIRCPAD_MACHINE_CIRC_SETUP,
1410 CIRCPAD_COMMAND_START,
1411 CIRCPAD_RESPONSE_OK, 0);
1413 /* verify no padding was negotiated */
1414 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1415 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1417 circpad_padding_negotiated(relay_side,
1418 CIRCPAD_MACHINE_CIRC_SETUP,
1419 CIRCPAD_COMMAND_START,
1420 CIRCPAD_RESPONSE_ERR, 0);
1422 /* verify no padding was negotiated */
1423 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1424 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1426 done:
1427 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1428 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
1429 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
1430 circuitmux_free(dummy_channel.cmux);
1431 monotime_disable_test_mocking();
1432 UNMOCK(node_get_by_id);
1433 UNMOCK(circuit_package_relay_cell);
1434 UNMOCK(circuitmux_attach_circuit);
1435 nodes_free();
1436 testing_disable_reproducible_rng();
1439 void
1440 test_circuitpadding_negotiation(void *arg)
1443 * Test plan:
1444 * 1. Test circuit where padding is supported by middle
1445 * a. Make sure padding negotiation is sent
1446 * b. Test padding negotiation delivery and parsing
1447 * 2. Test circuit where padding is unsupported by middle
1448 * a. Make sure padding negotiation is not sent
1449 * 3. Test failure to negotiate a machine due to desync.
1451 int64_t actual_mocked_monotime_start;
1452 (void)arg;
1454 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
1456 client_side = TO_CIRCUIT(origin_circuit_new());
1457 dummy_channel.cmux = circuitmux_alloc();
1458 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
1460 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1461 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1462 nodes_init();
1464 monotime_init();
1465 monotime_enable_test_mocking();
1466 actual_mocked_monotime_start = MONOTIME_MOCK_START;
1467 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
1468 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
1469 curr_mocked_time = actual_mocked_monotime_start;
1471 timers_initialize();
1472 circpad_machines_init();
1474 MOCK(node_get_by_id,
1475 node_get_by_id_mock);
1477 MOCK(circuit_package_relay_cell,
1478 circuit_package_relay_cell_mock);
1480 /* Build two hops */
1481 simulate_single_hop_extend(client_side, relay_side, 1);
1482 simulate_single_hop_extend(client_side, relay_side, 1);
1484 /* verify padding was negotiated */
1485 tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
1486 tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
1488 /* verify echo was sent */
1489 tt_int_op(n_relay_cells, OP_EQ, 1);
1490 tt_int_op(n_client_cells, OP_EQ, 1);
1492 /* Finish circuit */
1493 simulate_single_hop_extend(client_side, relay_side, 1);
1495 /* Test 2: Test no padding */
1496 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1497 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
1499 client_side = TO_CIRCUIT(origin_circuit_new());
1500 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
1501 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1502 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1504 simulate_single_hop_extend(client_side, relay_side, 1);
1505 simulate_single_hop_extend(client_side, relay_side, 0);
1507 /* verify no padding was negotiated */
1508 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1509 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1510 tt_int_op(n_relay_cells, OP_EQ, 1);
1511 tt_int_op(n_client_cells, OP_EQ, 1);
1513 /* verify no echo was sent */
1514 tt_int_op(n_relay_cells, OP_EQ, 1);
1515 tt_int_op(n_client_cells, OP_EQ, 1);
1517 /* Finish circuit */
1518 simulate_single_hop_extend(client_side, relay_side, 1);
1520 /* Force negotiate padding. */
1521 circpad_negotiate_padding(TO_ORIGIN_CIRCUIT(client_side),
1522 CIRCPAD_MACHINE_CIRC_SETUP,
1523 2, CIRCPAD_COMMAND_START, 0);
1525 /* verify no padding was negotiated */
1526 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1527 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1529 /* verify no echo was sent */
1530 tt_int_op(n_relay_cells, OP_EQ, 1);
1531 tt_int_op(n_client_cells, OP_EQ, 1);
1533 /* 3. Test failure to negotiate a machine due to desync */
1534 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1535 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
1537 client_side = TO_CIRCUIT(origin_circuit_new());
1538 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
1539 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1540 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1542 SMARTLIST_FOREACH(relay_padding_machines,
1543 circpad_machine_spec_t *,
1544 m, tor_free(m->states); tor_free(m));
1545 smartlist_free(relay_padding_machines);
1546 relay_padding_machines = smartlist_new();
1548 simulate_single_hop_extend(client_side, relay_side, 1);
1549 simulate_single_hop_extend(client_side, relay_side, 1);
1551 /* verify echo was sent */
1552 tt_int_op(n_client_cells, OP_EQ, 2);
1553 tt_int_op(n_relay_cells, OP_EQ, 2);
1555 /* verify no padding was negotiated */
1556 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
1557 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1558 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1559 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
1561 done:
1562 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1563 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
1564 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
1565 circuitmux_free(dummy_channel.cmux);
1566 monotime_disable_test_mocking();
1567 UNMOCK(node_get_by_id);
1568 UNMOCK(circuit_package_relay_cell);
1569 UNMOCK(circuitmux_attach_circuit);
1570 nodes_free();
1573 static void
1574 simulate_single_hop_extend(circuit_t *client, circuit_t *mid_relay,
1575 int padding)
1577 char whatevs_key[CPATH_KEY_MATERIAL_LEN];
1578 char digest[DIGEST_LEN];
1579 tor_addr_t addr;
1581 // Pretend a non-padding cell was sent
1582 circpad_cell_event_nonpadding_sent(client);
1584 // Receive extend cell at middle
1585 circpad_cell_event_nonpadding_received(mid_relay);
1587 // Advance time a tiny bit so we can calculate an RTT
1588 curr_mocked_time += 10 * TOR_NSEC_PER_MSEC;
1589 monotime_coarse_set_mock_time_nsec(curr_mocked_time);
1590 monotime_set_mock_time_nsec(curr_mocked_time);
1592 // Receive extended cell at middle
1593 circpad_cell_event_nonpadding_sent(mid_relay);
1595 // Receive extended cell at first hop
1596 circpad_cell_event_nonpadding_received(client);
1598 // Add a hop to cpath
1599 crypt_path_t *hop = tor_malloc_zero(sizeof(crypt_path_t));
1600 cpath_extend_linked_list(&TO_ORIGIN_CIRCUIT(client)->cpath, hop);
1602 hop->magic = CRYPT_PATH_MAGIC;
1603 hop->state = CPATH_STATE_OPEN;
1605 // add an extend info to indicate if this node supports padding or not.
1606 // (set the first byte of the digest for our mocked node_get_by_id)
1607 digest[0] = padding;
1609 hop->extend_info = extend_info_new(
1610 padding ? "padding" : "non-padding",
1611 digest, NULL, NULL, NULL,
1612 &addr, padding);
1614 cpath_init_circuit_crypto(hop, whatevs_key, sizeof(whatevs_key), 0, 0);
1616 hop->package_window = circuit_initial_package_window();
1617 hop->deliver_window = CIRCWINDOW_START;
1619 // Signal that the hop was added
1620 circpad_machine_event_circ_added_hop(TO_ORIGIN_CIRCUIT(client));
1623 static circpad_machine_spec_t *
1624 helper_create_length_machine(void)
1626 circpad_machine_spec_t *ret =
1627 tor_malloc_zero(sizeof(circpad_machine_spec_t));
1629 /* Start, burst */
1630 circpad_machine_states_init(ret, 2);
1632 ret->states[CIRCPAD_STATE_START].
1633 next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
1635 ret->states[CIRCPAD_STATE_BURST].
1636 next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
1638 ret->states[CIRCPAD_STATE_BURST].
1639 next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
1641 ret->states[CIRCPAD_STATE_BURST].
1642 next_state[CIRCPAD_EVENT_BINS_EMPTY] = CIRCPAD_STATE_END;
1644 /* No token removal.. end via state_length only */
1645 ret->states[CIRCPAD_STATE_BURST].token_removal =
1646 CIRCPAD_TOKEN_REMOVAL_NONE;
1648 /* Let's have this one end after 12 packets */
1649 ret->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
1650 ret->states[CIRCPAD_STATE_BURST].length_dist.param1 = 12;
1651 ret->states[CIRCPAD_STATE_BURST].length_dist.param2 = 13;
1652 ret->states[CIRCPAD_STATE_BURST].max_length = 12;
1654 ret->states[CIRCPAD_STATE_BURST].histogram_len = 4;
1656 ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0;
1657 ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1;
1658 ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000;
1659 ret->states[CIRCPAD_STATE_BURST].histogram_edges[3] = 10000000;
1661 ret->states[CIRCPAD_STATE_BURST].histogram[0] = 0;
1662 ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0;
1663 ret->states[CIRCPAD_STATE_BURST].histogram[2] = 6;
1665 ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6;
1666 ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0;
1667 ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 0;
1669 return ret;
1672 static circpad_machine_spec_t *
1673 helper_create_conditional_machine(void)
1675 circpad_machine_spec_t *ret =
1676 tor_malloc_zero(sizeof(circpad_machine_spec_t));
1678 /* Start, burst */
1679 circpad_machine_states_init(ret, 2);
1681 ret->states[CIRCPAD_STATE_START].
1682 next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
1684 ret->states[CIRCPAD_STATE_BURST].
1685 next_state[CIRCPAD_EVENT_PADDING_SENT] = CIRCPAD_STATE_BURST;
1687 ret->states[CIRCPAD_STATE_BURST].
1688 next_state[CIRCPAD_EVENT_LENGTH_COUNT] = CIRCPAD_STATE_END;
1690 /* Use EXACT removal strategy, otherwise setup_tokens() does not work */
1691 ret->states[CIRCPAD_STATE_BURST].token_removal =
1692 CIRCPAD_TOKEN_REMOVAL_EXACT;
1694 ret->states[CIRCPAD_STATE_BURST].histogram_len = 3;
1696 ret->states[CIRCPAD_STATE_BURST].histogram_edges[0] = 0;
1697 ret->states[CIRCPAD_STATE_BURST].histogram_edges[1] = 1;
1698 ret->states[CIRCPAD_STATE_BURST].histogram_edges[2] = 1000000;
1700 ret->states[CIRCPAD_STATE_BURST].histogram[0] = 6;
1701 ret->states[CIRCPAD_STATE_BURST].histogram[1] = 0;
1702 ret->states[CIRCPAD_STATE_BURST].histogram[2] = 0;
1704 ret->states[CIRCPAD_STATE_BURST].histogram_total_tokens = 6;
1705 ret->states[CIRCPAD_STATE_BURST].use_rtt_estimate = 0;
1706 ret->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1;
1708 return ret;
1711 static void
1712 helper_create_conditional_machines(void)
1714 circpad_machine_spec_t *add = helper_create_conditional_machine();
1716 if (!origin_padding_machines)
1717 origin_padding_machines = smartlist_new();
1718 if (!relay_padding_machines)
1719 relay_padding_machines = smartlist_new();
1721 add->machine_num = 2;
1722 add->is_origin_side = 1;
1723 add->should_negotiate_end = 1;
1724 add->target_hopnum = 2;
1726 /* Let's have this one end after 4 packets */
1727 add->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
1728 add->states[CIRCPAD_STATE_BURST].length_dist.param1 = 4;
1729 add->states[CIRCPAD_STATE_BURST].length_dist.param2 = 4;
1730 add->states[CIRCPAD_STATE_BURST].max_length = 4;
1732 add->conditions.requires_vanguards = 0;
1733 add->conditions.min_hops = 2;
1734 add->conditions.apply_state_mask = CIRCPAD_CIRC_BUILDING|
1735 CIRCPAD_CIRC_NO_STREAMS|CIRCPAD_CIRC_HAS_RELAY_EARLY;
1736 add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
1737 circpad_register_padding_machine(add, origin_padding_machines);
1739 add = helper_create_conditional_machine();
1740 add->machine_num = 3;
1741 add->is_origin_side = 1;
1742 add->should_negotiate_end = 1;
1743 add->target_hopnum = 2;
1745 /* Let's have this one end after 4 packets */
1746 add->states[CIRCPAD_STATE_BURST].length_dist.type = CIRCPAD_DIST_UNIFORM;
1747 add->states[CIRCPAD_STATE_BURST].length_dist.param1 = 4;
1748 add->states[CIRCPAD_STATE_BURST].length_dist.param2 = 4;
1749 add->states[CIRCPAD_STATE_BURST].max_length = 4;
1751 add->conditions.requires_vanguards = 1;
1752 add->conditions.min_hops = 3;
1753 add->conditions.apply_state_mask = CIRCPAD_CIRC_OPENED|
1754 CIRCPAD_CIRC_STREAMS|CIRCPAD_CIRC_HAS_NO_RELAY_EARLY;
1755 add->conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
1756 circpad_register_padding_machine(add, origin_padding_machines);
1758 add = helper_create_conditional_machine();
1759 add->machine_num = 2;
1760 circpad_register_padding_machine(add, relay_padding_machines);
1762 add = helper_create_conditional_machine();
1763 add->machine_num = 3;
1764 circpad_register_padding_machine(add, relay_padding_machines);
1767 void
1768 test_circuitpadding_state_length(void *arg)
1771 * Test plan:
1772 * * Explicitly test that with no token removal enabled, we hit
1773 * the state length limit due to either padding, or non-padding.
1774 * * Repeat test with an arbitrary token removal strategy, and
1775 * verify that if we run out of tokens due to padding before we
1776 * hit the state length, we still go to state end (all our
1777 * token removal tests only test nonpadding token removal).
1779 int64_t actual_mocked_monotime_start;
1780 (void)arg;
1781 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
1782 MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
1784 nodes_init();
1785 dummy_channel.cmux = circuitmux_alloc();
1786 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
1787 &dummy_channel));
1788 client_side = TO_CIRCUIT(origin_circuit_new());
1789 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1790 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1792 monotime_init();
1793 monotime_enable_test_mocking();
1794 actual_mocked_monotime_start = MONOTIME_MOCK_START;
1795 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
1796 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
1797 curr_mocked_time = actual_mocked_monotime_start;
1799 /* This is needed so that we are not considered to be dormant */
1800 note_user_activity(20);
1802 timers_initialize();
1803 circpad_machine_spec_t *client_machine =
1804 helper_create_length_machine();
1806 MOCK(circuit_package_relay_cell,
1807 circuit_package_relay_cell_mock);
1808 MOCK(node_get_by_id,
1809 node_get_by_id_mock);
1811 client_side->padding_machine[0] = client_machine;
1812 client_side->padding_info[0] =
1813 circpad_circuit_machineinfo_new(client_side, 0);
1814 circpad_machine_runtime_t *mi = client_side->padding_info[0];
1816 circpad_cell_event_padding_sent(client_side);
1817 tt_i64_op(mi->state_length, OP_EQ, 12);
1818 tt_ptr_op(mi->histogram, OP_EQ, NULL);
1820 /* Verify that non-padding does not change our state length */
1821 circpad_cell_event_nonpadding_sent(client_side);
1822 tt_i64_op(mi->state_length, OP_EQ, 12);
1824 /* verify that sending padding changes our state length */
1825 for (uint64_t i = mi->state_length-1; i > 0; i--) {
1826 circpad_send_padding_cell_for_callback(mi);
1827 tt_i64_op(mi->state_length, OP_EQ, i);
1829 circpad_send_padding_cell_for_callback(mi);
1831 tt_i64_op(mi->state_length, OP_EQ, -1);
1832 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
1834 /* Restart machine */
1835 mi->current_state = CIRCPAD_STATE_START;
1837 /* Now, count nonpadding as part of the state length */
1838 client_machine->states[CIRCPAD_STATE_BURST].length_includes_nonpadding = 1;
1840 circpad_cell_event_padding_sent(client_side);
1841 tt_i64_op(mi->state_length, OP_EQ, 12);
1843 /* Verify that non-padding does change our state length now */
1844 for (uint64_t i = mi->state_length-1; i > 0; i--) {
1845 circpad_cell_event_nonpadding_sent(client_side);
1846 tt_i64_op(mi->state_length, OP_EQ, i);
1849 circpad_cell_event_nonpadding_sent(client_side);
1850 tt_i64_op(mi->state_length, OP_EQ, -1);
1851 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
1853 /* Now, just test token removal when we send padding */
1854 client_machine->states[CIRCPAD_STATE_BURST].token_removal =
1855 CIRCPAD_TOKEN_REMOVAL_EXACT;
1857 /* Restart machine */
1858 mi->current_state = CIRCPAD_STATE_START;
1859 circpad_cell_event_padding_sent(client_side);
1860 tt_i64_op(mi->state_length, OP_EQ, 12);
1861 tt_ptr_op(mi->histogram, OP_NE, NULL);
1862 tt_int_op(mi->chosen_bin, OP_EQ, 2);
1864 /* verify that sending padding changes our state length and
1865 * our histogram now */
1866 for (uint32_t i = mi->histogram[2]-1; i > 0; i--) {
1867 circpad_send_padding_cell_for_callback(mi);
1868 tt_int_op(mi->chosen_bin, OP_EQ, 2);
1869 tt_int_op(mi->histogram[2], OP_EQ, i);
1872 tt_i64_op(mi->state_length, OP_EQ, 7);
1873 tt_int_op(mi->histogram[2], OP_EQ, 1);
1875 circpad_send_padding_cell_for_callback(mi);
1876 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
1878 done:
1879 tor_free(client_machine->states);
1880 tor_free(client_machine);
1882 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
1883 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
1885 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
1886 circuitmux_free(dummy_channel.cmux);
1887 timers_shutdown();
1888 monotime_disable_test_mocking();
1889 UNMOCK(circuit_package_relay_cell);
1890 UNMOCK(circuitmux_attach_circuit);
1891 UNMOCK(node_get_by_id);
1893 return;
1896 void
1897 test_circuitpadding_conditions(void *arg)
1900 * Test plan:
1901 * 0. Make a few origin and client machines with diff conditions
1902 * * vanguards, purposes, has_opened circs, no relay early
1903 * * Client side should_negotiate_end
1904 * * Length limits
1905 * 1. Test STATE_END transitions
1906 * 2. Test new machine after end with same conditions
1907 * 3. Test new machine due to changed conditions
1908 * * Esp: built event, no relay early, no streams
1909 * XXX: Diff test:
1910 * 1. Test STATE_END with pending timers
1911 * 2. Test marking a circuit before padding callback fires
1912 * 3. Test freeing a circuit before padding callback fires
1914 int64_t actual_mocked_monotime_start;
1915 (void)arg;
1916 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
1917 testing_enable_reproducible_rng();
1919 nodes_init();
1920 dummy_channel.cmux = circuitmux_alloc();
1921 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel,
1922 &dummy_channel));
1923 client_side = TO_CIRCUIT(origin_circuit_new());
1924 relay_side->purpose = CIRCUIT_PURPOSE_OR;
1925 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
1927 monotime_init();
1928 monotime_enable_test_mocking();
1929 actual_mocked_monotime_start = MONOTIME_MOCK_START;
1930 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
1931 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
1932 curr_mocked_time = actual_mocked_monotime_start;
1934 /* This is needed so that we are not considered to be dormant */
1935 note_user_activity(20);
1937 timers_initialize();
1938 helper_create_conditional_machines();
1940 MOCK(circuit_package_relay_cell,
1941 circuit_package_relay_cell_mock);
1942 MOCK(node_get_by_id,
1943 node_get_by_id_mock);
1945 /* Simulate extend. This should result in the original machine getting
1946 * added, since the circuit is not built */
1947 simulate_single_hop_extend(client_side, relay_side, 1);
1948 simulate_single_hop_extend(client_side, relay_side, 1);
1950 /* Verify that machine #2 is added */
1951 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
1952 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
1954 /* Deliver a padding cell to the client, to trigger burst state */
1955 circpad_cell_event_padding_sent(client_side);
1957 /* This should have trigger length shutdown condition on client.. */
1958 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
1959 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
1961 /* Verify machine is gone from both sides */
1962 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
1963 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
1965 /* Send another event.. verify machine gets re-added properly
1966 * (test race with shutdown) */
1967 simulate_single_hop_extend(client_side, relay_side, 1);
1968 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
1969 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
1971 TO_ORIGIN_CIRCUIT(client_side)->p_streams = 0;
1972 circpad_machine_event_circ_has_no_streams(TO_ORIGIN_CIRCUIT(client_side));
1973 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
1974 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
1976 /* Now make the circuit opened and send built event */
1977 TO_ORIGIN_CIRCUIT(client_side)->has_opened = 1;
1978 circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
1979 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
1980 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
1982 TO_ORIGIN_CIRCUIT(client_side)->remaining_relay_early_cells = 0;
1983 circpad_machine_event_circ_has_no_relay_early(
1984 TO_ORIGIN_CIRCUIT(client_side));
1985 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
1986 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
1988 get_options_mutable()->HSLayer2Nodes = (void*)1;
1989 TO_ORIGIN_CIRCUIT(client_side)->p_streams = (void*)1;
1990 circpad_machine_event_circ_has_streams(TO_ORIGIN_CIRCUIT(client_side));
1992 /* Verify different machine is added */
1993 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 3);
1994 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 3);
1996 /* Hold off on negotiated */
1997 deliver_negotiated = 0;
1999 /* Deliver a padding cell to the client, to trigger burst state */
2000 circpad_cell_event_padding_sent(client_side);
2002 /* This should have trigger length shutdown condition on client
2003 * but not the response for the padding machine */
2004 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
2005 tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
2007 /* Verify machine is gone from the relay (but negotiated not back yet */
2008 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
2009 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
2011 /* Add another hop and verify it's back */
2012 simulate_single_hop_extend(client_side, relay_side, 1);
2014 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 3);
2015 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 3);
2017 tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
2018 tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
2020 done:
2021 /* XXX: Free everything */
2022 testing_disable_reproducible_rng();
2023 return;
2026 /** Disabled unstable test until #29298 is implemented (see #29122) */
2027 #if 0
2028 void
2029 test_circuitpadding_circuitsetup_machine(void *arg)
2031 int64_t actual_mocked_monotime_start;
2033 * Test case plan:
2035 * 1. Simulate a normal circuit setup pattern
2036 * a. Application traffic
2038 * FIXME: This should focus more on exercising the machine
2039 * features rather than actual traffic patterns. For example,
2040 * test cancellation and bins empty/refill
2042 (void)arg;
2044 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
2046 dummy_channel.cmux = circuitmux_alloc();
2047 client_side = TO_CIRCUIT(origin_circuit_new());
2048 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
2050 relay_side->purpose = CIRCUIT_PURPOSE_OR;
2051 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2053 nodes_init();
2055 monotime_init();
2056 monotime_enable_test_mocking();
2057 actual_mocked_monotime_start = MONOTIME_MOCK_START;
2058 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
2059 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
2060 curr_mocked_time = actual_mocked_monotime_start;
2062 timers_initialize();
2063 circpad_machines_init();
2065 MOCK(circuit_package_relay_cell,
2066 circuit_package_relay_cell_mock);
2067 MOCK(node_get_by_id,
2068 node_get_by_id_mock);
2070 /* Test case #1: Build a 3 hop circuit, then wait and let pad */
2071 simulate_single_hop_extend(client_side, relay_side, 1);
2072 simulate_single_hop_extend(client_side, relay_side, 1);
2073 simulate_single_hop_extend(client_side, relay_side, 1);
2075 tt_int_op(n_client_cells, OP_EQ, 1);
2076 tt_int_op(n_relay_cells, OP_EQ, 1);
2077 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
2078 CIRCPAD_STATE_BURST);
2079 tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
2080 CIRCPAD_STATE_BURST);
2082 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2083 OP_NE, 0);
2084 tt_int_op(relay_side->padding_info[0]->is_padding_timer_scheduled,
2085 OP_EQ, 0);
2086 timers_advance_and_run(2000);
2087 tt_int_op(n_client_cells, OP_EQ, 2);
2088 tt_int_op(n_relay_cells, OP_EQ, 1);
2090 tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
2091 CIRCPAD_STATE_GAP);
2093 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2094 OP_EQ, 0);
2095 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2096 OP_NE, 0);
2097 timers_advance_and_run(5000);
2098 tt_int_op(n_client_cells, OP_EQ, 2);
2099 tt_int_op(n_relay_cells, OP_EQ, 2);
2101 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2102 OP_NE, 0);
2103 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2104 OP_EQ, 0);
2105 timers_advance_and_run(2000);
2106 tt_int_op(n_client_cells, OP_EQ, 3);
2107 tt_int_op(n_relay_cells, OP_EQ, 2);
2109 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2110 OP_EQ, 0);
2111 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2112 OP_NE, 0);
2113 timers_advance_and_run(5000);
2114 tt_int_op(n_client_cells, OP_EQ, 3);
2115 tt_int_op(n_relay_cells, OP_EQ, 3);
2117 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2118 OP_NE, 0);
2119 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2120 OP_EQ, 0);
2121 timers_advance_and_run(2000);
2122 tt_int_op(n_client_cells, OP_EQ, 4);
2123 tt_int_op(n_relay_cells, OP_EQ, 3);
2125 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2126 OP_EQ, 0);
2127 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2128 OP_NE, 0);
2129 timers_advance_and_run(5000);
2130 tt_int_op(n_client_cells, OP_EQ, 4);
2131 tt_int_op(n_relay_cells, OP_EQ, 4);
2133 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2134 OP_NE, 0);
2135 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2136 OP_EQ, 0);
2137 timers_advance_and_run(2000);
2138 tt_int_op(n_client_cells, OP_EQ, 5);
2139 tt_int_op(n_relay_cells, OP_EQ, 4);
2141 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2142 OP_EQ, 0);
2143 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2144 OP_NE, 0);
2145 timers_advance_and_run(5000);
2146 tt_int_op(n_client_cells, OP_EQ, 5);
2147 tt_int_op(n_relay_cells, OP_EQ, 5);
2149 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2150 OP_NE, 0);
2151 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2152 OP_EQ, 0);
2153 timers_advance_and_run(2000);
2154 tt_int_op(n_client_cells, OP_EQ, 6);
2155 tt_int_op(n_relay_cells, OP_EQ, 5);
2157 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2158 OP_EQ, 0);
2159 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2160 OP_NE, 0);
2161 timers_advance_and_run(5000);
2162 tt_int_op(n_client_cells, OP_EQ, 6);
2163 tt_int_op(n_relay_cells, OP_EQ, 6);
2165 tt_int_op(client_side->padding_info[0]->current_state,
2166 OP_EQ, CIRCPAD_STATE_END);
2167 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2168 OP_EQ, 0);
2169 tt_int_op(relay_side->padding_info[0]->current_state,
2170 OP_EQ, CIRCPAD_STATE_GAP);
2171 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2172 OP_EQ, 0);
2174 /* Verify we can't schedule padding in END state */
2175 circpad_decision_t ret =
2176 circpad_machine_schedule_padding(client_side->padding_info[0]);
2177 tt_int_op(ret, OP_EQ, CIRCPAD_STATE_UNCHANGED);
2179 /* Simulate application traffic */
2180 circpad_cell_event_nonpadding_sent(client_side);
2181 circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_OUT);
2182 circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_IN);
2183 circpad_deliver_recognized_relay_cell_events(client_side, RELAY_COMMAND_DATA,
2184 TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
2186 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
2187 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
2189 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
2190 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
2191 tt_int_op(n_client_cells, OP_EQ, 6);
2192 tt_int_op(n_relay_cells, OP_EQ, 7);
2194 // Test timer cancellation
2195 simulate_single_hop_extend(client_side, relay_side, 1);
2196 simulate_single_hop_extend(client_side, relay_side, 1);
2197 timers_advance_and_run(5000);
2198 circpad_cell_event_padding_received(client_side);
2200 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
2201 CIRCPAD_STATE_BURST);
2202 tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
2203 CIRCPAD_STATE_GAP);
2205 tt_int_op(n_client_cells, OP_EQ, 8);
2206 tt_int_op(n_relay_cells, OP_EQ, 8);
2207 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2208 OP_NE, 0);
2209 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2210 OP_NE, 0);
2212 /* Test timer cancel due to state rules */
2213 circpad_cell_event_nonpadding_sent(client_side);
2214 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2215 OP_EQ, 0);
2216 circpad_cell_event_padding_received(client_side);
2217 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2218 OP_NE, 0);
2220 /* Simulate application traffic to cancel timer */
2221 circpad_cell_event_nonpadding_sent(client_side);
2222 circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_OUT);
2223 circpad_deliver_unrecognized_cell_events(relay_side, CELL_DIRECTION_IN);
2224 circpad_deliver_recognized_relay_cell_events(client_side, RELAY_COMMAND_DATA,
2225 TO_ORIGIN_CIRCUIT(client_side)->cpath->next);
2227 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
2228 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
2230 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
2231 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
2233 /* No cells sent, except negotiate end from relay */
2234 tt_int_op(n_client_cells, OP_EQ, 8);
2235 tt_int_op(n_relay_cells, OP_EQ, 9);
2237 /* Test mark for close and free */
2238 simulate_single_hop_extend(client_side, relay_side, 1);
2239 simulate_single_hop_extend(client_side, relay_side, 1);
2240 timers_advance_and_run(5000);
2241 circpad_cell_event_padding_received(client_side);
2243 tt_int_op(n_client_cells, OP_EQ, 10);
2244 tt_int_op(n_relay_cells, OP_EQ, 10);
2246 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
2247 CIRCPAD_STATE_BURST);
2248 tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
2249 CIRCPAD_STATE_GAP);
2251 tt_u64_op(client_side->padding_info[0]->padding_scheduled_at_usec,
2252 OP_NE, 0);
2253 tt_u64_op(relay_side->padding_info[0]->padding_scheduled_at_usec,
2254 OP_NE, 0);
2255 circuit_mark_for_close(client_side, END_CIRC_REASON_FLAG_REMOTE);
2256 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
2257 timers_advance_and_run(5000);
2259 /* No cells sent */
2260 tt_int_op(n_client_cells, OP_EQ, 10);
2261 tt_int_op(n_relay_cells, OP_EQ, 10);
2263 done:
2264 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
2266 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
2267 circuitmux_free(dummy_channel.cmux);
2268 timers_shutdown();
2269 monotime_disable_test_mocking();
2270 UNMOCK(circuit_package_relay_cell);
2271 UNMOCK(circuitmux_attach_circuit);
2273 return;
2275 #endif /* 0 */
2277 /** Helper function: Initializes a padding machine where every state uses the
2278 * uniform probability distribution. */
2279 static void
2280 helper_circpad_circ_distribution_machine_setup(int min, int max)
2282 circpad_machine_states_init(&circ_client_machine, 7);
2284 circpad_state_t *zero_st = &circ_client_machine.states[0];
2285 zero_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 1;
2286 zero_st->iat_dist.type = CIRCPAD_DIST_UNIFORM;
2287 /* param2 is upper bound, param1 is lower */
2288 zero_st->iat_dist.param1 = min;
2289 zero_st->iat_dist.param2 = max;
2290 zero_st->dist_added_shift_usec = min;
2291 zero_st->dist_max_sample_usec = max;
2293 circpad_state_t *first_st = &circ_client_machine.states[1];
2294 first_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 2;
2295 first_st->iat_dist.type = CIRCPAD_DIST_LOGISTIC;
2296 /* param1 is Mu, param2 is sigma. */
2297 first_st->iat_dist.param1 = 9;
2298 first_st->iat_dist.param2 = 3;
2299 first_st->dist_added_shift_usec = min;
2300 first_st->dist_max_sample_usec = max;
2302 circpad_state_t *second_st = &circ_client_machine.states[2];
2303 second_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 3;
2304 second_st->iat_dist.type = CIRCPAD_DIST_LOG_LOGISTIC;
2305 /* param1 is Alpha, param2 is 1.0/Beta */
2306 second_st->iat_dist.param1 = 1;
2307 second_st->iat_dist.param2 = 0.5;
2308 second_st->dist_added_shift_usec = min;
2309 second_st->dist_max_sample_usec = max;
2311 circpad_state_t *third_st = &circ_client_machine.states[3];
2312 third_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 4;
2313 third_st->iat_dist.type = CIRCPAD_DIST_GEOMETRIC;
2314 /* param1 is 'p' (success probability) */
2315 third_st->iat_dist.param1 = 0.2;
2316 third_st->dist_added_shift_usec = min;
2317 third_st->dist_max_sample_usec = max;
2319 circpad_state_t *fourth_st = &circ_client_machine.states[4];
2320 fourth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 5;
2321 fourth_st->iat_dist.type = CIRCPAD_DIST_WEIBULL;
2322 /* param1 is k, param2 is Lambda */
2323 fourth_st->iat_dist.param1 = 1.5;
2324 fourth_st->iat_dist.param2 = 1;
2325 fourth_st->dist_added_shift_usec = min;
2326 fourth_st->dist_max_sample_usec = max;
2328 circpad_state_t *fifth_st = &circ_client_machine.states[5];
2329 fifth_st->next_state[CIRCPAD_EVENT_NONPADDING_RECV] = 6;
2330 fifth_st->iat_dist.type = CIRCPAD_DIST_PARETO;
2331 /* param1 is sigma, param2 is xi */
2332 fifth_st->iat_dist.param1 = 1;
2333 fifth_st->iat_dist.param2 = 5;
2334 fifth_st->dist_added_shift_usec = min;
2335 fifth_st->dist_max_sample_usec = max;
2338 /** Simple test that the padding delays sampled from a uniform distribution
2339 * actually fail within the uniform distribution range. */
2340 static void
2341 test_circuitpadding_sample_distribution(void *arg)
2343 circpad_machine_runtime_t *mi;
2344 int n_samples;
2345 int n_states;
2347 (void) arg;
2349 /* mock this function so that we dont actually schedule any padding */
2350 MOCK(circpad_machine_schedule_padding,
2351 circpad_machine_schedule_padding_mock);
2352 testing_enable_reproducible_rng();
2354 /* Initialize a machine with multiple probability distributions */
2355 circpad_machines_init();
2356 helper_circpad_circ_distribution_machine_setup(0, 10);
2358 /* Initialize machine and circuits */
2359 client_side = TO_CIRCUIT(origin_circuit_new());
2360 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2361 client_side->padding_machine[0] = &circ_client_machine;
2362 client_side->padding_info[0] =
2363 circpad_circuit_machineinfo_new(client_side, 0);
2364 mi = client_side->padding_info[0];
2366 /* For every state, sample a bunch of values from the distribution and ensure
2367 * they fall within range. */
2368 for (n_states = 0 ; n_states < 6; n_states++) {
2369 /* Make sure we in the right state */
2370 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ, n_states);
2372 for (n_samples = 0; n_samples < 100; n_samples++) {
2373 circpad_delay_t delay = circpad_machine_sample_delay(mi);
2374 tt_int_op(delay, OP_GE, 0);
2375 tt_int_op(delay, OP_LE, 10);
2378 /* send a non-padding cell to move to the next machine state */
2379 circpad_cell_event_nonpadding_received(client_side);
2382 done:
2383 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
2384 UNMOCK(circpad_machine_schedule_padding);
2385 testing_disable_reproducible_rng();
2388 static circpad_decision_t
2389 circpad_machine_spec_transition_mock(circpad_machine_runtime_t *mi,
2390 circpad_event_t event)
2392 (void) mi;
2393 (void) event;
2395 return CIRCPAD_STATE_UNCHANGED;
2398 /* Test per-machine padding rate limits */
2399 static void
2400 test_circuitpadding_machine_rate_limiting(void *arg)
2402 (void) arg;
2403 bool retval;
2404 circpad_machine_runtime_t *mi;
2405 int i;
2407 /* Ignore machine transitions for the purposes of this function, we only
2408 * really care about padding counts */
2409 MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
2410 MOCK(circpad_send_command_to_hop, circpad_send_command_to_hop_mock);
2411 testing_enable_reproducible_rng();
2413 /* Setup machine and circuits */
2414 client_side = TO_CIRCUIT(origin_circuit_new());
2415 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2416 helper_create_basic_machine();
2417 client_side->padding_machine[0] = &circ_client_machine;
2418 client_side->padding_info[0] =
2419 circpad_circuit_machineinfo_new(client_side, 0);
2420 mi = client_side->padding_info[0];
2421 /* Set up the machine info so that we can get through the basic functions */
2422 mi->state_length = CIRCPAD_STATE_LENGTH_INFINITE;
2424 /* First we are going to test the per-machine rate limits */
2425 circ_client_machine.max_padding_percent = 50;
2426 circ_client_machine.allowed_padding_count = 100;
2428 /* Check padding limit, should be fine since we haven't sent anything yet. */
2429 retval = circpad_machine_reached_padding_limit(mi);
2430 tt_int_op(retval, OP_EQ, 0);
2432 /* Send 99 padding cells which is below circpad_global_allowed_cells=100, so
2433 * the rate limit will not trigger */
2434 for (i=0;i<99;i++) {
2435 circpad_send_padding_cell_for_callback(mi);
2437 retval = circpad_machine_reached_padding_limit(mi);
2438 tt_int_op(retval, OP_EQ, 0);
2440 /* Now send another padding cell to pass circpad_global_allowed_cells=100,
2441 and see that the limit will trigger */
2442 circpad_send_padding_cell_for_callback(mi);
2443 retval = circpad_machine_reached_padding_limit(mi);
2444 tt_int_op(retval, OP_EQ, 1);
2446 retval = circpad_machine_schedule_padding(mi);
2447 tt_int_op(retval, OP_EQ, CIRCPAD_STATE_UNCHANGED);
2449 /* Cover wrap */
2450 for (;i<UINT16_MAX;i++) {
2451 circpad_send_padding_cell_for_callback(mi);
2453 tt_int_op(mi->padding_sent, OP_EQ, UINT16_MAX/2+1);
2455 tt_ptr_op(client_side->padding_info[0], OP_EQ, mi);
2456 for (i=0;i<UINT16_MAX;i++) {
2457 circpad_cell_event_nonpadding_sent(client_side);
2460 tt_int_op(mi->nonpadding_sent, OP_EQ, UINT16_MAX/2);
2461 tt_int_op(mi->padding_sent, OP_EQ, UINT16_MAX/4+1);
2463 done:
2464 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
2465 testing_disable_reproducible_rng();
2468 /* Test global padding rate limits */
2469 static void
2470 test_circuitpadding_global_rate_limiting(void *arg)
2472 (void) arg;
2473 bool retval;
2474 circpad_machine_runtime_t *mi;
2475 int i;
2476 int64_t actual_mocked_monotime_start;
2478 /* Ignore machine transitions for the purposes of this function, we only
2479 * really care about padding counts */
2480 MOCK(circpad_machine_spec_transition, circpad_machine_spec_transition_mock);
2481 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
2482 MOCK(circuit_package_relay_cell,
2483 circuit_package_relay_cell_mock);
2484 MOCK(monotime_absolute_usec, mock_monotime_absolute_usec);
2485 testing_enable_reproducible_rng();
2487 monotime_init();
2488 monotime_enable_test_mocking();
2489 actual_mocked_monotime_start = MONOTIME_MOCK_START;
2490 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
2491 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
2492 curr_mocked_time = actual_mocked_monotime_start;
2493 timers_initialize();
2495 client_side = TO_CIRCUIT(origin_circuit_new());
2496 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2497 dummy_channel.cmux = circuitmux_alloc();
2499 /* Setup machine and circuits */
2500 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
2501 relay_side->purpose = CIRCUIT_PURPOSE_OR;
2502 helper_create_basic_machine();
2503 relay_side->padding_machine[0] = &circ_client_machine;
2504 relay_side->padding_info[0] =
2505 circpad_circuit_machineinfo_new(relay_side, 0);
2506 mi = relay_side->padding_info[0];
2507 /* Set up the machine info so that we can get through the basic functions */
2508 mi->state_length = CIRCPAD_STATE_LENGTH_INFINITE;
2510 simulate_single_hop_extend(client_side, relay_side, 1);
2511 simulate_single_hop_extend(client_side, relay_side, 1);
2513 /* Now test the global limits by setting up the consensus */
2514 networkstatus_t vote1;
2515 vote1.net_params = smartlist_new();
2516 smartlist_split_string(vote1.net_params,
2517 "circpad_global_allowed_cells=100 circpad_global_max_padding_pct=50",
2518 NULL, 0, 0);
2519 /* Register global limits with the padding subsystem */
2520 circpad_new_consensus_params(&vote1);
2522 /* Check padding limit, should be fine since we haven't sent anything yet. */
2523 retval = circpad_machine_reached_padding_limit(mi);
2524 tt_int_op(retval, OP_EQ, 0);
2526 /* Send 99 padding cells which is below circpad_global_allowed_cells=100, so
2527 * the rate limit will not trigger */
2528 for (i=0;i<99;i++) {
2529 circpad_send_padding_cell_for_callback(mi);
2531 retval = circpad_machine_reached_padding_limit(mi);
2532 tt_int_op(retval, OP_EQ, 0);
2534 /* Now send another padding cell to pass circpad_global_allowed_cells=100,
2535 and see that the limit will trigger */
2536 circpad_send_padding_cell_for_callback(mi);
2537 retval = circpad_machine_reached_padding_limit(mi);
2538 tt_int_op(retval, OP_EQ, 1);
2540 retval = circpad_machine_schedule_padding(mi);
2541 tt_int_op(retval, OP_EQ, CIRCPAD_STATE_UNCHANGED);
2543 /* Now send 92 non-padding cells to get near the
2544 * circpad_global_max_padding_pct=50 limit; in particular with 96 non-padding
2545 * cells, the padding traffic is still 51% of total traffic so limit should
2546 * trigger */
2547 for (i=0;i<92;i++) {
2548 circpad_cell_event_nonpadding_sent(relay_side);
2550 retval = circpad_machine_reached_padding_limit(mi);
2551 tt_int_op(retval, OP_EQ, 1);
2553 /* Send another non-padding cell to bring the padding traffic to 50% of total
2554 * traffic and get past the limit */
2555 circpad_cell_event_nonpadding_sent(relay_side);
2556 retval = circpad_machine_reached_padding_limit(mi);
2557 tt_int_op(retval, OP_EQ, 0);
2559 done:
2560 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
2561 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
2562 circuitmux_free(dummy_channel.cmux);
2563 SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
2564 smartlist_free(vote1.net_params);
2565 testing_disable_reproducible_rng();
2568 /* Test reduced and disabled padding */
2569 static void
2570 test_circuitpadding_reduce_disable(void *arg)
2572 (void) arg;
2573 int64_t actual_mocked_monotime_start;
2575 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
2576 testing_enable_reproducible_rng();
2578 nodes_init();
2579 dummy_channel.cmux = circuitmux_alloc();
2580 relay_side = (circuit_t *)new_fake_orcirc(&dummy_channel,
2581 &dummy_channel);
2582 client_side = (circuit_t *)origin_circuit_new();
2583 relay_side->purpose = CIRCUIT_PURPOSE_OR;
2584 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2586 circpad_machines_init();
2587 helper_create_conditional_machines();
2589 monotime_init();
2590 monotime_enable_test_mocking();
2591 actual_mocked_monotime_start = MONOTIME_MOCK_START;
2592 monotime_set_mock_time_nsec(actual_mocked_monotime_start);
2593 monotime_coarse_set_mock_time_nsec(actual_mocked_monotime_start);
2594 curr_mocked_time = actual_mocked_monotime_start;
2595 timers_initialize();
2597 /* This is needed so that we are not considered to be dormant */
2598 note_user_activity(20);
2600 MOCK(circuit_package_relay_cell,
2601 circuit_package_relay_cell_mock);
2602 MOCK(node_get_by_id,
2603 node_get_by_id_mock);
2605 /* Simulate extend. This should result in the original machine getting
2606 * added, since the circuit is not built */
2607 simulate_single_hop_extend(client_side, relay_side, 1);
2608 simulate_single_hop_extend(client_side, relay_side, 1);
2610 /* Verify that machine #2 is added */
2611 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
2612 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
2614 /* Deliver a padding cell to the client, to trigger burst state */
2615 circpad_cell_event_padding_sent(client_side);
2617 /* This should have trigger length shutdown condition on client.. */
2618 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
2619 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
2621 /* Verify machine is gone from both sides */
2622 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
2623 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
2625 /* Now test the reduced padding machine by setting up the consensus */
2626 networkstatus_t vote1;
2627 vote1.net_params = smartlist_new();
2628 smartlist_split_string(vote1.net_params,
2629 "circpad_padding_reduced=1", NULL, 0, 0);
2631 /* Register reduced padding machine with the padding subsystem */
2632 circpad_new_consensus_params(&vote1);
2634 simulate_single_hop_extend(client_side, relay_side, 1);
2636 /* Verify that machine #0 is added */
2637 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
2638 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
2640 tt_int_op(
2641 circpad_machine_reached_padding_limit(client_side->padding_info[0]),
2642 OP_EQ, 0);
2643 tt_int_op(
2644 circpad_machine_reached_padding_limit(relay_side->padding_info[0]),
2645 OP_EQ, 0);
2647 /* Test that machines get torn down when padding is disabled */
2648 SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
2649 smartlist_free(vote1.net_params);
2650 vote1.net_params = smartlist_new();
2651 smartlist_split_string(vote1.net_params,
2652 "circpad_padding_disabled=1", NULL, 0, 0);
2654 /* Register reduced padding machine with the padding subsystem */
2655 circpad_new_consensus_params(&vote1);
2657 tt_int_op(
2658 circpad_machine_schedule_padding(client_side->padding_info[0]),
2659 OP_EQ, CIRCPAD_STATE_UNCHANGED);
2660 tt_int_op(
2661 circpad_machine_schedule_padding(relay_side->padding_info[0]),
2662 OP_EQ, CIRCPAD_STATE_UNCHANGED);
2664 /* Signal that circuit is built: this event causes us to re-evaluate
2665 * machine conditions (which don't apply because padding is disabled). */
2666 circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
2668 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
2669 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
2670 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
2671 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
2673 SMARTLIST_FOREACH(vote1.net_params, char *, cp, tor_free(cp));
2674 smartlist_free(vote1.net_params);
2675 vote1.net_params = NULL;
2676 circpad_new_consensus_params(&vote1);
2678 get_options_mutable()->ReducedCircuitPadding = 1;
2680 simulate_single_hop_extend(client_side, relay_side, 1);
2682 /* Verify that machine #0 is added */
2683 tt_int_op(client_side->padding_machine[0]->machine_num, OP_EQ, 2);
2684 tt_int_op(relay_side->padding_machine[0]->machine_num, OP_EQ, 2);
2686 tt_int_op(
2687 circpad_machine_reached_padding_limit(client_side->padding_info[0]),
2688 OP_EQ, 0);
2689 tt_int_op(
2690 circpad_machine_reached_padding_limit(relay_side->padding_info[0]),
2691 OP_EQ, 0);
2693 get_options_mutable()->CircuitPadding = 0;
2695 tt_int_op(
2696 circpad_machine_schedule_padding(client_side->padding_info[0]),
2697 OP_EQ, CIRCPAD_STATE_UNCHANGED);
2698 tt_int_op(
2699 circpad_machine_schedule_padding(relay_side->padding_info[0]),
2700 OP_EQ, CIRCPAD_STATE_UNCHANGED);
2702 /* Signal that circuit is built: this event causes us to re-evaluate
2703 * machine conditions (which don't apply because padding is disabled). */
2705 circpad_machine_event_circ_built(TO_ORIGIN_CIRCUIT(client_side));
2707 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
2708 tt_ptr_op(client_side->padding_machine[0], OP_EQ, NULL);
2709 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
2710 tt_ptr_op(relay_side->padding_machine[0], OP_EQ, NULL);
2712 done:
2713 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
2714 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
2715 circuitmux_free(dummy_channel.cmux);
2716 testing_disable_reproducible_rng();
2719 /** Just a basic machine whose whole purpose is to reach the END state */
2720 static void
2721 helper_create_ender_machine(void)
2723 /* Start, burst */
2724 circpad_machine_states_init(&circ_client_machine, 2);
2726 circ_client_machine.states[CIRCPAD_STATE_START].
2727 next_state[CIRCPAD_EVENT_NONPADDING_RECV] = CIRCPAD_STATE_END;
2729 circ_client_machine.conditions.apply_state_mask = CIRCPAD_STATE_ALL;
2730 circ_client_machine.conditions.apply_purpose_mask = CIRCPAD_PURPOSE_ALL;
2733 static time_t mocked_timeofday;
2734 /** Set timeval to a mock date and time. This is necessary
2735 * to make tor_gettimeofday() mockable. */
2736 static void
2737 mock_tor_gettimeofday(struct timeval *timeval)
2739 timeval->tv_sec = mocked_timeofday;
2740 timeval->tv_usec = 0;
2743 /** Test manual managing of circuit lifetimes by the circuitpadding
2744 * subsystem. In particular this test goes through all the cases of the
2745 * circpad_marked_circuit_for_padding() function, via
2746 * circuit_mark_for_close() as well as
2747 * circuit_expire_old_circuits_clientside(). */
2748 static void
2749 test_circuitpadding_manage_circuit_lifetime(void *arg)
2751 circpad_machine_runtime_t *mi;
2753 (void) arg;
2755 client_side = (circuit_t *)origin_circuit_new();
2756 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2757 monotime_enable_test_mocking();
2758 MOCK(tor_gettimeofday, mock_tor_gettimeofday);
2759 mocked_timeofday = 23;
2761 helper_create_ender_machine();
2763 /* Enable manual circuit lifetime manage for this test */
2764 circ_client_machine.manage_circ_lifetime = 1;
2766 /* Test setup */
2767 client_side->padding_machine[0] = &circ_client_machine;
2768 client_side->padding_info[0] =
2769 circpad_circuit_machineinfo_new(client_side, 0);
2770 mi = client_side->padding_info[0];
2772 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START);
2774 /* Check that the circuit is not marked for close */
2775 tt_int_op(client_side->marked_for_close, OP_EQ, 0);
2776 tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
2778 /* Mark this circuit for close due to a remote reason */
2779 circuit_mark_for_close(client_side,
2780 END_CIRC_REASON_FLAG_REMOTE|END_CIRC_REASON_NONE);
2781 tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
2782 tt_int_op(client_side->marked_for_close, OP_NE, 0);
2783 tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
2784 client_side->marked_for_close = 0;
2786 /* Mark this circuit for close due to a protocol issue */
2787 circuit_mark_for_close(client_side, END_CIRC_REASON_TORPROTOCOL);
2788 tt_int_op(client_side->marked_for_close, OP_NE, 0);
2789 tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_GENERAL);
2790 client_side->marked_for_close = 0;
2792 /* Mark a measurement circuit for close */
2793 client_side->purpose = CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT;
2794 circuit_mark_for_close(client_side, END_CIRC_REASON_NONE);
2795 tt_int_op(client_side->marked_for_close, OP_NE, 0);
2796 tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT);
2797 client_side->marked_for_close = 0;
2799 /* Mark a general circuit for close */
2800 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2801 circuit_mark_for_close(client_side, END_CIRC_REASON_NONE);
2803 /* Check that this circuit is still not marked for close since we are
2804 * managing the lifetime manually, but the circuit was tagged as such by the
2805 * circpadding subsystem */
2806 tt_int_op(client_side->marked_for_close, OP_EQ, 0);
2807 tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
2809 /* We just tested case (1) from the comments of
2810 * circpad_circuit_should_be_marked_for_close() */
2812 /* Transition the machine to the END state but did not delete its machine */
2813 tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
2814 circpad_cell_event_nonpadding_received(client_side);
2815 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
2817 /* We just tested case (3) from the comments of
2818 * circpad_circuit_should_be_marked_for_close().
2819 * Now let's go for case (2). */
2821 /* Reset the close mark */
2822 client_side->marked_for_close = 0;
2824 /* Mark this circuit for close */
2825 circuit_mark_for_close(client_side, 0);
2827 /* See that the circ got closed since we are already in END state */
2828 tt_int_op(client_side->marked_for_close, OP_NE, 0);
2830 /* We just tested case (2). Now let's see that case (4) is unreachable as
2831 that comment claims */
2833 /* First, reset all close marks and tags */
2834 client_side->marked_for_close = 0;
2835 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2837 /* Now re-create the ender machine so that we can transition to END again */
2838 /* Free up some stuff first */
2839 circpad_circuit_free_all_machineinfos(client_side);
2840 tor_free(circ_client_machine.states);
2841 helper_create_ender_machine();
2843 client_side->padding_machine[0] = &circ_client_machine;
2844 client_side->padding_info[0] =
2845 circpad_circuit_machineinfo_new(client_side, 0);
2846 mi = client_side->padding_info[0];
2848 /* Check we are in START. */
2849 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_START);
2851 /* Test that we don't expire this circuit yet */
2852 client_side->timestamp_dirty = 0;
2853 client_side->state = CIRCUIT_STATE_OPEN;
2854 tor_gettimeofday(&client_side->timestamp_began);
2855 TO_ORIGIN_CIRCUIT(client_side)->circuit_idle_timeout = 23;
2856 mocked_timeofday += 24;
2857 circuit_expire_old_circuits_clientside();
2858 circuit_expire_old_circuits_clientside();
2859 circuit_expire_old_circuits_clientside();
2860 tt_int_op(client_side->timestamp_dirty, OP_NE, 0);
2861 tt_int_op(client_side->marked_for_close, OP_EQ, 0);
2862 tt_int_op(client_side->purpose, OP_EQ, CIRCUIT_PURPOSE_C_CIRCUIT_PADDING);
2864 /* Runaway circpad test: if the machine does not transition to end,
2865 * test that after CIRCPAD_DELAY_MAX_SECS, we get marked anyway */
2866 mocked_timeofday = client_side->timestamp_dirty
2867 + get_options()->MaxCircuitDirtiness + 2;
2868 client_side->padding_info[0]->last_cell_time_sec =
2869 approx_time()-(CIRCPAD_DELAY_MAX_SECS+10);
2870 circuit_expire_old_circuits_clientside();
2871 tt_int_op(client_side->marked_for_close, OP_NE, 0);
2873 /* Test back to normal: if we had activity, we won't close */
2874 client_side->padding_info[0]->last_cell_time_sec = approx_time();
2875 client_side->marked_for_close = 0;
2876 circuit_expire_old_circuits_clientside();
2877 tt_int_op(client_side->marked_for_close, OP_EQ, 0);
2879 /* Transition to END, but before we're past the dirty timer */
2880 mocked_timeofday = client_side->timestamp_dirty;
2881 circpad_cell_event_nonpadding_received(client_side);
2882 tt_int_op(mi->current_state, OP_EQ, CIRCPAD_STATE_END);
2884 /* Verify that the circuit was not closed. */
2885 tt_int_op(client_side->marked_for_close, OP_EQ, 0);
2887 /* Now that we are in END state, we can be closed by expiry, but via
2888 * the timestamp_dirty path, not the idle path. So first test not dirty
2889 * enough. */
2890 mocked_timeofday = client_side->timestamp_dirty;
2891 circuit_expire_old_circuits_clientside();
2892 tt_int_op(client_side->marked_for_close, OP_EQ, 0);
2893 mocked_timeofday = client_side->timestamp_dirty
2894 + get_options()->MaxCircuitDirtiness + 2;
2895 circuit_expire_old_circuits_clientside();
2896 tt_int_op(client_side->marked_for_close, OP_NE, 0);
2898 done:
2899 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
2900 tor_free(circ_client_machine.states);
2901 monotime_disable_test_mocking();
2902 UNMOCK(tor_gettimeofday);
2905 /** Helper for the test_circuitpadding_hs_machines test:
2907 * - Create a client and relay circuit.
2908 * - Setup right circuit purpose and attach a machine to the client circuit.
2909 * - Verify that state transitions work as intended and state length gets
2910 * enforced.
2912 * This function is able to do this test both for intro and rend circuits
2913 * depending on the value of <b>test_intro_circs</b>.
2915 static void
2916 helper_test_hs_machines(bool test_intro_circs)
2918 /* Setup the circuits */
2919 origin_circuit_t *origin_client_side = origin_circuit_new();
2920 client_side = TO_CIRCUIT(origin_client_side);
2921 client_side->purpose = CIRCUIT_PURPOSE_C_GENERAL;
2923 dummy_channel.cmux = circuitmux_alloc();
2924 relay_side = TO_CIRCUIT(new_fake_orcirc(&dummy_channel, &dummy_channel));
2925 relay_side->purpose = CIRCUIT_PURPOSE_OR;
2927 /* extend the client circ to two hops */
2928 simulate_single_hop_extend(client_side, relay_side, 1);
2929 simulate_single_hop_extend(client_side, relay_side, 1);
2931 /* machines only apply on opened circuits */
2932 origin_client_side->has_opened = 1;
2934 /************************************/
2936 /* Attaching the client machine now won't work here because of a wrong
2937 * purpose */
2938 tt_assert(!client_side->padding_machine[0]);
2939 circpad_add_matching_machines(origin_client_side, origin_padding_machines);
2940 tt_assert(!client_side->padding_machine[0]);
2942 /* Change the purpose, see the machine getting attached */
2943 client_side->purpose = test_intro_circs ?
2944 CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT : CIRCUIT_PURPOSE_C_REND_JOINED;
2945 circpad_add_matching_machines(origin_client_side, origin_padding_machines);
2946 tt_ptr_op(client_side->padding_info[0], OP_NE, NULL);
2947 tt_ptr_op(client_side->padding_machine[0], OP_NE, NULL);
2949 tt_ptr_op(relay_side->padding_info[0], OP_NE, NULL);
2950 tt_ptr_op(relay_side->padding_machine[0], OP_NE, NULL);
2952 /* Verify that the right machine is attached */
2953 tt_str_op(client_side->padding_machine[0]->name, OP_EQ,
2954 test_intro_circs ? "client_ip_circ" : "client_rp_circ");
2955 tt_str_op(relay_side->padding_machine[0]->name, OP_EQ,
2956 test_intro_circs ? "relay_ip_circ": "relay_rp_circ");
2958 /***********************************/
2960 /* Intro machines are at START state, but rend machines have already skipped
2961 * to OBFUSCATE_CIRC_SETUP because of the sent PADDING_NEGOTIATE. */
2962 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
2963 CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
2964 tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
2965 CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
2967 /*Send non-padding to move the machines from START to OBFUSCATE_CIRC_SETUP */
2968 circpad_cell_event_nonpadding_received(client_side);
2969 circpad_cell_event_nonpadding_received(relay_side);
2970 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
2971 CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
2972 tt_int_op(relay_side->padding_info[0]->current_state, OP_EQ,
2973 CIRCPAD_STATE_OBFUSCATE_CIRC_SETUP);
2975 /* Check that the state lengths have been sampled and are within range */
2976 circpad_machine_runtime_t *client_machine_runtime =
2977 client_side->padding_info[0];
2978 circpad_machine_runtime_t *relay_machine_runtime =
2979 relay_side->padding_info[0];
2981 if (test_intro_circs) {
2982 /* on the client side, we don't send any padding so
2983 * state length is not set */
2984 tt_i64_op(client_machine_runtime->state_length, OP_EQ, -1);
2985 /* relay side has state limits. check them */
2986 tt_i64_op(relay_machine_runtime->state_length, OP_GE,
2987 INTRO_MACHINE_MINIMUM_PADDING);
2988 tt_i64_op(relay_machine_runtime->state_length, OP_LT,
2989 INTRO_MACHINE_MAXIMUM_PADDING);
2990 } else {
2991 tt_i64_op(client_machine_runtime->state_length, OP_EQ, 1);
2992 tt_i64_op(relay_machine_runtime->state_length, OP_EQ, 1);
2995 if (test_intro_circs) {
2996 int i;
2997 /* Send state_length worth of padding from the relay and see that the
2998 * client state goes to END */
2999 for (i = (int) relay_machine_runtime->state_length ; i > 0 ; i--) {
3000 circpad_send_padding_cell_for_callback(relay_machine_runtime);
3002 /* See that the machine has been teared down after all the length has been
3003 * exhausted (the padding info should now be null on both sides) */
3004 tt_ptr_op(relay_side->padding_info[0], OP_EQ, NULL);
3005 tt_ptr_op(client_side->padding_info[0], OP_EQ, NULL);
3006 } else {
3007 int i;
3008 /* Send state_length worth of padding and see that the state goes to END */
3009 for (i = (int) client_machine_runtime->state_length ; i > 0 ; i--) {
3010 circpad_send_padding_cell_for_callback(client_machine_runtime);
3012 /* See that the machine has been teared down after all the length has been
3013 * exhausted. */
3014 tt_int_op(client_side->padding_info[0]->current_state, OP_EQ,
3015 CIRCPAD_STATE_END);
3018 done:
3019 free_fake_orcirc(TO_OR_CIRCUIT(relay_side));
3020 circuitmux_detach_all_circuits(dummy_channel.cmux, NULL);
3021 circuitmux_free(dummy_channel.cmux);
3022 free_fake_origin_circuit(TO_ORIGIN_CIRCUIT(client_side));
3025 /** Test that the HS circuit padding machines work as intended. */
3026 static void
3027 test_circuitpadding_hs_machines(void *arg)
3029 (void)arg;
3031 /* Test logic:
3033 * 1) Register the HS machines, which aim to hide the presence of
3034 * onion service traffic on the client-side
3036 * 2) Call helper_test_hs_machines() to perform tests for the intro circuit
3037 * machines and for the rend circuit machines.
3040 MOCK(circuitmux_attach_circuit, circuitmux_attach_circuit_mock);
3041 MOCK(circuit_package_relay_cell, circuit_package_relay_cell_mock);
3042 MOCK(circuit_get_nth_node, circuit_get_nth_node_mock);
3043 MOCK(circpad_machine_schedule_padding,circpad_machine_schedule_padding_mock);
3045 origin_padding_machines = smartlist_new();
3046 relay_padding_machines = smartlist_new();
3048 nodes_init();
3050 monotime_init();
3051 monotime_enable_test_mocking();
3052 monotime_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
3053 monotime_coarse_set_mock_time_nsec(1*TOR_NSEC_PER_USEC);
3054 curr_mocked_time = 1*TOR_NSEC_PER_USEC;
3056 timers_initialize();
3058 /* This is needed so that we are not considered to be dormant */
3059 note_user_activity(20);
3061 /************************************/
3063 /* Register the HS machines */
3064 circpad_machine_client_hide_intro_circuits(origin_padding_machines);
3065 circpad_machine_client_hide_rend_circuits(origin_padding_machines);
3066 circpad_machine_relay_hide_intro_circuits(relay_padding_machines);
3067 circpad_machine_relay_hide_rend_circuits(relay_padding_machines);
3069 /***********************************/
3071 /* Do the tests for the intro circuit machines */
3072 helper_test_hs_machines(true);
3073 /* Do the tests for the rend circuit machines */
3074 helper_test_hs_machines(false);
3076 timers_shutdown();
3077 monotime_disable_test_mocking();
3079 SMARTLIST_FOREACH_BEGIN(origin_padding_machines,
3080 circpad_machine_spec_t *, m) {
3081 machine_spec_free(m);
3082 } SMARTLIST_FOREACH_END(m);
3084 SMARTLIST_FOREACH_BEGIN(relay_padding_machines,
3085 circpad_machine_spec_t *, m) {
3086 machine_spec_free(m);
3087 } SMARTLIST_FOREACH_END(m);
3089 smartlist_free(origin_padding_machines);
3090 smartlist_free(relay_padding_machines);
3092 UNMOCK(circuitmux_attach_circuit);
3093 UNMOCK(circuit_package_relay_cell);
3094 UNMOCK(circuit_get_nth_node);
3095 UNMOCK(circpad_machine_schedule_padding);
3098 /** Test that we effectively ignore non-padding cells in padding circuits. */
3099 static void
3100 test_circuitpadding_ignore_non_padding_cells(void *arg)
3102 int retval;
3103 relay_header_t rh;
3105 (void) arg;
3107 client_side = (circuit_t *)origin_circuit_new();
3108 client_side->purpose = CIRCUIT_PURPOSE_C_CIRCUIT_PADDING;
3110 rh.command = RELAY_COMMAND_BEGIN;
3112 setup_full_capture_of_logs(LOG_INFO);
3113 retval = handle_relay_cell_command(NULL, client_side, NULL, NULL, &rh, 0);
3114 tt_int_op(retval, OP_EQ, 0);
3115 expect_log_msg_containing("Ignored cell");
3117 done:
3121 #define TEST_CIRCUITPADDING(name, flags) \
3122 { #name, test_##name, (flags), NULL, NULL }
3124 struct testcase_t circuitpadding_tests[] = {
3125 TEST_CIRCUITPADDING(circuitpadding_tokens, TT_FORK),
3126 TEST_CIRCUITPADDING(circuitpadding_state_length, TT_FORK),
3127 TEST_CIRCUITPADDING(circuitpadding_negotiation, TT_FORK),
3128 TEST_CIRCUITPADDING(circuitpadding_wronghop, TT_FORK),
3129 /** Disabled unstable test until #29298 is implemented (see #29122) */
3130 // TEST_CIRCUITPADDING(circuitpadding_circuitsetup_machine, TT_FORK),
3131 TEST_CIRCUITPADDING(circuitpadding_conditions, TT_FORK),
3132 TEST_CIRCUITPADDING(circuitpadding_rtt, TT_FORK),
3133 TEST_CIRCUITPADDING(circuitpadding_sample_distribution, TT_FORK),
3134 TEST_CIRCUITPADDING(circuitpadding_machine_rate_limiting, TT_FORK),
3135 TEST_CIRCUITPADDING(circuitpadding_global_rate_limiting, TT_FORK),
3136 TEST_CIRCUITPADDING(circuitpadding_reduce_disable, TT_FORK),
3137 TEST_CIRCUITPADDING(circuitpadding_token_removal_lower, TT_FORK),
3138 TEST_CIRCUITPADDING(circuitpadding_token_removal_higher, TT_FORK),
3139 TEST_CIRCUITPADDING(circuitpadding_closest_token_removal, TT_FORK),
3140 TEST_CIRCUITPADDING(circuitpadding_closest_token_removal_usec, TT_FORK),
3141 TEST_CIRCUITPADDING(circuitpadding_token_removal_exact, TT_FORK),
3142 TEST_CIRCUITPADDING(circuitpadding_manage_circuit_lifetime, TT_FORK),
3143 TEST_CIRCUITPADDING(circuitpadding_hs_machines, TT_FORK),
3144 TEST_CIRCUITPADDING(circuitpadding_ignore_non_padding_cells, TT_FORK),
3145 END_OF_TESTCASES