commit 10a6390deb3c9ff9fbd8078fc812abf6c77ad67f Author: teor (Tim Wilson-Brown) teor2345@gmail.com Date: Mon Nov 16 20:40:17 2015 +1100
Add controller getinfo exit-policy/reject-private
exit-policy/reject-private lists the reject rules added by ExitPolicyRejectPrivate. This makes it easier for stem to display exit policies.
Add unit tests for getinfo exit-policy/*.
Completes ticket #17183. Patch by "teor". --- changes/getinfo-private-exitpolicy | 6 + src/or/control.c | 6 + src/or/policies.c | 307 ++++++++++++++++++++++-------------- src/or/policies.h | 15 +- src/test/test_policy.c | 302 ++++++++++++++++++++++++----------- 5 files changed, 417 insertions(+), 219 deletions(-)
diff --git a/changes/getinfo-private-exitpolicy b/changes/getinfo-private-exitpolicy new file mode 100644 index 0000000..e834516 --- /dev/null +++ b/changes/getinfo-private-exitpolicy @@ -0,0 +1,6 @@ + o Minor features (exit policies, controllers): + - Add controller getinfo exit-policy/reject-private/[default,relay] + for the reject rules added by ExitPolicyRejectPrivate. This makes + it easier for stem to display exit policies. + - Add unit tests for getinfo exit-policy/*. + Completes ticket #17183. Patch by "teor". diff --git a/src/or/control.c b/src/or/control.c index 7d72342..7e65611 100644 --- a/src/or/control.c +++ b/src/or/control.c @@ -2562,6 +2562,12 @@ static const getinfo_item_t getinfo_items[] = { "v3 Networkstatus consensus as retrieved from a DirPort."), ITEM("exit-policy/default", policies, "The default value appended to the configured exit policy."), + ITEM("exit-policy/reject-private/default", policies, + "The default rules appended to the configured exit policy by" + " ExitPolicyRejectPrivate."), + ITEM("exit-policy/reject-private/relay", policies, + "The relay-specific rules appended to the configured exit policy by" + " ExitPolicyRejectPrivate."), ITEM("exit-policy/full", policies, "The entire exit policy of onion router"), ITEM("exit-policy/ipv4", policies, "IPv4 parts of exit policy"), ITEM("exit-policy/ipv6", policies, "IPv6 parts of exit policy"), diff --git a/src/or/policies.c b/src/or/policies.c index 0e7b3bd..f4cde43 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -63,17 +63,14 @@ static const char *private_nets[] = { };
static int policies_parse_exit_policy_internal( - config_line_t *cfg, - smartlist_t **dest, - int ipv6_exit, - int rejectprivate, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, - int reject_interface_addresses, - int reject_configured_port_addresses, - int add_default_policy); + config_line_t *cfg, + smartlist_t **dest, + int ipv6_exit, + int rejectprivate, + const smartlist_t *configured_addresses, + int reject_interface_addresses, + int reject_configured_port_addresses, + int add_default_policy);
/** Replace all "private" entries in *<b>policy</b> with their expanded * equivalents. */ @@ -868,7 +865,7 @@ addr_policy_intersects(addr_policy_t *a, addr_policy_t *b)
/** Add the exit policy described by <b>more</b> to <b>policy</b>. */ -static void +STATIC void append_exit_policy_string(smartlist_t **policy, const char *more) { config_line_t tmp; @@ -885,6 +882,9 @@ append_exit_policy_string(smartlist_t **policy, const char *more) void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr) { + tor_assert(dest); + tor_assert(addr); + addr_policy_t p, *add; memset(&p, 0, sizeof(p)); p.policy_type = ADDR_POLICY_REJECT; @@ -902,17 +902,68 @@ addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr)
}
+/* Is addr public for the purposes of rejection? */ +static int +tor_addr_is_public_for_reject(const tor_addr_t *addr) +{ + return !tor_addr_is_null(addr) && !tor_addr_is_internal(addr, 0); +} + +/* Add "reject <b>addr</b>:*" to <b>dest</b>, creating the list as needed. + * Filter the address, only adding an IPv4 reject rule if ipv4_rules + * is true, and similarly for ipv6_rules. Check each address returns true for + * tor_addr_is_public_for_reject before adding it. + */ +static void +addr_policy_append_reject_addr_filter(smartlist_t **dest, + const tor_addr_t *addr, + int ipv4_rules, + int ipv6_rules) +{ + tor_assert(dest); + tor_assert(addr); + + /* Only reject IP addresses which are public */ + if (tor_addr_is_public_for_reject(addr)) { + + /* Reject IPv4 addresses and IPv6 addresses based on the filters */ + int is_ipv4 = tor_addr_is_v4(addr); + if ((is_ipv4 && ipv4_rules) || (!is_ipv4 && ipv6_rules)) { + addr_policy_append_reject_addr(dest, addr); + } + } +} + /** Add "reject addr:*" to <b>dest</b>, for each addr in addrs, creating the * list as needed. */ void addr_policy_append_reject_addr_list(smartlist_t **dest, const smartlist_t *addrs) { + tor_assert(dest); + tor_assert(addrs); + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, addr) { addr_policy_append_reject_addr(dest, addr); } SMARTLIST_FOREACH_END(addr); }
+/** Add "reject addr:*" to <b>dest</b>, for each addr in addrs, creating the + * list as needed. Filter using */ +static void +addr_policy_append_reject_addr_list_filter(smartlist_t **dest, + const smartlist_t *addrs, + int ipv4_rules, + int ipv6_rules) +{ + tor_assert(dest); + tor_assert(addrs); + + SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, addr) { + addr_policy_append_reject_addr_filter(dest, addr, ipv4_rules, ipv6_rules); + } SMARTLIST_FOREACH_END(addr); +} + /** Detect and excise "dead code" from the policy *<b>dest</b>. */ static void exit_policy_remove_redundancies(smartlist_t *dest) @@ -997,21 +1048,12 @@ exit_policy_remove_redundancies(smartlist_t *dest) } }
-/* Is addr public for the purposes of rejection? */ -static int -tor_addr_is_public_for_reject(const tor_addr_t *addr) -{ - return !tor_addr_is_null(addr) && !tor_addr_is_internal(addr, 0); -} - /** Reject private helper for policies_parse_exit_policy_internal: rejects * publicly routable addresses on this exit relay. * * Add reject entries to the linked list *dest: - * - if local_address is non-zero, treat it as a host-order IPv4 address, - * and add an entry that rejects it as a destination. - * - if ipv6_local_address, ipv4_outbound_address, or ipv6_outbound_address - * are non-NULL, add entries that reject them as destinations. + * - if configured_addresses is non-NULL, add entries that reject each + * tor_addr_t* in the list as a destination. * - if reject_interface_addresses is true, add entries that reject each * public IPv4 and IPv6 address of each interface on this machine. * - if reject_configured_port_addresses is true, add entries that reject @@ -1027,60 +1069,16 @@ void policies_parse_exit_policy_reject_private( smartlist_t **dest, int ipv6_exit, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, + const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses) { tor_assert(dest);
- /* Reject our local IPv4 address */ - if (local_address) { - tor_addr_t v4_local; - tor_addr_from_ipv4h(&v4_local, local_address); - if (tor_addr_is_public_for_reject(&v4_local)) { - addr_policy_append_reject_addr(dest, &v4_local); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject %s:*' for our " - "published IPv4 address", fmt_addr32(local_address)); - } - } - - /* Reject the outbound IPv4 connection address */ - if (ipv4_outbound_address - && tor_addr_is_public_for_reject(ipv4_outbound_address)) { - addr_policy_append_reject_addr(dest, ipv4_outbound_address); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject %s:*' for " - "our outbound IPv4 connection address", - fmt_addr(ipv4_outbound_address)); - } - - /* If we're not an IPv6 exit, all IPv6 addresses have already been rejected - * by policies_parse_exit_policy_internal */ - if (ipv6_exit) { - - /* Reject our local IPv6 address */ - if (ipv6_local_address != NULL - && tor_addr_is_public_for_reject(ipv6_local_address)) { - if (tor_addr_is_v4(ipv6_local_address)) { - log_warn(LD_CONFIG, "IPv4 address '%s' provided as our IPv6 local " - "address", fmt_addr(ipv6_local_address)); - } else { - addr_policy_append_reject_addr(dest, ipv6_local_address); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject [%s]:*' for " - "our published IPv6 address", fmt_addr(ipv6_local_address)); - } - } - - /* Reject the outbound IPv6 connection address */ - if (ipv6_outbound_address - && tor_addr_is_public_for_reject(ipv6_outbound_address)) { - addr_policy_append_reject_addr(dest, ipv6_outbound_address); - log_info(LD_CONFIG, "Adding a reject ExitPolicy 'reject [%s]:*' for " - "our outbound IPv6 connection address", - fmt_addr(ipv6_outbound_address)); - } + /* Reject configured addresses, if they are from public netblocks. */ + if (configured_addresses) { + addr_policy_append_reject_addr_list_filter(dest, configured_addresses, + 1, ipv6_exit); }
/* Reject configured port addresses, if they are from public netblocks. */ @@ -1089,14 +1087,9 @@ policies_parse_exit_policy_reject_private(
SMARTLIST_FOREACH_BEGIN(port_addrs, port_cfg_t *, port) {
- /* Only reject IP addresses which are public */ - if (!port->is_unix_addr && tor_addr_is_public_for_reject(&port->addr)) { - - /* Reject IPv4 addresses. If we are an IPv6 exit, also reject IPv6 - * addresses */ - if (tor_addr_is_v4(&port->addr) || ipv6_exit) { - addr_policy_append_reject_addr(dest, &port->addr); - } + /* Only reject port IP addresses, not port unix sockets */ + if (!port->is_unix_addr) { + addr_policy_append_reject_addr_filter(dest, &port->addr, 1, ipv6_exit); } } SMARTLIST_FOREACH_END(port); } @@ -1107,13 +1100,14 @@ policies_parse_exit_policy_reject_private(
/* Reject public IPv4 addresses on any interface */ public_addresses = get_interface_address6_list(LOG_INFO, AF_INET, 0); - addr_policy_append_reject_addr_list(dest, public_addresses); + addr_policy_append_reject_addr_list_filter(dest, public_addresses, 1, 0); free_interface_address6_list(public_addresses);
+ /* Don't look for IPv6 addresses if we're configured as IPv4-only */ if (ipv6_exit) { /* Reject public IPv6 addresses on any interface */ public_addresses = get_interface_address6_list(LOG_INFO, AF_INET6, 0); - addr_policy_append_reject_addr_list(dest, public_addresses); + addr_policy_append_reject_addr_list_filter(dest, public_addresses, 0, 1); free_interface_address6_list(public_addresses); } } @@ -1149,13 +1143,11 @@ policies_parse_exit_policy_reject_private( * see router_add_exit_policy. */ static int -policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, +policies_parse_exit_policy_internal(config_line_t *cfg, + smartlist_t **dest, int ipv6_exit, int rejectprivate, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, + const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses, int add_default_policy) @@ -1168,10 +1160,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, append_exit_policy_string(dest, "reject private:*"); /* Reject IPv4 and IPv6 publicly routable addresses on this exit relay */ policies_parse_exit_policy_reject_private( - dest, ipv6_exit, local_address, - ipv6_local_address, - ipv4_outbound_address, - ipv6_outbound_address, + dest, ipv6_exit, + configured_addresses, reject_interface_addresses, reject_configured_port_addresses); } @@ -1256,12 +1246,8 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, * If <b>EXIT_POLICY_REJECT_PRIVATE</b> bit is set in <b>options</b>: * - prepend an entry that rejects all destinations in all netblocks * reserved for private use. - * - if local_address is non-zero, treat it as a host-order IPv4 address, - * and prepend an entry that rejects it as a destination. - * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as - * a destination. - * - if reject_interface_addresses is true, prepend entries that reject each - * public IPv4 and IPv6 address of each interface on this machine. + * - prepend entries that reject publicly routable addresses on this exit + * relay by calling policies_parse_exit_policy_internal * * If <b>EXIT_POLICY_ADD_DEFAULT</b> bit is set in <b>options</b>, append * default exit policy entries to <b>result</b> smartlist. @@ -1269,10 +1255,7 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address) + const smartlist_t *configured_addresses) { int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0; int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0; @@ -1280,15 +1263,51 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest,
return policies_parse_exit_policy_internal(cfg,dest,ipv6_enabled, reject_private, - local_address, - ipv6_local_address, - ipv4_outbound_address, - ipv6_outbound_address, + configured_addresses, reject_private, reject_private, add_default); }
+/** Helper function that adds addr to a smartlist as long as it is non-NULL + * and not tor_addr_is_null(). */ +static void +policies_add_addr_to_smartlist(smartlist_t *addr_list, const tor_addr_t *addr) +{ + if (addr && !tor_addr_is_null(addr)) { + smartlist_add(addr_list, (void *)addr); + } +} + +/** Helper function that adds ipv4h_addr to a smartlist as a tor_addr_t *, + * by converting it to a tor_addr_t and passing it to + * policies_add_addr_to_smartlist. */ +static void +policies_add_ipv4h_to_smartlist(smartlist_t *addr_list, uint32_t ipv4h_addr) +{ + if (ipv4h_addr) { + tor_addr_t ipv4_tor_addr; + tor_addr_from_ipv4h(&ipv4_tor_addr, ipv4h_addr); + policies_add_addr_to_smartlist(addr_list, (void *)&ipv4_tor_addr); + } +} + +/** Helper function that adds or_options->OutboundBindAddressIPv[4|6]_ to a + * smartlist as a tor_addr_t *, as long as or_options is non-NULL, + * by passing them to policies_add_addr_to_smartlist. */ +static void +policies_add_outbound_addresses_to_smartlist(smartlist_t *addr_list, + const or_options_t *or_options) +{ + if (or_options) { + policies_add_addr_to_smartlist(addr_list, + &or_options->OutboundBindAddressIPv4_); + policies_add_addr_to_smartlist(addr_list, + &or_options->OutboundBindAddressIPv6_); + } +} + + /** Parse <b>ExitPolicy</b> member of <b>or_options</b> into <b>result</b> * smartlist. * If <b>or_options->IPv6Exit</b> is false, prepend an entry that @@ -1298,11 +1317,13 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, * - prepend an entry that rejects all destinations in all netblocks reserved * for private use. * - if local_address is non-zero, treat it as a host-order IPv4 address, and - * prepend an entry that rejects it as a destination. - * - if ipv6_local_address is non-NULL, prepend an entry that rejects it as a - * destination. - * - if reject_interface_addresses is true, prepend entries that reject each - * public IPv4 and IPv6 address of each interface on this machine. + * add it to the list of configured addresses. + * - if ipv6_local_address is non-NULL, and not the null tor_addr_t, add it + * to the list of configured addresses. + * - if or_options->OutboundBindAddressIPv4_ is not the null tor_addr_t, add + * it to the list of configured addresses. + * - if or_options->OutboundBindAddressIPv6_ is not the null tor_addr_t, add + * it to the list of configured addresses. * * If <b>or_options->BridgeRelay</b> is false, append entries of default * Tor exit policy into <b>result</b> smartlist. @@ -1317,13 +1338,17 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, smartlist_t **result) { exit_policy_parser_cfg_t parser_cfg = 0; + smartlist_t *configured_addresses = smartlist_new(); + int rv = 0;
+ /* Short-circuit for non-exit relays */ if (or_options->ExitRelay == 0) { append_exit_policy_string(result, "reject *4:*"); append_exit_policy_string(result, "reject *6:*"); return 0; }
+ /* Configure the parser */ if (or_options->IPv6Exit) { parser_cfg |= EXIT_POLICY_IPV6_ENABLED; } @@ -1336,11 +1361,20 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, parser_cfg |= EXIT_POLICY_ADD_DEFAULT; }
- return policies_parse_exit_policy(or_options->ExitPolicy,result, - parser_cfg,local_address, - ipv6_local_address, - &or_options->OutboundBindAddressIPv4_, - &or_options->OutboundBindAddressIPv6_); + /* Add the configured addresses to the tor_addr_t* list */ + policies_add_ipv4h_to_smartlist(configured_addresses, local_address); + policies_add_addr_to_smartlist(configured_addresses, ipv6_local_address); + policies_add_outbound_addresses_to_smartlist(configured_addresses, + or_options); + + rv = policies_parse_exit_policy(or_options->ExitPolicy, result, parser_cfg, + configured_addresses); + + /* We don't need to free the pointers in this list, they are either constant + * or locally scoped. */ + smartlist_free(configured_addresses); + + return rv; }
/** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating @@ -2085,6 +2119,49 @@ getinfo_helper_policies(control_connection_t *conn, (void) errmsg; if (!strcmp(question, "exit-policy/default")) { *answer = tor_strdup(DEFAULT_EXIT_POLICY); + } else if (!strcmp(question, "exit-policy/reject-private/default")) { + smartlist_t *private_policy_strings; + const char **priv = private_nets; + + private_policy_strings = smartlist_new(); + + while (*priv != NULL) { + /* IPv6 addresses are in "[]" and contain ":", + * IPv4 addresses are not in "[]" and contain "." */ + smartlist_add_asprintf(private_policy_strings, "reject %s:*", *priv); + priv++; + } + + *answer = smartlist_join_strings(private_policy_strings, + ",", 0, NULL); + + SMARTLIST_FOREACH(private_policy_strings, char *, str, tor_free(str)); + smartlist_free(private_policy_strings); + } else if (!strcmp(question, "exit-policy/reject-private/relay")) { + const or_options_t *options = get_options(); + const routerinfo_t *me = router_get_my_routerinfo(); + smartlist_t *private_policy_list = smartlist_new(); + smartlist_t *configured_addresses = smartlist_new(); + + if (!me) { + *errmsg = "router_get_my_routerinfo returned NULL"; + return -1; + } + + /* Add the configured addresses to the tor_addr_t* list */ + policies_add_ipv4h_to_smartlist(configured_addresses, me->addr); + policies_add_addr_to_smartlist(configured_addresses, &me->ipv6_addr); + policies_add_outbound_addresses_to_smartlist(configured_addresses, + options); + + policies_parse_exit_policy_reject_private( + &private_policy_list, + options->IPv6Exit, + configured_addresses, + 1, 1); + *answer = policy_dump_to_string(private_policy_list, 1, 1); + + addr_policy_list_free(private_policy_list); } else if (!strcmpstart(question, "exit-policy/")) { const routerinfo_t *me = router_get_my_routerinfo();
diff --git a/src/or/policies.h b/src/or/policies.h index d7cc5a3..72e62c7 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -44,7 +44,6 @@ addr_policy_t *addr_policy_get_canonical_entry(addr_policy_t *ent); int cmp_addr_policies(smartlist_t *a, smartlist_t *b); MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy, (const tor_addr_t *addr, uint16_t port, const smartlist_t *policy)); - addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port, const node_t *node);
@@ -55,17 +54,11 @@ int policies_parse_exit_policy_from_options( smartlist_t **result); int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address); + const smartlist_t *configured_addresses); void policies_parse_exit_policy_reject_private( smartlist_t **dest, int ipv6_exit, - uint32_t local_address, - const tor_addr_t *ipv6_local_address, - const tor_addr_t *ipv4_outbound_address, - const tor_addr_t *ipv6_outbound_address, + const smartlist_t *configured_addresses, int reject_interface_addresses, int reject_configured_port_addresses); void policies_exit_policy_append_reject_star(smartlist_t **dest); @@ -99,5 +92,9 @@ addr_policy_result_t compare_tor_addr_to_short_policy( const tor_addr_t *addr, uint16_t port, const short_policy_t *policy);
+#ifdef POLICIES_PRIVATE +void append_exit_policy_string(smartlist_t **policy, const char *more); +#endif + #endif
diff --git a/src/test/test_policy.c b/src/test/test_policy.c index 18d9594..9ab3abe 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -6,6 +6,7 @@ #include "config.h" #include "router.h" #include "routerparse.h" +#define POLICIES_PRIVATE #include "policies.h" #include "test.h"
@@ -51,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, NULL, NULL); + EXIT_POLICY_ADD_DEFAULT, NULL); tt_int_op(r,OP_EQ, 0);
summary = policy_summarize(policy, AF_INET); @@ -82,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; @@ -117,18 +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, NULL, NULL)); + 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, NULL, - NULL)); + addr_list)); + smartlist_free(addr_list); + addr_list = NULL;
tt_assert(policy12);
@@ -209,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, NULL, NULL)); + 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, NULL, NULL)); + EXIT_POLICY_ADD_DEFAULT, + NULL));
tt_assert(policy9);
@@ -271,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, NULL, NULL)); + EXIT_POLICY_ADD_DEFAULT, NULL)); tt_assert(policy);
//test_streq(policy->string, "accept *:80"); @@ -523,118 +528,91 @@ static void test_policies_reject_exit_address(void *arg) { smartlist_t *policy = NULL; - tor_addr_t ipv4_addr; - tor_addr_t ipv6_addr; + 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);
- /* test that local_address is interpreted as an IPv4 host-order address and - * rejected on an IPv4-only exit */ - policies_parse_exit_policy_reject_private(&policy, 0, TEST_IPV4_ADDR, NULL, - NULL, NULL, 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_list = smartlist_new(); + ipv6_list = smartlist_new(); + both_list = smartlist_new(); + dupl_list = smartlist_new();
- /* test that local_address is interpreted as an IPv4 host-order address and - * rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, TEST_IPV4_ADDR, NULL, - NULL, NULL, 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; + 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);
- /* test that ipv6_local_address is rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, 0, &ipv6_addr, NULL, - NULL, 0, 0); + /* 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, &ipv6_addr)); + tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); addr_policy_list_free(policy); policy = NULL;
- /* test that ipv6_local_address is NOT rejected on an IPv4-only exit + /* 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, 0, &ipv6_addr, NULL, - NULL, 0, 0); + policies_parse_exit_policy_reject_private(&policy, 0, ipv6_list, 0, 0); tt_assert(policy == NULL);
- done: + /* 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); -} - -/** Run unit tests for rejecting outbound connection addresses on this - * exit relay using policies_parse_exit_policy_reject_private */ -static void -test_policies_reject_outbound_address(void *arg) -{ - smartlist_t *policy = NULL; - tor_addr_t ipv4_addr, ipv6_addr; - (void)arg; - - tor_addr_from_ipv4h(&ipv4_addr, TEST_IPV4_ADDR); - tor_addr_parse(&ipv6_addr, TEST_IPV6_ADDR); + policy = NULL;
- /* test that OutboundBindAddressIPv4_ is rejected on an IPv4-only exit */ - policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, &ipv4_addr, - NULL, 0, 0); + /* 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;
- /* test that OutboundBindAddressIPv4_ is rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, &ipv4_addr, - NULL, 0, 0); + /* 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 OutboundBindAddressIPv6_ is rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, NULL, - &ipv6_addr, 0, 0); + /* 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 OutboundBindAddressIPv6_ is 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 with IPv6 addresses on IPv4-only exits) */ - policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, - &ipv6_addr, 0, 0); - tt_assert(policy == NULL); - - /* test that OutboundBindAddressIPv4_ is rejected on an IPv4-only exit, - * but OutboundBindAddressIPv6_ 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, 0, NULL, &ipv4_addr, - &ipv6_addr, 0, 0); + /* 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) == 1); + 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 OutboundBindAddressIPv4_ and OutboundBindAddressIPv6_ are - * rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, &ipv4_addr, - &ipv6_addr, 0, 0); + /* 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)); @@ -642,8 +620,12 @@ test_policies_reject_outbound_address(void *arg) addr_policy_list_free(policy); policy = NULL;
-done: + 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; @@ -683,8 +665,7 @@ test_policies_reject_port_address(void *arg) * 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, 0, NULL, NULL, NULL, - 0, 1); + 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)); @@ -692,8 +673,7 @@ test_policies_reject_port_address(void *arg) policy = NULL;
/* test that IPv4 and IPv6 ports are rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, 0, NULL, NULL, NULL, - 0, 1); + 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)); @@ -728,14 +708,12 @@ test_policies_reject_interface_address(void *arg) (void)arg;
/* test that no addresses are rejected when none are supplied/requested */ - policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL, - 0, 0); + 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, 0, NULL, NULL, NULL, - 1, 0); + 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); @@ -744,8 +722,7 @@ test_policies_reject_interface_address(void *arg)
/* test that IPv4 and IPv6 interface addresses are rejected on an IPv4/IPv6 * exit */ - policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL, - 1, 0); + 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))); @@ -848,13 +825,148 @@ 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_outbound_address", test_policies_reject_outbound_address, 0, NULL, NULL }, { "reject_port_address", test_policies_reject_port_address, 0, NULL, NULL }, END_OF_TESTCASES };