commit c56eeaa962a33079685bbb7c30c944a594197275 Author: Matt Traudt sirmatt@ksu.edu Date: Thu Jun 7 20:54:11 2018 -0400
Initial revision of RelayNS/Relay class
With unused support for ed25519 keys --- sbws/globals.py | 3 + sbws/lib/relaylist.py | 120 ++++++++++++++++++-------------- sbws/lib/resultdump.py | 4 +- sbws/util/stem.py | 3 +- tests/integration/lib/test_relaylist.py | 17 +++++ tests/unit/conftest.py | 50 +------------ tests/unit/lib/test_relaylist.py | 13 ---- 7 files changed, 93 insertions(+), 117 deletions(-)
diff --git a/sbws/globals.py b/sbws/globals.py index a6621ab..a16682c 100644 --- a/sbws/globals.py +++ b/sbws/globals.py @@ -22,6 +22,9 @@ TORRC_STARTING_POINT = { 'CookieAuthentication': '1', # To avoid path bias warnings 'UseEntryGuards': '0', + # Because we need things from full server descriptors (namely for now: the + # bandwidth line) + 'UseMicrodescriptors': '0', }
SCALE_CONSTANT = 7500 diff --git a/sbws/lib/relaylist.py b/sbws/lib/relaylist.py index 6d0743d..c0ca9ad 100644 --- a/sbws/lib/relaylist.py +++ b/sbws/lib/relaylist.py @@ -1,5 +1,5 @@ from stem.descriptor.router_status_entry import RouterStatusEntryV3 - +from stem.descriptor.server_descriptor import ServerDescriptor import sbws.util.stem as stem_utils from stem import Flag from stem import DescriptorUnavailable @@ -13,16 +13,73 @@ from sbws.globals import resolve log = logging.getLogger(__name__)
-class RelayNS(RouterStatusEntryV3): - """Inherit from RouterStatusEntryV3 and add the attribute - master_key_ed25519. +class Relay: + def __init__(self, fp, cont, ns=None, desc=None): + ''' + Given a relay fingerprint, fetch all the information about a relay that + sbws currently needs and store it in this class. Acts as an abstraction + to hide the confusion that is Tor consensus/descriptor stuff. + + :param str fp: fingerprint of the relay. + :param cont: active and valid stem Tor controller connection + ''' + assert isinstance(fp, str) + assert len(fp) == 40 + assert stem_utils.is_controller_okay(cont) + if ns is not None: + assert isinstance(ns, RouterStatusEntryV3) + self._ns = ns + else: + self._ns = cont.get_network_status(fp, default=None) + if desc is not None: + assert isinstance(desc, ServerDescriptor) + self._desc = desc + else: + self._desc = cont.get_server_descriptor(fp, default=None) + + def _from_desc(self, attr): + if not self._desc: + return None + assert hasattr(self._desc, attr) + return getattr(self._desc, attr) + + def _from_ns(self, attr): + if not self._ns: + return None + assert hasattr(self._ns, attr) + return getattr(self._ns, attr) + + @property + def nickname(self): + return self._from_ns('nickname') + + @property + def fingerprint(self): + return self._from_ns('fingerprint') + + @property + def flags(self): + return self._from_ns('flags') + + @property + def exit_policy(self): + return self._from_desc('exit_policy') + + @property + def average_bandwidth(self): + return self._from_desc('average_bandwidth') + + @property + def bandwidth(self): + return self._from_ns('bandwidth') + + @property + def address(self): + return self._from_ns('address')
- :param str ed25519: the ed25519 master key base 64 encoded. - """ - def __init__(self, ed25519=None, *args, **kwargs): - super().__init__(*args, **kwargs) - if ed25519 is not None: - self.master_key_ed25519 = ed25519 + @property + def ed25519_master_key(self): + return self._from_desc('ed25519_master_key').rstrip('=')
class RelayList: @@ -82,40 +139,6 @@ class RelayList: # return [r for r in relays if r.measured is not None] return [r for r in relays if not r.is_unmeasured]
- def relay_ed25519_master_key(self, ns): - """Obtain ed25519 master key of the relay represented by - the network status relay line. - - :param RouterStatusEntryV3 ns: the network status relay - :returns: str, the ed25519 master key base 64 encoded without - trailing '='s. - """ - # In theory this is never going to be the case? - if ns.identifier is None or ns.identifier_type != 'ed25519': - log.debug('Getting microdescriptor to obtain ed25519 identity.') - mdesc = self._controller.get_microdescriptor(ns.fingerprint, None) - if mdesc is not None: - if 'ed25519' in mdesc.identifiers.keys(): - ed25519 = mdesc.identifiers['ed25519'].rstrip('=') - log.debug('Found ed25519 master key.') - return ed25519 - log.debug('No ed25519 master-key found') - log.debug('Could not get microdescriptor') - # In case Tor can not retrive microdescriptors, - # try with server descriptors. - log.debug('Getting server descriptor to obtain ' - 'ed25519 master key.') - sdesc = self._controller.get_server_descriptor(ns.fingerprint, - None) - if sdesc is not None: - ed25519 = sdesc.ed25519_master_key().rstrip('=') - log.debug('Found ed25519 master key.') - return ed25519 - log.debug('Could not get server descriptor') - return None - log.debug('Relay has already ed25519 master key') - return ns.identifier - def exits_can_exit_to(self, host, port): ''' Return exits that can MOST LIKELY exit to the given host:port. **host** @@ -179,13 +202,8 @@ class RelayList: def _init_relays(self): c = self._controller assert stem_utils.is_controller_okay(c) - relays = [] - # for each network status relay, obtain the ed25519 master key - # and generate a new list of RelayNS objects - for ns in c.get_network_statuses(): - ed25519 = self.relay_ed25519_master_key(ns) - rns = RelayNS(ed25519=ed25519, content=ns._raw_contents) - relays.append(rns) + relays = [Relay(ns.fingerprint, c, ns=ns) + for ns in c.get_network_statuses()] return relays
def _refresh(self): diff --git a/sbws/lib/resultdump.py b/sbws/lib/resultdump.py index 7cff36f..ffa493d 100644 --- a/sbws/lib/resultdump.py +++ b/sbws/lib/resultdump.py @@ -11,9 +11,9 @@ from queue import Empty from datetime import datetime from datetime import timedelta from enum import Enum -from stem.descriptor.router_status_entry import RouterStatusEntryV3 from sbws.globals import RESULT_VERSION from sbws.util.filelock import DirectoryLock +from sbws.lib.relaylist import Relay
log = logging.getLogger(__name__)
@@ -481,7 +481,7 @@ class ResultDump: 'Ignoring %s', type(data))
def results_for_relay(self, relay): - assert isinstance(relay, RouterStatusEntryV3) + assert isinstance(relay, Relay) fp = relay.fingerprint with self.data_lock: if fp not in self.data: diff --git a/sbws/util/stem.py b/sbws/util/stem.py index 5291bba..0341d74 100644 --- a/sbws/util/stem.py +++ b/sbws/util/stem.py @@ -2,7 +2,6 @@ from stem.control import (Controller, Listener) from stem import (SocketError, InvalidRequest, UnsatisfiableRequest) from stem.connection import IncorrectSocketType import stem.process -from stem.descriptor.router_status_entry import RouterStatusEntryV3 from configparser import ConfigParser from threading import RLock import copy @@ -223,7 +222,7 @@ def only_relays_with_bandwidth(controller, relays, min_bw=None, max_bw=None): assert max_bw is None or max_bw >= 0 ret = [] for relay in relays: - assert isinstance(relay, RouterStatusEntryV3) + assert hasattr(relay, 'bandwidth') if min_bw is not None and relay.bandwidth < min_bw: continue if max_bw is not None and relay.bandwidth > max_bw: diff --git a/tests/integration/lib/test_relaylist.py b/tests/integration/lib/test_relaylist.py new file mode 100644 index 0000000..8f16ef8 --- /dev/null +++ b/tests/integration/lib/test_relaylist.py @@ -0,0 +1,17 @@ +from sbws.lib.relaylist import Relay + + +def test_relay_properties(persistent_launch_tor): + cont = persistent_launch_tor + # AA45C13025C037F056E734169891878ED0880231 is auth1 + fp = 'AA45C13025C037F056E734169891878ED0880231' + relay = Relay(fp, cont) + assert relay.nickname == 'auth1' + assert relay.fingerprint == 'AA45C13025C037F056E734169891878ED0880231' + assert 'Authority' in relay.flags + assert not relay.exit_policy or not relay.exit_policy.is_exiting_allowed() + assert relay.average_bandwidth == 1073741824 + assert relay.bandwidth == 0 + assert relay.address == '127.10.0.1' + assert relay.ed25519_master_key == \ + 'wLglSEw9/DHfpNrlrqjVRSnGLVWfnm0vYxkryH4aT6Q' diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py index 2847fe1..0701646 100644 --- a/tests/unit/conftest.py +++ b/tests/unit/conftest.py @@ -2,9 +2,8 @@ from sbws.lib.resultdump import ResultError from sbws.lib.resultdump import ResultSuccess from sbws.lib.resultdump import Result from sbws.lib.resultdump import write_result_to_datadir -from sbws.util.config import get_config, _get_default_config +from sbws.util.config import get_config from sbws.util.parser import create_parser -import sbws.util.stem as stem_utils import sbws.core.init from tempfile import TemporaryDirectory import pytest @@ -28,53 +27,6 @@ class _PseudoArguments(argparse.Namespace): setattr(self, key, kw[key])
-@pytest.fixture -def tmpdir(tmpdir_factory, request): - base = str(hash(request.node.nodeid))[:3] - bn = tmpdir_factory.mktemp(base) - return bn - - -@pytest.fixture() -def datadir(request): - """ get, read, open test files from the "data" directory. """ - class D: - def __init__(self, basepath): - self.basepath = basepath - - def open(self, name, mode="r"): - return self.basepath.join(name).open(mode) - - def join(self, name): - return self.basepath.join(name).strpath - - def read_bytes(self, name): - with self.open(name, "rb") as f: - return f.read() - - def read(self, name): - with self.open(name, "r") as f: - return f.read() - - def readlines(self, name): - with self.open(name, "r") as f: - return f.readlines() - return D(request.fspath.dirpath("data")) - - -@pytest.fixture() -def start_tor(request, tmpdir): - """Star Tor or connect to existing socket in a temporal directory.""" - conf = _get_default_config() - home = tmpdir.join('.sbws') - conf['paths']['sbws_home'] = home.strpath - controller, _ = stem_utils.init_controller( - path=conf['tor']['control_socket']) - if not controller: - controller = stem_utils.launch_tor(conf) - return controller - - @pytest.fixture(scope='session') def parser(): return create_parser() diff --git a/tests/unit/lib/test_relaylist.py b/tests/unit/lib/test_relaylist.py deleted file mode 100644 index cdb71c2..0000000 --- a/tests/unit/lib/test_relaylist.py +++ /dev/null @@ -1,13 +0,0 @@ -from sbws.lib.relaylist import RelayList - - -def test_relaylist_master_key_ed25519(start_tor): - # This test starts tor, so it is slow. And it will fail whenever there are - # network problems - controller = start_tor - rl = RelayList(None, None, controller) - relay = [r for r in rl.relays if r.nickname == 'moria1'][0] - assert relay.fingerprint == '9695DFC35FFEB861329B9F1AB04C46397020CE31' - assert relay.identifier is None - assert relay.master_key_ed25519 == \ - 'yp0fwtp4aa/VMyZJGz8vN7Km3zYet1YBZwqZEk1CwHI'
tor-commits@lists.torproject.org