commit ac2b277a9b09451c0270d4397ab96087ce2cbaad Author: Damian Johnson atagar@torproject.org Date: Tue Jul 31 12:45:27 2018 -0700
Using 'GETINFO md/all' to get microdescriptors if available
Thanks to rl1987 tor now has a GETINFO method to retrieve microdescriptors (similar to 'GETINFO desc/all-recent', 'GETINFO ns/all', etc).
https://gitweb.torproject.org/torspec.git/commit/?id=b5396d5 https://trac.torproject.org/projects/tor/ticket/26210 --- docs/change_log.rst | 1 + stem/control.py | 50 +++++++++++++++++++++++++++++++------------------- stem/version.py | 2 ++ 3 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index aa8231ba..ca8b6805 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -52,6 +52,7 @@ The following are only available within Stem's `git repository * Stacktrace if :func:`stem.connection.connect` had a string port argument * More reliable ExitPolicy resolution (:trac:`25739`) * More reliable caching during configuration changes, especially in multiple-controller situations (:trac:`25821`) + * :func:`~stem.control.Controller.get_microdescriptors` reads descriptors from the control port if available (:spec:`b5396d5`) * Added the delivered_read, delivered_written, overhead_read, and overhead_written attributes to :class:`~stem.response.events.CircuitBandwidthEvent` (:spec:`fbb38ec`) * The *config* attribute of :class:`~stem.response.events.ConfChangedEvent` couldn't represent tor configuration options with multiple values. It has been replaced with new *changed* and *unset* attributes. * Replaced socket's :func:`~stem.socket.ControlPort.get_address`, :func:`~stem.socket.ControlPort.get_port`, and :func:`~stem.socket.ControlSocketFile.get_socket_path` with attributes diff --git a/stem/control.py b/stem/control.py index b1918ce9..77e6140e 100644 --- a/stem/control.py +++ b/stem/control.py @@ -1746,9 +1746,10 @@ class Controller(BaseController): Provides an iterator for all of the microdescriptors that tor currently knows about.
- **Tor does not expose this information via the control protocol** - (:trac:`8323`). Until it does this reads the microdescriptors from disk, - and hence won't work remotely or if we lack read permissions. + Prior to Tor 0.3.5.1 this information was not available via the control + protocol. When connected to prior versions we read the microdescriptors + directly from disk instead, which will not work remotely or if our process + lacks read permissions.
:param list default: items to provide if the query fails
@@ -1760,27 +1761,38 @@ class Controller(BaseController): default was provided """
- try: - data_directory = self.get_conf('DataDirectory') - except stem.ControllerError as exc: - raise stem.OperationFailed(message = 'Unable to determine the data directory (%s)' % exc) + if self.get_version() >= stem.version.Requirement.GETINFO_MICRODESCRIPTORS: + desc_content = self.get_info('md/all', get_bytes = True) + + if not desc_content: + raise stem.DescriptorUnavailable('Descriptor information is unavailable, tor might still be downloading it') + + for desc in stem.descriptor.microdescriptor._parse_file(io.BytesIO(desc_content)): + yield desc + else: + # TODO: remove when tor versions that require this are obsolete + + try: + data_directory = self.get_conf('DataDirectory') + except stem.ControllerError as exc: + raise stem.OperationFailed(message = 'Unable to determine the data directory (%s)' % exc)
- cached_descriptor_path = os.path.join(data_directory, 'cached-microdescs') + cached_descriptor_path = os.path.join(data_directory, 'cached-microdescs')
- if not os.path.exists(data_directory): - raise stem.OperationFailed(message = "Data directory reported by tor doesn't exist (%s)" % data_directory) - elif not os.path.exists(cached_descriptor_path): - raise stem.OperationFailed(message = "Data directory doesn't contain cached microdescriptors (%s)" % cached_descriptor_path) + if not os.path.exists(data_directory): + raise stem.OperationFailed(message = "Data directory reported by tor doesn't exist (%s)" % data_directory) + elif not os.path.exists(cached_descriptor_path): + raise stem.OperationFailed(message = "Data directory doesn't contain cached microdescriptors (%s)" % cached_descriptor_path)
- with stem.descriptor.reader.DescriptorReader([cached_descriptor_path]) as reader: - for desc in reader: - # It shouldn't be possible for these to be something other than - # microdescriptors but as the saying goes: trust but verify. + with stem.descriptor.reader.DescriptorReader([cached_descriptor_path]) as reader: + for desc in reader: + # It shouldn't be possible for these to be something other than + # microdescriptors but as the saying goes: trust but verify.
- if not isinstance(desc, stem.descriptor.microdescriptor.Microdescriptor): - raise stem.OperationFailed(message = 'BUG: Descriptor reader provided non-microdescriptor content (%s)' % type(desc)) + if not isinstance(desc, stem.descriptor.microdescriptor.Microdescriptor): + raise stem.OperationFailed(message = 'BUG: Descriptor reader provided non-microdescriptor content (%s)' % type(desc))
- yield desc + yield desc
@with_default() def get_server_descriptor(self, relay = None, default = UNDEFINED): diff --git a/stem/version.py b/stem/version.py index 7e15fe51..b6a866f0 100644 --- a/stem/version.py +++ b/stem/version.py @@ -62,6 +62,7 @@ easily parsed and compared, for instance... **FEATURE_VERBOSE_NAMES** 'VERBOSE_NAMES' optional feature **GETINFO_CONFIG_TEXT** 'GETINFO config-text' query **GETINFO_GEOIP_AVAILABLE** 'GETINFO ip-to-country/ipv4-available' query and its ipv6 counterpart + **GETINFO_MICRODESCRIPTORS** 'GETINFO md/all' query **HIDDEN_SERVICE_V3** Support for v3 hidden services **HSFETCH** HSFETCH requests **HSPOST** HSPOST requests @@ -380,6 +381,7 @@ Requirement = stem.util.enum.Enum( ('FEATURE_VERBOSE_NAMES', Version('0.2.2.1-alpha')), ('GETINFO_CONFIG_TEXT', Version('0.2.2.7-alpha')), ('GETINFO_GEOIP_AVAILABLE', Version('0.3.2.1-alpha')), + ('GETINFO_MICRODESCRIPTORS', Version('0.3.5.1-alpha')), ('HIDDEN_SERVICE_V3', Version('0.3.3.1-alpha')), ('HSFETCH', Version('0.2.7.1-alpha')), ('HSPOST', Version('0.2.7.1-alpha')),
tor-commits@lists.torproject.org