[tor-commits] [tor/master] Block OutboundBindAddressIPv[4|6]_ and configured ports on exit relays

nickm at torproject.org nickm at torproject.org
Fri Nov 20 15:54:16 UTC 2015


commit 66fac9fbadae529349f00172760688cf3caeb64d
Author: teor (Tim Wilson-Brown) <teor2345 at 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
 };
 





More information about the tor-commits mailing list