[tor-commits] [stem/master] Missing version 3 attributes

atagar at torproject.org atagar at torproject.org
Mon Mar 26 00:10:01 UTC 2012


commit 7dc7d82bd7b7f70f3dfae21dd607502b4eff6477
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Mar 24 19:38:27 2012 -0700

    Missing version 3 attributes
    
    Adding the server descriptor attributes that are new as of version 3. The only
    attributes that I'm still excluding are eventdns (because it's dead) and
    read/write-history (since they're extra-info now).
---
 stem/descriptor/server_descriptor.py       |   56 +++++++++++++++++++++++++--
 test/integ/descriptor/server_descriptor.py |    6 +++
 2 files changed, 57 insertions(+), 5 deletions(-)

diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index c301840..ceee835 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -33,26 +33,31 @@ PGP_BLOCK_START = re.compile("^-----BEGIN ([%s%s]+)-----$" % (KEYWORD_CHAR, WHIT
 PGP_BLOCK_END   = "-----END %s-----"
 
 # entries must have exactly one of the following
-# TODO: spec doesn't list 'router-signature', but that's a spec bug I should fix
 REQUIRED_FIELDS = (
+  "router",
+  "bandwidth",
   "published",
   "onion-key",
   "signing-key",
-  "bandwidth",
   "router-signature",
 )
 
 # optional entries that can appear at most once
 SINGLE_FIELDS = (
-  "contact",
-  "uptime",
+  "platform",
   "fingerprint",
   "hibernating",
+  "uptime",
+  "contact",
   "read-history",
   "write-history",
   "eventdns",
-  "platform",
   "family",
+  "caches-extra-info",
+  "extra-info-digest",
+  "hidden-service-dir",
+  "protocols",
+  "allow-single-hop-exits",
 )
 
 def parse_file_v3(descriptor_file, validate = True):
@@ -203,7 +208,13 @@ class ServerDescriptorV3(stem.descriptor.Descriptor):
     uptime (int)             - relay's uptime when published in seconds
     published (datetime.datetime) - time in GMT when the descriptor was generated (*)
     contact (str)            - relay's contact information
+    link_protocols (list)    - link protocols supported by the relay
+    circuit_protocols (list) - circuit protocols supported by the relay
     hibernating (bool)       - flag to indicate if the relay was hibernating when published (*)
+    allow_single_hop_exits (bool) - flag to indicate if single hop exiting is allowed from it (*)
+    extra_info_cache (bool)  - flag to indicate if it's a mirror for extra-info documents (*)
+    extra_info_digest (str)  - hex encoded digest of our extra-info document
+    hidden_service_dir (list) - hidden service descriptor versions that it stores
     exit_policy (stem.exit_policy.ExitPolicy) - relay's stated exit policy
     family (list)            - nicknames or fingerprints of relays it has a declared family with (*)
     average_bandwidth (int)  - rate of traffic relay is willing to relay in bytes/s (*)
@@ -253,7 +264,13 @@ class ServerDescriptorV3(stem.descriptor.Descriptor):
     self.uptime = None
     self.published = None
     self.contact = None
+    self.link_protocols = None
+    self.circuit_protocols = None
     self.hibernating = False
+    self.allow_single_hop_exits = False
+    self.extra_info_cache = False
+    self.extra_info_digest = None
+    self.hidden_service_dir = None
     self.family = []
     self.average_bandwidth = None
     self.burst_bandwidth = None
@@ -337,6 +354,9 @@ class ServerDescriptorV3(stem.descriptor.Descriptor):
       for keyword in SINGLE_FIELDS + REQUIRED_FIELDS:
         if keyword in entries and len(entries[keyword]) > 1:
           raise ValueError("The '%s' entry can only appear once in a descriptor" % keyword)
+      
+      if not self.exit_policy:
+        raise ValueError("Descriptor must have at least one 'accept' or 'reject' entry")
     
     # parse all the entries into our attributes
     for keyword, values in entries.items():
@@ -444,6 +464,23 @@ class ServerDescriptorV3(stem.descriptor.Descriptor):
           raise ValueError("Hibernating line had an invalid value, must be zero or one: %s" % value)
         
         self.hibernating = value == "1"
+      elif keyword == "allow-single-hop-exits":
+        self.allow_single_hop_exits = True
+      elif keyword == "caches-extra-info":
+        self.extra_info_cache = True
+      elif keyword == "extra-info-digest":
+        # this is fourty hex digits which just so happens to be the same a
+        # fingerprint
+        
+        if validate and not stem.util.tor_tools.is_valid_fingerprint(value):
+          raise ValueError("Hidden service digests should consist of fourty hex digits: %s" % value)
+        
+        self.extra_info_digest = value
+      elif keyword == "hidden-service-dir":
+        if value:
+          self.hidden_service_dir = value.split(" ")
+        else:
+          self.hidden_service_dir = ["2"]
       elif keyword == "uptime":
         if not value.isdigit():
           if not validate: continue
@@ -470,6 +507,15 @@ class ServerDescriptorV3(stem.descriptor.Descriptor):
         self.signature = block_contents
       elif keyword == "contact":
         self.contact = value
+      elif keyword == "protocols":
+        protocols_match = re.match("^Link (.*) Circuit (.*)$", value)
+        
+        if protocols_match:
+          link_versions, circuit_versions = protocols_match.groups()
+          self.link_protocols = link_versions.split(" ")
+          self.circuit_protocols = circuit_versions.split(" ")
+        elif validate:
+          raise ValueError("Protocols line did not match the expected pattern: %s" % line)
       elif keyword == "family":
         self.family = value.split(" ")
       else:
diff --git a/test/integ/descriptor/server_descriptor.py b/test/integ/descriptor/server_descriptor.py
index 5a070a2..a956606 100644
--- a/test/integ/descriptor/server_descriptor.py
+++ b/test/integ/descriptor/server_descriptor.py
@@ -68,7 +68,13 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
     self.assertEquals(588217, desc.uptime)
     self.assertEquals(expected_published, desc.published)
     self.assertEquals("www.atagar.com/contact", desc.contact)
+    self.assertEquals(["1", "2"], desc.link_protocols)
+    self.assertEquals(["1"], desc.circuit_protocols)
     self.assertEquals(False, desc.hibernating)
+    self.assertEquals(False, desc.allow_single_hop_exits)
+    self.assertEquals(False, desc.extra_info_cache)
+    self.assertEquals("D225B728768D7EA4B5587C13A7A9D22EBBEE6E66", desc.extra_info_digest)
+    self.assertEquals(["2"], desc.hidden_service_dir)
     self.assertEquals(expected_family, desc.family)
     self.assertEquals(153600, desc.average_bandwidth)
     self.assertEquals(256000, desc.burst_bandwidth)





More information about the tor-commits mailing list