From 0cb82013cceba8ade6ae83e983b609df3a848f72 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 6 May 2015 23:37:38 +1000 Subject: [PATCH 1/4] Fix TestingDirAuthVoteHSDir docs: HSDir flag needs DirPort Fix an error in the manual page and comments for TestingDirAuthVoteHSDir, 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). --- doc/tor.1.txt | 2 +- src/or/or.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 3a54957f8f..bc706e7156 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -2347,7 +2347,7 @@ The following options are used for running a testing Tor network. [[TestingDirAuthVoteHSDir]] **TestingDirAuthVoteHSDir** __node__,__node__,__...__:: A list of identity fingerprints and country codes and 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. + In order for this option to have any effect, **TestingTorNetwork** diff --git a/src/or/or.h b/src/or/or.h index f6aee13f5b..4a313515f4 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4100,7 +4100,7 @@ typedef struct { routerset_t *TestingDirAuthVoteGuard; /** Relays in a testing network which should be voted HSDir - * regardless of uptime and ORPort connectivity. + * regardless of uptime and DirPort. * Respects VoteOnHidServDirectoriesV2. */ routerset_t *TestingDirAuthVoteHSDir; From 359faf5e4b4a88663201c2b42dd89a6f77569856 Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 6 May 2015 23:40:23 +1000 Subject: [PATCH 2/4] New TestingDirAuthVote{Exit,Guard,HSDir}IsStrict flags "option to prevent guard,exit,hsdir flag assignment" "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". Patch modified by "teor": VoteOnHidServDirectoriesV2 is now obsolete, so TestingDirAuthVoteHSDir always votes on HSDirs. Closes ticket 14882. Patch by "robgjansen". Commit message and changes file by "teor" with quotes from "robgjansen". --- .../feature14882-TestingDirAuthVoteIsStrict | 18 +++++++++++++++ doc/tor.1.txt | 22 +++++++++++++++++++ src/or/config.c | 3 +++ src/or/dirserv.c | 6 +++++ src/or/or.h | 3 +++ 5 files changed, 52 insertions(+) create mode 100644 changes/feature14882-TestingDirAuthVoteIsStrict diff --git a/changes/feature14882-TestingDirAuthVoteIsStrict b/changes/feature14882-TestingDirAuthVoteIsStrict new file mode 100644 index 0000000000..62d513e27e --- /dev/null +++ b/changes/feature14882-TestingDirAuthVoteIsStrict @@ -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). diff --git a/doc/tor.1.txt b/doc/tor.1.txt index bc706e7156..af99570bd4 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -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 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__,__...__:: A list of identity fingerprints and country codes and address patterns of nodes to vote Guard for regardless of their @@ -2344,6 +2352,13 @@ The following options are used for running a testing Tor network. In order for this option to have any effect, **TestingTorNetwork** 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__,__...__:: A list of identity fingerprints and country codes and address patterns of nodes to vote HSDir for regardless of their @@ -2353,6 +2368,13 @@ The following options are used for running a testing Tor network. In order for this option to have any effect, **TestingTorNetwork** 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**:: If this option is set, then Tor controllers may register for CONN_BW events. Changing this requires that **TestingTorNetwork** is set. diff --git a/src/or/config.c b/src/or/config.c index 618c941fb4..c991bbc84f 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -479,8 +479,11 @@ static config_var_t option_vars_[] = { V(TestingMicrodescMaxDownloadTries, UINT, "8"), V(TestingCertMaxDownloadTries, UINT, "8"), V(TestingDirAuthVoteExit, ROUTERSET, NULL), + V(TestingDirAuthVoteExitIsStrict, BOOL, "0"), V(TestingDirAuthVoteGuard, ROUTERSET, NULL), + V(TestingDirAuthVoteGuardIsStrict, BOOL, "0"), V(TestingDirAuthVoteHSDir, ROUTERSET, NULL), + V(TestingDirAuthVoteHSDirIsStrict, BOOL, "0"), VAR("___UsingTestNetworkDefaults", BOOL, UsingTestNetworkDefaults_, "0"), { NULL, CONFIG_TYPE_OBSOLETE, 0, NULL } diff --git a/src/or/dirserv.c b/src/or/dirserv.c index 8eeba54374..f81d56ae10 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2195,16 +2195,22 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit, rs, 0)) { rs->is_exit = 1; + } else if (options->TestingDirAuthVoteExitIsStrict) { + rs->is_exit = 0; } if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, rs, 0)) { rs->is_possible_guard = 1; + } else if (options->TestingDirAuthVoteGuardIsStrict) { + rs->is_possible_guard = 0; } if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir, rs, 0)) { rs->is_hs_dir = 1; + } else if (options->TestingDirAuthVoteHSDirIsStrict) { + rs->is_hs_dir = 0; } } } diff --git a/src/or/or.h b/src/or/or.h index 4a313515f4..cf9f2b1414 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -4094,15 +4094,18 @@ typedef struct { /** Relays in a testing network which should be voted Exit * regardless of exit policy. */ routerset_t *TestingDirAuthVoteExit; + int TestingDirAuthVoteExitIsStrict; /** Relays in a testing network which should be voted Guard * regardless of uptime and bandwidth. */ routerset_t *TestingDirAuthVoteGuard; + int TestingDirAuthVoteGuardIsStrict; /** Relays in a testing network which should be voted HSDir * regardless of uptime and DirPort. * Respects VoteOnHidServDirectoriesV2. */ routerset_t *TestingDirAuthVoteHSDir; + int TestingDirAuthVoteHSDirIsStrict; /** Enable CONN_BW events. Only altered on testing networks. */ int TestingEnableConnBwEvent; From d1c94dcbea76d4ddd8ccf6c2c94f2fe99ea570e2 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 14 Aug 2015 12:09:00 +1000 Subject: [PATCH 3/4] Refactor TestingDirAuthVote* into dirserv_set_routerstatus_testing Make it easier to unit test TestingDirAuthVote{Exit,Guard,HSDir} by refactoring the code which sets flags based on them into a new function dirserv_set_routerstatus_testing. --- src/or/dirserv.c | 54 ++++++++++++++++++++++++++++-------------------- src/or/dirserv.h | 2 ++ 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/or/dirserv.c b/src/or/dirserv.c index f81d56ae10..58ab009cbf 100644 --- a/src/or/dirserv.c +++ b/src/or/dirserv.c @@ -2187,31 +2187,41 @@ set_routerstatus_from_routerinfo(routerstatus_t *rs, 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 (routerset_contains_routerstatus(options->TestingDirAuthVoteExit, - rs, 0)) { - rs->is_exit = 1; - } else if (options->TestingDirAuthVoteExitIsStrict) { - rs->is_exit = 0; - } + dirserv_set_routerstatus_testing(rs); + } +} - if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, - rs, 0)) { - rs->is_possible_guard = 1; - } else if (options->TestingDirAuthVoteGuardIsStrict) { - rs->is_possible_guard = 0; - } +/** 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(); - if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir, - rs, 0)) { - rs->is_hs_dir = 1; - } else if (options->TestingDirAuthVoteHSDirIsStrict) { - rs->is_hs_dir = 0; - } + tor_assert(options->TestingTorNetwork); + + if (routerset_contains_routerstatus(options->TestingDirAuthVoteExit, + rs, 0)) { + rs->is_exit = 1; + } else if (options->TestingDirAuthVoteExitIsStrict) { + rs->is_exit = 0; + } + + if (routerset_contains_routerstatus(options->TestingDirAuthVoteGuard, + rs, 0)) { + rs->is_possible_guard = 1; + } else if (options->TestingDirAuthVoteGuardIsStrict) { + rs->is_possible_guard = 0; + } + + if (routerset_contains_routerstatus(options->TestingDirAuthVoteHSDir, + rs, 0)) { + rs->is_hs_dir = 1; + } else if (options->TestingDirAuthVoteHSDirIsStrict) { + rs->is_hs_dir = 0; } } diff --git a/src/or/dirserv.h b/src/or/dirserv.h index 8a4e68dcf5..d07339bc12 100644 --- a/src/or/dirserv.h +++ b/src/or/dirserv.h @@ -109,6 +109,8 @@ int validate_recommended_package_line(const char *line); #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 */ #define MAX_MEASUREMENT_AGE (3*24*60*60) /* 3 days */ From 3acb27af3db084166c61e0b40f89deea299df420 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 18 Aug 2015 21:50:15 +1000 Subject: [PATCH 4/4] Add unit tests for dirserv_set_routerstatus_testing Test that TestingDirAuthVote{Exit,Guard,HSDir}[Strict] work on routersets matching all routers, one router, and no routers. TestingDirAuthVote{Exit,Guard,HSDir} set the corresponding flag on routerstatuses which match the routerset, but leave other flags unmodified. TestingDirAuthVote{Exit,Guard,HSDir}Strict clear the corresponding flag on routerstatuses which don't match the routerset. --- src/test/test_dir.c | 277 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) diff --git a/src/test/test_dir.c b/src/test/test_dir.c index 35bd8ea166..855746e749 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -24,6 +24,7 @@ #include "routerkeys.h" #include "routerlist.h" #include "routerparse.h" +#include "routerset.h" #include "test.h" #include "torcert.h" @@ -2979,6 +2980,281 @@ test_dir_fmt_control_ns(void *arg) 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 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_alt), DIR(fmt_control_ns, 0), + DIR(dirserv_set_routerstatus_testing, 0), DIR(http_handling, 0), DIR(purpose_needs_anonymity, 0), DIR(fetch_type, 0),