1 /* Copyright (c) 2017-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Test hidden service cell functionality.
9 #define CIRCUITLIST_PRIVATE
10 #define NETWORKSTATUS_PRIVATE
11 #define HS_DOS_PRIVATE
12 #define HS_INTROPOINT_PRIVATE
14 #include "test/test.h"
15 #include "test/test_helpers.h"
16 #include "test/log_test_helpers.h"
18 #include "app/config/config.h"
19 #include "lib/time/compat_time.h"
21 #include "core/or/circuitlist.h"
22 #include "core/or/circuituse.h"
23 #include "core/or/or_circuit_st.h"
25 #include "feature/hs/hs_dos.h"
26 #include "feature/hs/hs_intropoint.h"
27 #include "feature/nodelist/networkstatus.h"
30 setup_mock_consensus(void)
32 current_ns_consensus
= tor_malloc_zero(sizeof(networkstatus_t
));
33 current_ns_consensus
->net_params
= smartlist_new();
34 smartlist_add(current_ns_consensus
->net_params
,
35 (void *) "HiddenServiceEnableIntroDoSDefense=1");
36 hs_dos_consensus_has_changed(current_ns_consensus
);
40 free_mock_consensus(void)
42 smartlist_free(current_ns_consensus
->net_params
);
43 tor_free(current_ns_consensus
);
47 test_can_send_intro2(void *arg
)
49 static const uint64_t BILLION
= 1000000000;
51 or_circuit_t
*or_circ
= NULL
;
58 get_options_mutable()->ORPort_set
= 1;
59 setup_mock_consensus();
60 monotime_enable_test_mocking();
61 monotime_coarse_set_mock_time_nsec(now
);
63 or_circ
= or_circuit_new(1, NULL
);
65 /* Make that circuit a service intro point. */
66 circuit_change_purpose(TO_CIRCUIT(or_circ
), CIRCUIT_PURPOSE_INTRO_POINT
);
67 hs_dos_setup_default_intro2_defenses(or_circ
);
68 or_circ
->introduce2_dos_defense_enabled
= 1;
70 /* Brand new circuit, we should be able to send INTRODUCE2 cells. */
71 tt_int_op(true, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
73 /* Simulate that 10 cells have arrived in 1 second. There should be no
74 * refill since the bucket is already at maximum on the first cell. */
75 monotime_coarse_set_mock_time_nsec(now
+= BILLION
);
76 for (int i
= 0; i
< 10; i
++) {
77 tt_int_op(true, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
79 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
,
80 get_intro2_burst_consensus_param(NULL
) - 10);
82 /* Fully refill the bucket minus 1 cell. */
83 monotime_coarse_set_mock_time_nsec(now
+= BILLION
);
84 tt_int_op(true, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
85 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
,
86 get_intro2_burst_consensus_param(NULL
) - 1);
88 /* Receive an INTRODUCE2 at each second. We should have the bucket full
89 * since at every second it gets refilled. */
90 for (int i
= 0; i
< 10; i
++) {
91 monotime_coarse_set_mock_time_nsec(now
+= BILLION
);
92 tt_int_op(true, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
94 /* Last check if we can send the cell decrements the bucket so minus 1. */
95 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
,
96 get_intro2_burst_consensus_param(NULL
) - 1);
98 /* Manually reset bucket for next test. */
99 token_bucket_ctr_reset(&or_circ
->introduce2_bucket
,
100 (uint32_t) monotime_coarse_absolute_sec());
101 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
,
102 get_intro2_burst_consensus_param(NULL
));
104 /* Do a full burst in the current second which should empty the bucket and
105 * we shouldn't be allowed to send one more cell after that. We go minus 1
106 * cell else the very last check if we can send the INTRO2 cell returns
107 * false because the bucket goes down to 0. */
108 for (uint32_t i
= 0; i
< get_intro2_burst_consensus_param(NULL
) - 1; i
++) {
109 tt_int_op(true, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
111 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
, 1);
112 /* Get the last remaining cell, we shouldn't be allowed to send it. */
113 tt_int_op(false, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
114 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
, 0);
116 /* Make sure the next 100 cells aren't allowed and bucket stays at 0. */
117 for (int i
= 0; i
< 100; i
++) {
118 tt_int_op(false, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
119 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
, 0);
122 /* One second has passed, we should have the rate minus 1 cell added. */
123 monotime_coarse_set_mock_time_nsec(now
+= BILLION
);
124 tt_int_op(true, OP_EQ
, hs_dos_can_send_intro2(or_circ
));
125 tt_uint_op(token_bucket_ctr_get(&or_circ
->introduce2_bucket
), OP_EQ
,
126 get_intro2_rate_consensus_param(NULL
) - 1);
129 circuit_free_(TO_CIRCUIT(or_circ
));
132 free_mock_consensus();
133 monotime_disable_test_mocking();
137 test_validate_dos_extension_params(void *arg
)
143 /* Validate the default values. */
144 ret
= cell_dos_extension_parameters_are_valid(
145 get_intro2_rate_consensus_param(NULL
),
146 get_intro2_burst_consensus_param(NULL
));
149 /* Valid custom rate/burst. */
150 ret
= cell_dos_extension_parameters_are_valid(17, 42);
152 ret
= cell_dos_extension_parameters_are_valid(INT32_MAX
, INT32_MAX
);
156 ret
= cell_dos_extension_parameters_are_valid(UINT64_MAX
, 42);
160 ret
= cell_dos_extension_parameters_are_valid(42, UINT64_MAX
);
163 /* Value of 0 is valid (but should disable defenses) */
164 ret
= cell_dos_extension_parameters_are_valid(0, 0);
167 /* Can't have burst smaller than rate. */
168 ret
= cell_dos_extension_parameters_are_valid(42, 40);
175 struct testcase_t hs_dos_tests
[] = {
176 { "can_send_intro2", test_can_send_intro2
, TT_FORK
,
178 { "validate_dos_extension_params", test_validate_dos_extension_params
,
179 TT_FORK
, NULL
, NULL
},