Line data Source code
1 : /* Copyright (c) 2013-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : #define CHANNEL_OBJECT_PRIVATE
5 : #define CIRCUITBUILD_PRIVATE
6 : #define CIRCUITLIST_PRIVATE
7 : #define HS_CIRCUITMAP_PRIVATE
8 : #include "core/or/or.h"
9 : #include "core/or/channel.h"
10 : #include "core/or/circuitbuild.h"
11 : #include "core/or/circuitlist.h"
12 : #include "core/or/circuitmux_ewma.h"
13 : #include "feature/hs/hs_circuitmap.h"
14 : #include "test/test.h"
15 : #include "test/log_test_helpers.h"
16 :
17 : #include "core/or/or_circuit_st.h"
18 : #include "core/or/origin_circuit_st.h"
19 :
20 : #include "lib/container/bitarray.h"
21 :
22 : static channel_t *
23 3 : new_fake_channel(void)
24 : {
25 3 : channel_t *chan = tor_malloc_zero(sizeof(channel_t));
26 3 : channel_init(chan);
27 3 : return chan;
28 : }
29 :
30 : static struct {
31 : int ncalls;
32 : void *cmux;
33 : void *circ;
34 : cell_direction_t dir;
35 : } cam;
36 :
37 : static void
38 5 : circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ,
39 : cell_direction_t dir)
40 : {
41 5 : ++cam.ncalls;
42 5 : cam.cmux = cmux;
43 5 : cam.circ = circ;
44 5 : cam.dir = dir;
45 5 : }
46 :
47 : static struct {
48 : int ncalls;
49 : void *cmux;
50 : void *circ;
51 : } cdm;
52 :
53 : static void
54 5 : circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
55 : {
56 5 : ++cdm.ncalls;
57 5 : cdm.cmux = cmux;
58 5 : cdm.circ = circ;
59 5 : }
60 :
61 : #define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
62 : tt_int_op(cam.ncalls, OP_EQ, 1); \
63 : tt_ptr_op(cam.cmux, OP_EQ, (mux_)); \
64 : tt_ptr_op(cam.circ, OP_EQ, (circ_)); \
65 : tt_int_op(cam.dir, OP_EQ, (dir_)); \
66 : memset(&cam, 0, sizeof(cam)); \
67 : } while (0)
68 :
69 : #define GOT_CMUX_DETACH(mux_, circ_) do { \
70 : tt_int_op(cdm.ncalls, OP_EQ, 1); \
71 : tt_ptr_op(cdm.cmux, OP_EQ, (mux_)); \
72 : tt_ptr_op(cdm.circ, OP_EQ, (circ_)); \
73 : memset(&cdm, 0, sizeof(cdm)); \
74 : } while (0)
75 :
76 : static void
77 1 : test_clist_maps(void *arg)
78 : {
79 1 : channel_t *ch1 = new_fake_channel();
80 1 : channel_t *ch2 = new_fake_channel();
81 1 : channel_t *ch3 = new_fake_channel();
82 1 : or_circuit_t *or_c1=NULL, *or_c2=NULL;
83 :
84 1 : (void) arg;
85 :
86 1 : MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
87 1 : MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
88 1 : memset(&cam, 0, sizeof(cam));
89 1 : memset(&cdm, 0, sizeof(cdm));
90 :
91 1 : tt_assert(ch1);
92 1 : tt_assert(ch2);
93 1 : tt_assert(ch3);
94 :
95 1 : ch1->cmux = tor_malloc(1);
96 1 : ch2->cmux = tor_malloc(1);
97 1 : ch3->cmux = tor_malloc(1);
98 :
99 1 : or_c1 = or_circuit_new(100, ch2);
100 1 : tt_assert(or_c1);
101 1 : GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
102 1 : tt_int_op(or_c1->p_circ_id, OP_EQ, 100);
103 1 : tt_ptr_op(or_c1->p_chan, OP_EQ, ch2);
104 :
105 1 : or_c2 = or_circuit_new(100, ch1);
106 1 : tt_assert(or_c2);
107 1 : GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
108 1 : tt_int_op(or_c2->p_circ_id, OP_EQ, 100);
109 1 : tt_ptr_op(or_c2->p_chan, OP_EQ, ch1);
110 :
111 1 : circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
112 1 : GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
113 :
114 1 : circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
115 1 : GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
116 :
117 1 : tt_ptr_op(circuit_get_by_circid_channel(200, ch1), OP_EQ, TO_CIRCUIT(or_c1));
118 1 : tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
119 1 : tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
120 : /* Try the same thing again, to test the "fast" path. */
121 1 : tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, TO_CIRCUIT(or_c1));
122 1 : tt_assert(circuit_id_in_use_on_channel(100, ch2));
123 1 : tt_assert(! circuit_id_in_use_on_channel(101, ch2));
124 :
125 : /* Try changing the circuitid and channel of that circuit. */
126 1 : circuit_set_p_circid_chan(or_c1, 500, ch3);
127 1 : GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
128 1 : GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
129 1 : tt_ptr_op(circuit_get_by_circid_channel(100, ch2), OP_EQ, NULL);
130 1 : tt_assert(! circuit_id_in_use_on_channel(100, ch2));
131 1 : tt_ptr_op(circuit_get_by_circid_channel(500, ch3), OP_EQ, TO_CIRCUIT(or_c1));
132 :
133 : /* Now let's see about destroy handling. */
134 1 : tt_assert(! circuit_id_in_use_on_channel(205, ch2));
135 1 : tt_assert(circuit_id_in_use_on_channel(200, ch2));
136 1 : channel_note_destroy_pending(ch2, 200);
137 1 : channel_note_destroy_pending(ch2, 205);
138 1 : channel_note_destroy_pending(ch1, 100);
139 1 : tt_assert(circuit_id_in_use_on_channel(205, ch2));
140 1 : tt_assert(circuit_id_in_use_on_channel(200, ch2));
141 1 : tt_assert(circuit_id_in_use_on_channel(100, ch1));
142 :
143 1 : tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
144 1 : tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, TO_CIRCUIT(or_c2));
145 1 : tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, TO_CIRCUIT(or_c2));
146 :
147 : /* Okay, now free ch2 and make sure that the circuit ID is STILL not
148 : * usable, because we haven't declared the destroy to be nonpending */
149 1 : tt_int_op(cdm.ncalls, OP_EQ, 0);
150 1 : circuit_free_(TO_CIRCUIT(or_c2));
151 1 : or_c2 = NULL; /* prevent free */
152 1 : tt_int_op(cdm.ncalls, OP_EQ, 2);
153 1 : memset(&cdm, 0, sizeof(cdm));
154 1 : tt_assert(circuit_id_in_use_on_channel(200, ch2));
155 1 : tt_assert(circuit_id_in_use_on_channel(100, ch1));
156 1 : tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
157 1 : tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
158 :
159 : /* Now say that the destroy is nonpending */
160 1 : channel_note_destroy_not_pending(ch2, 200);
161 1 : tt_ptr_op(circuit_get_by_circid_channel(200, ch2), OP_EQ, NULL);
162 1 : channel_note_destroy_not_pending(ch1, 100);
163 1 : tt_ptr_op(circuit_get_by_circid_channel(100, ch1), OP_EQ, NULL);
164 1 : tt_assert(! circuit_id_in_use_on_channel(200, ch2));
165 1 : tt_assert(! circuit_id_in_use_on_channel(100, ch1));
166 :
167 1 : done:
168 1 : if (or_c1)
169 1 : circuit_free_(TO_CIRCUIT(or_c1));
170 1 : if (or_c2)
171 0 : circuit_free_(TO_CIRCUIT(or_c2));
172 1 : if (ch1)
173 1 : tor_free(ch1->cmux);
174 1 : if (ch2)
175 1 : tor_free(ch2->cmux);
176 1 : if (ch3)
177 1 : tor_free(ch3->cmux);
178 1 : tor_free(ch1);
179 1 : tor_free(ch2);
180 1 : tor_free(ch3);
181 1 : UNMOCK(circuitmux_attach_circuit);
182 1 : UNMOCK(circuitmux_detach_circuit);
183 1 : }
184 :
185 : static void
186 1 : test_rend_token_maps(void *arg)
187 : {
188 1 : or_circuit_t *c1, *c2, *c3, *c4;
189 1 : origin_circuit_t *c5;
190 1 : const uint8_t tok1[REND_TOKEN_LEN] = "The cat can't tell y";
191 1 : const uint8_t tok2[REND_TOKEN_LEN] = "ou its name, and it ";
192 1 : const uint8_t tok3[REND_TOKEN_LEN] = "doesn't really care.";
193 : /* -- Adapted from a quote by Fredrik Lundh. */
194 :
195 1 : (void)arg;
196 1 : (void)tok1; //xxxx
197 :
198 1 : hs_circuitmap_init();
199 :
200 1 : c1 = or_circuit_new(0, NULL);
201 1 : c2 = or_circuit_new(0, NULL);
202 1 : c3 = or_circuit_new(0, NULL);
203 1 : c4 = or_circuit_new(0, NULL);
204 1 : c5 = origin_circuit_new();
205 :
206 1 : ed25519_public_key_t intro_pk1 = { {1} }; /* Junk, not important. */
207 1 : ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */
208 1 : ed25519_public_key_t intro_pk3 = { {3} }; /* Junk, not important. */
209 :
210 : /* Make sure we really filled up the tok* variables */
211 1 : tt_int_op(tok1[REND_TOKEN_LEN-1], OP_EQ, 'y');
212 1 : tt_int_op(tok2[REND_TOKEN_LEN-1], OP_EQ, ' ');
213 1 : tt_int_op(tok3[REND_TOKEN_LEN-1], OP_EQ, '.');
214 :
215 : /* No maps; nothing there. */
216 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
217 1 : tt_ptr_op(NULL, OP_EQ,
218 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk1));
219 :
220 1 : hs_circuitmap_register_rend_circ_relay_side(c1, tok1);
221 1 : hs_circuitmap_register_intro_circ_v3_relay_side(c2, &intro_pk2);
222 :
223 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok3));
224 1 : tt_ptr_op(NULL, OP_EQ,
225 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
226 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
227 1 : tt_ptr_op(NULL, OP_EQ,
228 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
229 :
230 : /* Without purpose set, we don't get the circuits */
231 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
232 1 : tt_ptr_op(NULL, OP_EQ,
233 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
234 :
235 1 : c1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
236 1 : c2->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
237 :
238 : /* Okay, make sure they show up now. */
239 1 : tt_ptr_op(c1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
240 1 : tt_ptr_op(c2, OP_EQ,
241 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
242 :
243 : /* Two items at the same place with the same token. */
244 1 : c3->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
245 1 : hs_circuitmap_register_rend_circ_relay_side(c3, tok2);
246 1 : tt_ptr_op(c2, OP_EQ,
247 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
248 1 : tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
249 :
250 : /* Marking a circuit makes it not get returned any more */
251 1 : circuit_mark_for_close(TO_CIRCUIT(c1), END_CIRC_REASON_FINISHED);
252 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
253 1 : circuit_free_(TO_CIRCUIT(c1));
254 1 : c1 = NULL;
255 :
256 : /* Freeing a circuit makes it not get returned any more. */
257 1 : circuit_free_(TO_CIRCUIT(c2));
258 1 : c2 = NULL;
259 1 : tt_ptr_op(NULL, OP_EQ,
260 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
261 :
262 : /* c3 -- are you still there? */
263 1 : tt_ptr_op(c3, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
264 : /* Change its cookie. This never happens in Tor per se, but hey. */
265 1 : c3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
266 1 : hs_circuitmap_register_intro_circ_v3_relay_side(c3, &intro_pk3);
267 :
268 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
269 1 : tt_ptr_op(c3, OP_EQ,
270 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
271 :
272 : /* Now replace c3 with c4. */
273 1 : c4->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
274 1 : hs_circuitmap_register_intro_circ_v3_relay_side(c4, &intro_pk3);
275 :
276 1 : tt_ptr_op(c4, OP_EQ,
277 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
278 :
279 1 : tt_ptr_op(TO_CIRCUIT(c3)->hs_token, OP_EQ, NULL);
280 1 : tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_NE, NULL);
281 1 : tt_mem_op(TO_CIRCUIT(c4)->hs_token->token, OP_EQ, &intro_pk3,
282 1 : REND_TOKEN_LEN);
283 :
284 : /* Now clear c4's cookie. */
285 1 : hs_circuitmap_remove_circuit(TO_CIRCUIT(c4));
286 1 : tt_ptr_op(TO_CIRCUIT(c4)->hs_token, OP_EQ, NULL);
287 1 : tt_ptr_op(NULL, OP_EQ,
288 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk3));
289 :
290 : /* Now let's do a check for the client-side rend circuitmap */
291 1 : c5->base_.purpose = CIRCUIT_PURPOSE_C_ESTABLISH_REND;
292 1 : hs_circuitmap_register_rend_circ_client_side(c5, tok1);
293 :
294 1 : tt_ptr_op(c5, OP_EQ, hs_circuitmap_get_rend_circ_client_side(tok1));
295 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_client_side(tok2));
296 :
297 1 : done:
298 0 : if (c1)
299 0 : circuit_free_(TO_CIRCUIT(c1));
300 1 : if (c2)
301 0 : circuit_free_(TO_CIRCUIT(c2));
302 1 : if (c3)
303 1 : circuit_free_(TO_CIRCUIT(c3));
304 1 : if (c4)
305 1 : circuit_free_(TO_CIRCUIT(c4));
306 1 : if (c5)
307 1 : circuit_free_(TO_CIRCUIT(c5));
308 1 : }
309 :
310 : static void
311 1 : mock_channel_dump_statistics(channel_t *chan, int severity)
312 : {
313 1 : (void)chan;
314 1 : (void)severity;
315 1 : }
316 :
317 : static void
318 1 : test_pick_circid(void *arg)
319 : {
320 1 : bitarray_t *ba = NULL;
321 1 : channel_t *chan1, *chan2;
322 1 : circid_t circid;
323 1 : int i;
324 1 : (void) arg;
325 :
326 1 : MOCK(channel_dump_statistics, mock_channel_dump_statistics);
327 :
328 1 : chan1 = tor_malloc_zero(sizeof(channel_t));
329 1 : chan2 = tor_malloc_zero(sizeof(channel_t));
330 1 : chan2->wide_circ_ids = 1;
331 :
332 1 : chan1->cmux = circuitmux_alloc();
333 1 : chan2->cmux = circuitmux_alloc();
334 :
335 : /* CIRC_ID_TYPE_NEITHER is supposed to create a warning. */
336 1 : chan1->circ_id_type = CIRC_ID_TYPE_NEITHER;
337 1 : setup_full_capture_of_logs(LOG_WARN);
338 1 : tt_int_op(0, OP_EQ, get_unique_circ_id_by_chan(chan1));
339 1 : expect_single_log_msg_containing("Trying to pick a circuit ID for a "
340 : "connection from a client with no identity.");
341 1 : teardown_capture_of_logs();
342 :
343 : /* Basic tests, with no collisions */
344 1 : chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
345 51 : for (i = 0; i < 50; ++i) {
346 50 : circid = get_unique_circ_id_by_chan(chan1);
347 50 : tt_uint_op(0, OP_LT, circid);
348 50 : tt_uint_op(circid, OP_LT, (1<<15));
349 : }
350 1 : chan1->circ_id_type = CIRC_ID_TYPE_HIGHER;
351 51 : for (i = 0; i < 50; ++i) {
352 50 : circid = get_unique_circ_id_by_chan(chan1);
353 50 : tt_uint_op((1<<15), OP_LT, circid);
354 50 : tt_uint_op(circid, OP_LT, (1<<16));
355 : }
356 :
357 1 : chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
358 51 : for (i = 0; i < 50; ++i) {
359 50 : circid = get_unique_circ_id_by_chan(chan2);
360 50 : tt_uint_op(0, OP_LT, circid);
361 50 : tt_uint_op(circid, OP_LT, (1u<<31));
362 : }
363 1 : chan2->circ_id_type = CIRC_ID_TYPE_HIGHER;
364 51 : for (i = 0; i < 50; ++i) {
365 50 : circid = get_unique_circ_id_by_chan(chan2);
366 50 : tt_uint_op((1u<<31), OP_LT, circid);
367 : }
368 :
369 : /* Now make sure that we can behave well when we are full up on circuits */
370 1 : chan1->circ_id_type = CIRC_ID_TYPE_LOWER;
371 1 : chan2->circ_id_type = CIRC_ID_TYPE_LOWER;
372 1 : chan1->wide_circ_ids = chan2->wide_circ_ids = 0;
373 1 : ba = bitarray_init_zero((1<<15));
374 29234 : for (i = 0; i < (1<<15); ++i) {
375 29233 : circid = get_unique_circ_id_by_chan(chan1);
376 29233 : if (circid == 0) {
377 1 : tt_int_op(i, OP_GT, (1<<14));
378 : break;
379 : }
380 29232 : tt_uint_op(circid, OP_LT, (1<<15));
381 29232 : tt_assert(! bitarray_is_set(ba, circid));
382 29232 : bitarray_set(ba, circid);
383 29232 : channel_mark_circid_unusable(chan1, circid);
384 : }
385 1 : tt_int_op(i, OP_LT, (1<<15));
386 : /* Make sure that being full on chan1 does not interfere with chan2 */
387 101 : for (i = 0; i < 100; ++i) {
388 100 : circid = get_unique_circ_id_by_chan(chan2);
389 100 : tt_uint_op(circid, OP_GT, 0);
390 100 : tt_uint_op(circid, OP_LT, (1<<15));
391 100 : channel_mark_circid_unusable(chan2, circid);
392 : }
393 :
394 1 : done:
395 1 : circuitmux_free(chan1->cmux);
396 1 : circuitmux_free(chan2->cmux);
397 1 : tor_free(chan1);
398 1 : tor_free(chan2);
399 1 : bitarray_free(ba);
400 1 : circuit_free_all();
401 1 : teardown_capture_of_logs();
402 1 : UNMOCK(channel_dump_statistics);
403 1 : }
404 :
405 : /** Test that the circuit pools of our HS circuitmap are isolated based on
406 : * their token type. */
407 : static void
408 1 : test_hs_circuitmap_isolation(void *arg)
409 : {
410 1 : or_circuit_t *circ1 = NULL;
411 1 : origin_circuit_t *circ2 = NULL;
412 1 : or_circuit_t *circ3 = NULL;
413 1 : origin_circuit_t *circ4 = NULL;
414 :
415 1 : (void)arg;
416 :
417 1 : hs_circuitmap_init();
418 :
419 1 : ed25519_public_key_t intro_pk1 = { {1} }; /* Junk, not important. */
420 1 : ed25519_public_key_t intro_pk2 = { {2} }; /* Junk, not important. */
421 :
422 : {
423 1 : const uint8_t tok1[REND_TOKEN_LEN] = "bet i got some of th";
424 :
425 1 : circ1 = or_circuit_new(0, NULL);
426 1 : tt_assert(circ1);
427 1 : circ1->base_.purpose = CIRCUIT_PURPOSE_REND_POINT_WAITING;
428 :
429 : /* check that circuitmap is empty right? */
430 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
431 :
432 : /* Register circ1 with tok1 as relay-side rend circ */
433 1 : hs_circuitmap_register_rend_circ_relay_side(circ1, tok1);
434 :
435 : /* check that service-side getters don't work */
436 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_service_side(tok1));
437 1 : tt_ptr_op(NULL, OP_EQ,
438 : hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk1));
439 :
440 : /* Check that the right getter works. */
441 1 : tt_ptr_op(circ1, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok1));
442 : }
443 :
444 : {
445 1 : const uint8_t tok2[REND_TOKEN_LEN] = "you dont know anythi";
446 :
447 1 : circ2 = origin_circuit_new();
448 1 : tt_assert(circ2);
449 1 : circ2->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
450 1 : circ3 = or_circuit_new(0, NULL);
451 1 : tt_assert(circ3);
452 1 : circ3->base_.purpose = CIRCUIT_PURPOSE_INTRO_POINT;
453 1 : circ4 = origin_circuit_new();
454 1 : tt_assert(circ4);
455 1 : circ4->base_.purpose = CIRCUIT_PURPOSE_S_ESTABLISH_INTRO;
456 :
457 : /* Register circ2 with tok2 as service-side intro v2 circ */
458 1 : hs_circuitmap_register_intro_circ_v3_service_side(circ2, &intro_pk2);
459 : /* Register circ3 with tok2 again but for different purpose */
460 1 : hs_circuitmap_register_intro_circ_v3_relay_side(circ3, &intro_pk2);
461 :
462 : /* Check that the getters work */
463 1 : tt_ptr_op(circ2, OP_EQ,
464 : hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk2));
465 1 : tt_ptr_op(circ3, OP_EQ,
466 : hs_circuitmap_get_intro_circ_v3_relay_side(&intro_pk2));
467 :
468 : /* Register circ4 with tok2: it should override circ2 */
469 1 : hs_circuitmap_register_intro_circ_v3_service_side(circ4, &intro_pk2);
470 :
471 : /* check that relay-side getters don't work */
472 1 : tt_ptr_op(NULL, OP_EQ, hs_circuitmap_get_rend_circ_relay_side(tok2));
473 :
474 : /* Check that the getter returns circ4; the last circuit registered with
475 : * that token. */
476 1 : tt_ptr_op(circ4, OP_EQ,
477 : hs_circuitmap_get_intro_circ_v3_service_side(&intro_pk2));
478 : }
479 :
480 1 : done:
481 1 : circuit_free_(TO_CIRCUIT(circ1));
482 1 : circuit_free_(TO_CIRCUIT(circ2));
483 1 : circuit_free_(TO_CIRCUIT(circ3));
484 1 : circuit_free_(TO_CIRCUIT(circ4));
485 1 : }
486 :
487 : struct testcase_t circuitlist_tests[] = {
488 : { "maps", test_clist_maps, TT_FORK, NULL, NULL },
489 : { "rend_token_maps", test_rend_token_maps, TT_FORK, NULL, NULL },
490 : { "pick_circid", test_pick_circid, TT_FORK, NULL, NULL },
491 : { "hs_circuitmap_isolation", test_hs_circuitmap_isolation,
492 : TT_FORK, NULL, NULL },
493 : END_OF_TESTCASES
494 : };
|