[tor-commits] [tor/master] Add controller getinfo exit-policy/reject-private

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


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





More information about the tor-commits mailing list