[tor-commits] [tor/master] Fix IPv6 support in policy_summary_reject and policy_summary_accept

nickm at torproject.org nickm at torproject.org
Wed Feb 1 14:55:10 UTC 2017


commit 4667a40ca944134866b95b10407a7e471206aa00
Author: teor <teor2345 at gmail.com>
Date:   Wed Feb 1 15:28:46 2017 +1100

    Fix IPv6 support in policy_summary_reject and policy_summary_accept
    
    This interim fix results in too many IPv6 rejections.
    
    No behaviour change for IPv4 counts, except for overflow fixes that
    would require 4 billion redundant 0.0.0.0/0 policy entries to trigger.
    
    Part of 21357
---
 src/or/policies.c | 60 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/src/or/policies.c b/src/or/policies.c
index 71062eb..cac475d 100644
--- a/src/or/policies.c
+++ b/src/or/policies.c
@@ -2304,6 +2304,12 @@ policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts)
  * IPv4 /8 address blocks */
 #define REJECT_CUTOFF_COUNT_IPV4 (U64_LITERAL(1) << \
                                   (IPV4_BITS - 7))
+
+#define IPV6_BITS                (128)
+/* Ports are rejected in an IPv6 summary if they are rejected in at least one
+ * IPv6 /64. */
+#define REJECT_CUTOFF_COUNT_IPV6 (UINT64_MAX)
+
 /** Split an exit policy summary so that prt_min and prt_max
  * fall at exactly the start and end of an item respectively.
  */
@@ -2336,40 +2342,68 @@ policy_summary_split(smartlist_t *summary,
   return start_at_index;
 }
 
-/** Mark port ranges as accepted if they are below the reject_count */
+/** Mark port ranges as accepted if they are below the reject_count for family
+ */
 static void
 policy_summary_accept(smartlist_t *summary,
-                      uint16_t prt_min, uint16_t prt_max)
+                      uint16_t prt_min, uint16_t prt_max,
+                      sa_family_t family)
 {
+  tor_assert_nonfatal_once(family == AF_INET || family == AF_INET6);
+  uint64_t family_reject_count = ((family == AF_INET) ?
+                                  REJECT_CUTOFF_COUNT_IPV4 :
+                                  REJECT_CUTOFF_COUNT_IPV6);
+
   int i = policy_summary_split(summary, prt_min, prt_max);
   while (i < smartlist_len(summary) &&
          AT(i)->prt_max <= prt_max) {
     if (!AT(i)->accepted &&
-        AT(i)->reject_count <= REJECT_CUTOFF_COUNT_IPV4)
+        AT(i)->reject_count <= family_reject_count)
       AT(i)->accepted = 1;
     i++;
   }
   tor_assert(i < smartlist_len(summary) || prt_max==65535);
 }
 
-/** Count the number of addresses in a network with prefixlen maskbits
- * against the given portrange. */
+/** Count the number of addresses in a network in family with prefixlen
+ * maskbits against the given portrange. */
 static void
 policy_summary_reject(smartlist_t *summary,
                       maskbits_t maskbits,
-                      uint16_t prt_min, uint16_t prt_max)
+                      uint16_t prt_min, uint16_t prt_max,
+                      sa_family_t family)
 {
+  tor_assert_nonfatal_once(family == AF_INET || family == AF_INET6);
+
   int i = policy_summary_split(summary, prt_min, prt_max);
-  /* XXX: ipv4 specific */
+
   /* The length of a single address mask */
-  int addrbits = IPV4_BITS;
+  int addrbits = (family == AF_INET) ? IPV4_BITS : IPV6_BITS;
   tor_assert_nonfatal_once(addrbits >= maskbits);
 
-  uint64_t count = (U64_LITERAL(1) << (addrbits-maskbits));
+  uint64_t count = 0;
+  if (addrbits - maskbits >= 64) {
+    tor_assert_nonfatal_once(family == AF_INET6);
+    /* The address range is so large, it's an automatic rejection for all ports
+     * in the range. */
+    count = UINT64_MAX;
+  } else {
+    count = (U64_LITERAL(1) << (addrbits - maskbits));
+  }
   tor_assert_nonfatal_once(count > 0);
   while (i < smartlist_len(summary) &&
          AT(i)->prt_max <= prt_max) {
-    AT(i)->reject_count += count;
+    if (AT(i)->reject_count <= UINT64_MAX - count) {
+      AT(i)->reject_count += count;
+    } else {
+      /* IPv4 would require a 4-billion address redundant policy to get here,
+       * but IPv6 just needs to have ::/0 */
+      if (family == AF_INET) {
+        tor_assert_nonfatal_unreached_once();
+      }
+      /* If we do get here, use saturating arithmetic */
+      AT(i)->reject_count = UINT64_MAX;
+    }
     i++;
   }
   tor_assert(i < smartlist_len(summary) || prt_max==65535);
@@ -2389,7 +2423,7 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
 {
   if (p->policy_type == ADDR_POLICY_ACCEPT) {
     if (p->maskbits == 0) {
-      policy_summary_accept(summary, p->prt_min, p->prt_max);
+      policy_summary_accept(summary, p->prt_min, p->prt_max, p->addr.family);
     }
   } else if (p->policy_type == ADDR_POLICY_REJECT) {
 
@@ -2410,7 +2444,8 @@ policy_summary_add_item(smartlist_t *summary, addr_policy_t *p)
      }
 
      if (!is_private) {
-       policy_summary_reject(summary, p->maskbits, p->prt_min, p->prt_max);
+       policy_summary_reject(summary, p->maskbits, p->prt_min, p->prt_max,
+                             p->addr.family);
      }
   } else
     tor_assert(0);
@@ -2444,7 +2479,6 @@ policy_summarize(smartlist_t *policy, sa_family_t family)
     }
     if (f != family)
       continue;
-    /* XXXX-ipv6 More family work is needed */
     policy_summary_add_item(summary, p);
   } SMARTLIST_FOREACH_END(p);
 





More information about the tor-commits mailing list