commit 157d9a84b53a538401b510e09b1439fdd99b8c77 Author: Damian Johnson atagar@torproject.org Date: Wed May 17 09:54:21 2017 -0700
Support padding-counts in extrainfo descriptors
Adding support for the new addition in...
https://gitweb.torproject.org/torspec.git/commit/?id=0803997
Presently all values in the mapping are integers but the spec doesn't note if that will always be the case or not. Reached out to Mike for clarification. --- docs/change_log.rst | 1 + stem/descriptor/extrainfo_descriptor.py | 38 ++++++++++++++++++++++++ test/unit/descriptor/extrainfo_descriptor.py | 43 ++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+)
diff --git a/docs/change_log.rst b/docs/change_log.rst index cd5dcd5..c9b96af 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -60,6 +60,7 @@ The following are only available within Stem's `git repository * Sped descriptor reading by ~25% by deferring defaulting when validating * Added server descriptor's new extra_info_sha256_digest attribute (:spec:`0f03581`) * Added server descriptor's new protocol attribute (:spec:`eb4fb3c`) + * Added extrainfo descriptor's new padding_counts attributes (:spec:`0803997`) * Shared randomness properties weren't being read in votes (:trac:`21102`)
* **Utilities** diff --git a/stem/descriptor/extrainfo_descriptor.py b/stem/descriptor/extrainfo_descriptor.py index 2843c8a..fc4a124 100644 --- a/stem/descriptor/extrainfo_descriptor.py +++ b/stem/descriptor/extrainfo_descriptor.py @@ -331,6 +331,29 @@ def _parse_cell_circuits_per_decline_line(descriptor, entries): descriptor.cell_circuits_per_decile = int(value)
+def _parse_padding_counts_line(descriptor, entries): + # "padding-counts" YYYY-MM-DD HH:MM:SS (NSEC s) key=val key=val... + + value = _value('padding-counts', entries) + timestamp, interval, remainder = _parse_timestamp_and_interval('padding-counts', value) + entries = {} + + for entry in remainder.split(' '): + if '=' not in entry: + raise ValueError('Entries in padding-counts line should be key=value mappings: padding-counts %s' % value) + + k, v = entry.split('=', 1) + + if not v: + raise ValueError('Entry in padding-counts line had a blank value: padding-counts %s' % value) + + entries[k] = int(v) if v.isdigit() else v + + setattr(descriptor, 'padding_counts_end', timestamp) + setattr(descriptor, 'padding_counts_interval', interval) + setattr(descriptor, 'padding_counts', entries) + + def _parse_dirreq_line(keyword, recognized_counts_attr, unrecognized_counts_attr, descriptor, entries): value = _value(keyword, entries)
@@ -699,6 +722,12 @@ class ExtraInfoDescriptor(Descriptor): :var int hs_dir_onions_seen: rounded count of the identities seen :var int hs_dir_onions_seen_attr: ***** attributes provided for the hs_dir_onions_seen
+ **Padding Count Attributes:** + + :var dict padding_counts: ***** padding parameters + :var datetime padding_counts_end: end of the period when padding data is being collected + :var int padding_counts_interval: length in seconds of the interval + **Bridge Attributes:**
:var datetime bridge_stats_end: end of the period when stats were gathered @@ -715,6 +744,10 @@ class ExtraInfoDescriptor(Descriptor): .. versionchanged:: 1.4.0 Added the hs_stats_end, hs_rend_cells, hs_rend_cells_attr, hs_dir_onions_seen, and hs_dir_onions_seen_attr attributes. + + .. versionchanged:: 1.6.0 + Added the padding_counts, padding_counts_end, and padding_counts_interval + attributes. """
ATTRIBUTES = { @@ -792,6 +825,10 @@ class ExtraInfoDescriptor(Descriptor): 'hs_dir_onions_seen': (None, _parse_hidden_service_dir_onions_seen_line), 'hs_dir_onions_seen_attr': ({}, _parse_hidden_service_dir_onions_seen_line),
+ 'padding_counts': ({}, _parse_padding_counts_line), + 'padding_counts_end': (None, _parse_padding_counts_line), + 'padding_counts_interval': (None, _parse_padding_counts_line), + 'bridge_stats_end': (None, _parse_bridge_stats_end_line), 'bridge_stats_interval': (None, _parse_bridge_stats_end_line), 'bridge_ips': (None, _parse_bridge_ips_line), @@ -837,6 +874,7 @@ class ExtraInfoDescriptor(Descriptor): 'hidserv-stats-end': _parse_hidden_service_stats_end_line, 'hidserv-rend-relayed-cells': _parse_hidden_service_rend_relayed_cells_line, 'hidserv-dir-onions-seen': _parse_hidden_service_dir_onions_seen_line, + 'padding-counts': _parse_padding_counts_line, 'dirreq-v2-ips': _parse_dirreq_v2_ips_line, 'dirreq-v3-ips': _parse_dirreq_v3_ips_line, 'dirreq-v2-reqs': _parse_dirreq_v2_reqs_line, diff --git a/test/unit/descriptor/extrainfo_descriptor.py b/test/unit/descriptor/extrainfo_descriptor.py index a59d0f0..798320e 100644 --- a/test/unit/descriptor/extrainfo_descriptor.py +++ b/test/unit/descriptor/extrainfo_descriptor.py @@ -636,6 +636,49 @@ k0d2aofcVbHr4fPQOSST0LXDrhFl5Fqo5um296zpJGvRUeO6S44U/EfJAGShtqWw expect_invalid_attr(self, {keyword: entry}, stat_attr) expect_invalid_attr(self, {keyword: entry}, extra_attr, {})
+ def test_padding_counts(self): + """ + Check the 'hidserv-dir-onions-seen' lines. + """ + + desc = RelayExtraInfoDescriptor.create({'padding-counts': '2017-05-17 11:02:58 (86400 s) bin-size=10000 write-drop=0 write-pad=10000 write-total=10000 read-drop=0 read-pad=10000 read-total=3780000 enabled-read-pad=0 enabled-read-total=0 enabled-write-pad=0 enabled-write-total=0 max-chanpad-timers=0 non-numeric=test'}) + + self.assertEqual({ + 'bin-size': 10000, + 'write-drop': 0, + 'write-pad': 10000, + 'write-total': 10000, + 'read-drop': 0, + 'read-pad': 10000, + 'read-total': 3780000, + 'enabled-read-pad': 0, + 'enabled-read-total': 0, + 'enabled-write-pad': 0, + 'enabled-write-total': 0, + 'max-chanpad-timers': 0, + 'non-numeric': 'test', # presently all values are ints but the spec allows for anything + }, desc.padding_counts) + + self.assertEqual(datetime.datetime(2017, 5, 17, 11, 2, 58), desc.padding_counts_end) + self.assertEqual(86400, desc.padding_counts_interval) + + test_entries = ( + '', + '2012-05-03', + '2012-05-03 12:07:60 (500 s)', + '2012-05-03 12:07:50 (500 s', + '2012-05-03 12:07:50 (500s)', + '2012-05-03 12:07:50 (500 s)bin-size=10', + '2012-05-03 12:07:50 (500 s) bin-size', + '2012-05-03 12:07:50 (500 s) bin-size=', + ) + + for entry in test_entries: + desc = expect_invalid_attr(self, {'padding-counts': entry}) + self.assertEqual({}, desc.padding_counts) + self.assertEqual(None, desc.padding_counts_end) + self.assertEqual(None, desc.padding_counts_interval) + def test_locale_mapping_lines(self): """ Uses valid and invalid data to tests lines of the form...
tor-commits@lists.torproject.org