1 /* Copyright (c) 2014-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
6 * \brief Some helper functions to avoid code duplication in unit tests.
9 #define ROUTERLIST_PRIVATE
10 #define CONFIG_PRIVATE
11 #define CONNECTION_PRIVATE
12 #define CONNECTION_OR_PRIVATE
13 #define MAINLOOP_PRIVATE
16 #include "core/or/or.h"
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"
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"
34 #include "feature/nodelist/nodelist.h"
35 #include "feature/nodelist/routerlist.h"
37 #include "app/config/config.h"
38 #include "app/main/subsysmgr.h"
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"
47 #include "feature/nodelist/node_st.h"
48 #include "feature/nodelist/routerlist_st.h"
50 #ifdef HAVE_SYS_STAT_H
59 #endif /* defined(_WIN32) */
61 #include "test/test.h"
62 #include "test/test_helpers.h"
63 #include "test/test_connection.h"
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
70 #include "test_descriptors.inc"
71 #include "core/or/circuitlist.h"
72 #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS
73 ENABLE_GCC_WARNING("-Woverlength-strings")
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
80 get_yesterday_date_str(void)
82 static char buf
[ISO_TIME_LEN
+1];
84 time_t yesterday
= time(NULL
) - 24*60*60;
85 format_iso_time(buf
, yesterday
);
89 /* NOP replacement for router_descriptor_is_older_than() */
91 router_descriptor_is_older_than_replacement(const routerinfo_t
*router
,
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. */
103 helper_setup_fake_routerlist(void)
106 routerlist_t
*our_routerlist
= NULL
;
107 const smartlist_t
*our_nodelist
= NULL
;
109 /* Read the file that contains our test descriptors. */
111 /* We need to mock this function otherwise the descriptors will not
112 accepted as they are too old. */
113 MOCK(router_descriptor_is_older_than
,
114 router_descriptor_is_older_than_replacement
);
116 // Pick a time when these descriptors' certificates were valid.
117 update_approx_time(1603981036);
119 /* Load all the test descriptors to the routerlist. */
120 retval
= router_load_routers_from_string(TEST_DESCRIPTORS
,
121 NULL
, SAVED_IN_JOURNAL
,
123 tt_int_op(retval
, OP_EQ
, HELPER_NUMBER_OF_DESCRIPTORS
);
125 update_approx_time(0); // this restores the regular approx_time behavior
127 /* Sanity checking of routerlist and nodelist. */
128 our_routerlist
= router_get_routerlist();
129 tt_int_op(smartlist_len(our_routerlist
->routers
), OP_EQ
,
130 HELPER_NUMBER_OF_DESCRIPTORS
);
131 routerlist_assert_ok(our_routerlist
);
133 our_nodelist
= nodelist_get_list();
134 tt_int_op(smartlist_len(our_nodelist
), OP_EQ
, HELPER_NUMBER_OF_DESCRIPTORS
);
136 /* Mark all routers as non-guards but up and running! */
137 SMARTLIST_FOREACH_BEGIN(our_nodelist
, node_t
*, node
) {
138 node
->is_running
= 1;
140 node
->is_possible_guard
= 0;
141 } SMARTLIST_FOREACH_END(node
);
144 UNMOCK(router_descriptor_is_older_than
);
148 connection_write_to_buf_mock(const char *string
, size_t len
,
149 connection_t
*conn
, int compressed
)
156 buf_add(conn
->outbuf
, string
, len
);
160 buf_get_contents(buf_t
*buf
, size_t *sz_out
)
166 *sz_out
= buf_datalen(buf
);
167 if (*sz_out
>= ULONG_MAX
)
168 return NULL
; /* C'mon, really? */
169 out
= tor_malloc(*sz_out
+ 1);
170 if (buf_get_bytes(buf
, out
, (unsigned long)*sz_out
) != 0) {
174 out
[*sz_out
] = '\0'; /* Hopefully gratuitous. */
178 /* Set up a fake origin circuit with the specified number of cells,
179 * Return a pointer to the newly-created dummy circuit */
181 dummy_origin_circuit_new(int n_cells
)
183 origin_circuit_t
*circ
= origin_circuit_new();
187 for (i
=0; i
< n_cells
; ++i
) {
188 crypto_rand((void*)&cell
, sizeof(cell
));
189 cell_queue_append_packed_copy(TO_CIRCUIT(circ
),
190 &TO_CIRCUIT(circ
)->n_chan_cells
,
194 TO_CIRCUIT(circ
)->purpose
= CIRCUIT_PURPOSE_C_GENERAL
;
195 return TO_CIRCUIT(circ
);
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!!"
204 mock_tor_addr_lookup__fail_on_bad_addrs(const char *name
,
205 uint16_t family
, tor_addr_t
*out
)
207 if (name
&& strchr(name
, '!')) {
210 return tor_addr_lookup__real(name
, family
, out
);
214 create_directory(const char *parent_dir
, const char *name
)
217 tor_asprintf(&dir
, "%s"PATH_SEPARATOR
"%s", parent_dir
, name
);
219 tt_int_op(mkdir(dir
), OP_EQ
, 0);
221 tt_int_op(mkdir(dir
, 0700), OP_EQ
, 0);
231 create_file(const char *parent_dir
, const char *name
, const char *contents
)
234 tor_asprintf(&path
, "%s"PATH_SEPARATOR
"%s", parent_dir
, name
);
235 contents
= contents
== NULL
? "" : contents
;
236 tt_int_op(write_str_to_file(path
, contents
, 0), OP_EQ
, 0);
245 create_test_directory_structure(const char *parent_dir
)
254 char *forbidden
= NULL
;
256 dir1
= create_directory(parent_dir
, "dir1");
258 dir2
= create_directory(parent_dir
, "dir2");
260 file1
= create_file(parent_dir
, "file1", "Test 1");
262 file2
= create_file(parent_dir
, "file2", "Test 2");
264 dot
= create_file(parent_dir
, ".test-hidden", "Test .");
266 empty
= create_file(parent_dir
, "empty", NULL
);
268 forbidden
= create_directory(parent_dir
, "forbidden");
269 tt_assert(forbidden
);
271 tt_int_op(chmod(forbidden
, 0), OP_EQ
, 0);
285 /*********** Helper funcs for making new connections/streams *****************/
287 /* Helper for test_conn_get_connection() */
289 fake_close_socket(tor_socket_t sock
)
295 /* Helper for test_conn_get_proxy_or_connection() */
297 mock_connection_or_change_state(or_connection_t
*conn
, uint8_t state
)
300 conn
->base_
.state
= state
;
303 static int mock_connection_connect_sockaddr_called
= 0;
304 static int fake_socket_number
= TEST_CONN_FD_INIT
;
306 /* Helper for test_conn_get_connection() */
308 mock_connection_connect_sockaddr(connection_t
*conn
,
309 const struct sockaddr
*sa
,
311 const struct sockaddr
*bindaddr
,
312 socklen_t bindaddr_len
,
321 tor_assert(socket_error
);
323 mock_connection_connect_sockaddr_called
++;
325 conn
->s
= fake_socket_number
++;
326 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 tt_int_op(connection_add_connecting(conn
), OP_EQ
, 0);
333 /* Fake "connected" status */
338 test_conn_get_proxy_or_connection(unsigned int proxy_type
)
340 or_connection_t
*conn
= NULL
;
342 tor_addr_t proxy_addr
;
346 MOCK(connection_connect_sockaddr
,
347 mock_connection_connect_sockaddr
);
348 MOCK(connection_write_to_buf_impl_
,
349 connection_write_to_buf_mock
);
350 MOCK(connection_or_change_state
,
351 mock_connection_or_change_state
);
352 MOCK(tor_close_socket
, fake_close_socket
);
354 tor_init_connection_lists();
356 conn
= or_connection_new(CONN_TYPE_OR
, TEST_CONN_FAMILY
);
359 /* Set up a destination address. */
360 test_conn_lookup_addr_helper(TEST_CONN_ADDRESS
, TEST_CONN_FAMILY
,
362 tt_assert(!tor_addr_is_null(&dst_addr
));
364 conn
->proxy_type
= proxy_type
;
365 conn
->base_
.proxy_state
= PROXY_INFANT
;
367 tor_addr_copy_tight(&conn
->base_
.addr
, &dst_addr
);
368 conn
->base_
.address
= tor_addr_to_str_dup(&dst_addr
);
369 conn
->base_
.port
= TEST_CONN_PORT
;
371 /* Set up a proxy address. */
372 test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2
, TEST_CONN_FAMILY
,
374 tt_assert(!tor_addr_is_null(&proxy_addr
));
376 conn
->base_
.state
= OR_CONN_STATE_CONNECTING
;
378 mock_connection_connect_sockaddr_called
= 0;
379 in_progress
= connection_connect(TO_CONN(conn
), TEST_CONN_ADDRESS_PORT
,
380 &proxy_addr
, TEST_CONN_PORT
, &socket_err
);
381 tt_int_op(mock_connection_connect_sockaddr_called
, OP_EQ
, 1);
382 tt_assert(!socket_err
);
383 tt_assert(in_progress
== 0 || in_progress
== 1);
385 assert_connection_ok(TO_CONN(conn
), time(NULL
));
387 in_progress
= connection_or_finished_connecting(conn
);
388 tt_int_op(in_progress
, OP_EQ
, 0);
390 assert_connection_ok(TO_CONN(conn
), time(NULL
));
392 UNMOCK(connection_connect_sockaddr
);
393 UNMOCK(connection_write_to_buf_impl_
);
394 UNMOCK(connection_or_change_state
);
395 UNMOCK(tor_close_socket
);
400 UNMOCK(connection_connect_sockaddr
);
401 UNMOCK(connection_write_to_buf_impl_
);
402 UNMOCK(connection_or_change_state
);
403 UNMOCK(tor_close_socket
);
404 connection_free_(TO_CONN(conn
));
408 /** Create and return a new connection/stream */
410 test_conn_get_connection(uint8_t state
, uint8_t type
, uint8_t purpose
)
412 connection_t
*conn
= NULL
;
417 MOCK(connection_connect_sockaddr
,
418 mock_connection_connect_sockaddr
);
419 MOCK(tor_close_socket
, fake_close_socket
);
421 tor_init_connection_lists();
423 conn
= connection_new(type
, TEST_CONN_FAMILY
);
426 test_conn_lookup_addr_helper(TEST_CONN_ADDRESS
, TEST_CONN_FAMILY
, &addr
);
427 tt_assert(!tor_addr_is_null(&addr
));
429 tor_addr_copy_tight(&conn
->addr
, &addr
);
430 conn
->port
= TEST_CONN_PORT
;
431 mock_connection_connect_sockaddr_called
= 0;
432 in_progress
= connection_connect(conn
, TEST_CONN_ADDRESS_PORT
, &addr
,
433 TEST_CONN_PORT
, &socket_err
);
434 tt_int_op(mock_connection_connect_sockaddr_called
, OP_EQ
, 1);
435 tt_assert(!socket_err
);
436 tt_assert(in_progress
== 0 || in_progress
== 1);
438 /* fake some of the attributes so the connection looks OK */
440 conn
->purpose
= purpose
;
441 assert_connection_ok(conn
, time(NULL
));
443 UNMOCK(connection_connect_sockaddr
);
444 UNMOCK(tor_close_socket
);
449 UNMOCK(connection_connect_sockaddr
);
450 UNMOCK(tor_close_socket
);
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
459 helper_parse_options(const char *conf
)
463 or_options_t
*opt
= NULL
;
464 config_line_t
*line
= NULL
;
466 /* Kind of pointless to call this with a NULL value. */
471 ret
= config_get_lines(conf
, &line
, 1);
475 ret
= config_assign(get_options_mgr(), opt
, line
, 0, &msg
);
481 config_free_lines(line
);
483 or_options_free(opt
);
490 * Dispatch alertfn callback: flush all messages right now. Implements
494 alertfn_immediate(dispatch_t
*d
, channel_id_t chan
, void *arg
)
497 dispatch_flush(d
, chan
, INT_MAX
);
501 * Setup helper for tests that need pubsub active
503 * Does not hook up mainloop events. Does set immediate delivery for
507 helper_setup_pubsub(const struct testcase_t
*testcase
)
509 dispatch_t
*dispatcher
= NULL
;
510 pubsub_builder_t
*builder
= pubsub_builder_new();
511 channel_id_t chan
= get_channel_id("orconn");
514 (void)subsystems_add_pubsub(builder
);
515 dispatcher
= pubsub_builder_finalize(builder
, NULL
);
516 tor_assert(dispatcher
);
517 dispatch_set_alert_fn(dispatcher
, chan
, alertfn_immediate
, NULL
);
518 chan
= get_channel_id("ocirc");
519 dispatch_set_alert_fn(dispatcher
, chan
, alertfn_immediate
, NULL
);
524 * Cleanup helper for tests that need pubsub active
527 helper_cleanup_pubsub(const struct testcase_t
*testcase
, void *dispatcher_
)
529 dispatch_t
*dispatcher
= dispatcher_
;
532 dispatch_free(dispatcher
);
536 const struct testcase_setup_t helper_pubsub_setup
= {
537 helper_setup_pubsub
, helper_cleanup_pubsub
541 new_test_origin_circuit(bool has_opened
,
542 struct timeval circ_start_time
,
544 extend_info_t
**ei_list
)
546 origin_circuit_t
*origin_circ
= origin_circuit_new();
548 TO_CIRCUIT(origin_circ
)->purpose
= CIRCUIT_PURPOSE_C_GENERAL
;
550 origin_circ
->build_state
= tor_malloc_zero(sizeof(cpath_build_state_t
));
551 origin_circ
->build_state
->desired_path_len
= path_len
;
554 for (int i
= 0; i
< path_len
; i
++) {
555 extend_info_t
*ei
= ei_list
[i
];
556 cpath_append_hop(&origin_circ
->cpath
, ei
);
561 origin_circ
->has_opened
= 1;
562 TO_CIRCUIT(origin_circ
)->state
= CIRCUIT_STATE_OPEN
;
563 origin_circ
->cpath
->state
= CPATH_STATE_OPEN
;
565 TO_CIRCUIT(origin_circ
)->timestamp_began
= circ_start_time
;
566 TO_CIRCUIT(origin_circ
)->timestamp_created
= circ_start_time
;
567 origin_circ
->cpath
->state
= CPATH_STATE_CLOSED
;