aboutsummaryrefslogtreecommitdiff
path: root/src/test/test_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/test_policy.c')
-rw-r--r--src/test/test_policy.c1589
1 files changed, 1501 insertions, 88 deletions
diff --git a/src/test/test_policy.c b/src/test/test_policy.c
index 4cdcd034bb..a939ebf54f 100644
--- a/src/test/test_policy.c
+++ b/src/test/test_policy.c
@@ -1,9 +1,12 @@
-/* Copyright (c) 2013, The Tor Project, Inc. */
+/* Copyright (c) 2013-2016, The Tor Project, Inc. */
/* 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"
@@ -22,7 +25,7 @@ test_short_policy_parse(const char *input,
short_policy = parse_short_policy(input);
tt_assert(short_policy);
out = write_short_policy(short_policy);
- tt_str_op(out, ==, expected);
+ tt_str_op(out, OP_EQ, expected);
done:
tor_free(out);
@@ -47,17 +50,20 @@ test_policy_summary_helper(const char *policy_str,
line.value = (char *)policy_str;
line.next = NULL;
- r = policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1);
- test_eq(r, 0);
+ r = policies_parse_exit_policy(&line, &policy,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_ADD_DEFAULT, NULL);
+ tt_int_op(r,OP_EQ, 0);
+
summary = policy_summarize(policy, AF_INET);
- test_assert(summary != NULL);
- test_streq(summary, expected_summary);
+ tt_assert(summary != NULL);
+ tt_str_op(summary,OP_EQ, expected_summary);
short_policy = parse_short_policy(summary);
tt_assert(short_policy);
summary_after = write_short_policy(short_policy);
- test_streq(summary, summary_after);
+ tt_str_op(summary,OP_EQ, summary_after);
done:
tor_free(summary_after);
@@ -74,130 +80,296 @@ test_policies_general(void *arg)
int i;
smartlist_t *policy = NULL, *policy2 = NULL, *policy3 = NULL,
*policy4 = NULL, *policy5 = NULL, *policy6 = NULL,
- *policy7 = NULL;
+ *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;
short_policy_t *short_parsed = NULL;
+ int malformed_list = -1;
(void)arg;
policy = smartlist_new();
- p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
- test_assert(p != NULL);
- test_eq(ADDR_POLICY_REJECT, p->policy_type);
+ p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
+ tt_int_op(ADDR_POLICY_REJECT,OP_EQ, p->policy_type);
tor_addr_from_ipv4h(&tar, 0xc0a80000u);
- test_eq(0, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
- test_eq(16, p->maskbits);
- test_eq(1, p->prt_min);
- test_eq(65535, p->prt_max);
+ tt_int_op(0,OP_EQ, tor_addr_compare(&p->addr, &tar, CMP_EXACT));
+ tt_int_op(16,OP_EQ, p->maskbits);
+ tt_int_op(1,OP_EQ, p->prt_min);
+ tt_int_op(65535,OP_EQ, p->prt_max);
smartlist_add(policy, p);
tor_addr_from_ipv4h(&tar, 0x01020304u);
- test_assert(ADDR_POLICY_ACCEPTED ==
+ tt_assert(ADDR_POLICY_ACCEPTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
tor_addr_make_unspec(&tar);
- test_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
+ tt_assert(ADDR_POLICY_PROBABLY_ACCEPTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
tor_addr_from_ipv4h(&tar, 0xc0a80102);
- test_assert(ADDR_POLICY_REJECTED ==
+ tt_assert(ADDR_POLICY_REJECTED ==
compare_tor_addr_to_addr_policy(&tar, 2, policy));
- test_assert(0 == policies_parse_exit_policy(NULL, &policy2, 1, 1, 0, 1));
- test_assert(policy2);
+ tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy2,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_REJECT_PRIVATE |
+ EXIT_POLICY_ADD_DEFAULT, NULL));
+
+ tt_assert(policy2);
+
+ 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,
+ addr_list));
+ smartlist_free(addr_list);
+ addr_list = NULL;
+
+ tt_assert(policy12);
policy3 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("reject *:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject *:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy3, p);
- p = router_parse_addr_policy_item_from_string("accept *:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("accept *:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy3, p);
policy4 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("accept *:443",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("accept *:443", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy4, p);
- p = router_parse_addr_policy_item_from_string("accept *:443",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("accept *:443", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy4, p);
policy5 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 0.0.0.0/8:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 169.254.0.0/16:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 127.0.0.0/8:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 192.168.0.0/16:*",
+ -1, &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 10.0.0.0/8:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 172.16.0.0/12:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject 80.190.250.90:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject *:1-65534",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject *:1-65534", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("reject *:65535",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("reject *:65535", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
- p = router_parse_addr_policy_item_from_string("accept *:1-65535",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("accept *:1-65535", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy5, p);
policy6 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("accept 43.3.0.0/9:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy6, p);
policy7 = smartlist_new();
- p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*",-1);
- test_assert(p != NULL);
+ p = router_parse_addr_policy_item_from_string("accept 0.0.0.0/8:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
smartlist_add(policy7, p);
- test_assert(!exit_policy_is_general_exit(policy));
- test_assert(exit_policy_is_general_exit(policy2));
- test_assert(!exit_policy_is_general_exit(NULL));
- test_assert(!exit_policy_is_general_exit(policy3));
- test_assert(!exit_policy_is_general_exit(policy4));
- test_assert(!exit_policy_is_general_exit(policy5));
- test_assert(!exit_policy_is_general_exit(policy6));
- test_assert(!exit_policy_is_general_exit(policy7));
-
- test_assert(cmp_addr_policies(policy, policy2));
- test_assert(cmp_addr_policies(policy, NULL));
- test_assert(!cmp_addr_policies(policy2, policy2));
- test_assert(!cmp_addr_policies(NULL, NULL));
-
- test_assert(!policy_is_reject_star(policy2, AF_INET));
- test_assert(policy_is_reject_star(policy, AF_INET));
- test_assert(policy_is_reject_star(NULL, AF_INET));
+ tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy8,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_REJECT_PRIVATE |
+ 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,
+ NULL));
+
+ tt_assert(policy9);
+
+ /* accept6 * and reject6 * produce IPv6 wildcards only */
+ policy10 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("accept6 *:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
+ smartlist_add(policy10, p);
+
+ policy11 = smartlist_new();
+ p = router_parse_addr_policy_item_from_string("reject6 *:*", -1,
+ &malformed_list);
+ tt_assert(p != NULL);
+ smartlist_add(policy11, p);
+
+ tt_assert(!exit_policy_is_general_exit(policy));
+ tt_assert(exit_policy_is_general_exit(policy2));
+ tt_assert(!exit_policy_is_general_exit(NULL));
+ tt_assert(!exit_policy_is_general_exit(policy3));
+ tt_assert(!exit_policy_is_general_exit(policy4));
+ tt_assert(!exit_policy_is_general_exit(policy5));
+ tt_assert(!exit_policy_is_general_exit(policy6));
+ tt_assert(!exit_policy_is_general_exit(policy7));
+ tt_assert(exit_policy_is_general_exit(policy8));
+ tt_assert(exit_policy_is_general_exit(policy9));
+ tt_assert(!exit_policy_is_general_exit(policy10));
+ tt_assert(!exit_policy_is_general_exit(policy11));
+
+ tt_assert(cmp_addr_policies(policy, policy2));
+ tt_assert(cmp_addr_policies(policy, NULL));
+ tt_assert(!cmp_addr_policies(policy2, policy2));
+ tt_assert(!cmp_addr_policies(NULL, NULL));
+
+ tt_assert(!policy_is_reject_star(policy2, AF_INET));
+ tt_assert(policy_is_reject_star(policy, AF_INET));
+ tt_assert(policy_is_reject_star(policy10, AF_INET));
+ tt_assert(!policy_is_reject_star(policy10, AF_INET6));
+ tt_assert(policy_is_reject_star(policy11, AF_INET));
+ tt_assert(policy_is_reject_star(policy11, AF_INET6));
+ tt_assert(policy_is_reject_star(NULL, AF_INET));
+ tt_assert(policy_is_reject_star(NULL, AF_INET6));
addr_policy_list_free(policy);
policy = NULL;
+ /* make sure assume_action works */
+ malformed_list = 0;
+ p = router_parse_addr_policy_item_from_string("127.0.0.1",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("127.0.0.1:*",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("[::]",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("[::]:*",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("[face::b]",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("[b::aaaa]",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("*",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("*4",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("*6",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(p);
+ addr_policy_free(p);
+ tt_assert(!malformed_list);
+
+ /* These are all ambiguous IPv6 addresses, it's good that we reject them */
+ p = router_parse_addr_policy_item_from_string("acce::abcd",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(!p);
+ tt_assert(malformed_list);
+ malformed_list = 0;
+
+ p = router_parse_addr_policy_item_from_string("7:1234",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(!p);
+ tt_assert(malformed_list);
+ malformed_list = 0;
+
+ p = router_parse_addr_policy_item_from_string("::",
+ ADDR_POLICY_ACCEPT,
+ &malformed_list);
+ tt_assert(!p);
+ tt_assert(malformed_list);
+ malformed_list = 0;
+
/* make sure compacting logic works. */
policy = NULL;
line.key = (char*)"foo";
line.value = (char*)"accept *:80,reject private:*,reject *:*";
line.next = NULL;
- test_assert(0 == policies_parse_exit_policy(&line, &policy, 1, 0, 0, 1));
- test_assert(policy);
+ tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy,
+ EXIT_POLICY_IPV6_ENABLED |
+ EXIT_POLICY_ADD_DEFAULT, NULL));
+ tt_assert(policy);
+
//test_streq(policy->string, "accept *:80");
//test_streq(policy->next->string, "reject *:*");
- test_eq(smartlist_len(policy), 4);
+ tt_int_op(smartlist_len(policy),OP_EQ, 4);
/* test policy summaries */
/* check if we properly ignore private IP addresses */
@@ -271,7 +443,7 @@ test_policies_general(void *arg)
/* Try parsing various broken short policies */
#define TT_BAD_SHORT_POLICY(s) \
do { \
- tt_ptr_op(NULL, ==, (short_parsed = parse_short_policy((s)))); \
+ tt_ptr_op(NULL, OP_EQ, (short_parsed = parse_short_policy((s)))); \
} while (0)
TT_BAD_SHORT_POLICY("accept 200-199");
TT_BAD_SHORT_POLICY("");
@@ -287,6 +459,68 @@ test_policies_general(void *arg)
TT_BAD_SHORT_POLICY("accept 1-,3");
TT_BAD_SHORT_POLICY("accept 1-,3");
+ /* Make sure that IPv4 addresses are ignored in accept6/reject6 lines. */
+ p = router_parse_addr_policy_item_from_string("accept6 1.2.3.4:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("reject6 2.4.6.0/24:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(!malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("accept6 *4:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(!malformed_list);
+
+ /* Make sure malformed policies are detected as such. */
+ p = router_parse_addr_policy_item_from_string("bad_token *4:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("accept6 **:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("accept */15:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("reject6 */:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("accept 127.0.0.1/33:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("accept6 [::1]/129:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("reject 8.8.8.8/-1:*", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("reject 8.8.4.4:10-5", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
+ p = router_parse_addr_policy_item_from_string("reject 1.2.3.4:-1", -1,
+ &malformed_list);
+ tt_assert(p == NULL);
+ tt_assert(malformed_list);
+
/* Test a too-long policy. */
{
int i;
@@ -301,7 +535,7 @@ test_policies_general(void *arg)
smartlist_free(chunks);
short_parsed = parse_short_policy(policy);/* shouldn't be accepted */
tor_free(policy);
- tt_ptr_op(NULL, ==, short_parsed);
+ tt_ptr_op(NULL, OP_EQ, short_parsed);
}
/* truncation ports */
@@ -337,6 +571,11 @@ test_policies_general(void *arg)
addr_policy_list_free(policy5);
addr_policy_list_free(policy6);
addr_policy_list_free(policy7);
+ addr_policy_list_free(policy8);
+ addr_policy_list_free(policy9);
+ addr_policy_list_free(policy10);
+ addr_policy_list_free(policy11);
+ addr_policy_list_free(policy12);
tor_free(policy_str);
if (sm) {
SMARTLIST_FOREACH(sm, char *, s, tor_free(s));
@@ -345,11 +584,329 @@ 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;
+
+/** Returns test_configured_ports */
+static 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);
+}
+
+smartlist_t *mock_ipv4_addrs = NULL;
+smartlist_t *mock_ipv6_addrs = NULL;
+
+/* mock get_interface_address6_list, returning a deep copy of the template
+ * address list ipv4_interface_address_list or ipv6_interface_address_list */
+static smartlist_t *
+mock_get_interface_address6_list(int severity,
+ sa_family_t family,
+ int include_internal)
+{
+ (void)severity;
+ (void)include_internal;
+ smartlist_t *clone_list = smartlist_new();
+ smartlist_t *template_list = NULL;
+
+ if (family == AF_INET) {
+ template_list = mock_ipv4_addrs;
+ } else if (family == AF_INET6) {
+ template_list = mock_ipv6_addrs;
+ } else {
+ return NULL;
+ }
+
+ tt_assert(template_list);
+
+ SMARTLIST_FOREACH_BEGIN(template_list, tor_addr_t *, src_addr) {
+ tor_addr_t *dest_addr = malloc(sizeof(tor_addr_t));
+ memset(dest_addr, 0, sizeof(*dest_addr));
+ tor_addr_copy_tight(dest_addr, src_addr);
+ smartlist_add(clone_list, dest_addr);
+ } SMARTLIST_FOREACH_END(src_addr);
+
+ return clone_list;
+
+ done:
+ free_interface_address6_list(clone_list);
+ return NULL;
+}
+
+/** 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);
+ tor_addr_t ipv4_addr, ipv6_addr;
+ (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
+ * (and allow for duplicates)
+ */
+ 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 (and allow for duplicates) */
+ policies_parse_exit_policy_reject_private(&policy, 1, 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;
+ }
+
+ /* Now do it all again, but mocked */
+ tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR);
+ mock_ipv4_addrs = smartlist_new();
+ smartlist_add(mock_ipv4_addrs, (void *)&ipv4_addr);
+
+ tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR);
+ mock_ipv6_addrs = smartlist_new();
+ smartlist_add(mock_ipv6_addrs, (void *)&ipv6_addr);
+
+ MOCK(get_interface_address6_list, mock_get_interface_address6_list);
+
+ /* 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);
+ tt_assert(policy);
+ tt_assert(smartlist_len(policy) == smartlist_len(mock_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, 1, NULL, 1, 0);
+ tt_assert(policy);
+ tt_assert(smartlist_len(policy) == (smartlist_len(mock_ipv4_addrs)
+ + smartlist_len(mock_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);
+
+ UNMOCK(get_interface_address6_list);
+ /* we don't use free_interface_address6_list on these lists because their
+ * address pointers are stack-based */
+ smartlist_free(mock_ipv4_addrs);
+ smartlist_free(mock_ipv6_addrs);
+}
+
+#undef TEST_IPV4_ADDR
+#undef TEST_IPV6_ADDR
+
static void
test_dump_exit_policy_to_string(void *arg)
{
char *ep;
addr_policy_t *policy_entry;
+ int malformed_list = -1;
routerinfo_t *ri = tor_malloc_zero(sizeof(routerinfo_t));
@@ -359,63 +916,68 @@ test_dump_exit_policy_to_string(void *arg)
ri->exit_policy = NULL; // expecting "reject *:*"
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("reject *:*",ep);
+ tt_str_op("reject *:*",OP_EQ, ep);
tor_free(ep);
ri->exit_policy = smartlist_new();
ri->policy_is_reject_star = 0;
- policy_entry = router_parse_addr_policy_item_from_string("accept *:*",-1);
+ policy_entry = router_parse_addr_policy_item_from_string("accept *:*", -1,
+ &malformed_list);
smartlist_add(ri->exit_policy,policy_entry);
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*",ep);
+ tt_str_op("accept *:*",OP_EQ, ep);
tor_free(ep);
- policy_entry = router_parse_addr_policy_item_from_string("reject *:25",-1);
+ policy_entry = router_parse_addr_policy_item_from_string("reject *:25", -1,
+ &malformed_list);
smartlist_add(ri->exit_policy,policy_entry);
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25",ep);
+ tt_str_op("accept *:*\nreject *:25",OP_EQ, ep);
tor_free(ep);
policy_entry =
- router_parse_addr_policy_item_from_string("reject 8.8.8.8:*",-1);
+ router_parse_addr_policy_item_from_string("reject 8.8.8.8:*", -1,
+ &malformed_list);
smartlist_add(ri->exit_policy,policy_entry);
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*",ep);
+ tt_str_op("accept *:*\nreject *:25\nreject 8.8.8.8:*",OP_EQ, ep);
tor_free(ep);
policy_entry =
- router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*",-1);
+ router_parse_addr_policy_item_from_string("reject6 [FC00::]/7:*", -1,
+ &malformed_list);
smartlist_add(ri->exit_policy,policy_entry);
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
- "reject6 [fc00::]/7:*",ep);
+ tt_str_op("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
+ "reject6 [fc00::]/7:*",OP_EQ, ep);
tor_free(ep);
policy_entry =
- router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*",-1);
+ router_parse_addr_policy_item_from_string("accept6 [c000::]/3:*", -1,
+ &malformed_list);
smartlist_add(ri->exit_policy,policy_entry);
ep = router_dump_exit_policy_to_string(ri,1,1);
- test_streq("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
- "reject6 [fc00::]/7:*\naccept6 [c000::]/3:*",ep);
+ tt_str_op("accept *:*\nreject *:25\nreject 8.8.8.8:*\n"
+ "reject6 [fc00::]/7:*\naccept6 [c000::]/3:*",OP_EQ, ep);
done:
@@ -428,10 +990,861 @@ test_dump_exit_policy_to_string(void *arg)
tor_free(ep);
}
+static routerinfo_t *mock_desc_routerinfo = NULL;
+static 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;
+
+ memset(&mock_my_routerinfo, 0, sizeof(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;
+ mock_options.ExitPolicyRejectPrivate = 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);
+ addr_policy_list_free(mock_my_routerinfo.exit_policy);
+}
+
+#undef DEFAULT_POLICY_STRING
+#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
+
+/* Check that fascist_firewall_choose_address_rs() returns the expected
+ * results. */
+#define CHECK_CHOSEN_ADDR_RS(fake_rs, fw_connection, pref_only, expect_rv, \
+ expect_ap) \
+ STMT_BEGIN \
+ tor_addr_port_t chosen_rs_ap; \
+ tor_addr_make_null(&chosen_rs_ap.addr, AF_INET); \
+ chosen_rs_ap.port = 0; \
+ tt_int_op(fascist_firewall_choose_address_rs(&(fake_rs), \
+ (fw_connection), \
+ (pref_only), \
+ &chosen_rs_ap), \
+ OP_EQ, (expect_rv)); \
+ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_rs_ap.addr)); \
+ tt_int_op((expect_ap).port, OP_EQ, chosen_rs_ap.port); \
+ STMT_END
+
+/* Check that fascist_firewall_choose_address_node() returns the expected
+ * results. */
+#define CHECK_CHOSEN_ADDR_NODE(fake_node, fw_connection, pref_only, \
+ expect_rv, expect_ap) \
+ STMT_BEGIN \
+ tor_addr_port_t chosen_node_ap; \
+ tor_addr_make_null(&chosen_node_ap.addr, AF_INET); \
+ chosen_node_ap.port = 0; \
+ tt_int_op(fascist_firewall_choose_address_node(&(fake_node), \
+ (fw_connection), \
+ (pref_only), \
+ &chosen_node_ap), \
+ OP_EQ, (expect_rv)); \
+ tt_assert(tor_addr_eq(&(expect_ap).addr, &chosen_node_ap.addr)); \
+ tt_int_op((expect_ap).port, OP_EQ, chosen_node_ap.port); \
+ STMT_END
+
+/* Check that fascist_firewall_choose_address_rs and
+ * fascist_firewall_choose_address_node() both return the expected results. */
+#define CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, fw_connection, pref_only, \
+ expect_rv, expect_ap) \
+ STMT_BEGIN \
+ CHECK_CHOSEN_ADDR_RS(fake_rs, fw_connection, pref_only, expect_rv, \
+ expect_ap); \
+ CHECK_CHOSEN_ADDR_NODE(fake_node, fw_connection, pref_only, expect_rv, \
+ expect_ap); \
+ STMT_END
+
+/** 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;
+
+ /* Sanity check fascist_firewall_choose_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;
+
+ /* Prefer IPv4 */
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ FIREWALL_OR_CONNECTION, 0, 0)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ FIREWALL_OR_CONNECTION, 1, 0)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1,
+ FIREWALL_DIR_CONNECTION, 0, 0)
+ == &ipv4_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 1,
+ FIREWALL_DIR_CONNECTION, 1, 0)
+ == &ipv4_dir_ap);
+
+ /* Prefer IPv6 */
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0, 1)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1, 1)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0, 1)
+ == &ipv6_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &ipv6_dir_ap, 0,
+ FIREWALL_DIR_CONNECTION, 1, 1)
+ == &ipv6_dir_ap);
+
+ /* Unusual inputs */
+
+ /* null preferred OR addresses */
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &n_ipv6_ap, 0,
+ FIREWALL_OR_CONNECTION, 0, 1)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_or_ap, 1,
+ FIREWALL_OR_CONNECTION, 0, 0)
+ == &ipv6_or_ap);
+
+ /* null both OR addresses */
+ tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ FIREWALL_OR_CONNECTION, 0, 1)
+ == NULL);
+ tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ FIREWALL_OR_CONNECTION, 0, 0)
+ == NULL);
+
+ /* null preferred Dir addresses */
+ tt_assert(fascist_firewall_choose_address(&ipv4_dir_ap, &n_ipv6_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0, 1)
+ == &ipv4_dir_ap);
+ tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &ipv6_dir_ap, 1,
+ FIREWALL_DIR_CONNECTION, 0, 0)
+ == &ipv6_dir_ap);
+
+ /* null both Dir addresses */
+ tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 0,
+ FIREWALL_DIR_CONNECTION, 0, 1)
+ == NULL);
+ tt_assert(fascist_firewall_choose_address(&n_ipv4_ap, &n_ipv6_ap, 1,
+ FIREWALL_DIR_CONNECTION, 0, 0)
+ == NULL);
+
+ /* Prefer IPv4 but want IPv6 (contradictory) */
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 0, 0)
+ == &ipv4_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 0,
+ FIREWALL_OR_CONNECTION, 1, 0)
+ == &ipv4_or_ap);
+
+ /* Prefer IPv6 but want IPv4 (contradictory) */
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ FIREWALL_OR_CONNECTION, 0, 1)
+ == &ipv6_or_ap);
+ tt_assert(fascist_firewall_choose_address(&ipv4_or_ap, &ipv6_or_ap, 1,
+ FIREWALL_OR_CONNECTION, 1, 1)
+ == &ipv6_or_ap);
+
+ /* Make a fake rs. There will be no corresponding node.
+ * This is what happens when there's no consensus and we're bootstrapping
+ * from authorities / fallbacks. */
+ routerstatus_t fake_rs;
+ memset(&fake_rs, 0, sizeof(routerstatus_t));
+ /* In a routerstatus, the OR and Dir addresses are the same */
+ fake_rs.addr = tor_addr_to_ipv4h(&ipv4_or_ap.addr);
+ fake_rs.or_port = ipv4_or_ap.port;
+ fake_rs.dir_port = ipv4_dir_ap.port;
+
+ tor_addr_copy(&fake_rs.ipv6_addr, &ipv6_or_ap.addr);
+ fake_rs.ipv6_orport = ipv6_or_ap.port;
+ /* In a routerstatus, the IPv4 and IPv6 DirPorts are the same.*/
+ ipv6_dir_ap.port = TEST_IPV4_DIR_PORT;
+
+ /* Make a fake node. Even though it contains the fake_rs, a lookup won't
+ * find the node from the rs, because they're not in the hash table. */
+ node_t fake_node;
+ memset(&fake_node, 0, sizeof(node_t));
+ fake_node.rs = &fake_rs;
+
+ /* 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;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* Auto (Preferring IPv4) */
+ mock_options.ClientPreferIPv6ORPort = -1;
+ mock_options.ClientPreferIPv6DirPort = -1;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* Preferring IPv6 */
+ mock_options.ClientPreferIPv6ORPort = 1;
+ mock_options.ClientPreferIPv6DirPort = 1;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv6_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv6_dir_ap);
+
+ /* Preferring IPv4 OR / IPv6 Dir */
+ mock_options.ClientPreferIPv6ORPort = 0;
+ mock_options.ClientPreferIPv6DirPort = 1;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv6_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv6_dir_ap);
+
+ /* Preferring IPv6 OR / IPv4 Dir */
+ mock_options.ClientPreferIPv6ORPort = 1;
+ mock_options.ClientPreferIPv6DirPort = 0;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 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;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* Auto:
+ * - bridge clients prefer the configured bridge OR address from the node,
+ * (the configured address family sets node.ipv6_preferred)
+ * - other clients prefer IPv4 OR by default (see above),
+ * - all clients, including bridge clients, prefer IPv4 Dir by default.
+ */
+ mock_options.ClientPreferIPv6ORPort = -1;
+ mock_options.ClientPreferIPv6DirPort = -1;
+
+ /* Simulate the initialisation of fake_node.ipv6_preferred with a bridge
+ * configured with an IPv4 address */
+ fake_node.ipv6_preferred = 0;
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 0, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 1, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* Simulate the initialisation of fake_node.ipv6_preferred with a bridge
+ * configured with an IPv6 address */
+ fake_node.ipv6_preferred = 1;
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 0, 1, ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 1, 1, ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* When a rs has no node, it defaults to IPv4 under auto. */
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_OR_CONNECTION, 0, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_OR_CONNECTION, 1, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_DIR_CONNECTION, 0, 1, ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_DIR_CONNECTION, 1, 1, ipv4_dir_ap);
+
+ /* Preferring IPv6 */
+ mock_options.ClientPreferIPv6ORPort = 1;
+ mock_options.ClientPreferIPv6DirPort = 1;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv6_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv6_dir_ap);
+
+ /* In the default configuration (Auto / IPv6 off), bridge clients should
+ * use both IPv4 and IPv6, but only prefer IPv6 for bridges configured with
+ * an IPv6 address, regardless of ClientUseIPv6. (See above.) */
+ mock_options.ClientUseIPv6 = 0;
+ mock_options.ClientPreferIPv6ORPort = -1;
+ mock_options.ClientPreferIPv6DirPort = -1;
+ /* Simulate the initialisation of fake_node.ipv6_preferred with a bridge
+ * configured with an IPv4 address */
+ fake_node.ipv6_preferred = 0;
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 0, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 1, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* Simulate the initialisation of fake_node.ipv6_preferred with a bridge
+ * configured with an IPv6 address */
+ fake_node.ipv6_preferred = 1;
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 0, 1, ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_OR_CONNECTION, 1, 1, ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_NODE(fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ /* When a rs has no node, it defaults to IPv4 under auto. */
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_OR_CONNECTION, 0, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_OR_CONNECTION, 1, 1, ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_DIR_CONNECTION, 0, 1, ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RS(fake_rs, FIREWALL_DIR_CONNECTION, 1, 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;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 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;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv6_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 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;
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv6_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv6_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv6_dir_ap);
+
+ /* Choose an address with ORPort_set 1 (server mode).
+ * This means "use IPv4" regardless of the other settings. */
+ memset(&mock_options, 0, sizeof(or_options_t));
+ mock_options.ORPort_set = 1;
+ mock_options.ClientUseIPv4 = 0;
+ mock_options.ClientUseIPv6 = 1;
+ mock_options.ClientPreferIPv6ORPort = 1;
+ mock_options.ClientPreferIPv6DirPort = 1;
+
+ /* Simulate the initialisation of fake_node.ipv6_preferred */
+ fake_node.ipv6_preferred = fascist_firewall_prefer_ipv6_orport(
+ &mock_options);
+
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 0, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_OR_CONNECTION, 1, 1,
+ ipv4_or_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 0, 1,
+ ipv4_dir_ap);
+ CHECK_CHOSEN_ADDR_RN(fake_rs, fake_node, FIREWALL_DIR_CONNECTION, 1, 1,
+ ipv4_dir_ap);
+
+ 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
+
+#undef CHECK_CHOSEN_ADDR_RS
+#undef CHECK_CHOSEN_ADDR_NODE
+#undef CHECK_CHOSEN_ADDR_RN
+
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 },
+ { "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
};