Merge remote-tracking branch 'teor/feature14882-TestingDirAuthVoteIsStrict-v3'

This commit is contained in:
Nick Mathewson 2015-08-18 09:53:50 -04:00
commit 2f5202c636
7 changed files with 359 additions and 18 deletions

View File

@ -0,0 +1,18 @@
o Minor features (testing, authorities):
- New TestingDirAuthVote{Exit,Guard,HSDir}IsStrict flags.
"A node will never receive the corresponding flag unless
that node is specified in the
TestingDirAuthVote{Exit,Guard,HSDir} list, regardless of
its uptime, bandwidth, exit policy, or DirPort".
Closes ticket 14882. Patch by "robgjansen", modified by
"teor" as VoteOnHidServDirectoriesV2 is now obsolete.
Commit message and changes file by "teor" & "robgjansen".
o Minor features (testing, authorities, documentation):
- Fix an error in the manual page and comments for
TestingDirAuthVoteHSDir[IsStrict], which suggested that a
HSDir required "ORPort connectivity". While this is true,
it is in no way unique to the HSDir flag. Of all the flags,
only HSDirs need a DirPort configured in order for the
authorities to assign that particular flag.
Fixed as part of 14882. Patch by "teor".
Bugfix on 0.2.6.3 (f9d57473e1ff on 10 January 2015).

View File

@ -2335,6 +2335,14 @@ The following options are used for running a testing Tor network.
has to be set. See the **ExcludeNodes** option for more has to be set. See the **ExcludeNodes** option for more
information on how to specify nodes. information on how to specify nodes.
[[TestingDirAuthVoteExitIsStrict]] **TestingDirAuthVoteExitIsStrict** **0**|**1** ::
If True (1), a node will never receive the Exit flag unless it is specified
in the **TestingDirAuthVoteExit** list, regardless of its uptime, bandwidth,
or exit policy.
+
In order for this option to have any effect, **TestingTorNetwork**
has to be set.
[[TestingDirAuthVoteGuard]] **TestingDirAuthVoteGuard** __node__,__node__,__...__:: [[TestingDirAuthVoteGuard]] **TestingDirAuthVoteGuard** __node__,__node__,__...__::
A list of identity fingerprints and country codes and A list of identity fingerprints and country codes and
address patterns of nodes to vote Guard for regardless of their address patterns of nodes to vote Guard for regardless of their
@ -2344,15 +2352,29 @@ The following options are used for running a testing Tor network.
In order for this option to have any effect, **TestingTorNetwork** In order for this option to have any effect, **TestingTorNetwork**
has to be set. has to be set.
[[TestingDirAuthVoteGuardIsStrict]] **TestingDirAuthVoteGuardIsStrict** **0**|**1** ::
If True (1), a node will never receive the Guard flag unless it is specified
in the **TestingDirAuthVoteGuard** list, regardless of its uptime and bandwidth.
+
In order for this option to have any effect, **TestingTorNetwork**
has to be set.
[[TestingDirAuthVoteHSDir]] **TestingDirAuthVoteHSDir** __node__,__node__,__...__:: [[TestingDirAuthVoteHSDir]] **TestingDirAuthVoteHSDir** __node__,__node__,__...__::
A list of identity fingerprints and country codes and A list of identity fingerprints and country codes and
address patterns of nodes to vote HSDir for regardless of their address patterns of nodes to vote HSDir for regardless of their
uptime and ORPort connectivity. See the **ExcludeNodes** option for more uptime and DirPort. See the **ExcludeNodes** option for more
information on how to specify nodes. information on how to specify nodes.
+ +
In order for this option to have any effect, **TestingTorNetwork** In order for this option to have any effect, **TestingTorNetwork**
and **VoteOnHidServDirectoriesV2** both have to be set. and **VoteOnHidServDirectoriesV2** both have to be set.
[[TestingDirAuthVoteHSDirIsStrict]] **TestingDirAuthVoteHSDirIsStrict** **0**|**1** ::
If True (1), a node will never receive the HSDir flag unless it is specified
in the **TestingDirAuthVoteHSDir** list, regardless of its uptime and DirPort.
+
In order for this option to have any effect, **TestingTorNetwork**
has to be set.
[[TestingEnableConnBwEvent]] **TestingEnableConnBwEvent** **0**|**1**:: [[TestingEnableConnBwEvent]] **TestingEnableConnBwEvent** **0**|**1**::
If this option is set, then Tor controllers may register for CONN_BW If this option is set, then Tor controllers may register for CONN_BW
events. Changing this requires that **TestingTorNetwork** is set. events. Changing this requires that **TestingTorNetwork** is set.

