commit 66fac9fbadae529349f00172760688cf3caeb64d Author: teor (Tim Wilson-Brown) teor2345@gmail.com Date: Mon Nov 16 15:54:57 2015 +1100
Block OutboundBindAddressIPv[4|6]_ and configured ports on exit relays
Modify policies_parse_exit_policy_reject_private so it also blocks the addresses configured for OutboundBindAddressIPv4_ and OutboundBindAddressIPv6_, and any publicly routable port addresses on exit relays.
Add and update unit tests for these functions. --- src/or/config.c | 9 ++- src/or/config.h | 4 +- src/or/policies.c | 156 ++++++++++++++++++++++++++++++------------ src/or/policies.h | 29 ++++---- src/or/router.c | 2 +- src/test/test_policy.c | 177 ++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 303 insertions(+), 74 deletions(-)
diff --git a/src/or/config.c b/src/or/config.c index 22039b4..9028414 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -562,7 +562,6 @@ static char *get_bindaddr_from_transport_listen_line(const char *line, static int parse_dir_authority_line(const char *line, dirinfo_type_t required_type, int validate_only); -static void port_cfg_free(port_cfg_t *port); static int parse_ports(or_options_t *options, int validate_only, char **msg_out, int *n_ports_out, int *world_writable_control_socket); @@ -5737,7 +5736,7 @@ parse_dir_fallback_line(const char *line, }
/** Allocate and return a new port_cfg_t with reasonable defaults. */ -static port_cfg_t * +STATIC port_cfg_t * port_cfg_new(size_t namelen) { tor_assert(namelen <= SIZE_T_CEILING - sizeof(port_cfg_t) - 1); @@ -5749,7 +5748,7 @@ port_cfg_new(size_t namelen) }
/** Free all storage held in <b>port</b> */ -static void +STATIC void port_cfg_free(port_cfg_t *port) { tor_free(port); @@ -6673,8 +6672,8 @@ check_server_ports(const smartlist_t *ports,
/** Return a list of port_cfg_t for client ports parsed from the * options. */ -const smartlist_t * -get_configured_ports(void) +MOCK_IMPL(const smartlist_t *, +get_configured_ports,(void)) { if (!configured_ports) configured_ports = smartlist_new(); diff --git a/src/or/config.h b/src/or/config.h index 51f7e90..7e88688 100644 --- a/src/or/config.h +++ b/src/or/config.h @@ -76,7 +76,7 @@ int write_to_data_subdir(const char* subdir, const char* fname,
int get_num_cpus(const or_options_t *options);
-const smartlist_t *get_configured_ports(void); +MOCK_DECL(const smartlist_t *,get_configured_ports,(void)); int get_first_advertised_port_by_type_af(int listener_type, int address_family); #define get_primary_or_port() \ @@ -140,6 +140,8 @@ smartlist_t *get_options_for_server_transport(const char *transport); extern struct config_format_t options_format; #endif
+STATIC port_cfg_t *port_cfg_new(size_t namelen); +STATIC void port_cfg_free(port_cfg_t *port); STATIC void or_options_free(or_options_t *options); STATIC int options_validate(or_options_t *old_options, or_options_t *options, diff --git a/src/or/policies.c b/src/or/policies.c index f534632..91ca867 100644 --- a/src/or/policies.c +++ b/src/or/policies.c @@ -62,14 +62,18 @@ static const char *private_nets[] = { NULL };
-static int policies_parse_exit_policy_internal(config_line_t *cfg, - smartlist_t **dest, - int ipv6_exit, - int rejectprivate, - uint32_t local_address, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses, - int add_default_policy); +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);
/** Replace all "private" entries in *<b>policy</b> with their expanded * equivalents. */ @@ -443,7 +447,7 @@ validate_addr_policies(const or_options_t *options, char **msg) smartlist_t *addr_policy=NULL; *msg = NULL;
- if (policies_parse_exit_policy_from_options(options,0,NULL,0,&addr_policy)) { + if (policies_parse_exit_policy_from_options(options,0,NULL,&addr_policy)) { REJECT("Error in ExitPolicy entry."); }
@@ -993,16 +997,25 @@ 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 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 + * 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 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 + * each IPv4 and IPv6 address configured for a port. * * IPv6 entries are only added if ipv6_exit is true. (All IPv6 addresses are * already blocked by policies_parse_exit_policy_internal if ipv6_exit is @@ -1011,35 +1024,83 @@ exit_policy_remove_redundancies(smartlist_t *dest) * The list *dest is created as needed. */ void -policies_parse_exit_policy_reject_private(smartlist_t **dest, - int ipv6_exit, - uint32_t local_address, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses) +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, + 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); - 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)); + 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 our local IPv6 address */ - if (ipv6_exit && ipv6_local_address != NULL) { - 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); + /* 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 published IPv6 address", fmt_addr(ipv6_local_address)); + "our outbound IPv6 connection address", + fmt_addr(ipv6_outbound_address)); } }
+ /* Reject configured port addresses, if they are from public netblocks. */ + if (reject_configured_port_addresses) { + const smartlist_t *port_addrs = get_configured_ports(); + + 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); + } + } + } SMARTLIST_FOREACH_END(port); + } + /* Reject local addresses from public netblocks on any interface. */ if (reject_interface_addresses) { smartlist_t *public_addresses = NULL; @@ -1074,8 +1135,8 @@ policies_parse_exit_policy_reject_private(smartlist_t **dest, * * If <b>rejectprivate</b> is true: * - prepend "reject private:*" to the policy. - * - call policies_parse_exit_policy_reject_private to reject publicly - * routable addresses on this exit relay + * - prepend entries that reject publicly routable addresses on this exit + * relay by calling policies_parse_exit_policy_reject_private * * If cfg doesn't end in an absolute accept or reject and if * <b>add_default_policy</b> is true, add the default exit @@ -1092,8 +1153,11 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, int ipv6_exit, int rejectprivate, uint32_t local_address, - tor_addr_t *ipv6_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) { if (!ipv6_exit) { @@ -1103,9 +1167,13 @@ policies_parse_exit_policy_internal(config_line_t *cfg, smartlist_t **dest, /* Reject IPv4 and IPv6 reserved private netblocks */ 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, - reject_interface_addresses); + policies_parse_exit_policy_reject_private( + dest, ipv6_exit, local_address, + ipv6_local_address, + ipv4_outbound_address, + ipv6_outbound_address, + reject_interface_addresses, + reject_configured_port_addresses); } if (parse_addr_policy(cfg, dest, -1)) return -1; @@ -1202,8 +1270,9 @@ int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, uint32_t local_address, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses) + const tor_addr_t *ipv6_local_address, + const tor_addr_t *ipv4_outbound_address, + const tor_addr_t *ipv6_outbound_address) { int ipv6_enabled = (options & EXIT_POLICY_IPV6_ENABLED) ? 1 : 0; int reject_private = (options & EXIT_POLICY_REJECT_PRIVATE) ? 1 : 0; @@ -1213,7 +1282,10 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, reject_private, local_address, ipv6_local_address, - reject_interface_addresses, + ipv4_outbound_address, + ipv6_outbound_address, + reject_private, + reject_private, add_default); }
@@ -1241,8 +1313,7 @@ policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, int policies_parse_exit_policy_from_options(const or_options_t *or_options, uint32_t local_address, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses, + const tor_addr_t *ipv6_local_address, smartlist_t **result) { exit_policy_parser_cfg_t parser_cfg = 0; @@ -1268,7 +1339,8 @@ policies_parse_exit_policy_from_options(const or_options_t *or_options, return policies_parse_exit_policy(or_options->ExitPolicy,result, parser_cfg,local_address, ipv6_local_address, - reject_interface_addresses); + &or_options->OutboundBindAddressIPv4_, + &or_options->OutboundBindAddressIPv6_); }
/** Add "reject *:*" to the end of the policy in *<b>dest</b>, allocating diff --git a/src/or/policies.h b/src/or/policies.h index 97350f5..26f92ad 100644 --- a/src/or/policies.h +++ b/src/or/policies.h @@ -48,21 +48,26 @@ MOCK_DECL(addr_policy_result_t, compare_tor_addr_to_addr_policy, addr_policy_result_t compare_tor_addr_to_node_policy(const tor_addr_t *addr, uint16_t port, const node_t *node);
-int policies_parse_exit_policy_from_options(const or_options_t *or_options, - uint32_t local_address, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses, - smartlist_t **result); +int policies_parse_exit_policy_from_options( + const or_options_t *or_options, + uint32_t local_address, + const tor_addr_t *ipv6_local_address, + 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, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses); -void policies_parse_exit_policy_reject_private(smartlist_t **dest, - int ipv6_exit, - uint32_t local_address, - tor_addr_t *ipv6_local_address, - int reject_interface_addresses); + const tor_addr_t *ipv6_local_address, + const tor_addr_t *ipv4_outbound_address, + const tor_addr_t *ipv6_outbound_address); +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, + int reject_interface_addresses, + int reject_configured_port_addresses); void policies_exit_policy_append_reject_star(smartlist_t **dest); void addr_policy_append_reject_addr(smartlist_t **dest, const tor_addr_t *addr); diff --git a/src/or/router.c b/src/or/router.c index 1790416..95e5ad8 100644 --- a/src/or/router.c +++ b/src/or/router.c @@ -1922,7 +1922,7 @@ router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e) /* DNS is screwed up; don't claim to be an exit. */ policies_exit_policy_append_reject_star(&ri->exit_policy); } else { - policies_parse_exit_policy_from_options(options,ri->addr,&ri->ipv6_addr,1, + policies_parse_exit_policy_from_options(options,ri->addr,&ri->ipv6_addr, &ri->exit_policy); } ri->policy_is_reject_star = diff --git a/src/test/test_policy.c b/src/test/test_policy.c index cbeb057..18d9594 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -2,6 +2,8 @@ /* See LICENSE for licensing information */
#include "or.h" +#define CONFIG_PRIVATE +#include "config.h" #include "router.h" #include "routerparse.h" #include "policies.h" @@ -49,7 +51,7 @@ test_policy_summary_helper(const char *policy_str,
r = policies_parse_exit_policy(&line, &policy, EXIT_POLICY_IPV6_ENABLED | - EXIT_POLICY_ADD_DEFAULT, 0, NULL, 0); + EXIT_POLICY_ADD_DEFAULT, 0, NULL, NULL, NULL); tt_int_op(r,OP_EQ, 0);
summary = policy_summarize(policy, AF_INET); @@ -116,7 +118,7 @@ test_policies_general(void *arg) EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + NULL, NULL, NULL));
tt_assert(policy2);
@@ -125,7 +127,8 @@ test_policies_general(void *arg) EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | EXIT_POLICY_ADD_DEFAULT, - 0x0306090cu, &tar, 1)); + 0x0306090cu, &tar, NULL, + NULL));
tt_assert(policy12);
@@ -207,14 +210,14 @@ test_policies_general(void *arg) EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_REJECT_PRIVATE | EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + NULL, NULL, NULL));
tt_assert(policy8);
tt_int_op(0, OP_EQ, policies_parse_exit_policy(NULL, &policy9, EXIT_POLICY_REJECT_PRIVATE | EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + NULL, NULL, NULL));
tt_assert(policy9);
@@ -269,7 +272,7 @@ test_policies_general(void *arg) tt_int_op(0, OP_EQ, policies_parse_exit_policy(&line,&policy, EXIT_POLICY_IPV6_ENABLED | EXIT_POLICY_ADD_DEFAULT, 0, - NULL, 0)); + NULL, NULL, NULL)); tt_assert(policy);
//test_streq(policy->string, "accept *:80"); @@ -530,7 +533,7 @@ test_policies_reject_exit_address(void *arg) /* 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, - 0); + NULL, NULL, 0, 0); tt_assert(policy); tt_assert(smartlist_len(policy) == 1); tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); @@ -540,7 +543,7 @@ test_policies_reject_exit_address(void *arg) /* 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, - 0); + NULL, NULL, 0, 0); tt_assert(policy); tt_assert(smartlist_len(policy) == 1); tt_assert(test_policy_has_address_helper(policy, &ipv4_addr)); @@ -548,7 +551,8 @@ test_policies_reject_exit_address(void *arg) policy = NULL;
/* test that ipv6_local_address is rejected on an IPv4/IPv6 exit */ - policies_parse_exit_policy_reject_private(&policy, 1, 0, &ipv6_addr, 0); + policies_parse_exit_policy_reject_private(&policy, 1, 0, &ipv6_addr, NULL, + NULL, 0, 0); tt_assert(policy); tt_assert(smartlist_len(policy) == 1); tt_assert(test_policy_has_address_helper(policy, &ipv6_addr)); @@ -559,13 +563,155 @@ test_policies_reject_exit_address(void *arg) * (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, 0); + policies_parse_exit_policy_reject_private(&policy, 0, 0, &ipv6_addr, NULL, + NULL, 0, 0); tt_assert(policy == NULL);
done: 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); + + /* 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); + 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); + 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); + 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); + 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_ 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); + 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); +} + +static smartlist_t *test_configured_ports = NULL; +const smartlist_t *mock_get_configured_ports(void); + +/** Returns test_configured_ports */ +const smartlist_t * +mock_get_configured_ports(void) +{ + return test_configured_ports; +} + +/** Run unit tests for rejecting publicly routable configured port addresses + * on this exit relay using policies_parse_exit_policy_reject_private */ +static void +test_policies_reject_port_address(void *arg) +{ + smartlist_t *policy = NULL; + port_cfg_t *ipv4_port = NULL; + port_cfg_t *ipv6_port = NULL; + (void)arg; + + test_configured_ports = smartlist_new(); + + ipv4_port = port_cfg_new(0); + tor_addr_from_ipv4h(&ipv4_port->addr, TEST_IPV4_ADDR); + smartlist_add(test_configured_ports, ipv4_port); + + ipv6_port = port_cfg_new(0); + tor_addr_parse(&ipv6_port->addr, TEST_IPV6_ADDR); + smartlist_add(test_configured_ports, ipv6_port); + + MOCK(get_configured_ports, mock_get_configured_ports); + + /* test that an IPv4 port is rejected on an IPv4-only exit, but an IPv6 port + * is NOT rejected (all IPv6 addresses are rejected by + * policies_parse_exit_policy_internal on IPv4-only exits, so + * policies_parse_exit_policy_reject_private doesn't need to do anything + * with IPv6 addresses on IPv4-only exits) */ + policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, 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, 0, NULL, NULL, NULL, + 0, 1); + tt_assert(policy); + tt_assert(smartlist_len(policy) == 2); + tt_assert(test_policy_has_address_helper(policy, &ipv4_port->addr)); + tt_assert(test_policy_has_address_helper(policy, &ipv6_port->addr)); + addr_policy_list_free(policy); + policy = NULL; + +done: + addr_policy_list_free(policy); + if (test_configured_ports) { + SMARTLIST_FOREACH(test_configured_ports, + port_cfg_t *, p, port_cfg_free(p)); + smartlist_free(test_configured_ports); + test_configured_ports = NULL; + } + UNMOCK(get_configured_ports); +} + #undef TEST_IPV4_ADDR #undef TEST_IPV6_ADDR
@@ -582,12 +728,14 @@ 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, 0); + policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, 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, 1); + policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL, + 1, 0); if (policy) { tt_assert(smartlist_len(policy) == smartlist_len(public_ipv4_addrs)); addr_policy_list_free(policy); @@ -596,7 +744,8 @@ 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, 1); + policies_parse_exit_policy_reject_private(&policy, 0, 0, NULL, NULL, NULL, + 1, 0); if (policy) { tt_assert(smartlist_len(policy) == (smartlist_len(public_ipv4_addrs) + smartlist_len(public_ipv6_addrs))); @@ -705,6 +854,8 @@ struct testcase_t policy_tests[] = { { "general", test_policies_general, 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 };