tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 }