[tor-commits] [arm/release] Util function for getting a relay's exit policy

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


commit 2828ee86dee7028bc2a1265a26204f54af45c181
Author: Damian Johnson <atagar at torproject.org>
Date:   Mon Sep 12 10:07:52 2011 -0700

    Util function for getting a relay's exit policy
    
    Function that fetches a relay's exit policy, first using the descriptor and
    falling back to its consensus entry. I'm a little concerned that obsolete
    descriptor data can throw this off but not sure of a better method for doing
    this...
---
 src/util/torTools.py |   78 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/src/util/torTools.py b/src/util/torTools.py
index c81847c..7c14d18 100644
--- a/src/util/torTools.py
+++ b/src/util/torTools.py
@@ -14,7 +14,7 @@ import Queue
 
 from TorCtl import TorCtl, TorUtil
 
-from util import enum, log, procTools, sysTools, uiTools
+from util import connections, enum, log, procTools, sysTools, uiTools
 
 # enums for tor's controller state:
 # INIT - attached to a new controller
@@ -1117,10 +1117,10 @@ class Controller(TorCtl.PostEventListener):
         isPrivateRejected = self.getOption("ExitPolicyRejectPrivate", True)
         
         if isPrivateRejected:
-          result = ExitPolicy("reject private", result)
-          
           myAddress = self.getInfo("address")
           if myAddress: result = ExitPolicy("reject %s" % myAddress, result)
+          
+          result = ExitPolicy("reject private", result)
       else:
         # no ORPort is set so all relaying is disabled
         result = ExitPolicy("reject *:*", None)
@@ -1250,6 +1250,78 @@ class Controller(TorCtl.PostEventListener):
     
     return result
   
+  def getRelayExitPolicy(self, relayFingerprint, allowImprecision = True):
+    """
+    Provides the ExitPolicy instance associated with the given relay. The tor
+    consensus entries don't indicate if private addresses are rejected or
+    address-specific policies, so this is only used as a fallback if a recent
+    descriptor is unavailable. This returns None if unable to determine the
+    policy.
+    
+    Arguments:
+      relayFingerprint - fingerprint of the relay
+      allowImprecision - make use of consensus policies as a fallback
+    """
+    
+    self.connLock.acquire()
+    
+    result = None
+    if self.isAlive():
+      # attempts to fetch the policy via the descriptor
+      descriptor = self.getDescriptorEntry(relayFingerprint)
+      
+      if descriptor:
+        exitPolicyEntries = []
+        for line in descriptor.split("\n"):
+          if line.startswith("accept ") or line.startswith("reject "):
+            exitPolicyEntries.append(line)
+        
+        # construct the policy chain
+        for entry in reversed(exitPolicyEntries):
+          result = ExitPolicy(entry, result)
+      elif allowImprecision:
+        # Falls back to using the consensus entry, which is both less precise
+        # and unavailable with older tor versions. This assumes that the relay
+        # has ExitPolicyRejectPrivate set and won't include address-specific
+        # policies.
+        
+        consensusLine, relayAddress = None, None
+        
+        nsEntry = self.getConsensusEntry(relayFingerprint)
+        if nsEntry:
+          for line in nsEntry.split("\n"):
+            if line.startswith("r "):
+              # fetch the relay's public address, which we'll need for the
+              # ExitPolicyRejectPrivate policy entry
+              
+              lineComp = line.split(" ")
+              if len(lineComp) >= 7 and connections.isValidIpAddress(lineComp[6]):
+                relayAddress = lineComp[6]
+            elif line.startswith("p "):
+              consensusLine = line
+              break
+        
+        if consensusLine:
+          acceptance, ports = consensusLine.split(" ")[1:]
+          
+          # starts with a reject-all for whitelists and accept-all for blacklists
+          if acceptance == "accept":
+            result = ExitPolicy("reject *:*", None)
+          else:
+            result = ExitPolicy("accept *:*", None)
+          
+          # adds each of the ports listed in the consensus
+          for port in reversed(ports.split(",")):
+            result = ExitPolicy("%s *:%s" % (acceptance, port), result)
+          
+          # adds ExitPolicyRejectPrivate since this is the default
+          if relayAddress: result = ExitPolicy("reject %s" % relayAddress, result)
+          result = ExitPolicy("reject private", result)
+    
+    self.connLock.release()
+    
+    return result
+  
   def getRelayAddress(self, relayFingerprint, default = None):
     """
     Provides the (IP Address, ORPort) tuple for a given relay. If the lookup





More information about the tor-commits mailing list