Stem Docs



Parsing for Tor microdescriptors, which contain a distilled version of a relay's server descriptor. As of Tor version Tor no longer downloads server descriptors by default, opting for microdescriptors instead.

Unlike most descriptor documents these aren't available on the metrics site (since they don't contain any information that the server descriptors don't).

The limited information in microdescriptors make them rather clunky to use compared with server descriptors. For instance microdescriptors lack the relay's fingerprint, making it difficut to use them to look up the relay's other descriptors.

To do so you need to match the microdescriptor's digest against its corresponding router status entry. For added fun as of this writing the controller doesn't even surface those router status entries (ticket 7953).

For instance, here's an example that prints the nickname and fingerprints of the exit relays.

import os

from stem.control import Controller
from stem.descriptor import parse_file

with Controller.from_port(port = 9051) as controller:

  exit_digests = set()
  data_dir = controller.get_conf('DataDirectory')

  for desc in controller.get_microdescriptors():
    if desc.exit_policy.is_exiting_allowed():

  print 'Exit Relays:'

  for desc in parse_file(os.path.join(data_dir, 'cached-microdesc-consensus')):
    if desc.digest in exit_digests:
      print '  %s (%s)' % (desc.nickname, desc.fingerprint)

Doing the same is trivial with server descriptors...

from stem.descriptor import parse_file

print 'Exit Relays:'

for desc in parse_file('/home/atagar/.tor/cached-descriptors'):
  if desc.exit_policy.is_exiting_allowed():
    print '  %s (%s)' % (desc.nickname, desc.fingerprint)

Module Overview:

Microdescriptor - Tor microdescriptor.
class stem.descriptor.microdescriptor.Microdescriptor(raw_contents, validate=False, annotations=None)[source]

Bases: stem.descriptor.Descriptor

Microdescriptor (descriptor specification)

  • digest (str) -- * hex digest for this microdescriptor, this can be used to match against the corresponding digest attribute of a RouterStatusEntryMicroV3
  • onion_key (str) -- * key used to encrypt EXTEND cells
  • ntor_onion_key (str) -- base64 key used to encrypt EXTEND in the ntor protocol
  • or_addresses (list) -- * alternative for our address/or_port attributes, each entry is a tuple of the form (address (str), port (int), is_ipv6 (bool))
  • family (list) -- * nicknames or fingerprints of declared family
  • exit_policy (stem.exit_policy.MicroExitPolicy) -- * relay's exit policy
  • exit_policy_v6 (stem.exit_policy.MicroExitPolicy) -- * exit policy for IPv6
  • identifiers (hash) -- mapping of key types (like rsa1024 or ed25519) to their base64 encoded identity, this is only used for collision prevention (ticket 11743)
  • protocols (dict) -- mapping of protocols to their supported versions
  • identifier (str) -- base64 encoded identity digest (deprecated, use identifiers instead)
  • identifier_type (str) -- identity digest key type (deprecated, use identifiers instead)

* attribute is required when we're parsed with validation

Changed in version 1.1.0: Added the identifier and identifier_type attributes.

Changed in version 1.5.0: Added the identifiers attribute, and deprecated identifier and identifier_type since the field can now appear multiple times.

Changed in version 1.6.0: Added the protocols attribute.

get_annotations(*args, **kwds)[source]

Provides content that appeared prior to the descriptor. If this comes from the cached-microdescs then this commonly contains content like...

@last-listed 2013-02-24 00:18:30
Returns:dict with the key/value pairs in our annotations

Provides the lines of content that appeared prior to the descriptor. This is the same as the get_annotations() results, but with the unparsed lines and ordering retained.

Returns:list with the lines of annotation that came before this descriptor