test_helpers.c (15577B)
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 get_yesterday_date_str(void) 81 { 82 static char buf[ISO_TIME_LEN+1]; 83 84 time_t yesterday = time(NULL) - 24*60*60; 85 format_iso_time(buf, yesterday); 86 return buf; 87 } 88 89 /* NOP replacement for router_descriptor_is_older_than() */ 90 static int 91 router_descriptor_is_older_than_replacement(const routerinfo_t *router, 92 int seconds) 93 { 94 (void) router; 95 (void) seconds; 96 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 helper_setup_fake_routerlist(void) 104 { 105 int retval; 106 routerlist_t *our_routerlist = NULL; 107 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 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 update_approx_time(1603981036); 118 119 /* Load all the test descriptors to the routerlist. */ 120 retval = router_load_routers_from_string(TEST_DESCRIPTORS, 121 NULL, SAVED_IN_JOURNAL, 122 NULL, 0, NULL); 123 tt_int_op(retval, OP_EQ, HELPER_NUMBER_OF_DESCRIPTORS); 124 125 update_approx_time(0); // this restores the regular approx_time behavior 126 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); 132 133 our_nodelist = nodelist_get_list(); 134 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 SMARTLIST_FOREACH_BEGIN(our_nodelist, node_t *, node) { 138 node->is_running = 1; 139 node->is_valid = 1; 140 node->is_possible_guard = 0; 141 } SMARTLIST_FOREACH_END(node); 142 143 done: 144 UNMOCK(router_descriptor_is_older_than); 145 } 146 147 void 148 connection_write_to_buf_mock(const char *string, size_t len, 149 connection_t *conn, int compressed) 150 { 151 (void) compressed; 152 153 tor_assert(string); 154 tor_assert(conn); 155 156 buf_add(conn->outbuf, string, len); 157 } 158 159 char * 160 buf_get_contents(buf_t *buf, size_t *sz_out) 161 { 162 tor_assert(buf); 163 tor_assert(sz_out); 164 165 char *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) { 171 tor_free(out); 172 return NULL; 173 } 174 out[*sz_out] = '\0'; /* Hopefully gratuitous. */ 175 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 dummy_origin_circuit_new(int n_cells) 182 { 183 origin_circuit_t *circ = origin_circuit_new(); 184 int i; 185 cell_t cell; 186 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, 191 1, &cell, 1, 0); 192 } 193 194 TO_CIRCUIT(circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; 195 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 mock_tor_addr_lookup__fail_on_bad_addrs(const char *name, 205 uint16_t family, tor_addr_t *out) 206 { 207 if (name && strchr(name, '!')) { 208 return -1; 209 } 210 return tor_addr_lookup__real(name, family, out); 211 } 212 213 static char * 214 create_directory(const char *parent_dir, const char *name) 215 { 216 char *dir = NULL; 217 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 tt_int_op(mkdir(dir, 0700), OP_EQ, 0); 222 #endif 223 return dir; 224 225 done: 226 tor_free(dir); 227 return NULL; 228 } 229 230 static char * 231 create_file(const char *parent_dir, const char *name, const char *contents) 232 { 233 char *path = NULL; 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); 237 return path; 238 239 done: 240 tor_free(path); 241 return NULL; 242 } 243 244 int 245 create_test_directory_structure(const char *parent_dir) 246 { 247 int ret = -1; 248 char *dir1 = NULL; 249 char *dir2 = NULL; 250 char *file1 = NULL; 251 char *file2 = NULL; 252 char *dot = NULL; 253 char *empty = NULL; 254 char *forbidden = NULL; 255 256 dir1 = create_directory(parent_dir, "dir1"); 257 tt_assert(dir1); 258 dir2 = create_directory(parent_dir, "dir2"); 259 tt_assert(dir2); 260 file1 = create_file(parent_dir, "file1", "Test 1"); 261 tt_assert(file1); 262 file2 = create_file(parent_dir, "file2", "Test 2"); 263 tt_assert(file2); 264 dot = create_file(parent_dir, ".test-hidden", "Test ."); 265 tt_assert(dot); 266 empty = create_file(parent_dir, "empty", NULL); 267 tt_assert(empty); 268 forbidden = create_directory(parent_dir, "forbidden"); 269 tt_assert(forbidden); 270 #ifndef _WIN32 271 tt_int_op(chmod(forbidden, 0), OP_EQ, 0); 272 #endif 273 ret = 0; 274 done: 275 tor_free(dir1); 276 tor_free(dir2); 277 tor_free(file1); 278 tor_free(file2); 279 tor_free(dot); 280 tor_free(empty); 281 tor_free(forbidden); 282 return ret; 283 } 284 285 /*********** Helper funcs for making new connections/streams *****************/ 286 287 /* Helper for test_conn_get_connection() */ 288 static int 289 fake_close_socket(tor_socket_t sock) 290 { 291 (void)sock; 292 return 0; 293 } 294 295 /* Helper for test_conn_get_proxy_or_connection() */ 296 void 297 mock_connection_or_change_state(or_connection_t *conn, uint8_t state) 298 { 299 tor_assert(conn); 300 conn->base_.state = state; 301 } 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 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 (void)sa_len; 316 (void)bindaddr; 317 (void)bindaddr_len; 318 319 tor_assert(conn); 320 tor_assert(sa); 321 tor_assert(socket_error); 322 323 mock_connection_connect_sockaddr_called++; 324 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); 331 332 done: 333 /* Fake "connected" status */ 334 return 1; 335 } 336 337 or_connection_t * 338 test_conn_get_proxy_or_connection(unsigned int proxy_type) 339 { 340 or_connection_t *conn = NULL; 341 tor_addr_t dst_addr; 342 tor_addr_t proxy_addr; 343 int socket_err = 0; 344 int in_progress = 0; 345 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); 353 354 tor_init_connection_lists(); 355 356 conn = or_connection_new(CONN_TYPE_OR, TEST_CONN_FAMILY); 357 tt_assert(conn); 358 359 /* Set up a destination address. */ 360 test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, 361 &dst_addr); 362 tt_assert(!tor_addr_is_null(&dst_addr)); 363 364 conn->proxy_type = proxy_type; 365 conn->base_.proxy_state = PROXY_INFANT; 366 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; 370 371 /* Set up a proxy address. */ 372 test_conn_lookup_addr_helper(TEST_CONN_ADDRESS_2, TEST_CONN_FAMILY, 373 &proxy_addr); 374 tt_assert(!tor_addr_is_null(&proxy_addr)); 375 376 conn->base_.state = OR_CONN_STATE_CONNECTING; 377 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); 384 385 assert_connection_ok(TO_CONN(conn), time(NULL)); 386 387 in_progress = connection_or_finished_connecting(conn); 388 tt_int_op(in_progress, OP_EQ, 0); 389 390 assert_connection_ok(TO_CONN(conn), time(NULL)); 391 392 UNMOCK(connection_connect_sockaddr); 393 UNMOCK(connection_write_to_buf_impl_); 394 UNMOCK(connection_or_change_state); 395 UNMOCK(tor_close_socket); 396 return conn; 397 398 /* On failure */ 399 done: 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)); 405 return NULL; 406 } 407 408 /** Create and return a new connection/stream */ 409 connection_t * 410 test_conn_get_connection(uint8_t state, uint8_t type, uint8_t purpose) 411 { 412 connection_t *conn = NULL; 413 tor_addr_t addr; 414 int socket_err = 0; 415 int in_progress = 0; 416 417 MOCK(connection_connect_sockaddr, 418 mock_connection_connect_sockaddr); 419 MOCK(tor_close_socket, fake_close_socket); 420 421 tor_init_connection_lists(); 422 423 conn = connection_new(type, TEST_CONN_FAMILY); 424 tt_assert(conn); 425 426 test_conn_lookup_addr_helper(TEST_CONN_ADDRESS, TEST_CONN_FAMILY, &addr); 427 tt_assert(!tor_addr_is_null(&addr)); 428 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); 437 438 /* fake some of the attributes so the connection looks OK */ 439 conn->state = state; 440 conn->purpose = purpose; 441 assert_connection_ok(conn, time(NULL)); 442 443 UNMOCK(connection_connect_sockaddr); 444 UNMOCK(tor_close_socket); 445 return conn; 446 447 /* On failure */ 448 done: 449 UNMOCK(connection_connect_sockaddr); 450 UNMOCK(tor_close_socket); 451 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 helper_parse_options(const char *conf) 460 { 461 int ret = 0; 462 char *msg = NULL; 463 or_options_t *opt = NULL; 464 config_line_t *line = NULL; 465 466 /* Kind of pointless to call this with a NULL value. */ 467 tt_assert(conf); 468 469 opt = options_new(); 470 tt_assert(opt); 471 ret = config_get_lines(conf, &line, 1); 472 if (ret != 0) { 473 goto done; 474 } 475 ret = config_assign(get_options_mgr(), opt, line, 0, &msg); 476 if (ret != 0) { 477 goto done; 478 } 479 480 done: 481 config_free_lines(line); 482 if (ret != 0) { 483 or_options_free(opt); 484 opt = NULL; 485 } 486 return opt; 487 } 488 489 /** 490 * Dispatch alertfn callback: flush all messages right now. Implements 491 * DELIV_IMMEDIATE. 492 **/ 493 static void 494 alertfn_immediate(dispatch_t *d, channel_id_t chan, void *arg) 495 { 496 (void) arg; 497 dispatch_flush(d, chan, INT_MAX); 498 } 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 helper_setup_pubsub(const struct testcase_t *testcase) 508 { 509 dispatch_t *dispatcher = NULL; 510 pubsub_builder_t *builder = pubsub_builder_new(); 511 channel_id_t chan = get_channel_id("orconn"); 512 513 (void)testcase; 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); 520 return dispatcher; 521 } 522 523 /** 524 * Cleanup helper for tests that need pubsub active 525 */ 526 int 527 helper_cleanup_pubsub(const struct testcase_t *testcase, void *dispatcher_) 528 { 529 dispatch_t *dispatcher = dispatcher_; 530 531 (void)testcase; 532 dispatch_free(dispatcher); 533 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 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 origin_circuit_t *origin_circ = origin_circuit_new(); 547 548 TO_CIRCUIT(origin_circ)->purpose = CIRCUIT_PURPOSE_C_GENERAL; 549 550 origin_circ->build_state = tor_malloc_zero(sizeof(cpath_build_state_t)); 551 origin_circ->build_state->desired_path_len = path_len; 552 553 if (ei_list) { 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); 557 } 558 } 559 560 if (has_opened) { 561 origin_circ->has_opened = 1; 562 TO_CIRCUIT(origin_circ)->state = CIRCUIT_STATE_OPEN; 563 origin_circ->cpath->state = CPATH_STATE_OPEN; 564 } else { 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; 568 } 569 570 return origin_circ; 571 }