diff options
author | Nick Mathewson <nickm@torproject.org> | 2016-02-11 12:20:20 -0500 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2016-02-11 12:20:20 -0500 |
commit | ba2be81fc36ba6140247873799b747605fb07bd4 (patch) | |
tree | bf63ac0c702babc4f467af10f4ae85620b3fb8e4 /src/test | |
parent | cae59b913f7daa154c6b1eb9083d1f582c8d2a1e (diff) | |
parent | c213f277cde00b258b159446f8d975026194c034 (diff) | |
download | tor-ba2be81fc36ba6140247873799b747605fb07bd4.tar.gz tor-ba2be81fc36ba6140247873799b747605fb07bd4.zip |
Merge remote-tracking branch 'teor/feature17840-v11-merged-v2'
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/test_entrynodes.c | 226 | ||||
-rw-r--r-- | src/test/test_policy.c | 536 | ||||
-rw-r--r-- | src/test/test_routerlist.c | 73 |
3 files changed, 830 insertions, 5 deletions
diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index 0011d3698a..fd19db095d 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -9,14 +9,16 @@ #include "or.h" #include "test.h" + +#include "config.h" #include "entrynodes.h" -#include "routerparse.h" #include "nodelist.h" -#include "util.h" +#include "policies.h" #include "routerlist.h" +#include "routerparse.h" #include "routerset.h" #include "statefile.h" -#include "config.h" +#include "util.h" #include "test_helpers.h" @@ -70,6 +72,14 @@ fake_network_setup(const struct testcase_t *testcase) return dummy_state; } +static or_options_t mocked_options; + +static const or_options_t * +mock_get_options(void) +{ + return &mocked_options; +} + /** Test choose_random_entry() with none of our routers being guard nodes. */ static void test_choose_random_entry_no_guards(void *arg) @@ -78,6 +88,14 @@ test_choose_random_entry_no_guards(void *arg) (void) arg; + MOCK(get_options, mock_get_options); + + /* Check that we get a guard if it passes preferred + * address settings */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientPreferIPv6ORPort = 0; + /* Try to pick an entry even though none of our routers are guards. */ chosen_entry = choose_random_entry(NULL); @@ -86,8 +104,55 @@ test_choose_random_entry_no_guards(void *arg) can't find a proper entry guard. */ tt_assert(chosen_entry); + /* And with the other IP version active */ + mocked_options.ClientUseIPv6 = 1; + chosen_entry = choose_random_entry(NULL); + tt_assert(chosen_entry); + + /* And with the preference on auto */ + mocked_options.ClientPreferIPv6ORPort = -1; + chosen_entry = choose_random_entry(NULL); + tt_assert(chosen_entry); + + /* Check that we don't get a guard if it doesn't pass mandatory address + * settings */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 0; + mocked_options.ClientPreferIPv6ORPort = 0; + + chosen_entry = choose_random_entry(NULL); + + /* If we don't allow IPv4 at all, we don't get a guard*/ + tt_assert(!chosen_entry); + + /* Check that we get a guard if it passes allowed but not preferred address + * settings */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientUseIPv6 = 1; + mocked_options.ClientPreferIPv6ORPort = 1; + + chosen_entry = choose_random_entry(NULL); + tt_assert(chosen_entry); + + /* Check that we get a guard if it passes preferred address settings when + * they're auto */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientPreferIPv6ORPort = -1; + + chosen_entry = choose_random_entry(NULL); + tt_assert(chosen_entry); + + /* And with IPv6 active */ + mocked_options.ClientUseIPv6 = 1; + + chosen_entry = choose_random_entry(NULL); + tt_assert(chosen_entry); + done: - ; + memset(&mocked_options, 0, sizeof(mocked_options)); + UNMOCK(get_options); } /** Test choose_random_entry() with only one of our routers being a @@ -101,17 +166,78 @@ test_choose_random_entry_one_possible_guard(void *arg) (void) arg; + MOCK(get_options, mock_get_options); + /* Set one of the nodes to be a guard. */ our_nodelist = nodelist_get_list(); the_guard = smartlist_get(our_nodelist, 4); /* chosen by fair dice roll */ the_guard->is_possible_guard = 1; + /* Check that we get the guard if it passes preferred + * address settings */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientPreferIPv6ORPort = 0; + /* Pick an entry. Make sure we pick the node we marked as guard. */ chosen_entry = choose_random_entry(NULL); tt_ptr_op(chosen_entry, OP_EQ, the_guard); + /* And with the other IP version active */ + mocked_options.ClientUseIPv6 = 1; + chosen_entry = choose_random_entry(NULL); + tt_ptr_op(chosen_entry, OP_EQ, the_guard); + + /* And with the preference on auto */ + mocked_options.ClientPreferIPv6ORPort = -1; + chosen_entry = choose_random_entry(NULL); + tt_ptr_op(chosen_entry, OP_EQ, the_guard); + + /* Check that we don't get a guard if it doesn't pass mandatory address + * settings */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 0; + mocked_options.ClientPreferIPv6ORPort = 0; + + chosen_entry = choose_random_entry(NULL); + + /* If we don't allow IPv4 at all, we don't get a guard*/ + tt_assert(!chosen_entry); + + /* Check that we get a node if it passes allowed but not preferred + * address settings */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientUseIPv6 = 1; + mocked_options.ClientPreferIPv6ORPort = 1; + + chosen_entry = choose_random_entry(NULL); + + /* We disable the guard check and the preferred address check at the same + * time, so we can't be sure we get the guard */ + tt_assert(chosen_entry); + + /* Check that we get a node if it is allowed but not preferred when settings + * are auto */ + memset(&mocked_options, 0, sizeof(mocked_options)); + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientPreferIPv6ORPort = -1; + + chosen_entry = choose_random_entry(NULL); + + /* We disable the guard check and the preferred address check at the same + * time, so we can't be sure we get the guard */ + tt_assert(chosen_entry); + + /* and with IPv6 active */ + mocked_options.ClientUseIPv6 = 1; + + chosen_entry = choose_random_entry(NULL); + tt_assert(chosen_entry); + done: - ; + memset(&mocked_options, 0, sizeof(mocked_options)); + UNMOCK(get_options); } /** Helper to conduct tests for populate_live_entry_guards(). @@ -624,6 +750,93 @@ test_entry_is_live(void *arg) ; /* XXX */ } +#define TEST_IPV4_ADDR "123.45.67.89" +#define TEST_IPV6_ADDR "[1234:5678:90ab:cdef::]" + +static void +test_node_preferred_orport(void *arg) +{ + (void)arg; + tor_addr_t ipv4_addr; + const uint16_t ipv4_port = 4444; + tor_addr_t ipv6_addr; + const uint16_t ipv6_port = 6666; + routerinfo_t node_ri; + node_t node; + tor_addr_port_t ap; + + /* Setup options */ + memset(&mocked_options, 0, sizeof(mocked_options)); + /* We don't test ClientPreferIPv6ORPort here, because it's used in + * nodelist_set_consensus to setup node.ipv6_preferred, which we set + * directly. */ + MOCK(get_options, mock_get_options); + + /* Setup IP addresses */ + tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR); + tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR); + + /* Setup node_ri */ + memset(&node_ri, 0, sizeof(node_ri)); + node_ri.addr = tor_addr_to_ipv4h(&ipv4_addr); + node_ri.or_port = ipv4_port; + tor_addr_copy(&node_ri.ipv6_addr, &ipv6_addr); + node_ri.ipv6_orport = ipv6_port; + + /* Setup node */ + memset(&node, 0, sizeof(node)); + node.ri = &node_ri; + + /* Check the preferred address is IPv4 if we're only using IPv4, regardless + * of whether we prefer it or not */ + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientUseIPv6 = 0; + node.ipv6_preferred = 0; + node_get_pref_orport(&node, &ap); + tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr)); + tt_assert(ap.port == ipv4_port); + + node.ipv6_preferred = 1; + node_get_pref_orport(&node, &ap); + tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr)); + tt_assert(ap.port == ipv4_port); + + /* Check the preferred address is IPv4 if we're using IPv4 and IPv6, but + * don't prefer the IPv6 address */ + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientUseIPv6 = 1; + node.ipv6_preferred = 0; + node_get_pref_orport(&node, &ap); + tt_assert(tor_addr_eq(&ap.addr, &ipv4_addr)); + tt_assert(ap.port == ipv4_port); + + /* Check the preferred address is IPv6 if we prefer it and + * ClientUseIPv6 is 1, regardless of ClientUseIPv4 */ + mocked_options.ClientUseIPv4 = 1; + mocked_options.ClientUseIPv6 = 1; + node.ipv6_preferred = 1; + node_get_pref_orport(&node, &ap); + tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr)); + tt_assert(ap.port == ipv6_port); + + mocked_options.ClientUseIPv4 = 0; + node_get_pref_orport(&node, &ap); + tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr)); + tt_assert(ap.port == ipv6_port); + + /* Check the preferred address is IPv6 if we don't prefer it, but + * ClientUseIPv4 is 0 */ + mocked_options.ClientUseIPv4 = 0; + mocked_options.ClientUseIPv6 = 1; + node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(&mocked_options); + node_get_pref_orport(&node, &ap); + tt_assert(tor_addr_eq(&ap.addr, &ipv6_addr)); + tt_assert(ap.port == ipv6_port); + + done: + UNMOCK(get_options); +} + static const struct testcase_setup_t fake_network = { fake_network_setup, fake_network_cleanup }; @@ -654,6 +867,9 @@ struct testcase_t entrynodes_tests[] = { { "entry_is_live", test_entry_is_live, TT_FORK, &fake_network, NULL }, + { "node_preferred_orport", + test_node_preferred_orport, + 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 794978fc42..c044d9f210 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1129,6 +1129,538 @@ test_policies_getinfo_helper_policies(void *arg) #undef TEST_IPV4_ADDR #undef TEST_IPV6_ADDR +#define TEST_IPV4_ADDR_STR "1.2.3.4" +#define TEST_IPV6_ADDR_STR "[1002::4567]" +#define REJECT_IPv4_FINAL_STR "reject 0.0.0.0/0:*" +#define REJECT_IPv6_FINAL_STR "reject [::]/0:*" + +#define OTHER_IPV4_ADDR_STR "6.7.8.9" +#define OTHER_IPV6_ADDR_STR "[afff::]" + +/** Run unit tests for fascist_firewall_allows_address */ +static void +test_policies_fascist_firewall_allows_address(void *arg) +{ + (void)arg; + tor_addr_t ipv4_addr, ipv6_addr, r_ipv4_addr, r_ipv6_addr; + tor_addr_t n_ipv4_addr, n_ipv6_addr; + const uint16_t port = 1234; + smartlist_t *policy = NULL; + smartlist_t *e_policy = NULL; + addr_policy_t *item = NULL; + int malformed_list = 0; + + /* Setup the options and the items in the policies */ + memset(&mock_options, 0, sizeof(or_options_t)); + MOCK(get_options, mock_get_options); + + policy = smartlist_new(); + item = router_parse_addr_policy_item_from_string("accept " + TEST_IPV4_ADDR_STR ":*", + ADDR_POLICY_ACCEPT, + &malformed_list); + tt_assert(item); + tt_assert(!malformed_list); + smartlist_add(policy, item); + item = router_parse_addr_policy_item_from_string("accept " + TEST_IPV6_ADDR_STR, + ADDR_POLICY_ACCEPT, + &malformed_list); + tt_assert(item); + tt_assert(!malformed_list); + smartlist_add(policy, item); + /* Normally, policy_expand_unspec would do this for us */ + item = router_parse_addr_policy_item_from_string(REJECT_IPv4_FINAL_STR, + ADDR_POLICY_ACCEPT, + &malformed_list); + tt_assert(item); + tt_assert(!malformed_list); + smartlist_add(policy, item); + item = router_parse_addr_policy_item_from_string(REJECT_IPv6_FINAL_STR, + ADDR_POLICY_ACCEPT, + &malformed_list); + tt_assert(item); + tt_assert(!malformed_list); + smartlist_add(policy, item); + item = NULL; + + e_policy = smartlist_new(); + + /* + char *polstr = policy_dump_to_string(policy, 1, 1); + printf("%s\n", polstr); + tor_free(polstr); + */ + + /* Parse the addresses */ + tor_addr_parse(&ipv4_addr, TEST_IPV4_ADDR_STR); + tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR_STR); + tor_addr_parse(&r_ipv4_addr, OTHER_IPV4_ADDR_STR); + tor_addr_parse(&r_ipv6_addr, OTHER_IPV6_ADDR_STR); + tor_addr_make_null(&n_ipv4_addr, AF_INET); + tor_addr_make_null(&n_ipv6_addr, AF_INET6); + + /* Test the function's address matching with IPv4 and IPv6 on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0) + == 0); + + /* Preferring IPv4 */ + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0) + == 0); + + /* Preferring IPv6 */ + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1) + == 0); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1) + == 0); + + /* Test the function's address matching with UseBridges on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 1; + + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0) + == 0); + + /* Preferring IPv4 */ + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 0) + == 0); + + /* Preferring IPv6 */ + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 1, 1) + == 0); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 1, 1) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 1, 1) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 1, 1) + == 0); + + /* bridge clients always use IPv6, regardless of ClientUseIPv6 */ + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 0; + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0) + == 0); + + /* Test the function's address matching with IPv4 on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 0; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0) + == 0); + + /* Test the function's address matching with IPv6 on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 0; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0) + == 0); + + /* Test the function's address matching with ClientUseIPv4 0. + * This means "use IPv6" regardless of the other settings. */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 0; + mock_options.ClientUseIPv6 = 0; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&r_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&r_ipv6_addr, port, policy, 0, 0) + == 0); + + /* Test the function's address matching for unusual inputs */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 1; + + /* NULL and tor_addr_is_null addresses are rejected */ + tt_assert(fascist_firewall_allows_address(NULL, port, policy, 0, 0) == 0); + tt_assert(fascist_firewall_allows_address(&n_ipv4_addr, port, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&n_ipv6_addr, port, policy, 0, 0) + == 0); + + /* zero ports are rejected */ + tt_assert(fascist_firewall_allows_address(&ipv4_addr, 0, policy, 0, 0) + == 0); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, 0, policy, 0, 0) + == 0); + + /* NULL and empty policies accept everything */ + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, NULL, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, NULL, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv4_addr, port, e_policy, 0, 0) + == 1); + tt_assert(fascist_firewall_allows_address(&ipv6_addr, port, e_policy, 0, 0) + == 1); + + done: + addr_policy_free(item); + addr_policy_list_free(policy); + addr_policy_list_free(e_policy); + UNMOCK(get_options); +} + +#undef REJECT_IPv4_FINAL_STR +#undef REJECT_IPv6_FINAL_STR +#undef OTHER_IPV4_ADDR_STR +#undef OTHER_IPV6_ADDR_STR + +#define TEST_IPV4_OR_PORT 1234 +#define TEST_IPV4_DIR_PORT 2345 +#define TEST_IPV6_OR_PORT 61234 +#define TEST_IPV6_DIR_PORT 62345 + +/** Run unit tests for fascist_firewall_choose_address */ +static void +test_policies_fascist_firewall_choose_address(void *arg) +{ + (void)arg; + tor_addr_port_t ipv4_or_ap, ipv4_dir_ap, ipv6_or_ap, ipv6_dir_ap; + tor_addr_port_t n_ipv4_ap, n_ipv6_ap; + + /* Setup the options */ + memset(&mock_options, 0, sizeof(or_options_t)); + MOCK(get_options, mock_get_options); + + /* Parse the addresses */ + tor_addr_parse(&ipv4_or_ap.addr, TEST_IPV4_ADDR_STR); + ipv4_or_ap.port = TEST_IPV4_OR_PORT; + tor_addr_parse(&ipv4_dir_ap.addr, TEST_IPV4_ADDR_STR); + ipv4_dir_ap.port = TEST_IPV4_DIR_PORT; + + tor_addr_parse(&ipv6_or_ap.addr, TEST_IPV6_ADDR_STR); + ipv6_or_ap.port = TEST_IPV6_OR_PORT; + tor_addr_parse(&ipv6_dir_ap.addr, TEST_IPV6_ADDR_STR); + ipv6_dir_ap.port = TEST_IPV6_DIR_PORT; + + tor_addr_make_null(&n_ipv4_ap.addr, AF_INET); + n_ipv4_ap.port = 0; + tor_addr_make_null(&n_ipv6_ap.addr, AF_INET6); + n_ipv6_ap.port = 0; + + /* Choose an address with IPv4 and IPv6 on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 0; + + /* Preferring IPv4 */ + mock_options.ClientPreferIPv6ORPort = 0; + mock_options.ClientPreferIPv6DirPort = 0; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Auto (Preferring IPv4) */ + mock_options.ClientPreferIPv6ORPort = -1; + mock_options.ClientPreferIPv6DirPort = -1; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Preferring IPv6 */ + mock_options.ClientPreferIPv6ORPort = 1; + mock_options.ClientPreferIPv6DirPort = 1; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv6_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv6_dir_ap); + + /* Preferring IPv4 OR / IPv6 Dir */ + mock_options.ClientPreferIPv6ORPort = 0; + mock_options.ClientPreferIPv6DirPort = 1; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv6_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv6_dir_ap); + + /* Preferring IPv6 OR / IPv4 Dir */ + mock_options.ClientPreferIPv6ORPort = 1; + mock_options.ClientPreferIPv6DirPort = 0; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Choose an address with UseBridges on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.UseBridges = 1; + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + + /* Preferring IPv4 */ + mock_options.ClientPreferIPv6ORPort = 0; + mock_options.ClientPreferIPv6DirPort = 0; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Auto: + * - bridge clients prefer the configured bridge OR address, + * - other clients prefer IPv4 OR by default, + * - all clients prefer IPv4 Dir by default. + */ + mock_options.ClientPreferIPv6ORPort = -1; + mock_options.ClientPreferIPv6DirPort = -1; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Preferring IPv6 */ + mock_options.ClientPreferIPv6ORPort = 1; + mock_options.ClientPreferIPv6DirPort = 1; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv6_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv6_dir_ap); + + + /* In the default configuration (Auto / IPv6 off), bridge clients should + * still use IPv6, and only prefer it for bridges configured with an IPv6 + * address, regardless of ClientUseIPv6. */ + mock_options.ClientUseIPv6 = 0; + mock_options.ClientPreferIPv6ORPort = -1; + mock_options.ClientPreferIPv6DirPort = -1; + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Choose an address with IPv4 on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 0; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv4_dir_ap); + + /* Choose an address with IPv6 on */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 0; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv6_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv6_dir_ap); + + /* Choose an address with ClientUseIPv4 0. + * This means "use IPv6" regardless of the other settings. */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 0; + mock_options.ClientUseIPv6 = 0; + mock_options.UseBridges = 0; + + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 1) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv6_dir_ap); + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 1) + == &ipv6_dir_ap); + + /* Choose from unusual inputs */ + memset(&mock_options, 0, sizeof(or_options_t)); + mock_options.ClientUseIPv4 = 1; + mock_options.ClientUseIPv6 = 1; + mock_options.UseBridges = 1; + + tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &n_ipv6_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv4_or_ap); + tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_or_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == &ipv6_or_ap); + tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0, + FIREWALL_OR_CONNECTION, 0) + == NULL); + + tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv4_dir_ap); + tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_dir_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == &ipv6_dir_ap); + tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0, + FIREWALL_DIR_CONNECTION, 0) + == NULL); + + done: + UNMOCK(get_options); +} + +#undef TEST_IPV4_ADDR_STR +#undef TEST_IPV6_ADDR_STR +#undef TEST_IPV4_OR_PORT +#undef TEST_IPV4_DIR_PORT +#undef TEST_IPV6_OR_PORT +#undef TEST_IPV6_DIR_PORT + struct testcase_t policy_tests[] = { { "router_dump_exit_policy_to_string", test_dump_exit_policy_to_string, 0, NULL, NULL }, @@ -1139,6 +1671,10 @@ struct testcase_t policy_tests[] = { { "reject_interface_address", test_policies_reject_interface_address, 0, NULL, NULL }, { "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL }, + { "fascist_firewall_allows_address", + test_policies_fascist_firewall_allows_address, 0, NULL, NULL }, + { "fascist_firewall_choose_address", + test_policies_fascist_firewall_choose_address, 0, NULL, NULL }, END_OF_TESTCASES }; diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 8c4254ccd7..fdbd5abf3b 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -11,6 +11,7 @@ #define TOR_UNIT_TESTING #include "or.h" #include "config.h" +#include "connection.h" #include "container.h" #include "directory.h" #include "dirvote.h" @@ -371,6 +372,77 @@ test_router_pick_directory_server_impl(void *arg) policies_free_all(); } +connection_t *mocked_connection = NULL; + +/* Mock connection_get_by_type_addr_port_purpose by returning + * mocked_connection. */ +static connection_t * +mock_connection_get_by_type_addr_port_purpose(int type, + const tor_addr_t *addr, + uint16_t port, int purpose) +{ + (void)type; + (void)addr; + (void)port; + (void)purpose; + + return mocked_connection; +} + +#define TEST_ADDR_STR "127.0.0.1" +#define TEST_DIR_PORT 12345 + +static void +test_routerlist_router_is_already_dir_fetching(void *arg) +{ + (void)arg; + tor_addr_port_t test_ap, null_addr_ap, zero_port_ap; + + /* Setup */ + tor_addr_parse(&test_ap.addr, TEST_ADDR_STR); + test_ap.port = TEST_DIR_PORT; + tor_addr_make_null(&null_addr_ap.addr, AF_INET6); + null_addr_ap.port = TEST_DIR_PORT; + tor_addr_parse(&zero_port_ap.addr, TEST_ADDR_STR); + zero_port_ap.port = 0; + MOCK(connection_get_by_type_addr_port_purpose, + mock_connection_get_by_type_addr_port_purpose); + + /* Test that we never get 1 from a NULL connection */ + mocked_connection = NULL; + tt_assert(router_is_already_dir_fetching(&test_ap, 1, 1) == 0); + tt_assert(router_is_already_dir_fetching(&test_ap, 1, 0) == 0); + tt_assert(router_is_already_dir_fetching(&test_ap, 0, 1) == 0); + /* We always expect 0 in these cases */ + tt_assert(router_is_already_dir_fetching(&test_ap, 0, 0) == 0); + tt_assert(router_is_already_dir_fetching(NULL, 1, 1) == 0); + tt_assert(router_is_already_dir_fetching(&null_addr_ap, 1, 1) == 0); + tt_assert(router_is_already_dir_fetching(&zero_port_ap, 1, 1) == 0); + + /* Test that we get 1 with a connection in the appropriate circumstances */ + mocked_connection = connection_new(CONN_TYPE_DIR, AF_INET); + tt_assert(router_is_already_dir_fetching(&test_ap, 1, 1) == 1); + tt_assert(router_is_already_dir_fetching(&test_ap, 1, 0) == 1); + tt_assert(router_is_already_dir_fetching(&test_ap, 0, 1) == 1); + + /* Test that we get 0 even with a connection in the appropriate + * circumstances */ + tt_assert(router_is_already_dir_fetching(&test_ap, 0, 0) == 0); + tt_assert(router_is_already_dir_fetching(NULL, 1, 1) == 0); + tt_assert(router_is_already_dir_fetching(&null_addr_ap, 1, 1) == 0); + tt_assert(router_is_already_dir_fetching(&zero_port_ap, 1, 1) == 0); + + done: + /* If a connection is never set up, connection_free chokes on it. */ + buf_free(mocked_connection->inbuf); + buf_free(mocked_connection->outbuf); + tor_free(mocked_connection); + UNMOCK(connection_get_by_type_addr_port_purpose); +} + +#undef TEST_ADDR_STR +#undef TEST_DIR_PORT + #define NODE(name, flags) \ { #name, test_routerlist_##name, (flags), NULL, NULL } #define ROUTER(name,flags) \ @@ -379,6 +451,7 @@ test_router_pick_directory_server_impl(void *arg) struct testcase_t routerlist_tests[] = { NODE(initiate_descriptor_downloads, 0), NODE(launch_descriptor_downloads, 0), + NODE(router_is_already_dir_fetching, TT_FORK), ROUTER(pick_directory_server_impl, TT_FORK), END_OF_TESTCASES }; |