commit 2828ee86dee7028bc2a1265a26204f54af45c181
Author: Damian Johnson <atagar(a)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