|
@@ -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),
|