diff options
Diffstat (limited to 'src/test/test_policy.c')
-rw-r--r-- | src/test/test_policy.c | 410 |
1 files changed, 398 insertions, 12 deletions
diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 37c36fed99..9ab3abe35a 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -2,8 +2,11 @@ /* See LICENSE for licensing information */ #include "or.h" +#define CONFIG_PRIVATE +#include "config.h" #include "router.h" #include "routerparse.h" +#define POLICIES_PRIVATE #include "policies.h" #include "test.h" @@ -49,7 +52,7 @@ test_policy_summary_helper(const char *policy_str, r = policies_parse_exit_policy(&line, &policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT, 0, NULL, 0); + EXIT_POLICY_ADD_DEFAULT, NULL); tt_int_op(r,OP_EQ, 0); summary = policy_summarize(policy, AF_INET); @@ -80,7 +83,8 @@ test_policies_general(void *arg) *policy7 = NULL, *policy8 = NULL, *policy9 = NULL, *policy10 = NULL, *policy11 = NULL, *policy12 = NULL; addr_policy_t *p; - tor_addr_t tar; + tor_addr_t tar, tar2; + smartlist_t *addr_list = NULL; config_line_t line; smartlist_t *sm = NULL; char *policy_str = NULL; @@ -115,17 +119,22 @@ test_policies_general(void *arg) tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy2, EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | - EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + EXIT_POLICY_ADD_DEFAULT, NULL)); tt_assert(policy2); - tor_addr_parse(&tar, "[2000::1234]"); + tor_addr_from_ipv4h(&tar, 0x0306090cu); + tor_addr_parse(&tar2, "[2000::1234]"); + addr_list = smartlist_new(); + smartlist_add(addr_list, &tar); + smartlist_add(addr_list, &tar2); tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy12, EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | EXIT_POLICY_ADD_DEFAULT, - 0x0306090cu, &tar, 1)); + addr_list)); + smartlist_free(addr_list); + addr_list = NULL; tt_assert(policy12); @@ -206,15 +215,15 @@ test_policies_general(void *arg) tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy8, EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | - EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + EXIT_POLICY_ADD_DEFAULT, + NULL)); tt_assert(policy8); tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy9, EXIT_POLICY_REJECT_PRIVATE | - EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + EXIT_POLICY_ADD_DEFAULT, + NULL)); tt_assert(policy9); @@ -268,8 +277,7 @@ test_policies_general(void *arg) line.next = NULL; tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + EXIT_POLICY_ADD_DEFAULT, NULL)); tt_assert(policy); //test_streq(policy->string, "accept *:80"); @@ -489,6 +497,245 @@ test_policies_general(void *arg) short_policy_free(short_parsed); } +/** Helper: Check that policy_list contains address */ +static int +test_policy_has_address_helper(const smartlist_t *policy_list, + const tor_addr_t *addr) +{ + int found = 0; + + tt_assert(policy_list); + tt_assert(addr); + + SMARTLIST_FOREACH_BEGIN(policy_list, addr_policy_t*, p) { + if (tor_addr_eq(&p->addr, addr)) { + found = 1; + } + } SMARTLIST_FOREACH_END(p); + + return found; + + done: + return 0; +} + +#define TEST_IPV4_ADDR (0x01020304) +#define TEST_IPV6_ADDR ("2002::abcd") + +/** Run unit tests for rejecting the configured addresses on this exit relay + * using policies_parse_exit_policy_reject_private */ +static void +test_policies_reject_exit_address(void *arg) +{ + smartlist_t *policy = NULL; + tor_addr_t ipv4_addr, ipv6_addr; + smartlist_t *ipv4_list, *ipv6_list, *both_list, *dupl_list; + (void)arg; + + tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR); + tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR); + + ipv4_list = smartlist_new(); + ipv6_list = smartlist_new(); + both_list = smartlist_new(); + dupl_list = smartlist_new(); + + smartlist_add(ipv4_list, &ipv4_addr); + smartlist_add(both_list, &ipv4_addr); + smartlist_add(dupl_list, &ipv4_addr); + smartlist_add(dupl_list, &ipv4_addr); + smartlist_add(dupl_list, &ipv4_addr); + + smartlist_add(ipv6_list, &ipv6_addr); + smartlist_add(both_list, &ipv6_addr); + smartlist_add(dupl_list, &ipv6_addr); + smartlist_add(dupl_list, &ipv6_addr); + + /* IPv4-Only Exits */ + + /* test that IPv4 addresses are rejected on an IPv4-only exit */ + policies_parse_exit_policy_reject_private(&policy, 0, ipv4_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 1); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* test that IPv6 addresses are NOT rejected on an IPv4-only exit + * (all IPv6 addresses are rejected by policies_parse_exit_policy_internal + * on IPv4-only exits, so policies_parse_exit_policy_reject_private doesn't + * need to do anything) */ + policies_parse_exit_policy_reject_private(&policy, 0, ipv6_list, 0, 0); + tt_assert(policy == NULL); + + /* test that only IPv4 addresses are rejected on an IPv4-only exit */ + policies_parse_exit_policy_reject_private(&policy, 0, both_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 1); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* Test that lists with duplicate entries produce the same results */ + policies_parse_exit_policy_reject_private(&policy, 0, dupl_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 1); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* IPv4/IPv6 Exits */ + + /* test that IPv4 addresses are rejected on an IPv4/IPv6 exit */ + policies_parse_exit_policy_reject_private(&policy, 1, ipv4_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 1); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* test that IPv6 addresses are rejected on an IPv4/IPv6 exit */ + policies_parse_exit_policy_reject_private(&policy, 1, ipv6_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 1); + tt_assert(test_policy_has_address_helper(policy, &ipv6_addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* test that IPv4 and IPv6 addresses are rejected on an IPv4/IPv6 exit */ + policies_parse_exit_policy_reject_private(&policy, 1, both_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 2); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); + tt_assert(test_policy_has_address_helper(policy, &ipv6_addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* Test that lists with duplicate entries produce the same results */ + policies_parse_exit_policy_reject_private(&policy, 1, dupl_list, 0, 0); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 2); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); + tt_assert(test_policy_has_address_helper(policy, &ipv6_addr)); + addr_policy_list_free(policy); + policy = NULL; + + done: + addr_policy_list_free(policy); + smartlist_free(ipv4_list); + smartlist_free(ipv6_list); + smartlist_free(both_list); + smartlist_free(dupl_list); +} + +static smartlist_t *test_configured_ports = NULL; +const smartlist_t *mock_get_configured_ports(void); + +/** Returns test_configured_ports */ +const smartlist_t * +mock_get_configured_ports(void) +{ + return test_configured_ports; +} + +/** Run unit tests for rejecting publicly routable configured port addresses + * on this exit relay using policies_parse_exit_policy_reject_private */ +static void +test_policies_reject_port_address(void *arg) +{ + smartlist_t *policy = NULL; + port_cfg_t *ipv4_port = NULL; + port_cfg_t *ipv6_port = NULL; + (void)arg; + + test_configured_ports = smartlist_new(); + + ipv4_port = port_cfg_new(0); + tor_addr_from_ipv4h(&ipv4_port->addr, TEST_IPV4_ADDR); + smartlist_add(test_configured_ports, ipv4_port); + + ipv6_port = port_cfg_new(0); + tor_addr_parse(&ipv6_port->addr, TEST_IPV6_ADDR); + smartlist_add(test_configured_ports, ipv6_port); + + MOCK(get_configured_ports, mock_get_configured_ports); + + /* test that an IPv4 port is rejected on an IPv4-only exit, but an IPv6 port + * is NOT rejected (all IPv6 addresses are rejected by + * policies_parse_exit_policy_internal on IPv4-only exits, so + * policies_parse_exit_policy_reject_private doesn't need to do anything + * with IPv6 addresses on IPv4-only exits) */ + policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 1); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 1); + tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr)); + addr_policy_list_free(policy); + policy = NULL; + + /* test that IPv4 and IPv6 ports are rejected on an IPv4/IPv6 exit */ + policies_parse_exit_policy_reject_private(&policy, 1, NULL, 0, 1); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 2); + tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr)); + tt_assert(test_policy_has_address_helper(policy, &ipv6_port->addr)); + addr_policy_list_free(policy); + policy = NULL; + +done: + addr_policy_list_free(policy); + if (test_configured_ports) { + SMARTLIST_FOREACH(test_configured_ports, + port_cfg_t *, p, port_cfg_free(p)); + smartlist_free(test_configured_ports); + test_configured_ports = NULL; + } + UNMOCK(get_configured_ports); +} + +#undef TEST_IPV4_ADDR +#undef TEST_IPV6_ADDR + +/** Run unit tests for rejecting publicly routable interface addresses on this + * exit relay using policies_parse_exit_policy_reject_private */ +static void +test_policies_reject_interface_address(void *arg) +{ + smartlist_t *policy = NULL; + smartlist_t *public_ipv4_addrs = + get_interface_address6_list(LOG_INFO, AF_INET, 0); + smartlist_t *public_ipv6_addrs = + get_interface_address6_list(LOG_INFO, AF_INET6, 0); + (void)arg; + + /* test that no addresses are rejected when none are supplied/requested */ + policies_parse_exit_policy_reject_private(&policy, 0, NULL, 0, 0); + tt_assert(policy == NULL); + + /* test that only IPv4 interface addresses are rejected on an IPv4-only exit + */ + policies_parse_exit_policy_reject_private(&policy, 0, NULL, 1, 0); + if (policy) { + tt_assert(smartlist_len(policy) == smartlist_len(public_ipv4_addrs)); + addr_policy_list_free(policy); + policy = NULL; + } + + /* test that IPv4 and IPv6 interface addresses are rejected on an IPv4/IPv6 + * exit */ + policies_parse_exit_policy_reject_private(&policy, 0, NULL, 1, 0); + if (policy) { + tt_assert(smartlist_len(policy) == (smartlist_len(public_ipv4_addrs) + + smartlist_len(public_ipv6_addrs))); + addr_policy_list_free(policy); + policy = NULL; + } + + done: + addr_policy_list_free(policy); + free_interface_address6_list(public_ipv4_addrs); + free_interface_address6_list(public_ipv6_addrs); +} + static void test_dump_exit_policy_to_string(void *arg) { @@ -578,10 +825,149 @@ test_dump_exit_policy_to_string(void *arg) tor_free(ep); } +static routerinfo_t *mock_desc_routerinfo = NULL; +const routerinfo_t *mock_router_get_my_routerinfo(void) +{ + return mock_desc_routerinfo; +} + +#define DEFAULT_POLICY_STRING "reject *:*" +#define TEST_IPV4_ADDR (0x02040608) +#define TEST_IPV6_ADDR ("2003::ef01") + +static or_options_t mock_options; + +static const or_options_t * +mock_get_options(void) +{ + return &mock_options; +} + +/** Run unit tests for generating summary lines of exit policies */ +static void +test_policies_getinfo_helper_policies(void *arg) +{ + (void)arg; + int rv = 0; + size_t ipv4_len = 0, ipv6_len = 0; + char *answer = NULL; + const char *errmsg = NULL; + routerinfo_t mock_my_routerinfo; + + rv = getinfo_helper_policies(NULL, "exit-policy/default", &answer, &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + tt_assert(strlen(answer) > 0); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/default", + &answer, &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + tt_assert(strlen(answer) > 0); + tor_free(answer); + + memset(&mock_my_routerinfo, 0, sizeof(routerinfo_t)); + MOCK(router_get_my_routerinfo, mock_router_get_my_routerinfo); + mock_my_routerinfo.exit_policy = smartlist_new(); + mock_desc_routerinfo = &mock_my_routerinfo; + + memset(&mock_options, 0, sizeof(or_options_t)); + MOCK(get_options, mock_get_options); + + rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay", + &answer, &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + tt_assert(strlen(answer) == 0); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/ipv4", &answer, + &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + ipv4_len = strlen(answer); + tt_assert(ipv4_len == 0 || ipv4_len == strlen(DEFAULT_POLICY_STRING)); + tt_assert(ipv4_len == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING)); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/ipv6", &answer, + &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + ipv6_len = strlen(answer); + tt_assert(ipv6_len == 0 || ipv6_len == strlen(DEFAULT_POLICY_STRING)); + tt_assert(ipv6_len == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING)); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/full", &answer, + &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + /* It's either empty or it's the default */ + tt_assert(strlen(answer) == 0 || !strcasecmp(answer, DEFAULT_POLICY_STRING)); + tor_free(answer); + + mock_my_routerinfo.addr = TEST_IPV4_ADDR; + tor_addr_parse(&mock_my_routerinfo.ipv6_addr, TEST_IPV6_ADDR); + append_exit_policy_string(&mock_my_routerinfo.exit_policy, "accept *4:*"); + append_exit_policy_string(&mock_my_routerinfo.exit_policy, "reject *6:*"); + + mock_options.IPv6Exit = 1; + tor_addr_from_ipv4h(&mock_options.OutboundBindAddressIPv4_, TEST_IPV4_ADDR); + tor_addr_parse(&mock_options.OutboundBindAddressIPv6_, TEST_IPV6_ADDR); + + rv = getinfo_helper_policies(NULL, "exit-policy/reject-private/relay", + &answer, &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + tt_assert(strlen(answer) > 0); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/ipv4", &answer, + &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + ipv4_len = strlen(answer); + tt_assert(ipv4_len > 0); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/ipv6", &answer, + &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + ipv6_len = strlen(answer); + tt_assert(ipv6_len > 0); + tor_free(answer); + + rv = getinfo_helper_policies(NULL, "exit-policy/full", &answer, + &errmsg); + tt_assert(rv == 0); + tt_assert(answer != NULL); + tt_assert(strlen(answer) > 0); + tt_assert(strlen(answer) == ipv4_len + ipv6_len + 1); + tor_free(answer); + +done: + tor_free(answer); + UNMOCK(get_options); + UNMOCK(router_get_my_routerinfo); + smartlist_free(mock_my_routerinfo.exit_policy); +} + +#undef DEFAULT_POLICY_STRING +#undef TEST_IPV4_ADDR +#undef TEST_IPV6_ADDR + struct testcase_t policy_tests[] = { { "router_dump_exit_policy_to_string", test_dump_exit_policy_to_string, 0, NULL, NULL }, { "general", test_policies_general, 0, NULL, NULL }, + { "getinfo_helper_policies", test_policies_getinfo_helper_policies, 0, NULL, + NULL }, + { "reject_exit_address", test_policies_reject_exit_address, 0, NULL, NULL }, + { "reject_interface_address", test_policies_reject_interface_address, 0, NULL, NULL }, + { "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL }, END_OF_TESTCASES }; |