]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Don't assign Exit flag incorrectly
authorSebastian Hahn <sebastian@torproject.org>
Tue, 2 Feb 2010 13:51:51 +0000 (14:51 +0100)
committerSebastian Hahn <sebastian@torproject.org>
Wed, 3 Feb 2010 04:44:00 +0000 (05:44 +0100)
exit_policy_is_general_exit() assumed that there are no redundancies
in the passed policy, in the sense that we actively combine entries
in the policy to really get rid of any redundancy. Since we cannot
do that without massively rewriting the policy lines the relay
operators set, fix exit_policy_is_general_exit().

Fixes bug 1238, discovered by Martin Kowalczyk.

ChangeLog
src/or/policies.c

index 78e40396aa6ca92c38262ef59e9857c24489c77d..2cf77765e04989c0ad1f7be943b5cebffbdebbd9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,10 @@
 Changes in version 0.2.2.9-alpha - 2010-??-??
+  o Major bugfixes:
+    - Authorities could be tricked into giving out the Exit flag to relays
+      that didn't allow exiting to any ports. This could screw with load
+      balancing and stats. Bugfix on 0.1.1.6-alpha, fixes bug 1238. Bug
+      discovered by Martin Kowalczyk.
+
   o Minor bugfixes:
     - When deciding whether to use strange flags to turn TLS renegotiation
       on, detect the OpenSSL version at run-time, not compile time.  We
index 453138eb464b724271e89cceef274aee5eede699..ab308f764d02291ccf6b75b63a75b7930c868055 100644 (file)
@@ -865,6 +865,43 @@ policies_set_router_exitpolicy_to_reject_all(routerinfo_t *r)
   smartlist_add(r->exit_policy, item);
 }
 
+/** Return 1 if there is at least one /8 subnet in <b>policy</b> that
+ * allows exiting to <b>port</b>. */
+static int
+exit_policy_is_general_exit_helper(smartlist_t *policy, int port)
+{
+  uint32_t j;
+  /* Is this /8 rejected (1), or undecided (0)? */
+  char subnet_status[256];
+
+  memset(subnet_status, 0, sizeof(subnet_status));
+  SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
+    if (p->prt_min > port || p->prt_max < port)
+      continue; /* Doesn't cover our port. */
+    for (j = 0; j < 256; ++j) {
+      tor_addr_t addr;
+      if (subnet_status[j] != 0)
+        continue; /* We already reject some part of this /8 */
+      tor_addr_from_ipv4h(&addr, j<<24);
+      if (tor_addr_is_internal(&addr, 1)) /* 1 because * = 0.0.0.0 */
+        continue; /* Local or non-routable addresses */
+      if (tor_addr_compare_masked(&addr, &p->addr, p->maskbits,
+                                  CMP_EXACT) == 0) {
+        if (p->policy_type == ADDR_POLICY_ACCEPT) {
+          if (p->maskbits > 8)
+            continue; /* Narrower than a /8. */
+          /* We found an allowed subnet of at least size /8. Done
+           * for this port! */
+          return 1;
+        } else if (p->policy_type == ADDR_POLICY_REJECT) {
+          subnet_status[j] = 1;
+        }
+      }
+    }
+  });
+  return 0;
+}
+
 /** Return true iff <b>ri</b> is "useful as an exit node", meaning
  * it allows exit to at least one /8 address space for at least
  * two of ports 80, 443, and 6667. */
@@ -878,19 +915,7 @@ exit_policy_is_general_exit(smartlist_t *policy)
     return 0;
 
   for (i = 0; i < 3; ++i) {
-    SMARTLIST_FOREACH(policy, addr_policy_t *, p, {
-      if (p->prt_min > ports[i] || p->prt_max < ports[i])
-        continue; /* Doesn't cover our port. */
-      if (p->maskbits > 8)
-        continue; /* Narrower than a /8. */
-      if (tor_addr_is_loopback(&p->addr))
-        continue; /* 127.x or ::1. */
-      /* We have a match that is at least a /8. */
-      if (p->policy_type == ADDR_POLICY_ACCEPT) {
-        ++n_allowed;
-        break; /* stop considering this port */
-      }
-    });
+    n_allowed += exit_policy_is_general_exit_helper(policy, ports[i]);
   }
   return n_allowed >= 2;
 }