Line data Source code
1 : /* Copyright (c) 2014-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /* Unit tests for handling different kinds of relay cell */
5 :
6 : #define CIRCUITLIST_PRIVATE
7 : #define NETWORKSTATUS_PRIVATE
8 : #define SENDME_PRIVATE
9 : #define RELAY_PRIVATE
10 :
11 : #include "core/or/circuit_st.h"
12 : #include "core/or/or_circuit_st.h"
13 : #include "core/or/origin_circuit_st.h"
14 : #include "core/or/circuitlist.h"
15 : #include "core/or/relay.h"
16 : #include "core/or/sendme.h"
17 :
18 : #include "feature/nodelist/networkstatus.h"
19 : #include "feature/nodelist/networkstatus_st.h"
20 :
21 : #include "lib/crypt_ops/crypto_digest.h"
22 :
23 : #include "test/test.h"
24 : #include "test/log_test_helpers.h"
25 :
26 : static void
27 1 : setup_mock_consensus(void)
28 : {
29 2 : current_md_consensus = current_ns_consensus =
30 1 : tor_malloc_zero(sizeof(networkstatus_t));
31 1 : current_md_consensus->net_params = smartlist_new();
32 1 : current_md_consensus->routerstatus_list = smartlist_new();
33 1 : }
34 :
35 : static void
36 1 : free_mock_consensus(void)
37 : {
38 1 : SMARTLIST_FOREACH(current_md_consensus->routerstatus_list, void *, r,
39 : tor_free(r));
40 1 : smartlist_free(current_md_consensus->routerstatus_list);
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_v1_record_digest(void *arg)
47 : {
48 1 : or_circuit_t *or_circ = NULL;
49 1 : circuit_t *circ = NULL;
50 :
51 1 : (void) arg;
52 :
53 : /* Create our dummy circuit. */
54 1 : or_circ = or_circuit_new(1, NULL);
55 : /* Points it to the OR circuit now. */
56 1 : circ = TO_CIRCUIT(or_circ);
57 :
58 : /* The package window has to be a multiple of CIRCWINDOW_INCREMENT minus 1
59 : * in order to catch the CIRCWINDOW_INCREMENT-nth cell. Try something that
60 : * shouldn't be noted. */
61 1 : circ->package_window = CIRCWINDOW_INCREMENT;
62 1 : sendme_record_cell_digest_on_circ(circ, NULL);
63 1 : tt_assert(!circ->sendme_last_digests);
64 :
65 : /* This should work now. Package window at CIRCWINDOW_INCREMENT + 1. */
66 1 : circ->package_window++;
67 1 : sendme_record_cell_digest_on_circ(circ, NULL);
68 1 : tt_assert(circ->sendme_last_digests);
69 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
70 :
71 : /* Next cell in the package window shouldn't do anything. */
72 1 : circ->package_window++;
73 1 : sendme_record_cell_digest_on_circ(circ, NULL);
74 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
75 :
76 : /* The next CIRCWINDOW_INCREMENT should add one more digest. */
77 1 : circ->package_window = (CIRCWINDOW_INCREMENT * 2) + 1;
78 1 : sendme_record_cell_digest_on_circ(circ, NULL);
79 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 2);
80 :
81 1 : done:
82 1 : circuit_free_(circ);
83 1 : }
84 :
85 : static void
86 1 : test_v1_consensus_params(void *arg)
87 : {
88 1 : (void) arg;
89 :
90 1 : setup_mock_consensus();
91 1 : tt_assert(current_md_consensus);
92 :
93 : /* Both zeroes. */
94 1 : smartlist_add(current_md_consensus->net_params,
95 : (void *) "sendme_emit_min_version=0");
96 1 : smartlist_add(current_md_consensus->net_params,
97 : (void *) "sendme_accept_min_version=0");
98 1 : tt_int_op(get_emit_min_version(), OP_EQ, 0);
99 1 : tt_int_op(get_accept_min_version(), OP_EQ, 0);
100 1 : smartlist_clear(current_md_consensus->net_params);
101 :
102 : /* Both ones. */
103 1 : smartlist_add(current_md_consensus->net_params,
104 : (void *) "sendme_emit_min_version=1");
105 1 : smartlist_add(current_md_consensus->net_params,
106 : (void *) "sendme_accept_min_version=1");
107 1 : tt_int_op(get_emit_min_version(), OP_EQ, 1);
108 1 : tt_int_op(get_accept_min_version(), OP_EQ, 1);
109 1 : smartlist_clear(current_md_consensus->net_params);
110 :
111 : /* Different values from each other. */
112 1 : smartlist_add(current_md_consensus->net_params,
113 : (void *) "sendme_emit_min_version=1");
114 1 : smartlist_add(current_md_consensus->net_params,
115 : (void *) "sendme_accept_min_version=0");
116 1 : tt_int_op(get_emit_min_version(), OP_EQ, 1);
117 1 : tt_int_op(get_accept_min_version(), OP_EQ, 0);
118 1 : smartlist_clear(current_md_consensus->net_params);
119 :
120 : /* Validate is the cell version is coherent with our internal default value
121 : * and the one in the consensus. */
122 1 : smartlist_add(current_md_consensus->net_params,
123 : (void *) "sendme_accept_min_version=1");
124 : /* Minimum acceptable value is 1. */
125 1 : tt_int_op(cell_version_can_be_handled(1), OP_EQ, true);
126 : /* Minimum acceptable value is 1 so a cell version of 0 is refused. */
127 1 : tt_int_op(cell_version_can_be_handled(0), OP_EQ, false);
128 :
129 1 : done:
130 1 : free_mock_consensus();
131 1 : }
132 :
133 : static void
134 1 : test_v1_build_cell(void *arg)
135 : {
136 1 : uint8_t payload[RELAY_PAYLOAD_SIZE], digest[DIGEST_LEN];
137 1 : ssize_t ret;
138 1 : crypto_digest_t *cell_digest = NULL;
139 1 : or_circuit_t *or_circ = NULL;
140 1 : circuit_t *circ = NULL;
141 :
142 1 : (void) arg;
143 :
144 1 : or_circ = or_circuit_new(1, NULL);
145 1 : circ = TO_CIRCUIT(or_circ);
146 1 : circ->sendme_last_digests = smartlist_new();
147 :
148 1 : cell_digest = crypto_digest_new();
149 1 : tt_assert(cell_digest);
150 1 : crypto_digest_add_bytes(cell_digest, "AAAAAAAAAAAAAAAAAAAA", 20);
151 1 : crypto_digest_get_digest(cell_digest, (char *) digest, sizeof(digest));
152 1 : smartlist_add(circ->sendme_last_digests, tor_memdup(digest, sizeof(digest)));
153 :
154 : /* SENDME v1 payload is 3 bytes + 20 bytes digest. See spec. */
155 1 : ret = build_cell_payload_v1(digest, payload);
156 1 : tt_int_op(ret, OP_EQ, 23);
157 :
158 : /* Validation. */
159 :
160 : /* An empty payload means SENDME version 0 thus valid. */
161 1 : tt_int_op(sendme_is_valid(circ, payload, 0), OP_EQ, true);
162 : /* Current phoney digest should have been popped. */
163 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
164 :
165 : /* An unparseable cell means invalid. */
166 1 : setup_full_capture_of_logs(LOG_INFO);
167 1 : tt_int_op(sendme_is_valid(circ, (const uint8_t *) "A", 1), OP_EQ, false);
168 1 : expect_log_msg_containing("Unparseable SENDME cell received. "
169 1 : "Closing circuit.");
170 1 : teardown_capture_of_logs();
171 :
172 : /* No cell digest recorded for this. */
173 1 : setup_full_capture_of_logs(LOG_INFO);
174 1 : tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
175 1 : expect_log_msg_containing("We received a SENDME but we have no cell digests "
176 1 : "to match. Closing circuit.");
177 1 : teardown_capture_of_logs();
178 :
179 : /* Note the wrong digest in the circuit, cell should fail validation. */
180 1 : circ->package_window = CIRCWINDOW_INCREMENT + 1;
181 1 : sendme_record_cell_digest_on_circ(circ, NULL);
182 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
183 1 : setup_full_capture_of_logs(LOG_INFO);
184 1 : tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, false);
185 : /* After a validation, the last digests is always popped out. */
186 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
187 1 : expect_log_msg_containing("SENDME v1 cell digest do not match.");
188 1 : teardown_capture_of_logs();
189 :
190 : /* Record the cell digest into the circuit, cell should validate. */
191 1 : memcpy(or_circ->crypto.sendme_digest, digest, sizeof(digest));
192 1 : circ->package_window = CIRCWINDOW_INCREMENT + 1;
193 1 : sendme_record_cell_digest_on_circ(circ, NULL);
194 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 1);
195 1 : tt_int_op(sendme_is_valid(circ, payload, sizeof(payload)), OP_EQ, true);
196 : /* After a validation, the last digests is always popped out. */
197 1 : tt_int_op(smartlist_len(circ->sendme_last_digests), OP_EQ, 0);
198 :
199 1 : done:
200 1 : crypto_digest_free(cell_digest);
201 1 : circuit_free_(circ);
202 1 : }
203 :
204 : static void
205 1 : test_cell_payload_pad(void *arg)
206 : {
207 1 : size_t pad_offset, payload_len, expected_offset;
208 :
209 1 : (void) arg;
210 :
211 : /* Offset should be 0, not enough room for padding. */
212 1 : payload_len = RELAY_PAYLOAD_SIZE;
213 1 : pad_offset = get_pad_cell_offset(payload_len);
214 1 : tt_int_op(pad_offset, OP_EQ, 0);
215 1 : tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
216 :
217 : /* Still no room because we keep 4 extra bytes. */
218 1 : pad_offset = get_pad_cell_offset(payload_len - 4);
219 1 : tt_int_op(pad_offset, OP_EQ, 0);
220 1 : tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
221 :
222 : /* We should have 1 byte of padding. Meaning, the offset should be the
223 : * CELL_PAYLOAD_SIZE minus 1 byte. */
224 1 : expected_offset = CELL_PAYLOAD_SIZE - 1;
225 1 : pad_offset = get_pad_cell_offset(payload_len - 5);
226 1 : tt_int_op(pad_offset, OP_EQ, expected_offset);
227 1 : tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
228 :
229 : /* Now some arbitrary small payload length. The cell size is header + 10 +
230 : * extra 4 bytes we keep so the offset should be there. */
231 1 : expected_offset = RELAY_HEADER_SIZE + 10 + 4;
232 1 : pad_offset = get_pad_cell_offset(10);
233 1 : tt_int_op(pad_offset, OP_EQ, expected_offset);
234 1 : tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
235 :
236 : /* Data length of 0. */
237 1 : expected_offset = RELAY_HEADER_SIZE + 4;
238 1 : pad_offset = get_pad_cell_offset(0);
239 1 : tt_int_op(pad_offset, OP_EQ, expected_offset);
240 1 : tt_int_op(CELL_PAYLOAD_SIZE - pad_offset, OP_LE, CELL_PAYLOAD_SIZE);
241 :
242 1 : done:
243 1 : ;
244 1 : }
245 :
246 : static void
247 1 : test_cell_version_validation(void *arg)
248 : {
249 1 : (void) arg;
250 :
251 : /* We currently only support up to SENDME_MAX_SUPPORTED_VERSION so we are
252 : * going to test the boundaries there. */
253 :
254 1 : tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION));
255 :
256 : /* Version below our supported should pass. */
257 1 : tt_assert(cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION - 1));
258 :
259 : /* Extra version from our supported should fail. */
260 1 : tt_assert(!cell_version_can_be_handled(SENDME_MAX_SUPPORTED_VERSION + 1));
261 :
262 : /* Simple check for version 0. */
263 1 : tt_assert(cell_version_can_be_handled(0));
264 :
265 : /* We MUST handle the default cell version that we emit or accept. */
266 1 : tt_assert(cell_version_can_be_handled(SENDME_EMIT_MIN_VERSION_DEFAULT));
267 1 : tt_assert(cell_version_can_be_handled(SENDME_ACCEPT_MIN_VERSION_DEFAULT));
268 :
269 1 : done:
270 1 : ;
271 1 : }
272 :
273 : /* check our decisions about how much stuff to put into relay cells. */
274 : static void
275 1 : test_package_payload_len(void *arg)
276 : {
277 1 : (void)arg;
278 : /* this is not a real circuit: it only has the fields needed for this
279 : * test. */
280 1 : circuit_t *c = tor_malloc_zero(sizeof(circuit_t));
281 :
282 : /* check initial conditions. */
283 1 : circuit_reset_sendme_randomness(c);
284 1 : tt_assert(! c->have_sent_sufficiently_random_cell);
285 1 : tt_int_op(c->send_randomness_after_n_cells, OP_GE, CIRCWINDOW_INCREMENT / 2);
286 1 : tt_int_op(c->send_randomness_after_n_cells, OP_LT, CIRCWINDOW_INCREMENT);
287 :
288 : /* We have a bunch of cells before we need to send randomness, so the first
289 : * few can be packaged full. */
290 1 : int initial = c->send_randomness_after_n_cells;
291 1 : size_t n = connection_edge_get_inbuf_bytes_to_package(10000, 0, c);
292 1 : tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
293 1 : n = connection_edge_get_inbuf_bytes_to_package(95000, 1, c);
294 1 : tt_uint_op(RELAY_PAYLOAD_SIZE, OP_EQ, n);
295 1 : tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
296 :
297 : /* If package_partial isn't set, we won't package a partially full cell at
298 : * all. */
299 1 : n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 0, c);
300 1 : tt_int_op(n, OP_EQ, 0);
301 : /* no change in our state, since nothing was sent. */
302 1 : tt_assert(! c->have_sent_sufficiently_random_cell);
303 1 : tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 2);
304 :
305 : /* If package_partial is set and the partial cell is not going to have
306 : * _enough_ randomness, we package it, but we don't consider ourselves to
307 : * have sent a sufficiently random cell. */
308 1 : n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-1, 1, c);
309 1 : tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-1);
310 1 : tt_assert(! c->have_sent_sufficiently_random_cell);
311 1 : tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 3);
312 :
313 : /* Make sure we set have_set_sufficiently_random_cell as appropriate. */
314 1 : n = connection_edge_get_inbuf_bytes_to_package(RELAY_PAYLOAD_SIZE-64, 1, c);
315 1 : tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE-64);
316 1 : tt_assert(c->have_sent_sufficiently_random_cell);
317 1 : tt_int_op(c->send_randomness_after_n_cells, OP_EQ, initial - 4);
318 :
319 : /* Now let's look at what happens when we get down to zero. Since we have
320 : * sent a sufficiently random cell, we will not force this one to have a gap.
321 : */
322 1 : c->send_randomness_after_n_cells = 0;
323 1 : n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
324 1 : tt_int_op(n, OP_EQ, RELAY_PAYLOAD_SIZE);
325 : /* Now these will be reset. */
326 1 : tt_assert(! c->have_sent_sufficiently_random_cell);
327 1 : tt_int_op(c->send_randomness_after_n_cells, OP_GE,
328 : CIRCWINDOW_INCREMENT / 2 - 1);
329 :
330 : /* What would happen if we hadn't sent a sufficiently random cell? */
331 1 : c->send_randomness_after_n_cells = 0;
332 1 : n = connection_edge_get_inbuf_bytes_to_package(10000, 1, c);
333 1 : const size_t reduced_payload_size = RELAY_PAYLOAD_SIZE - 4 - 16;
334 1 : tt_int_op(n, OP_EQ, reduced_payload_size);
335 : /* Now these will be reset. */
336 1 : tt_assert(! c->have_sent_sufficiently_random_cell);
337 1 : tt_int_op(c->send_randomness_after_n_cells, OP_GE,
338 : CIRCWINDOW_INCREMENT / 2 - 1);
339 :
340 : /* Here is a fun case: if it's time to package a small cell, then
341 : * package_partial==0 should mean we accept that many bytes.
342 : */
343 1 : c->send_randomness_after_n_cells = 0;
344 1 : n = connection_edge_get_inbuf_bytes_to_package(reduced_payload_size, 0, c);
345 1 : tt_int_op(n, OP_EQ, reduced_payload_size);
346 :
347 1 : done:
348 1 : tor_free(c);
349 1 : }
350 :
351 : struct testcase_t sendme_tests[] = {
352 : { "v1_record_digest", test_v1_record_digest, TT_FORK,
353 : NULL, NULL },
354 : { "v1_consensus_params", test_v1_consensus_params, TT_FORK,
355 : NULL, NULL },
356 : { "v1_build_cell", test_v1_build_cell, TT_FORK,
357 : NULL, NULL },
358 : { "cell_payload_pad", test_cell_payload_pad, TT_FORK,
359 : NULL, NULL },
360 : { "cell_version_validation", test_cell_version_validation, TT_FORK,
361 : NULL, NULL },
362 : { "package_payload_len", test_package_payload_len, 0, NULL, NULL },
363 :
364 : END_OF_TESTCASES
365 : };
|