[tor-commits] [arm/release] Util for getting condensed exit policies

atagar at torproject.org atagar at torproject.org
Sun Sep 25 21:38:28 UTC 2011


commit 8a40c745ce5f040aef38963b2a047ba2f92ee392
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Sep 12 19:27:14 2011 -0700

    Util for getting condensed exit policies
    
    Expanding the ExitPolicy class to provide condensed exit policies like the tor
    consensus.
---
 src/util/torTools.py |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/src/util/torTools.py b/src/util/torTools.py
index 7c14d18..b9d9ac8 100644
--- a/src/util/torTools.py
+++ b/src/util/torTools.py
@@ -2286,6 +2286,21 @@ class Controller(TorCtl.PostEventListener):
     
     self.connLock.release()
 
+class ExitPolicyIterator:
+  """
+  Basic iterator for cycling through ExitPolicy entries.
+  """
+  
+  def __init__(self, head):
+    self.head = head
+  
+  def next(self):
+    if self.head:
+      lastHead = self.head
+      self.head = self.head.nextRule
+      return lastHead
+    else: raise StopIteration
+
 class ExitPolicy:
   """
   Single rule from the user's exit policy. These are chained together to form
@@ -2301,6 +2316,9 @@ class ExitPolicy:
       nextRule  - next rule to be checked when queries don't match this policy
     """
     
+    # cached summary string
+    self.summaryStr = None
+    
     # sanitize the input a bit, cleaning up tabs and stripping quotes
     ruleEntry = ruleEntry.replace("\\t", " ").replace("\"", "")
     
@@ -2405,6 +2423,80 @@ class ExitPolicy:
     if self.nextRule: return self.nextRule.check(ipAddress, port)
     else: return True # fell off the chain without a conclusion (shouldn't happen...)
   
+  def getSummary(self):
+    """
+    Provides a summary description of the policy chain similar to the
+    consensus. This excludes entries that don't cover all ips, and is either
+    a whitelist or blacklist policy based on the final entry. For instance...
+    accept 80, 443        # just accepts ports 80/443
+    reject 1-1024, 5555   # just accepts non-privilaged ports, excluding 5555
+    """
+    
+    if not self.summaryStr:
+      # determines if we're a whitelist or blacklist
+      isWhitelist = False # default in case we don't have a catch-all policy at the end
+      
+      for rule in self:
+        if rule.isIpWildcard and rule.isPortWildcard:
+          isWhitelist = not rule.isAccept
+          break
+      
+      # Iterates over the rules and adds the the ports we'll return (ie, allows
+      # if a whitelist and rejects if a blacklist). Reguardless of a port's
+      # allow/reject policy, all further entries with that port are ignored since
+      # policies respect the first matching rule.
+      
+      displayPorts, skipPorts = [], []
+      
+      for rule in self:
+        if not rule.isIpWildcard: continue
+        
+        if rule.minPort == rule.maxPort:
+          portRange = [rule.minPort]
+        else:
+          portRange = range(rule.minPort, rule.maxPort + 1)
+        
+        for port in portRange:
+          if port in skipPorts: continue
+          
+          # if accept + whitelist or reject + blacklist then add
+          if rule.isAccept == isWhitelist:
+            displayPorts.append(port)
+          
+          # all further entries with this port are to be ignored
+          skipPorts.append(port)
+      
+      # gets a list of the port ranges
+      if displayPorts:
+        displayRanges, tmpRange = [], []
+        displayPorts.sort()
+        displayPorts.append(None) # ending item to include last range in loop
+        
+        for port in displayPorts:
+          if not tmpRange or tmpRange[-1] + 1 == port:
+            tmpRange.append(port)
+          else:
+            if len(tmpRange) > 1:
+              displayRanges.append("%i-%i" % (tmpRange[0], tmpRange[-1]))
+            else:
+              displayRanges.append(str(tmpRange[0]))
+            
+            tmpRange = [port]
+      else:
+        # everything for the inverse
+        isWhitelist = not isWhitelist
+        displayRanges = ["1-65535"]
+      
+      # constructs the summary string
+      labelPrefix = "accept " if isWhitelist else "reject "
+      
+      self.summaryStr = (labelPrefix + ", ".join(displayRanges)).strip()
+    
+    return self.summaryStr
+  
+  def __iter__(self):
+    return ExitPolicyIterator(self)
+  
   def __str__(self):
     # This provides the actual policy rather than the entry used to construct
     # it so the 'private' keyword is expanded.





More information about the tor-commits mailing list