tor

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

test_mainloop.c (12076B)


      1 /* Copyright (c) 2018-2021, The Tor Project, Inc. */
      2 /* See LICENSE for licensing information */
      3 
      4 /**
      5 * \file test_mainloop.c
      6 * \brief Tests for functions closely related to the Tor main loop
      7 */
      8 
      9 #define CONFIG_PRIVATE
     10 #define MAINLOOP_PRIVATE
     11 #define STATEFILE_PRIVATE
     12 
     13 #include "test/test.h"
     14 #include "test/log_test_helpers.h"
     15 
     16 #include "lib/confmgt/confmgt.h"
     17 
     18 #include "core/or/or.h"
     19 #include "core/mainloop/connection.h"
     20 #include "core/mainloop/mainloop.h"
     21 #include "core/mainloop/mainloop_state_st.h"
     22 #include "core/mainloop/mainloop_sys.h"
     23 #include "core/mainloop/netstatus.h"
     24 
     25 #include "feature/hs/hs_service.h"
     26 
     27 #include "app/config/config.h"
     28 #include "app/config/statefile.h"
     29 #include "app/config/or_state_st.h"
     30 
     31 #include "app/main/subsysmgr.h"
     32 
     33 static const uint64_t BILLION = 1000000000;
     34 
     35 static void
     36 test_mainloop_update_time_normal(void *arg)
     37 {
     38  (void)arg;
     39 
     40  monotime_enable_test_mocking();
     41  /* This is arbitrary */
     42  uint64_t mt_now = UINT64_C(7493289274986);
     43  /* This time is in the past as of when this test was written. */
     44  time_t now = 1525272090;
     45  monotime_coarse_set_mock_time_nsec(mt_now);
     46  reset_uptime();
     47  update_current_time(now);
     48  tt_int_op(approx_time(), OP_EQ, now);
     49  tt_int_op(get_uptime(), OP_EQ, 0);
     50 
     51  update_current_time(now); // Same time as before is a no-op.
     52  tt_int_op(get_uptime(), OP_EQ, 0);
     53 
     54  now += 1;
     55  mt_now += BILLION;
     56  monotime_coarse_set_mock_time_nsec(mt_now);
     57  update_current_time(now);
     58  tt_int_op(approx_time(), OP_EQ, now);
     59  tt_int_op(get_uptime(), OP_EQ, 1);
     60 
     61  now += 2; // two-second jump is unremarkable.
     62  mt_now += 2*BILLION;
     63  update_current_time(now);
     64  monotime_coarse_set_mock_time_nsec(mt_now);
     65  tt_int_op(approx_time(), OP_EQ, now);
     66  tt_int_op(get_uptime(), OP_EQ, 3);
     67 
     68  now -= 1; // a one-second hop backwards is also unremarkable.
     69  update_current_time(now);
     70  tt_int_op(approx_time(), OP_EQ, now); // it changes the approx time...
     71  tt_int_op(get_uptime(), OP_EQ, 3); // but it doesn't roll back our uptime
     72 
     73 done:
     74  monotime_disable_test_mocking();
     75 }
     76 
     77 static void
     78 test_mainloop_update_time_jumps(void *arg)
     79 {
     80  (void)arg;
     81 
     82  monotime_enable_test_mocking();
     83  /* This is arbitrary */
     84  uint64_t mt_now = UINT64_C(7493289274986);
     85  /* This time is in the past as of when this test was written. */
     86  time_t now = 220897152;
     87  monotime_coarse_set_mock_time_nsec(mt_now);
     88  reset_uptime();
     89  update_current_time(now);
     90  tt_int_op(approx_time(), OP_EQ, now);
     91  tt_int_op(get_uptime(), OP_EQ, 0);
     92 
     93  /* Put some uptime on the clock.. */
     94  now += 3;
     95  mt_now += 3*BILLION;
     96  monotime_coarse_set_mock_time_nsec(mt_now);
     97  update_current_time(now);
     98  tt_int_op(approx_time(), OP_EQ, now);
     99  tt_int_op(get_uptime(), OP_EQ, 3);
    100 
    101  /* Now try jumping forward and backward, without updating the monotonic
    102   * clock.  */
    103  setup_capture_of_logs(LOG_NOTICE);
    104  now += 1800;
    105  update_current_time(now);
    106  expect_single_log_msg_containing(
    107               "Your system clock just jumped 1800 seconds forward");
    108  tt_int_op(approx_time(), OP_EQ, now);
    109  tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
    110  mock_clean_saved_logs();
    111 
    112  now -= 600;
    113  update_current_time(now);
    114  expect_single_log_msg_containing(
    115               "Your system clock just jumped 600 seconds backward");
    116  tt_int_op(approx_time(), OP_EQ, now);
    117  tt_int_op(get_uptime(), OP_EQ, 3); // no uptime change.
    118  mock_clean_saved_logs();
    119 
    120  /* uptime tracking should go normally now if the clock moves sensibly. */
    121  now += 2;
    122  mt_now += 2*BILLION;
    123  update_current_time(now);
    124  tt_int_op(approx_time(), OP_EQ, now);
    125  tt_int_op(get_uptime(), OP_EQ, 5);
    126 
    127  /* If we skip forward by a few minutes but the monotonic clock agrees,
    128   * we've just been idle: that counts as not worth warning about. */
    129  now += 1800;
    130  mt_now += 1800*BILLION;
    131  monotime_coarse_set_mock_time_nsec(mt_now);
    132  update_current_time(now);
    133  expect_no_log_entry();
    134  tt_int_op(approx_time(), OP_EQ, now);
    135  tt_int_op(get_uptime(), OP_EQ, 5); // this doesn't count to uptime, though.
    136 
    137  /* If we skip forward by a long time, even if the clock agrees, it's
    138   * idnless that counts. */
    139  now += 4000;
    140  mt_now += 4000*BILLION;
    141  monotime_coarse_set_mock_time_nsec(mt_now);
    142  update_current_time(now);
    143  expect_single_log_msg_containing("Tor has been idle for 4000 seconds");
    144  tt_int_op(approx_time(), OP_EQ, now);
    145  tt_int_op(get_uptime(), OP_EQ, 5);
    146 
    147 done:
    148  teardown_capture_of_logs();
    149  monotime_disable_test_mocking();
    150 }
    151 
    152 static int schedule_rescan_called = 0;
    153 static void
    154 mock_schedule_rescan_periodic_events(void)
    155 {
    156  ++schedule_rescan_called;
    157 }
    158 
    159 static void
    160 test_mainloop_user_activity(void *arg)
    161 {
    162  (void)arg;
    163  const time_t start = 1542658829;
    164  update_approx_time(start);
    165 
    166  MOCK(schedule_rescan_periodic_events, mock_schedule_rescan_periodic_events);
    167 
    168  reset_user_activity(start);
    169  tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
    170 
    171  set_network_participation(false);
    172 
    173  // reset can move backwards and forwards, but does not change network
    174  // participation.
    175  reset_user_activity(start-10);
    176  tt_i64_op(get_last_user_activity_time(), OP_EQ, start-10);
    177  reset_user_activity(start+10);
    178  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
    179 
    180  tt_int_op(schedule_rescan_called, OP_EQ, 0);
    181  tt_int_op(false, OP_EQ, is_participating_on_network());
    182 
    183  // "note" can only move forward.  Calling it from a non-participating
    184  // state makes us rescan the periodic callbacks and set participation.
    185  note_user_activity(start+20);
    186  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+20);
    187  tt_int_op(true, OP_EQ, is_participating_on_network());
    188  tt_int_op(schedule_rescan_called, OP_EQ, 1);
    189 
    190  // Calling it again will move us forward, but not call rescan again.
    191  note_user_activity(start+25);
    192  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
    193  tt_int_op(true, OP_EQ, is_participating_on_network());
    194  tt_int_op(schedule_rescan_called, OP_EQ, 1);
    195 
    196  // We won't move backwards.
    197  note_user_activity(start+20);
    198  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+25);
    199  tt_int_op(true, OP_EQ, is_participating_on_network());
    200  tt_int_op(schedule_rescan_called, OP_EQ, 1);
    201 
    202  // We _will_ adjust if the clock jumps though.
    203  netstatus_note_clock_jumped(500);
    204  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+525);
    205 
    206  netstatus_note_clock_jumped(-400);
    207  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+125);
    208 
    209 done:
    210  UNMOCK(schedule_rescan_periodic_events);
    211 }
    212 
    213 static unsigned int
    214 mock_get_num_services(void)
    215 {
    216  return 1;
    217 }
    218 
    219 static connection_t *
    220 mock_connection_gbtu(int type)
    221 {
    222  (void) type;
    223  return (void *)"hello fellow connections";
    224 }
    225 
    226 static void
    227 test_mainloop_check_participation(void *arg)
    228 {
    229  (void)arg;
    230  or_options_t *options = options_new();
    231  const time_t start = 1542658829;
    232  const time_t ONE_DAY = 24*60*60;
    233 
    234  options->DormantTimeoutEnabled = 1;
    235 
    236  // Suppose we've been idle for a day or two
    237  reset_user_activity(start - 2*ONE_DAY);
    238  set_network_participation(true);
    239  check_network_participation_callback(start, options);
    240  tt_int_op(is_participating_on_network(), OP_EQ, false);
    241  tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
    242 
    243  // suppose we've been idle for 2 days... but we are a server.
    244  reset_user_activity(start - 2*ONE_DAY);
    245  options->ORPort_set = 1;
    246  set_network_participation(true);
    247  check_network_participation_callback(start+2, options);
    248  tt_int_op(is_participating_on_network(), OP_EQ, true);
    249  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+2);
    250  options->ORPort_set = 0;
    251 
    252  // idle for 2 days, but we have a hidden service.
    253  reset_user_activity(start - 2*ONE_DAY);
    254  set_network_participation(true);
    255  MOCK(hs_service_get_num_services, mock_get_num_services);
    256  check_network_participation_callback(start+3, options);
    257  tt_int_op(is_participating_on_network(), OP_EQ, true);
    258  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+3);
    259  UNMOCK(hs_service_get_num_services);
    260 
    261  // idle for 2 days but we have at least one user connection
    262  MOCK(connection_get_by_type_nonlinked, mock_connection_gbtu);
    263  reset_user_activity(start - 2*ONE_DAY);
    264  set_network_participation(true);
    265  options->DormantTimeoutDisabledByIdleStreams = 1;
    266  check_network_participation_callback(start+10, options);
    267  tt_int_op(is_participating_on_network(), OP_EQ, true);
    268  tt_i64_op(get_last_user_activity_time(), OP_EQ, start+10);
    269 
    270  // as above, but DormantTimeoutDisabledByIdleStreams is not set
    271  reset_user_activity(start - 2*ONE_DAY);
    272  set_network_participation(true);
    273  options->DormantTimeoutDisabledByIdleStreams = 0;
    274  check_network_participation_callback(start+13, options);
    275  tt_int_op(is_participating_on_network(), OP_EQ, false);
    276  tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
    277  UNMOCK(connection_get_by_type_nonlinked);
    278  options->DormantTimeoutDisabledByIdleStreams = 1;
    279 
    280  // idle for 2 days but DormantClientTimeout is 3 days
    281  reset_user_activity(start - 2*ONE_DAY);
    282  set_network_participation(true);
    283  options->DormantClientTimeout = ONE_DAY * 3;
    284  check_network_participation_callback(start+30, options);
    285  tt_int_op(is_participating_on_network(), OP_EQ, true);
    286  tt_i64_op(get_last_user_activity_time(), OP_EQ, start-2*ONE_DAY);
    287 
    288 done:
    289  or_options_free(options);
    290  UNMOCK(hs_service_get_num_services);
    291  UNMOCK(connection_get_by_type_nonlinked);
    292 }
    293 
    294 static void
    295 test_mainloop_dormant_load_state(void *arg)
    296 {
    297  (void)arg;
    298  or_state_t *or_state = or_state_new();
    299  mainloop_state_t *state;
    300  {
    301    int idx = subsystems_get_state_idx(&sys_mainloop);
    302    tor_assert(idx >= 0);
    303    state = config_mgr_get_obj_mutable(get_state_mgr(), or_state, idx);
    304  }
    305  const time_t start = 1543956575;
    306 
    307  reset_user_activity(0);
    308  set_network_participation(false);
    309 
    310  // When we construct a new state, it starts out in "auto" mode.
    311  tt_int_op(state->Dormant, OP_EQ, -1);
    312 
    313  // Initializing from "auto" makes us start out (by default) non-Dormant,
    314  // with activity right now.
    315  netstatus_load_from_state(state, start);
    316  tt_assert(is_participating_on_network());
    317  tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
    318 
    319  // Initializing from dormant clears the last user activity time, and
    320  // makes us dormant.
    321  state->Dormant = 1;
    322  netstatus_load_from_state(state, start);
    323  tt_assert(! is_participating_on_network());
    324  tt_i64_op(get_last_user_activity_time(), OP_EQ, 0);
    325 
    326  // Initializing from non-dormant sets the last user activity time, and
    327  // makes us non-dormant.
    328  state->Dormant = 0;
    329  state->MinutesSinceUserActivity = 123;
    330  netstatus_load_from_state(state, start);
    331  tt_assert(is_participating_on_network());
    332  tt_i64_op(get_last_user_activity_time(), OP_EQ, start - 123*60);
    333 
    334  // If we would start dormant, but DormantCanceledByStartup is set, then
    335  // we start up non-dormant.
    336  state->Dormant = 1;
    337  get_options_mutable()->DormantCanceledByStartup = 1;
    338  netstatus_load_from_state(state, start);
    339  tt_assert(is_participating_on_network());
    340  tt_i64_op(get_last_user_activity_time(), OP_EQ, start);
    341 
    342 done:
    343  or_state_free(or_state);
    344 }
    345 
    346 static void
    347 test_mainloop_dormant_save_state(void *arg)
    348 {
    349  (void)arg;
    350  mainloop_state_t *state = tor_malloc_zero(sizeof(mainloop_state_t));
    351  const time_t start = 1543956575;
    352 
    353  // Can we save a non-dormant state correctly?
    354  reset_user_activity(start - 1000);
    355  set_network_participation(true);
    356  netstatus_flush_to_state(state, start);
    357 
    358  tt_int_op(state->Dormant, OP_EQ, 0);
    359  tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 1000 / 60);
    360 
    361  // Can we save a dormant state correctly?
    362  set_network_participation(false);
    363  netstatus_flush_to_state(state, start);
    364 
    365  tt_int_op(state->Dormant, OP_EQ, 1);
    366  tt_int_op(state->MinutesSinceUserActivity, OP_EQ, 0);
    367 
    368 done:
    369  tor_free(state);
    370 }
    371 
    372 #define MAINLOOP_TEST(name) \
    373  { #name, test_mainloop_## name , TT_FORK, NULL, NULL }
    374 
    375 struct testcase_t mainloop_tests[] = {
    376  MAINLOOP_TEST(update_time_normal),
    377  MAINLOOP_TEST(update_time_jumps),
    378  MAINLOOP_TEST(user_activity),
    379  MAINLOOP_TEST(check_participation),
    380  MAINLOOP_TEST(dormant_load_state),
    381  MAINLOOP_TEST(dormant_save_state),
    382  END_OF_TESTCASES
    383 };