mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-14 07:03:44 +01:00
05d314f888
Implement the ability to set flags per events which influences the set up of the event. This commit only adds one flag which is "need network" meaning that the event is not enabled if tor has disabled the network or if hibernation mode. Signed-off-by: David Goulet <dgoulet@torproject.org>
261 lines
7.9 KiB
C
261 lines
7.9 KiB
C
/* Copyright (c) 2018, The Tor Project, Inc. */
|
|
/* See LICENSE for licensing information */
|
|
|
|
/**
|
|
* \file test_periodic_event.c
|
|
* \brief Test the periodic events that Tor uses for different roles. They are
|
|
* part of the libevent mainloop
|
|
*/
|
|
|
|
#define CONFIG_PRIVATE
|
|
#define HS_SERVICE_PRIVATE
|
|
#define MAIN_PRIVATE
|
|
|
|
#include "test.h"
|
|
#include "test_helpers.h"
|
|
|
|
#include "or.h"
|
|
#include "config.h"
|
|
#include "hibernate.h"
|
|
#include "hs_service.h"
|
|
#include "main.h"
|
|
#include "periodic.h"
|
|
|
|
/** Helper function: This is replaced in some tests for the event callbacks so
|
|
* we don't actually go into the code path of those callbacks. */
|
|
static int
|
|
dumb_event_fn(time_t now, const or_options_t *options)
|
|
{
|
|
(void) now;
|
|
(void) options;
|
|
|
|
/* Will get rescheduled in 300 seconds. It just can't be 0. */
|
|
return 300;
|
|
}
|
|
|
|
static void
|
|
register_dummy_hidden_service(hs_service_t *service)
|
|
{
|
|
memset(service, 0, sizeof(hs_service_t));
|
|
memset(&service->keys.identity_pk, 'A', sizeof(service->keys.identity_pk));
|
|
(void) register_service(get_hs_service_map(), service);
|
|
}
|
|
|
|
static void
|
|
test_pe_initialize(void *arg)
|
|
{
|
|
(void) arg;
|
|
|
|
/* Initialize the events but the callback won't get called since we would
|
|
* need to run the main loop and then wait for a second delaying the unit
|
|
* tests. Instead, we'll test the callback work indepedently elsewhere. */
|
|
initialize_periodic_events();
|
|
|
|
/* Validate that all events have been set up. */
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
tt_assert(item->ev);
|
|
tt_assert(item->fn);
|
|
tt_u64_op(item->last_action_time, OP_EQ, 0);
|
|
/* Every event must have role(s) assign to it. This is done statically. */
|
|
tt_u64_op(item->roles, OP_NE, 0);
|
|
tt_uint_op(periodic_event_is_enabled(item), OP_EQ, 0);
|
|
}
|
|
|
|
done:
|
|
teardown_periodic_events();
|
|
}
|
|
|
|
static void
|
|
test_pe_launch(void *arg)
|
|
{
|
|
hs_service_t service;
|
|
or_options_t *options;
|
|
|
|
(void) arg;
|
|
|
|
hs_init();
|
|
/* We need to put tor in hibernation live state so the events requiring
|
|
* network gets enabled. */
|
|
consider_hibernation(time(NULL));
|
|
|
|
/* Hack: We'll set a dumb fn() of each events so they don't get called when
|
|
* dispatching them. We just want to test the state of the callbacks, not
|
|
* the whole code path. */
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
item->fn = dumb_event_fn;
|
|
}
|
|
|
|
/* Lets make sure that before intialization, we can't scan the periodic
|
|
* events list and launch them. Lets try by being a Client. */
|
|
options = get_options_mutable();
|
|
options->SocksPort_set = 1;
|
|
periodic_events_on_new_options(options);
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
|
|
}
|
|
|
|
initialize_periodic_events();
|
|
|
|
/* Now that we've initialized, rescan the list to launch. */
|
|
periodic_events_on_new_options(options);
|
|
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
if (item->roles & PERIODIC_EVENT_ROLE_CLIENT) {
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
|
|
tt_u64_op(item->last_action_time, OP_NE, 0);
|
|
} else {
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
|
|
tt_u64_op(item->last_action_time, OP_EQ, 0);
|
|
}
|
|
}
|
|
|
|
/* Remove Client but become a Relay. */
|
|
options->SocksPort_set = 0;
|
|
options->ORPort_set = 1;
|
|
periodic_events_on_new_options(options);
|
|
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
/* Only Client role should be disabled. */
|
|
if (item->roles == PERIODIC_EVENT_ROLE_CLIENT) {
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
|
|
/* Was previously enabled so they should never be to 0. */
|
|
tt_u64_op(item->last_action_time, OP_NE, 0);
|
|
}
|
|
if (item->roles & PERIODIC_EVENT_ROLE_RELAY) {
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
|
|
tt_u64_op(item->last_action_time, OP_NE, 0);
|
|
}
|
|
/* Non Relay role should be disabled! */
|
|
if (!(item->roles & PERIODIC_EVENT_ROLE_RELAY)) {
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
|
|
}
|
|
}
|
|
|
|
/* Disable everything and we'll enable them ALL. */
|
|
options->SocksPort_set = 0;
|
|
options->ORPort_set = 0;
|
|
periodic_events_on_new_options(options);
|
|
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 0);
|
|
}
|
|
|
|
/* Enable everything. */
|
|
options->SocksPort_set = 1; options->ORPort_set = 1;
|
|
options->BridgeRelay = 1; options->AuthoritativeDir = 1;
|
|
options->V3AuthoritativeDir = 1; options->BridgeAuthoritativeDir = 1;
|
|
register_dummy_hidden_service(&service);
|
|
periodic_events_on_new_options(options);
|
|
/* Remove it now so the hs_free_all() doesn't try to free stack memory. */
|
|
remove_service(get_hs_service_map(), &service);
|
|
|
|
for (int i = 0; periodic_events[i].name; ++i) {
|
|
periodic_event_item_t *item = &periodic_events[i];
|
|
tt_int_op(periodic_event_is_enabled(item), OP_EQ, 1);
|
|
}
|
|
|
|
done:
|
|
hs_free_all();
|
|
}
|
|
|
|
static void
|
|
test_pe_get_roles(void *arg)
|
|
{
|
|
int roles;
|
|
|
|
(void) arg;
|
|
|
|
/* Just so the HS global map exists. */
|
|
hs_init();
|
|
|
|
or_options_t *options = get_options_mutable();
|
|
tt_assert(options);
|
|
|
|
/* Nothing configured, should be no roles. */
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ, 0);
|
|
|
|
/* Indicate we have a SocksPort, roles should be come Client. */
|
|
options->SocksPort_set = 1;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_CLIENT);
|
|
|
|
/* Now, we'll add a ORPort so should now be a Relay + Client. */
|
|
options->ORPort_set = 1;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ,
|
|
(PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY));
|
|
|
|
/* Now add a Bridge. */
|
|
options->BridgeRelay = 1;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ,
|
|
(PERIODIC_EVENT_ROLE_CLIENT | PERIODIC_EVENT_ROLE_RELAY |
|
|
PERIODIC_EVENT_ROLE_BRIDGE));
|
|
tt_assert(roles & PERIODIC_EVENT_ROLE_ROUTER);
|
|
/* Unset client so we can solely test Router role. */
|
|
options->SocksPort_set = 0;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_ROUTER);
|
|
|
|
/* Reset options so we can test authorities. */
|
|
options->SocksPort_set = 0;
|
|
options->ORPort_set = 0;
|
|
options->BridgeRelay = 0;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ, 0);
|
|
|
|
/* Now upgrade to Dirauth. */
|
|
options->AuthoritativeDir = 1;
|
|
options->V3AuthoritativeDir = 1;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_DIRAUTH);
|
|
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
|
|
|
|
/* Now Bridge Authority. */
|
|
options->V3AuthoritativeDir = 0;
|
|
options->BridgeAuthoritativeDir = 1;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ, PERIODIC_EVENT_ROLE_BRIDGEAUTH);
|
|
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
|
|
|
|
/* Move that bridge auth to become a relay. */
|
|
options->ORPort_set = 1;
|
|
roles = get_my_roles(options);
|
|
tt_int_op(roles, OP_EQ,
|
|
(PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY));
|
|
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
|
|
|
|
/* And now an Hidden service. */
|
|
hs_service_t service;
|
|
register_dummy_hidden_service(&service);
|
|
roles = get_my_roles(options);
|
|
/* Remove it now so the hs_free_all() doesn't try to free stack memory. */
|
|
remove_service(get_hs_service_map(), &service);
|
|
tt_int_op(roles, OP_EQ,
|
|
(PERIODIC_EVENT_ROLE_BRIDGEAUTH | PERIODIC_EVENT_ROLE_RELAY |
|
|
PERIODIC_EVENT_ROLE_HS_SERVICE));
|
|
tt_assert(roles & PERIODIC_EVENT_ROLE_AUTHORITIES);
|
|
|
|
done:
|
|
hs_free_all();
|
|
}
|
|
|
|
#define PE_TEST(name) \
|
|
{ #name, test_pe_## name , TT_FORK, NULL, NULL }
|
|
|
|
struct testcase_t periodic_event_tests[] = {
|
|
PE_TEST(initialize),
|
|
PE_TEST(launch),
|
|
PE_TEST(get_roles),
|
|
|
|
END_OF_TESTCASES
|
|
};
|
|
|