Line data Source code
1 : /* Copyright (c) 2017-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file test_hs_cell.c
6 : * \brief Test hidden service cell functionality.
7 : */
8 :
9 : #define CIRCUITLIST_PRIVATE
10 : #define NETWORKSTATUS_PRIVATE
11 : #define HS_DOS_PRIVATE
12 : #define HS_INTROPOINT_PRIVATE
13 :
14 : #include "test/test.h"
15 : #include "test/test_helpers.h"
16 : #include "test/log_test_helpers.h"
17 :
18 : #include "app/config/config.h"
19 :
20 : #include "core/or/circuitlist.h"
21 : #include "core/or/circuituse.h"
22 : #include "core/or/or_circuit_st.h"
23 :
24 : #include "feature/hs/hs_dos.h"
25 : #include "feature/hs/hs_intropoint.h"
26 : #include "feature/nodelist/networkstatus.h"
27 :
28 : static void
29 1 : setup_mock_consensus(void)
30 : {
31 1 : current_ns_consensus = tor_malloc_zero(sizeof(networkstatus_t));
32 1 : current_ns_consensus->net_params = smartlist_new();
33 1 : smartlist_add(current_ns_consensus->net_params,
34 : (void *) "HiddenServiceEnableIntroDoSDefense=1");
35 1 : hs_dos_consensus_has_changed(current_ns_consensus);
36 1 : }
37 :
38 : static void
39 1 : free_mock_consensus(void)
40 : {
41 1 : smartlist_free(current_ns_consensus->net_params);
42 1 : tor_free(current_ns_consensus);
43 1 : }
44 :
45 : static void
46 1 : test_can_send_intro2(void *arg)
47 : {
48 1 : uint32_t now = (uint32_t) approx_time();
49 1 : or_circuit_t *or_circ = NULL;
50 :
51 1 : (void) arg;
52 :
53 1 : hs_init();
54 1 : hs_dos_init();
55 :
56 1 : get_options_mutable()->ORPort_set = 1;
57 1 : setup_mock_consensus();
58 :
59 1 : or_circ = or_circuit_new(1, NULL);
60 :
61 : /* Make that circuit a service intro point. */
62 1 : circuit_change_purpose(TO_CIRCUIT(or_circ), CIRCUIT_PURPOSE_INTRO_POINT);
63 1 : hs_dos_setup_default_intro2_defenses(or_circ);
64 1 : or_circ->introduce2_dos_defense_enabled = 1;
65 :
66 : /* Brand new circuit, we should be able to send INTRODUCE2 cells. */
67 1 : tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
68 :
69 : /* Simulate that 10 cells have arrived in 1 second. There should be no
70 : * refill since the bucket is already at maximum on the first cell. */
71 1 : update_approx_time(++now);
72 11 : for (int i = 0; i < 10; i++) {
73 10 : tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
74 : }
75 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
76 : get_intro2_burst_consensus_param(NULL) - 10);
77 :
78 : /* Fully refill the bucket minus 1 cell. */
79 1 : update_approx_time(++now);
80 1 : tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
81 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
82 : get_intro2_burst_consensus_param(NULL) - 1);
83 :
84 : /* Receive an INTRODUCE2 at each second. We should have the bucket full
85 : * since at every second it gets refilled. */
86 11 : for (int i = 0; i < 10; i++) {
87 10 : update_approx_time(++now);
88 10 : tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
89 : }
90 : /* Last check if we can send the cell decrements the bucket so minus 1. */
91 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
92 : get_intro2_burst_consensus_param(NULL) - 1);
93 :
94 : /* Manually reset bucket for next test. */
95 1 : token_bucket_ctr_reset(&or_circ->introduce2_bucket, now);
96 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
97 : get_intro2_burst_consensus_param(NULL));
98 :
99 : /* Do a full burst in the current second which should empty the bucket and
100 : * we shouldn't be allowed to send one more cell after that. We go minus 1
101 : * cell else the very last check if we can send the INTRO2 cell returns
102 : * false because the bucket goes down to 0. */
103 200 : for (uint32_t i = 0; i < get_intro2_burst_consensus_param(NULL) - 1; i++) {
104 199 : tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
105 : }
106 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 1);
107 : /* Get the last remaining cell, we shouldn't be allowed to send it. */
108 1 : tt_int_op(false, OP_EQ, hs_dos_can_send_intro2(or_circ));
109 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 0);
110 :
111 : /* Make sure the next 100 cells aren't allowed and bucket stays at 0. */
112 101 : for (int i = 0; i < 100; i++) {
113 100 : tt_int_op(false, OP_EQ, hs_dos_can_send_intro2(or_circ));
114 100 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ, 0);
115 : }
116 :
117 : /* One second has passed, we should have the rate minus 1 cell added. */
118 1 : update_approx_time(++now);
119 1 : tt_int_op(true, OP_EQ, hs_dos_can_send_intro2(or_circ));
120 1 : tt_uint_op(token_bucket_ctr_get(&or_circ->introduce2_bucket), OP_EQ,
121 : get_intro2_rate_consensus_param(NULL) - 1);
122 :
123 1 : done:
124 1 : circuit_free_(TO_CIRCUIT(or_circ));
125 :
126 1 : hs_free_all();
127 1 : free_mock_consensus();
128 1 : }
129 :
130 : static void
131 1 : test_validate_dos_extension_params(void *arg)
132 : {
133 1 : bool ret;
134 :
135 1 : (void) arg;
136 :
137 : /* Validate the default values. */
138 1 : ret = cell_dos_extension_parameters_are_valid(
139 1 : get_intro2_rate_consensus_param(NULL),
140 1 : get_intro2_burst_consensus_param(NULL));
141 1 : tt_assert(ret);
142 :
143 : /* Valid custom rate/burst. */
144 1 : ret = cell_dos_extension_parameters_are_valid(17, 42);
145 1 : tt_assert(ret);
146 1 : ret = cell_dos_extension_parameters_are_valid(INT32_MAX, INT32_MAX);
147 1 : tt_assert(ret);
148 :
149 : /* Invalid rate. */
150 1 : ret = cell_dos_extension_parameters_are_valid(UINT64_MAX, 42);
151 1 : tt_assert(!ret);
152 :
153 : /* Invalid burst. */
154 1 : ret = cell_dos_extension_parameters_are_valid(42, UINT64_MAX);
155 1 : tt_assert(!ret);
156 :
157 : /* Value of 0 is valid (but should disable defenses) */
158 1 : ret = cell_dos_extension_parameters_are_valid(0, 0);
159 1 : tt_assert(ret);
160 :
161 : /* Can't have burst smaller than rate. */
162 1 : ret = cell_dos_extension_parameters_are_valid(42, 40);
163 1 : tt_assert(!ret);
164 :
165 1 : done:
166 1 : return;
167 : }
168 :
169 : struct testcase_t hs_dos_tests[] = {
170 : { "can_send_intro2", test_can_send_intro2, TT_FORK,
171 : NULL, NULL },
172 : { "validate_dos_extension_params", test_validate_dos_extension_params,
173 : TT_FORK, NULL, NULL },
174 :
175 : END_OF_TESTCASES
176 : };
|