commit d5d5e2afe922c2e7c94c27208c5fca2bac4fbd4c Author: Damian Johnson atagar@torproject.org Date: Sun Jul 15 17:40:42 2018 -0700
Add or_addresses to RouterStatusEntryMicroV3
Router status entry 'a' lines previously only appeared in the standard consensus but now they appear in the microdescriptor consensus as well...
https://trac.torproject.org/projects/tor/ticket/26405 https://trac.torproject.org/projects/tor/ticket/23826 --- docs/change_log.rst | 1 + stem/descriptor/router_status_entry.py | 7 ++++ test/unit/descriptor/router_status_entry.py | 53 +++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+)
diff --git a/docs/change_log.rst b/docs/change_log.rst index 09237cba..16f54773 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -67,6 +67,7 @@ The following are only available within Stem's `git repository * Added the *orport_v6* attribute to the :class:`~stem.directory.Authority` class * Added server descriptor's new is_hidden_service_dir attribute * Added the network status vote's new bandwidth_file attribute (:spec:`84591df`) + * Added the microdescriptor router status entry's new or_addresses attribute (:trac:`26405`, :spec:`fdc8f3e8`) * Don't retry downloading descriptors when we've timed out * Don't download from tor26 and Bifroest, which are authorities that frequently timeout * `stem.descriptor.remote <api/descriptor/remote.html>`_ now consistently defaults **fall_back_to_authority** to false diff --git a/stem/descriptor/router_status_entry.py b/stem/descriptor/router_status_entry.py index 5b99ba0c..b4cd506a 100644 --- a/stem/descriptor/router_status_entry.py +++ b/stem/descriptor/router_status_entry.py @@ -662,6 +662,8 @@ class RouterStatusEntryMicroV3(RouterStatusEntry): Information about an individual router stored within a microdescriptor flavored network status document.
+ :var list or_addresses: ***** relay's OR addresses, this is a tuple listing + of the form (address (**str**), port (**int**), is_ipv6 (**bool**)) :var int bandwidth: bandwidth claimed by the relay (in kb/s) :var int measured: bandwidth measured to be available by the relay :var bool is_unmeasured: bandwidth measurement isn't based on three or more @@ -675,11 +677,15 @@ class RouterStatusEntryMicroV3(RouterStatusEntry): .. versionchanged:: 1.6.0 Added the protocols attribute.
+ .. versionchanged:: 1.7.0 + Added the or_addresses attribute. + ***** attribute is either required when we're parsed with validation or has a default value, others are left as **None** if undefined """
ATTRIBUTES = dict(RouterStatusEntry.ATTRIBUTES, **{ + 'or_addresses': ([], _parse_a_line), 'bandwidth': (None, _parse_w_line), 'measured': (None, _parse_w_line), 'is_unmeasured': (False, _parse_w_line), @@ -690,6 +696,7 @@ class RouterStatusEntryMicroV3(RouterStatusEntry): })
PARSER_FOR_LINE = dict(RouterStatusEntry.PARSER_FOR_LINE, **{ + 'a': _parse_a_line, 'w': _parse_w_line, 'm': _parse_microdescriptor_m_line, 'pr': _parse_pr_line, diff --git a/test/unit/descriptor/router_status_entry.py b/test/unit/descriptor/router_status_entry.py index a4c14e01..b376f869 100644 --- a/test/unit/descriptor/router_status_entry.py +++ b/test/unit/descriptor/router_status_entry.py @@ -26,6 +26,12 @@ from stem.descriptor.router_status_entry import ( _base64_to_hex, )
+try: + # Added in 2.7 + from collections import OrderedDict +except ImportError: + from stem.util.ordereddict import OrderedDict + ENTRY_WITHOUT_ED25519 = """\ r seele AAoQ1DAR6kkoo19hBAX5K0QztNw m0ynPuwzSextzsiXYJYA0Hce+Cs 2015-08-23 00:26:35 73.15.150.172 9001 0 s Running Stable Valid @@ -52,6 +58,16 @@ m 18,19,20 sha256=AkZH3gIvz3wunsroqh5izBJizdYuR7kn2oVbsvqgML8 m 21 sha256=AVp41YVxKEJCaoEf0+77Cdvyw5YgpyDXdob0+LSv/pE """
+ENTRY_WITH_IPV6 = """\ +r MYLEX AQt3KEVEEfSFzinUx5oUU0FRwsQ 2018-07-15 16:38:10 77.123.42.148 444 800 +a [2001:470:71:9b9:f66d:4ff:fee7:954c]:444 +m GWb+xjav0fsuwPwPNnUvW9Q1Ivk5nz8m1McECM4KY8A +s Fast Guard HSDir Running Stable V2Dir Valid +v Tor 0.2.5.16 +pr Cons=1 Desc=1 DirCache=1 HSDir=1 HSIntro=3 HSRend=1 Link=1-4 LinkAuth=1 Microdesc=1 Relay=1-2 +w Bandwidth=4950 +""" + expect_invalid_attr = functools.partial(base_expect_invalid_attr, RouterStatusEntryV3, 'nickname', 'Unnamed') expect_invalid_attr_for_text = functools.partial(base_expect_invalid_attr_for_text, RouterStatusEntryV3, 'nickname', 'Unnamed')
@@ -222,6 +238,43 @@ class TestRouterStatusEntry(unittest.TestCase): self.assertEqual('CAB27A6FFEF7A661C18B0B11120C3E8A77FC585C', entry.digest) self.assertEqual([], entry.get_unrecognized_lines())
+ def test_with_ipv6(self): + """ + Parse a router status entry with an IPv6 address. + """ + + expected_protocols = OrderedDict(( + ('Cons', [1]), + ('Desc', [1]), + ('DirCache', [1]), + ('HSDir', [1]), + ('HSIntro', [3]), + ('HSRend', [1]), + ('Link', [1, 2, 3, 4]), + ('LinkAuth', [1]), + ('Microdesc', [1]), + ('Relay', [1, 2]), + )) + + entry = RouterStatusEntryMicroV3(ENTRY_WITH_IPV6, validate = True) + self.assertEqual('MYLEX', entry.nickname) + self.assertEqual('010B7728454411F485CE29D4C79A14534151C2C4', entry.fingerprint) + self.assertEqual(datetime.datetime(2018, 7, 15, 16, 38, 10), entry.published) + self.assertEqual('77.123.42.148', entry.address) + self.assertEqual(444, entry.or_port) + self.assertEqual(800, entry.dir_port) + self.assertEqual(set([Flag.FAST, Flag.GUARD, Flag.HSDIR, Flag.RUNNING, Flag.STABLE, Flag.V2DIR, Flag.VALID]), set(entry.flags)) + self.assertEqual('Tor 0.2.5.16', entry.version_line) + self.assertEqual(Version('0.2.5.16'), entry.version) + self.assertEqual([('2001:470:71:9b9:f66d:4ff:fee7:954c', 444, True)], entry.or_addresses) + self.assertEqual(4950, entry.bandwidth) + self.assertEqual(None, entry.measured) + self.assertEqual(False, entry.is_unmeasured) + self.assertEqual([], entry.unrecognized_bandwidth_entries) + self.assertEqual(expected_protocols, entry.protocols) + self.assertEqual('1966FEC636AFD1FB2EC0FC0F36752F5BD43522F9399F3F26D4C70408CE0A63C0', entry.digest) + self.assertEqual([], entry.get_unrecognized_lines()) + def test_missing_fields(self): """ Parses a router status entry that's missing fields.
tor-commits@lists.torproject.org