[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [bridgedb/master] 4568 - Add class PluggableTransport to Bridges
commit 4300329a30f3b6aa3e390b140193dd50faa6e03f
Author: aagbsn <aagbsn@xxxxxxxx>
Date: Wed Jun 20 04:40:16 2012 -0700
4568 - Add class PluggableTransport to Bridges
Adds a class PluggableTransport and function parseExtraInfoFile()
to read pluggable transports from bridge extra-info descriptors.
Also adds transport support in FilteredBridgeSplitter.dumpAssignments
---
lib/bridgedb/Bridges.py | 133 +++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 129 insertions(+), 4 deletions(-)
diff --git a/lib/bridgedb/Bridges.py b/lib/bridgedb/Bridges.py
index 5a3949a..3d72d37 100644
--- a/lib/bridgedb/Bridges.py
+++ b/lib/bridgedb/Bridges.py
@@ -105,7 +105,7 @@ class Bridge:
## running,stable -- DOCDOC
## blockingCountries -- list of country codes blocking this bridge
def __init__(self, nickname, ip, orport, fingerprint=None, id_digest=None,
- or_addresses=None):
+ or_addresses=None, transports=None):
"""Create a new Bridge. One of fingerprint and id_digest must be
set."""
self.nickname = nickname
@@ -113,8 +113,11 @@ class Bridge:
self.orport = orport
if not or_addresses: or_addresses = {}
self.or_addresses = or_addresses
+ if not transports: transports = []
+ self.transports = transports
self.running = self.stable = None
self.blockingCountries = None
+
if id_digest is not None:
assert fingerprint is None
if len(id_digest) != DIGEST_LEN:
@@ -142,13 +145,14 @@ class Bridge:
self.nickname, self.ip, self.orport, self.fingerprint)
def getConfigLine(self, includeFingerprint=False, addressClass=None,
- request=None):
+ request=None, transport=None):
"""Returns a valid bridge line for inclusion in a torrc"""
#arguments:
# includeFingerprint
# addressClass - type of address to choose
# request - a string unique to this request
# e.g. email-address or uniformMap(ip)
+ # transport - a pluggable transport method name
if not request: request = 'default'
digest = get_hmac_fn('Order-Or-Addresses')(request)
@@ -157,6 +161,18 @@ class Bridge:
# default address type
if not addressClass: addressClass = ipaddr.IPv4Address
+ # pluggable transports
+ if transport:
+ # filter by 'methodname'
+ transports = filter(lambda x: transport == x.methodname,
+ self.transports)
+ # filter by 'addressClass'
+ transports = filter(lambda x: isinstance(x.address, addressClass),
+ transports)
+ if transports:
+ pt = transports[pos % len(transports)]
+ return pt.getTransportLine(includeFingerprint)
+
# filter addresses by address class
addresses = filter(lambda x: isinstance(x[0], addressClass),
self.or_addresses.items())
@@ -179,8 +195,6 @@ class Bridge:
def getAllConfigLines(self,includeFingerprint=False):
"""Generator. Iterate over all valid config lines for this bridge."""
- # warning: a bridge with large port ranges may generate thousands
- # of lines of output
for address,portlist in self.or_addresses.items():
if type(address) is ipaddr.IPv6Address:
ip = "[%s]" % address
@@ -192,6 +206,9 @@ class Bridge:
yield "bridge %s:%d %s" % (ip,orport,self.fingerprint)
else:
yield "bridge %s:%d" % (ip,orport)
+ for pt in self.transports:
+ yield pt.getTransportLine(includeFingerprints)
+
def assertOK(self):
assert is_valid_ip(self.ip)
@@ -352,6 +369,108 @@ def parseORAddressLine(line):
if address and portlist and len(portlist): return address,portlist
raise ParseORAddressError
+class PluggableTransport:
+ """
+ an object that represents a pluggable-transport method
+ and a reference to the relevant bridge
+ """
+ def __init__(self, bridge, methodname, address, port, argdict=None):
+
+ #XXX: assert are disabled with python -O
+ assert isinstance(bridge, Bridge)
+ assert type(address) in (ipaddr.IPv4Address, ipaddr.IPv6Address)
+ assert type(port) is int
+ assert (0 < port < 65536)
+ assert type(methodname) is str
+
+ self.bridge = bridge
+ self.address = address
+ self.port = port
+ self.methodname = methodname
+ if type(argdict) is dict:
+ self.argdict = argdict
+ else: self.argdict = {}
+
+ def getTransportLine(self, includeFingerprint=False):
+ """
+ returns a torrc bridge line for this transport
+ """
+ if isinstance(self.address,ipaddr.IPv6Address):
+ address = "[%s]" % self.address
+ else: address = self.address
+ host = "bridge %s %s:%d" % (self.methodname, address, self.port)
+ fp = ''
+ if includeFingerprint: fp = "keyid=%s" % self.bridge.fingerprint
+ args = " ".join(["%s=%s"%(k,v) for k,v in self.argdict.items()]).strip()
+ return "%s %s %s" % (host, fp, args)
+
+def parseExtraInfoFile(f):
+ """
+ parses lines in Bridges extra-info documents.
+ returns an object whose type corresponds to the
+ relevant set of extra-info lines.
+
+ presently supported lines and the accompanying type are:
+
+ { 'transport': PluggableTransport, }
+
+ 'transport' lines (torspec.git/proposals/180-pluggable-transport.txt)
+
+ Bridges put the 'transport' lines in their extra-info documents.
+ the format is:
+
+ transport SP <methodname> SP <address:port> [SP arglist] NL
+ """
+
+ ID = None
+ for line in f:
+ line = line.strip()
+
+ argdict = {}
+
+ # do we need to skip 'opt' here?
+ # if line.startswith("opt "):
+ # line = line[4:]
+
+ # get the bridge ID ?
+ if line.startswith("extra-info "): #XXX: get the router ID
+ line = line[11:]
+ (nickname, ID) = line.split()
+ if is_valid_fingerprint(ID):
+ ID = fromHex(ID)
+
+ # get the transport line
+ if ID and line.startswith("transport "):
+ fields = line[10:].split()
+ # [ arglist ] field, optional
+ if len(fields) >= 3:
+ arglist = fields[2:]
+ # parse arglist [k=v,...k=v] as argdict {k:v,...,k:v}
+ argdict = {}
+ for arg in arglist:
+ try: k,v = arg.split('=')
+ except ValueError: continue
+ argdict[k] = v
+
+ # get the required fields, method name and address
+ if len(fields) >= 2:
+ # get the method name
+ # Method names must be C identifiers
+ for regex in [re_ipv4, re_ipv6]:
+ try:
+ method_name = re.match('[_a-zA-Z][_a-zA-Z0-9]*',fields[0]).group()
+ m = regex.match(fields[1])
+ address = ipaddr.IPAddress(m.group(1))
+ port = int(m.group(2))
+ yield ID, method_name, address, port, argdict
+ except (IndexError, ValueError, AttributeError):
+ # skip this line
+ continue
+
+ # end of descriptor is defined how?
+ if ID and line.startswith("router-signature"):
+ ID = None
+
def parseStatusFile(f):
"""DOCDOC"""
ID = None
@@ -760,7 +879,9 @@ class FilteredBridgeSplitter(BridgeHolder):
logging.debug("insert bridge into %s" % n)
#XXX db.insertBridgeAndGetRing ??
+ # already 'assigned' by the FixedBridgeSplitter
#XXX persisent mapping?
+ # the filters rebuild
def addRing(self, ring, ringname, filterFn, populate_from=None):
"""Add a ring to this splitter.
@@ -804,6 +925,10 @@ class FilteredBridgeSplitter(BridgeHolder):
except TypeError:
desc.append(g.description)
+ # add transports
+ for transport in b.transports:
+ desc.append("transport=%s"%(transport.methodname))
+
# dedupe and group
desc = set(desc)
grouped = dict()
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits