Line data Source code
1 : /* Copyright (c) 2014-2021, The Tor Project, Inc. */
2 : /* See LICENSE for licensing information */
3 :
4 : /**
5 : * \file test_helpers.c
6 : * \brief Some helper functions to avoid code duplication in unit tests.
7 : */
8 :
9 : #define ROUTERLIST_PRIVATE
10 : #define CONFIG_PRIVATE
11 : #define CONNECTION_PRIVATE
12 : #define CONNECTION_OR_PRIVATE
13 : #define MAINLOOP_PRIVATE
14 :
15 : #include "orconfig.h"
16 : #include "core/or/or.h"
17 :
18 : #include "lib/buf/buffers.h"
19 : #include "lib/confmgt/confmgt.h"
20 : #include "lib/crypt_ops/crypto_rand.h"
21 : #include "lib/dispatch/dispatch.h"
22 : #include "lib/dispatch/dispatch_naming.h"
23 : #include "lib/encoding/confline.h"
24 : #include "lib/net/resolve.h"
25 : #include "lib/pubsub/pubsub_build.h"
26 : #include "lib/pubsub/pubsub_connect.h"
27 :
28 : #include "core/mainloop/connection.h"
29 : #include "core/mainloop/mainloop.h"
30 : #include "core/or/connection_or.h"
31 : #include "core/or/crypt_path.h"
32 : #include "core/or/relay.h"
33 :
34 : #include "feature/nodelist/nodelist.h"
35 : #include "feature/nodelist/routerlist.h"
36 :
37 : #include "app/config/config.h"
38 : #include "app/main/subsysmgr.h"
39 :
40 : #include "core/or/cell_st.h"
41 : #include "core/or/connection_st.h"
42 : #include "core/or/cpath_build_state_st.h"
43 : #include "core/or/crypt_path_st.h"
44 : #include "core/or/origin_circuit_st.h"
45 : #include "core/or/or_connection_st.h"
46 :
47 : #include "feature/nodelist/node_st.h"
48 : #include "feature/nodelist/routerlist_st.h"
49 :
50 : #ifdef HAVE_SYS_STAT_H
51 : #include <sys/stat.h>
52 : #endif
53 :
54 : #ifdef _WIN32
55 : /* For mkdir() */
56 : #include <direct.h>
57 : #else
58 : #include <dirent.h>
59 : #endif /* defined(_WIN32) */
60 :
61 : #include "test/test.h"
62 : #include "test/test_helpers.h"
63 : #include "test/test_connection.h"
64 :
65 : #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
66 : DISABLE_GCC_WARNING("-Woverlength-strings")
67 : /* We allow huge string constants in the unit tests, but not in the code
68 : * at large. */
69 : #endif
70 : #include "test_descriptors.inc"
71 : #include "core/or/circuitlist.h"
72 : #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
73 : ENABLE_GCC_WARNING("-Woverlength-strings")
74 : #endif
75 :
76 : /* Return a statically allocated string representing yesterday's date
77 : * in ISO format. We use it so that state file items are not found to
78 : * be outdated. */
79 : const char *
80 2 : get_yesterday_date_str(void)
81 : {
82 2 : static char buf[ISO_TIME_LEN+1];
83 :
84 2 : time_t yesterday = time(NULL) - 24*60*60;
85 2 : format_iso_time(buf, yesterday);
86 2 : return buf;
87 : }
88 :
89 : /* NOP replacement for router_descriptor_is_older_than() */
90 : static int
91 24 : router_descriptor_is_older_than_replacement(const routerinfo_t *router,
92 : int seconds)
93 : {
94 24 : (void) router;
95 24 : (void) seconds;
96 24 : return 0;
97 : }
98 :
99 : /** Parse a file containing router descriptors and load them to our
100 : routerlist. This function is used to setup an artificial network
101 : so that we can conduct tests on it. */
102 : void
103 3 : helper_setup_fake_routerlist(void)
104 : {
105 3 : int retval;
106 3 : routerlist_t *our_routerlist = NULL;
107 3 : const smartlist_t *our_nodelist = NULL;
108 :
109 : /* Read the file that contains our test descriptors. */
110 :
111 : /* We need to mock this function otherwise the descriptors will not
112 : accepted as they are too old. */
113 3 : MOCK(router_descriptor_is_older_than,
114 : router_descriptor_is_older_than_replacement);
115 :
116 : // Pick a time when these descriptors' certificates were valid.
117 3 : update_approx_time(1603981036);
118 :
119 : /* Load all the test descriptors to the routerlist. */
120 3 : retval = router_load_routers_from_string(TEST_DESCRIPTORS,
121 : NULL, SAVED_IN_JOURNAL,
122 : NULL, 0, NULL);
123 3 : tt_int_op(retval, OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
124 :
125 3 : update_approx_time(0); // this restores the regular approx_time behavior
126 :
127 : /* Sanity checking of routerlist and nodelist. */
128 3 : our_routerlist = router_get_routerlist();
129 3 : tt_int_op(smartlist_len(our_routerlist->routers), OP_EQ,
130 : HELPER_NUMBER_OF_DESCRIPTORS);
131 3 : routerlist_assert_ok(our_routerlist);
132 :
133 3 : our_nodelist = nodelist_get_list();
134 3 : tt_int_op(smartlist_len(our_nodelist), OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS);
135 :
136 : /* Mark all routers as non-guards but up and running! */
137 27 : SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) {
138 24 : node->is_running = 1;
139 24 : node->is_valid = 1;
140 24 : node->is_possible_guard = 0;
141 24 : } SMARTLIST_FOREACH_END(node);
142 :
143 3 : done:
144 3 : UNMOCK(router_descriptor_is_older_than);
145 3 : }
146 :
147 : void
148 94 : connection_write_to_buf_mock(const char *string, size_t len,
149 : connection_t *conn, int compressed)
150 : {
151 94 : (void) compressed;
152 :
153 94 : tor_assert(string);
154 94 : tor_assert(conn);
155 :
156 94 : buf_add(conn->outbuf, string, len);
157 94 : }
158 :
159 : char *
160 33 : buf_get_contents(buf_t *buf, size_t *sz_out)
161 : {
162 33 : tor_assert(buf);
163 33 : tor_assert(sz_out);
164 :
165 33 : char *out;
166 33 : *sz_out = buf_datalen(buf);
167 33 : if (*sz_out >= ULONG_MAX)
168 : return NULL; /* C'mon, really? */
169 33 : out = tor_malloc(*sz_out + 1);
170 33 : if (buf_get_bytes(buf, out, (unsigned long)*sz_out) != 0) {
171 0 : tor_free(out);
172 0 : return NULL;
173 : }
174 33 : out[*sz_out] = '\0'; /* Hopefully gratuitous. */
175 33 : return out;
176 : }
177 :
178 : /* Set up a fake origin circuit with the specified number of cells,
179 : * Return a pointer to the newly-created dummy circuit */
180 : circuit_t *
181 19 : dummy_origin_circuit_new(int n_cells)
182 : {
183 19 : origin_circuit_t *circ = origin_circuit_new();
184 19 : int i;
185 19 : cell_t cell;
186 :
187 358 : for (i=0; i < n_cells; ++i) {
188 320 : crypto_rand((void*)&cell, sizeof(cell));
189 320 : cell_queue_append_packed_copy(TO_CIRCUIT(circ),
190 : &TO_CIRCUIT(circ)->n_chan_cells,
191 : 1, &cell, 1, 0);
192 : }
193 :
194 19 : TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
195 19 : return TO_CIRCUIT(circ);
196 : }
197 :
198 : /** Mock-replacement. As tor_addr_lookup, but always fails on any
199 : * address containing a !. This is necessary for running the unit tests
200 : * on networks where DNS hijackers think it's helpful to give answers
201 : * for things like 1.2.3.4.5 or "invalidstuff!!"
202 : */
203 : int
204 8 : mock_tor_addr_lookup__fail_on_bad_addrs(const char *name,
205 : uint16_t family, tor_addr_t *out)
206 : {
207 8 : if (name && strchr(name, '!')) {
208 : return -1;
209 : }
210 0 : return tor_addr_lookup__real(name, family, out);
211 : }
212 :
213 : static char *
214 24 : create_directory(const char *parent_dir, const char *name)
215 : {
216 24 : char *dir = NULL;
217 24 : tor_asprintf(&dir, "%s"PATH_SEPARATOR"%s", parent_dir, name);
218 : #ifdef _WIN32
219 : tt_int_op(mkdir(dir), OP_EQ, 0);
220 : #else
221 24 : tt_int_op(mkdir(dir, 0700), OP_EQ, 0);
222 : #endif
223 24 : return dir;
224 :
225 0 : done:
226 0 : tor_free(dir);
227 0 : return NULL;
228 : }
229 :
230 : static char *
231 32 : create_file(const char *parent_dir, const char *name, const char *contents)
232 : {
233 32 : char *path = NULL;
234 32 : tor_asprintf(&path, "%s"PATH_SEPARATOR"%s", parent_dir, name);
235 32 : contents = contents == NULL ? "" : contents;
236 32 : tt_int_op(write_str_to_file(path, contents, 0), OP_EQ, 0);
237 32 : return path;
238 :
239 0 : done:
240 0 : tor_free(path);
241 0 : return NULL;
242 : }
243 :
244 : int
245 8 : create_test_directory_structure(const char *parent_dir)
246 : {
247 8 : int ret = -1;
248 8 : char *dir1 = NULL;
249 8 : char *dir2 = NULL;
250 8 : char *file1 = NULL;
251 8 : char *file2 = NULL;
252 8 : char *dot = NULL;
253 8 : char *empty = NULL;
254 8 : char *forbidden = NULL;
255 :
256 8 : dir1 = create_directory(parent_dir, "dir1");
257 8 : tt_assert(dir1);
258 8 : dir2 = create_directory(parent_dir, "dir2");
259 8 : tt_assert(dir2);
260 8 : file1 = create_file(parent_dir, "file1", "Test 1");
261 8 : tt_assert(file1);
262 8 : file2 = create_file(parent_dir, "file2", "Test 2");
263 8 : tt_assert(file2);
264 8 : dot = create_file(parent_dir, ".test-hidden", "Test .");
265 8 : tt_assert(dot);
266 8 : empty = create_file(parent_dir, "empty", NULL);
267 8 : tt_assert(empty);
268 8 : forbidden = create_directory(parent_dir, "forbidden");
269 8 : tt_assert(forbidden);
270 : #ifndef _WIN32
271 8 : tt_int_op(chmod(forbidden, 0), OP_EQ, 0);
272 : #endif
273 : ret = 0;
274 8 : done:
275 8 : tor_free(dir1);
276 8 : tor_free(dir2);
277 8 : tor_free(file1);
278 8 : tor_free(file2);
279 8 : tor_free(dot);
280 8 : tor_free(empty);
281 8 : tor_free(forbidden);
282 8 : return ret;
283 : }
284 :
285 : /*********** Helper funcs for making new connections/streams *****************/
286 :
287 : /* Helper for test_conn_get_connection() */
288 : static int
289 0 : fake_close_socket(tor_socket_t sock)
290 : {
291 0 : (void)sock;
292 0 : return 0;
293 : }
294 :
295 : /* Helper for test_conn_get_proxy_or_connection() */
296 : void
297 2 : mock_connection_or_change_state(or_connection_t *conn, uint8_t state)
298 : {
299 2 : tor_assert(conn);
300 2 : conn->base_.state = state;
301 2 : }
302 :
303 : static int mock_connection_connect_sockaddr_called = 0;
304 : static int fake_socket_number = TEST_CONN_FD_INIT;
305 :
306 : /* Helper for test_conn_get_connection() */
307 : static int
308 21 : mock_connection_connect_sockaddr(connection_t *conn,
309 : const struct sockaddr *sa,
310 : socklen_t sa_len,
311 : const struct sockaddr *bindaddr,
312 : socklen_t bindaddr_len,
313 : int *socket_error)
314 : {
315 21 : (void)sa_len;
316 21 : (void)bindaddr;
317 21 : (void)bindaddr_len;
318 :
319 21 : tor_assert(conn);
320 21 : tor_assert(sa);
321 21 : tor_assert(socket_error);
322 :
323 21 : mock_connection_connect_sockaddr_called++;
324 :
325 21 : conn->s = fake_socket_number++;
326 21 : tt_assert(SOCKET_OK(conn->s));
327 : /* We really should call tor_libevent_initialize() here. Because we don't,
328 : * we are relying on other parts of the code not checking if the_event_base
329 : * (and therefore event->ev_base) is NULL. */
330 21 : tt_int_op(connection_add_connecting(conn), OP_EQ, 0);
331 :
332 21 : done:
333 : /* Fake "connected" status */
334 21 : return 1;
335 : }
336 :
337 : or_connection_t *
338 2 : test_conn_get_proxy_or_connection(unsigned int proxy_type)
339 : {
340 2 : or_connection_t *conn = NULL;
341 2 : tor_addr_t dst_addr;
342 2 : tor_addr_t proxy_addr;
343 2 : int socket_err = 0;
344 2 : int in_progress = 0;
345 :
346 2 : MOCK(connection_connect_sockaddr,
347 : mock_connection_connect_sockaddr);
348 2 : MOCK(connection_write_to_buf_impl_,
349 : connection_write_to_buf_mock);
350 2 : MOCK(connection_or_change_state,
351 : mock_connection_or_change_state);
352 2 : MOCK(tor_close_socket, fake_close_socket);
353 :
354 2 : tor_init_connection_lists();
355 :
356 2 : conn = or_connection_new(CONN_TYPE_OR, TEST_CONN_FAMILY);
357 2 : tt_assert(conn);
358 :
359 : /* Set up a destination address. */
360 2 : test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY,
361 : &dst_addr);
362 2 : tt_assert(!tor_addr_is_null(&dst_addr));
363 :
364 2 : conn->proxy_type = proxy_type;
365 2 : conn->base_.proxy_state = PROXY_INFANT;
366 :
367 2 : tor_addr_copy_tight(&conn->base_.addr, &dst_addr);
368 2 : conn->base_.address = tor_addr_to_str_dup(&dst_addr);
369 2 : conn->base_.port = TEST_CONN_PORT;
370 :
371 : /* Set up a proxy address. */
372 2 : test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY,
373 : &proxy_addr);
374 2 : tt_assert(!tor_addr_is_null(&proxy_addr));
375 :
376 2 : conn->base_.state = OR_CONN_STATE_CONNECTING;
377 :
378 2 : mock_connection_connect_sockaddr_called = 0;
379 2 : in_progress = connection_connect(TO_CONN(conn), TEST_CONN_ADDRESS_PORT,
380 : &proxy_addr, TEST_CONN_PORT, &socket_err);
381 2 : tt_int_op(mock_connection_connect_sockaddr_called, OP_EQ, 1);
382 2 : tt_assert(!socket_err);
383 2 : tt_assert(in_progress == 0 || in_progress == 1);
384 :
385 2 : assert_connection_ok(TO_CONN(conn), time(NULL));
386 :
387 2 : in_progress = connection_or_finished_connecting(conn);
388 2 : tt_int_op(in_progress, OP_EQ, 0);
389 :
390 2 : assert_connection_ok(TO_CONN(conn), time(NULL));
391 :
392 2 : UNMOCK(connection_connect_sockaddr);
393 2 : UNMOCK(connection_write_to_buf_impl_);
394 2 : UNMOCK(connection_or_change_state);
395 2 : UNMOCK(tor_close_socket);
396 2 : return conn;
397 :
398 : /* On failure */
399 0 : done:
400 0 : UNMOCK(connection_connect_sockaddr);
401 0 : UNMOCK(connection_write_to_buf_impl_);
402 0 : UNMOCK(connection_or_change_state);
403 0 : UNMOCK(tor_close_socket);
404 0 : connection_free_(TO_CONN(conn));
405 0 : return NULL;
406 : }
407 :
408 : /** Create and return a new connection/stream */
409 : connection_t *
410 19 : test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose)
411 : {
412 19 : connection_t *conn = NULL;
413 19 : tor_addr_t addr;
414 19 : int socket_err = 0;
415 19 : int in_progress = 0;
416 :
417 19 : MOCK(connection_connect_sockaddr,
418 : mock_connection_connect_sockaddr);
419 19 : MOCK(tor_close_socket, fake_close_socket);
420 :
421 19 : tor_init_connection_lists();
422 :
423 19 : conn = connection_new(type, TEST_CONN_FAMILY);
424 19 : tt_assert(conn);
425 :
426 19 : test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr);
427 19 : tt_assert(!tor_addr_is_null(&addr));
428 :
429 19 : tor_addr_copy_tight(&conn->addr, &addr);
430 19 : conn->port = TEST_CONN_PORT;
431 19 : mock_connection_connect_sockaddr_called = 0;
432 19 : in_progress = connection_connect(conn, TEST_CONN_ADDRESS_PORT, &addr,
433 : TEST_CONN_PORT, &socket_err);
434 19 : tt_int_op(mock_connection_connect_sockaddr_called, OP_EQ, 1);
435 19 : tt_assert(!socket_err);
436 19 : tt_assert(in_progress == 0 || in_progress == 1);
437 :
438 : /* fake some of the attributes so the connection looks OK */
439 19 : conn->state = state;
440 19 : conn->purpose = purpose;
441 19 : assert_connection_ok(conn, time(NULL));
442 :
443 19 : UNMOCK(connection_connect_sockaddr);
444 19 : UNMOCK(tor_close_socket);
445 19 : return conn;
446 :
447 : /* On failure */
448 0 : done:
449 0 : UNMOCK(connection_connect_sockaddr);
450 0 : UNMOCK(tor_close_socket);
451 0 : return NULL;
452 : }
453 :
454 : /* Helper function to parse a set of torrc options in a text format and return
455 : * a newly allocated or_options_t object containing the configuration. On
456 : * error, NULL is returned indicating that the conf couldn't be parsed
457 : * properly. */
458 : or_options_t *
459 28 : helper_parse_options(const char *conf)
460 : {
461 28 : int ret = 0;
462 28 : char *msg = NULL;
463 28 : or_options_t *opt = NULL;
464 28 : config_line_t *line = NULL;
465 :
466 : /* Kind of pointless to call this with a NULL value. */
467 28 : tt_assert(conf);
468 :
469 28 : opt = options_new();
470 28 : tt_assert(opt);
471 28 : ret = config_get_lines(conf, &line, 1);
472 28 : if (ret != 0) {
473 0 : goto done;
474 : }
475 28 : ret = config_assign(get_options_mgr(), opt, line, 0, &msg);
476 28 : if (ret != 0) {
477 0 : goto done;
478 : }
479 :
480 28 : done:
481 28 : config_free_lines(line);
482 28 : if (ret != 0) {
483 0 : or_options_free(opt);
484 0 : opt = NULL;
485 : }
486 28 : return opt;
487 : }
488 :
489 : /**
490 : * Dispatch alertfn callback: flush all messages right now. Implements
491 : * DELIV_IMMEDIATE.
492 : **/
493 : static void
494 41 : alertfn_immediate(dispatch_t *d, channel_id_t chan, void *arg)
495 : {
496 41 : (void) arg;
497 41 : dispatch_flush(d, chan, INT_MAX);
498 41 : }
499 :
500 : /**
501 : * Setup helper for tests that need pubsub active
502 : *
503 : * Does not hook up mainloop events. Does set immediate delivery for
504 : * all channels.
505 : */
506 : void *
507 10 : helper_setup_pubsub(const struct testcase_t *testcase)
508 : {
509 10 : dispatch_t *dispatcher = NULL;
510 10 : pubsub_builder_t *builder = pubsub_builder_new();
511 10 : channel_id_t chan = get_channel_id("orconn");
512 :
513 10 : (void)testcase;
514 10 : (void)subsystems_add_pubsub(builder);
515 10 : dispatcher = pubsub_builder_finalize(builder, NULL);
516 10 : tor_assert(dispatcher);
517 10 : dispatch_set_alert_fn(dispatcher, chan, alertfn_immediate, NULL);
518 10 : chan = get_channel_id("ocirc");
519 10 : dispatch_set_alert_fn(dispatcher, chan, alertfn_immediate, NULL);
520 10 : return dispatcher;
521 : }
522 :
523 : /**
524 : * Cleanup helper for tests that need pubsub active
525 : */
526 : int
527 10 : helper_cleanup_pubsub(const struct testcase_t *testcase, void *dispatcher_)
528 : {
529 10 : dispatch_t *dispatcher = dispatcher_;
530 :
531 10 : (void)testcase;
532 10 : dispatch_free(dispatcher);
533 10 : return 1;
534 : }
535 :
536 : const struct testcase_setup_t helper_pubsub_setup = {
537 : helper_setup_pubsub, helper_cleanup_pubsub
538 : };
539 :
540 : origin_circuit_t *
541 12 : new_test_origin_circuit(bool has_opened,
542 : struct timeval circ_start_time,
543 : int path_len,
544 : extend_info_t **ei_list)
545 : {
546 12 : origin_circuit_t *origin_circ = origin_circuit_new();
547 :
548 12 : TO_CIRCUIT(origin_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL;
549 :
550 12 : origin_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t));
551 12 : origin_circ->build_state->desired_path_len = path_len;
552 :
553 12 : if (ei_list) {
554 47 : for (int i = 0; i < path_len; i++) {
555 35 : extend_info_t *ei = ei_list[i];
556 35 : cpath_append_hop(&origin_circ->cpath, ei);
557 : }
558 : }
559 :
560 12 : if (has_opened) {
561 7 : origin_circ->has_opened = 1;
562 7 : TO_CIRCUIT(origin_circ)->state = CIRCUIT_STATE_OPEN;
563 7 : origin_circ->cpath->state = CPATH_STATE_OPEN;
564 : } else {
565 5 : TO_CIRCUIT(origin_circ)->timestamp_began = circ_start_time;
566 5 : TO_CIRCUIT(origin_circ)->timestamp_created = circ_start_time;
567 5 : origin_circ->cpath->state = CPATH_STATE_CLOSED;
568 : }
569 :
570 12 : return origin_circ;
571 : }
|