commit ac5be8cee5f58517c09217fd6860f7ef483dacc2
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Aug 5 20:14:18 2012 -0700
Fully parsing transport lines
The extrainfo descriptor's new transport lines were a little funny in that
they're only relevant to bridges, and when they apprear in bridges they're
scrubbed of everything except the transport name. This in turn meant that they
only appeared with transport names in the wild.
However, now that transport lines can appear in non-bridge relays I'll
sometimes see complete transport lines, so parsing and validating them
properly.
---
stem/descriptor/extrainfo_descriptor.py | 41 ++++++++++++++++++++++---
test/unit/descriptor/extrainfo_descriptor.py | 4 +-
2 files changed, 38 insertions(+), 7 deletions(-)
diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py
index 8d66df6..a589139 100644
--- a/stem/descriptor/extrainfo_descriptor.py
+++ b/stem/descriptor/extrainfo_descriptor.py
@@ -179,7 +179,7 @@ class ExtraInfoDescriptor(stem.descriptor.Descriptor):
:var str fingerprint: **\*** identity key fingerprint
:var datetime published: **\*** time in GMT when this descriptor was made
:var str geoip_db_digest: sha1 of geoIP database file
- :var list transport: transport method recognized by the bridge (ex. obfs3)
+ :var dict transport: **\*** mapping of transport methods to their (address, port, args) tuple, these usually appeear on bridges in which case all of those are None
**Bi-directional connection usage:**
@@ -288,7 +288,7 @@ class ExtraInfoDescriptor(stem.descriptor.Descriptor):
self.fingerprint = None
self.published = None
self.geoip_db_digest = None
- self.transport = None
+ self.transport = {}
self.conn_bi_direct_end = None
self.conn_bi_direct_interval = None
@@ -432,10 +432,41 @@ class ExtraInfoDescriptor(stem.descriptor.Descriptor):
# on non-bridges in the wild when the relay operator configured it this
# way.
- if self.transport is None:
- self.transport = []
+ name, address, port, args = None, None, None, None
- self.transport.append(value)
+ if not ' ' in value:
+ # scrubbed
+ name = value
+ else:
+ # not scrubbed
+ value_comp = value.split()
+
+ if len(value_comp) < 1:
+ raise ValueError("Transport line is missing its transport name: %s" % line)
+ else:
+ name = value_comp[0]
+
+ if len(value_comp) < 2:
+ raise ValueError("Transport line is missing its address:port value: %s" % line)
+ elif not ":" in value_comp[1]:
+ raise ValueError("Transport line's address:port entry is missing a colon: %s" % line)
+ else:
+ address, port_str = value_comp[1].split(':', 1)
+
+ if not stem.util.connection.is_valid_ip_address(address) or \
+ stem.util.connection.is_valid_ipv6_address(address):
+ raise ValueError("Transport line has a malformed address: %s" % line)
+ elif not stem.util.connection.is_valid_port(port_str):
+ raise ValueError("Transport line has a malformed port: %s" % line)
+
+ port = int(port_str)
+
+ if len(value_comp) >= 3:
+ args = value_comp[2:]
+ else:
+ args = []
+
+ self.transport[name] = (address, port, args)
elif keyword == "cell-circuits-per-decile":
# "cell-circuits-per-decile" num
diff --git a/test/unit/descriptor/extrainfo_descriptor.py b/test/unit/descriptor/extrainfo_descriptor.py
index 1008af7..54d6bf8 100644
--- a/test/unit/descriptor/extrainfo_descriptor.py
+++ b/test/unit/descriptor/extrainfo_descriptor.py
@@ -527,12 +527,12 @@ class TestExtraInfoDescriptor(unittest.TestCase):
desc_text = _make_descriptor({"transport": "obfs3"}, is_bridge = True)
desc = BridgeExtraInfoDescriptor(desc_text)
- self.assertEquals(["obfs3"], desc.transport)
+ self.assertEquals({"obfs3": (None, None, None)}, desc.transport)
self.assertEquals([], desc.get_unrecognized_lines())
desc_text = _make_descriptor({"transport": "obfs2 83.212.96.201:33570"})
desc = RelayExtraInfoDescriptor(desc_text)
- self.assertEquals(["obfs2 83.212.96.201:33570"], desc.transport)
+ self.assertEquals({"obfs2": ("83.212.96.201", 33570, [])}, desc.transport)
self.assertEquals([], desc.get_unrecognized_lines())
def _expect_invalid_attr(self, desc_text, attr = None, expected_value = None):