View File

@ -479,8 +479,11 @@ static config_var_t option_vars_[] = {
V(TestingMicrodescMaxDownloadTries, UINT, "8"), V(TestingMicrodescMaxDownloadTries, UINT, "8"),
V(TestingCertMaxDownloadTries, UINT, "8"), V(TestingCertMaxDownloadTries, UINT, "8"),
V(TestingDirAuthVoteExit, ROUTERSET, NULL), V(TestingDirAuthVoteExit, ROUTERSET, NULL),
V(TestingDirAuthVoteExitIsStrict, BOOL, "0"),
V(TestingDirAuthVoteGuard, ROUTERSET, NULL), V(TestingDirAuthVoteGuard, ROUTERSET, NULL),
V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"),
V(TestingDirAuthVoteHSDir, ROUTERSET, NULL), V(TestingDirAuthVoteHSDir, ROUTERSET, NULL),
V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"),
VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"), VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"),
{ NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL }

View File

@ -2187,25 +2187,41 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs,
rs->ipv6_orport = ri->ipv6_orport; rs->ipv6_orport = ri->ipv6_orport;
} }
/* Iff we are in a testing network, use TestingDirAuthVoteExit,
TestingDirAuthVoteGuard, and TestingDirAuthVoteHSDir to
give out the Exit, Guard, and HSDir flags, respectively.
But don't set the corresponding node flags. */
if (options->TestingTorNetwork) { if (options->TestingTorNetwork) {
dirserv_set_routerstatus_testing(rs);
}
}
/** Use TestingDirAuthVoteExit, TestingDirAuthVoteGuard, and
* TestingDirAuthVoteHSDir to give out the Exit, Guard, and HSDir flags,
* respectively. But don't set the corresponding node flags.
* Should only be called if TestingTorNetwork is set. */
STATIC void
dirserv_set_routerstatus_testing(routerstatus_t *rs)
{
const or_options_t *options = get_options();
tor_assert(options->TestingTorNetwork);
if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit, if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit,
rs, 0)) { rs, 0)) {
rs->is_exit = 1; rs->is_exit = 1;
} else if (options->TestingDirAuthVoteExitIsStrict) {
rs->is_exit = 0;
} }
if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard,
rs, 0)) { rs, 0)) {
rs->is_possible_guard = 1; rs->is_possible_guard = 1;
} else if (options->TestingDirAuthVoteGuardIsStrict) {
rs->is_possible_guard = 0;
} }
if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir, if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir,
rs, 0)) { rs, 0)) {
rs->is_hs_dir = 1; rs->is_hs_dir = 1;
} } else if (options->TestingDirAuthVoteHSDirIsStrict) {
rs->is_hs_dir = 0;
} }
} }

View File

@ -109,6 +109,8 @@ int validate_recommended_package_line(const char *line);
#ifdef DIRSERV_PRIVATE #ifdef DIRSERV_PRIVATE
STATIC void dirserv_set_routerstatus_testing(routerstatus_t *rs);
/* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */ /* Put the MAX_MEASUREMENT_AGE #define here so unit tests can see it */
#define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ #define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */

View File

@ -4094,15 +4094,18 @@ typedef struct {
/** Relays in a testing network which should be voted Exit /** Relays in a testing network which should be voted Exit
* regardless of exit policy. */ * regardless of exit policy. */
routerset_t *TestingDirAuthVoteExit; routerset_t *TestingDirAuthVoteExit;
int TestingDirAuthVoteExitIsStrict;
/** Relays in a testing network which should be voted Guard /** Relays in a testing network which should be voted Guard
* regardless of uptime and bandwidth. */ * regardless of uptime and bandwidth. */
routerset_t *TestingDirAuthVoteGuard; routerset_t *TestingDirAuthVoteGuard;
int TestingDirAuthVoteGuardIsStrict;
/** Relays in a testing network which should be voted HSDir /** Relays in a testing network which should be voted HSDir
* regardless of uptime and ORPort connectivity. * regardless of uptime and DirPort.
* Respects VoteOnHidServDirectoriesV2. */ * Respects VoteOnHidServDirectoriesV2. */
routerset_t *TestingDirAuthVoteHSDir; routerset_t *TestingDirAuthVoteHSDir;
int TestingDirAuthVoteHSDirIsStrict;
/** Enable CONN_BW events. Only altered on testing networks. */ /** Enable CONN_BW events. Only altered on testing networks. */
int TestingEnableConnBwEvent; int TestingEnableConnBwEvent;

View File

@ -24,6 +24,7 @@
#include "routerkeys.h" #include "routerkeys.h"
#include "routerlist.h" #include "routerlist.h"
#include "routerparse.h" #include "routerparse.h"
#include "routerset.h"
#include "test.h" #include "test.h"
#include "torcert.h" #include "torcert.h"
@ -2979,6 +2980,281 @@ test_dir_fmt_control_ns(void *arg)
tor_free(s); tor_free(s);
} }
static int mock_get_options_calls = 0;
static or_options_t *mock_options = NULL;
static void
reset_options(or_options_t *options, int *get_options_calls)
{
memset(options, 0, sizeof(or_options_t));
options->TestingTorNetwork = 1;
*get_options_calls = 0;
}
static const or_options_t *
mock_get_options(void)
{
++mock_get_options_calls;
tor_assert(mock_options);
return mock_options;
}
static void
reset_routerstatus(routerstatus_t *rs,
const char *hex_identity_digest,
int32_t ipv4_addr)
{
memset(rs, 0, sizeof(routerstatus_t));
base16_decode(rs->identity_digest, sizeof(rs->identity_digest),
hex_identity_digest, HEX_DIGEST_LEN);
/* A zero address matches everything, so the address needs to be set.
* But the specific value is irrelevant. */
rs->addr = ipv4_addr;
}
#define ROUTER_A_ID_STR "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
#define ROUTER_A_IPV4 0xAA008801
#define ROUTER_B_ID_STR "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
#define ROUTER_B_IPV4 0xBB008801
#define ROUTERSET_ALL_STR "*"
#define ROUTERSET_A_STR ROUTER_A_ID_STR
#define ROUTERSET_NONE_STR ""
/*
* Test that dirserv_set_routerstatus_testing sets router flags correctly
* Using "*" sets flags on A and B
* Using "A" sets flags on A
* Using "" sets flags on Neither
* If the router is not included:
* - if *Strict is set, the flag is set to 0,
* - otherwise, the flag is not modified. */
static void
test_dir_dirserv_set_routerstatus_testing(void *arg)
{
(void)arg;
/* Init options */
mock_options = malloc(sizeof(or_options_t));
reset_options(mock_options, &mock_get_options_calls);
MOCK(get_options, mock_get_options);
/* Init routersets */
routerset_t *routerset_all = routerset_new();
routerset_parse(routerset_all, ROUTERSET_ALL_STR, "All routers");
routerset_t *routerset_a = routerset_new();
routerset_parse(routerset_a, ROUTERSET_A_STR, "Router A only");
routerset_t *routerset_none = routerset_new();
/* Routersets are empty when provided by routerset_new(),
* so this is not strictly necessary */
routerset_parse(routerset_none, ROUTERSET_NONE_STR, "No routers");
/* Init routerstatuses */
routerstatus_t *rs_a = malloc(sizeof(routerstatus_t));
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
routerstatus_t *rs_b = malloc(sizeof(routerstatus_t));
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
/* Sanity check that routersets correspond to routerstatuses.
* Return values are {2, 3, 4} */
/* We want 3 ("*" means match all addresses) */
tt_assert(routerset_contains_routerstatus(routerset_all, rs_a, 0) == 3);
tt_assert(routerset_contains_routerstatus(routerset_all, rs_b, 0) == 3);
/* We want 4 (match id_digest [or nickname]) */
tt_assert(routerset_contains_routerstatus(routerset_a, rs_a, 0) == 4);
tt_assert(routerset_contains_routerstatus(routerset_a, rs_b, 0) == 0);
tt_assert(routerset_contains_routerstatus(routerset_none, rs_a, 0) == 0);
tt_assert(routerset_contains_routerstatus(routerset_none, rs_b, 0) == 0);
/* Check that "*" sets flags on all routers: Exit
* Check the flags aren't being confused with each other */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteExit = routerset_all;
mock_options->TestingDirAuthVoteExitIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
tt_assert(mock_get_options_calls == 1);
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 2);
tt_assert(rs_a->is_exit == 1);
tt_assert(rs_b->is_exit == 1);
/* Be paranoid - check no other flags are set */
tt_assert(rs_a->is_possible_guard == 0);
tt_assert(rs_b->is_possible_guard == 0);
tt_assert(rs_a->is_hs_dir == 0);
tt_assert(rs_b->is_hs_dir == 0);
/* Check that "*" sets flags on all routers: Guard & HSDir
* Cover the remaining flags in one test */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteGuard = routerset_all;
mock_options->TestingDirAuthVoteGuardIsStrict = 0;
mock_options->TestingDirAuthVoteHSDir = routerset_all;
mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
tt_assert(mock_get_options_calls == 1);
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 2);
tt_assert(rs_a->is_possible_guard == 1);
tt_assert(rs_b->is_possible_guard == 1);
tt_assert(rs_a->is_hs_dir == 1);
tt_assert(rs_b->is_hs_dir == 1);
/* Be paranoid - check exit isn't set */
tt_assert(rs_a->is_exit == 0);
tt_assert(rs_b->is_exit == 0);
/* Check routerset A sets all flags on router A,
* but leaves router B unmodified */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteExit = routerset_a;
mock_options->TestingDirAuthVoteExitIsStrict = 0;
mock_options->TestingDirAuthVoteGuard = routerset_a;
mock_options->TestingDirAuthVoteGuardIsStrict = 0;
mock_options->TestingDirAuthVoteHSDir = routerset_a;
mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
dirserv_set_routerstatus_testing(rs_a);
tt_assert(mock_get_options_calls == 1);
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 2);
tt_assert(rs_a->is_exit == 1);
tt_assert(rs_b->is_exit == 0);
tt_assert(rs_a->is_possible_guard == 1);
tt_assert(rs_b->is_possible_guard == 0);
tt_assert(rs_a->is_hs_dir == 1);
tt_assert(rs_b->is_hs_dir == 0);
/* Check routerset A unsets all flags on router B when Strict is set */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteExit = routerset_a;
mock_options->TestingDirAuthVoteExitIsStrict = 1;
mock_options->TestingDirAuthVoteGuard = routerset_a;
mock_options->TestingDirAuthVoteGuardIsStrict = 1;
mock_options->TestingDirAuthVoteHSDir = routerset_a;
mock_options->TestingDirAuthVoteHSDirIsStrict = 1;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 1);
tt_assert(rs_b->is_exit == 0);
tt_assert(rs_b->is_possible_guard == 0);
tt_assert(rs_b->is_hs_dir == 0);
/* Check routerset A doesn't modify flags on router B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteExit = routerset_a;
mock_options->TestingDirAuthVoteExitIsStrict = 0;
mock_options->TestingDirAuthVoteGuard = routerset_a;
mock_options->TestingDirAuthVoteGuardIsStrict = 0;
mock_options->TestingDirAuthVoteHSDir = routerset_a;
mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 1);
tt_assert(rs_b->is_exit == 1);
tt_assert(rs_b->is_possible_guard == 1);
tt_assert(rs_b->is_hs_dir == 1);
/* Check the empty routerset zeroes all flags
* on routers A & B with Strict set */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteExit = routerset_none;
mock_options->TestingDirAuthVoteExitIsStrict = 1;
mock_options->TestingDirAuthVoteGuard = routerset_none;
mock_options->TestingDirAuthVoteGuardIsStrict = 1;
mock_options->TestingDirAuthVoteHSDir = routerset_none;
mock_options->TestingDirAuthVoteHSDirIsStrict = 1;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 1);
tt_assert(rs_b->is_exit == 0);
tt_assert(rs_b->is_possible_guard == 0);
tt_assert(rs_b->is_hs_dir == 0);
/* Check the empty routerset doesn't modify any flags
* on A or B without Strict set */
reset_options(mock_options, &mock_get_options_calls);
reset_routerstatus(rs_a, ROUTER_A_ID_STR, ROUTER_A_IPV4);
reset_routerstatus(rs_b, ROUTER_B_ID_STR, ROUTER_B_IPV4);
mock_options->TestingDirAuthVoteExit = routerset_none;
mock_options->TestingDirAuthVoteExitIsStrict = 0;
mock_options->TestingDirAuthVoteGuard = routerset_none;
mock_options->TestingDirAuthVoteGuardIsStrict = 0;
mock_options->TestingDirAuthVoteHSDir = routerset_none;
mock_options->TestingDirAuthVoteHSDirIsStrict = 0;
rs_b->is_exit = 1;
rs_b->is_possible_guard = 1;
rs_b->is_hs_dir = 1;
dirserv_set_routerstatus_testing(rs_a);
tt_assert(mock_get_options_calls == 1);
dirserv_set_routerstatus_testing(rs_b);
tt_assert(mock_get_options_calls == 2);
tt_assert(rs_a->is_exit == 0);
tt_assert(rs_a->is_possible_guard == 0);
tt_assert(rs_a->is_hs_dir == 0);
tt_assert(rs_b->is_exit == 1);
tt_assert(rs_b->is_possible_guard == 1);
tt_assert(rs_b->is_hs_dir == 1);
done:
free(mock_options);
mock_options = NULL;
UNMOCK(get_options);
routerset_free(routerset_all);
routerset_free(routerset_a);
routerset_free(routerset_none);
free(rs_a);
free(rs_b);
}
static void static void
test_dir_http_handling(void *args) test_dir_http_handling(void *args)
{ {
@ -3244,6 +3520,7 @@ struct testcase_t dir_tests[] = {
DIR_LEGACY(clip_unmeasured_bw_kb), DIR_LEGACY(clip_unmeasured_bw_kb),
DIR_LEGACY(clip_unmeasured_bw_kb_alt), DIR_LEGACY(clip_unmeasured_bw_kb_alt),
DIR(fmt_control_ns, 0), DIR(fmt_control_ns, 0),
DIR(dirserv_set_routerstatus_testing, 0),
DIR(http_handling, 0), DIR(http_handling, 0),
DIR(purpose_needs_anonymity, 0), DIR(purpose_needs_anonymity, 0),
DIR(fetch_type, 0), DIR(fetch_type, 0),