예제 #1
0
def findpath(controller):
    """
    Generate Tor paths.
        "controller": authenticated Tor Controller from stem.control.
    """
    # Validate input parameters.
    assert isinstance(controller, Controller), \
        'Controller has wrong type: %s.' % type(controller)

    assert controller.get_version() > Version('0.2.3'), \
        ('Your tor version (%s) is too old. ' % controller.get_version() +
         'Tor version 0.2.3.x is required.')
    assert controller.get_version() < Version('0.2.4'), \
        ('Your tor version (%s) is too new. ' % controller.get_version() +
         'Tor version 0.2.3.x is required.')

    # Change guard nodes for every path.
    msg = controller.msg('DUMPGUARDS')
    assert msg.is_ok(), ("DUMPGUARDS command failed with error " +
                         "'%s'. Is your tor client patched?\n" % str(msg))

    # Get a path from tor.
    msg = controller.msg('FINDPATH')
    assert msg.is_ok(), ("FINDPATH command failed with error " +
                         "'%s'. Is your tor client patched?\n" % str(msg))
    sys.stdout.write("%s\n" % findall('[A-Z0-9]{40}', str(msg)))
예제 #2
0
파일: version.py 프로젝트: Foxboron/stem
    def assert_version_is_equal(self, first_version, second_version):
        """
    Asserts that the parsed version of the first version equals the second.
    """

        version1 = Version(first_version)
        version2 = Version(second_version)
        self.assertEqual(version1, version2)
예제 #3
0
파일: version.py 프로젝트: Foxboron/stem
    def assert_version_is_greater(self, first_version, second_version):
        """
    Asserts that the parsed version of the first version is greate than the
    second (also checking the inverse).
    """

        version1 = Version(first_version)
        version2 = Version(second_version)
        self.assertEqual(version1 > version2, True)
        self.assertEqual(version1 < version2, False)
예제 #4
0
파일: version.py 프로젝트: Foxboron/stem
    def test_requirements_multiple_rules(self):
        """
    Checks a VersionRequirements is the logical 'or' when it has multiple rules.
    """

        # rule to say 'anything but the 0.2.2.x series'
        requirements = stem.version._VersionRequirements()
        requirements.greater_than(Version('0.2.3.0'))
        requirements.less_than(Version('0.2.2.0'), False)

        self.assertTrue(Version('0.2.3.0') >= requirements)
        self.assertFalse(Version('0.2.2.0') >= requirements)

        for index in range(0, 100):
            self.assertFalse(Version('0.2.2.%i' % index) >= requirements)
예제 #5
0
  def test_without_ed25519(self):
    """
    Parses a router status entry without a ed25519 value.
    """

    microdescriptor_hashes = [
      ([13, 14, 15], {'sha256': 'uaAYTOVuYRqUwJpNfP2WizjzO0FiNQB4U97xSQu+vMc'}),
      ([16, 17], {'sha256': 'G6FmPe/ehgfb6tsRzFKDCwvvae+RICeP1MaP0vWDGyI'}),
      ([18, 19, 20, 21], {'sha256': '/XhIMOnhElo2UiKjL2S10uRka/fhg1CFfNd+9wgUwEE'}),
    ]

    entry = RouterStatusEntryV3(ENTRY_WITHOUT_ED25519, document = vote_document(), validate = True)
    self.assertEqual('seele', entry.nickname)
    self.assertEqual('000A10D43011EA4928A35F610405F92B4433B4DC', entry.fingerprint)
    self.assertEqual(datetime.datetime(2015, 8, 23, 0, 26, 35), entry.published)
    self.assertEqual('73.15.150.172', entry.address)
    self.assertEqual(9001, entry.or_port)
    self.assertEqual(None, entry.dir_port)
    self.assertEqual(set([Flag.RUNNING, Flag.STABLE, Flag.VALID]), set(entry.flags))
    self.assertEqual('Tor 0.2.6.10', entry.version_line)
    self.assertEqual(Version('0.2.6.10'), entry.version)
    self.assertEqual(102, entry.bandwidth)
    self.assertEqual(31, entry.measured)
    self.assertEqual(False, entry.is_unmeasured)
    self.assertEqual([], entry.unrecognized_bandwidth_entries)
    self.assertEqual(MicroExitPolicy('reject 1-65535'), entry.exit_policy)
    self.assertEqual(microdescriptor_hashes, entry.microdescriptor_hashes)
    self.assertEqual('ed25519', entry.identifier_type)
    self.assertEqual('none', entry.identifier)
    self.assertEqual('9B4CA73EEC3349EC6DCEC897609600D0771EF82B', entry.digest)
    self.assertEqual([], entry.get_unrecognized_lines())
예제 #6
0
  def test_with_ed25519(self):
    """
    Parses a router status entry with a ed25519 value.
    """

    microdescriptor_hashes = [
      ([13], {'sha256': 'PTSHzE7RKnRGZMRmBddSzDiZio254FUhv9+V4F5zq8s'}),
      ([14, 15], {'sha256': '0wsEwBbxJ8RtPmGYwilHQTVEw2pWzUBEVlSgEO77OyU'}),
      ([16, 17], {'sha256': 'JK2xhYr/VsCF60px+LsT990BCpfKfQTeMxRbD63o2vE'}),
      ([18, 19, 20], {'sha256': 'AkZH3gIvz3wunsroqh5izBJizdYuR7kn2oVbsvqgML8'}),
      ([21], {'sha256': 'AVp41YVxKEJCaoEf0+77Cdvyw5YgpyDXdob0+LSv/pE'}),
    ]

    entry = RouterStatusEntryV3(ENTRY_WITH_ED25519, document = vote_document(), validate = True)
    self.assertEqual('PDrelay1', entry.nickname)
    self.assertEqual('000149E6EF7102AACA9690D6E8DD2932124B94AB', entry.fingerprint)
    self.assertEqual(datetime.datetime(2015, 8, 23, 16, 52, 37), entry.published)
    self.assertEqual('95.215.44.189', entry.address)
    self.assertEqual(8080, entry.or_port)
    self.assertEqual(None, entry.dir_port)
    self.assertEqual(set([Flag.FAST, Flag.RUNNING, Flag.STABLE, Flag.VALID]), set(entry.flags))
    self.assertEqual('Tor 0.2.7.2-alpha-dev', entry.version_line)
    self.assertEqual(Version('0.2.7.2-alpha-dev'), entry.version)
    self.assertEqual(608, entry.bandwidth)
    self.assertEqual(472, entry.measured)
    self.assertEqual(False, entry.is_unmeasured)
    self.assertEqual([], entry.unrecognized_bandwidth_entries)
    self.assertEqual(MicroExitPolicy('reject 1-65535'), entry.exit_policy)
    self.assertEqual(microdescriptor_hashes, entry.microdescriptor_hashes)
    self.assertEqual('ed25519', entry.identifier_type)
    self.assertEqual('8RH34kO07Pp+XYwzdoATVyCibIvmbslUjRkAm7J4IA8', entry.identifier)
    self.assertEqual('CAB27A6FFEF7A661C18B0B11120C3E8A77FC585C', entry.digest)
    self.assertEqual([], entry.get_unrecognized_lines())
예제 #7
0
 def checkOutdateRelays(self, torVersion='0.2.3.0'):
     print "Checking relays with TOR version equals or less to %s " % (
         torVersion)
     for torNode in self.torNodes:
         if torNode.torVersion < Version(torVersion):
             print "[*] Older version of TOR detected: %s Nickname of the Relay %s IP Address reported %s" % (
                 torNode.torVersion, torNode.nickName, torNode.host)
예제 #8
0
파일: version.py 프로젝트: Foxboron/stem
    def assert_string_matches(self, version):
        """
    Parses the given version string then checks that its string representation
    matches the input.
    """

        self.assertEqual(version, str(Version(version)))
예제 #9
0
파일: version.py 프로젝트: tlyu/stem
    def test_with_multiple_extra(self):
        """
    Parse a version with multiple 'extra' fields.
    """

        version = Version('0.1.2 (release) (git-73ff13ab3cc9570d)')
        self.assert_versions_match(version, 0, 1, 2, None, None, 'release')
        self.assertEqual(['release', 'git-73ff13ab3cc9570d'],
                         version.all_extra)
        self.assertEqual('73ff13ab3cc9570d', version.git_commit)
예제 #10
0
    def test_versions(self):
        """
    Handles a variety of version inputs.
    """

        test_values = {
            'Tor 0.2.2.35': Version('0.2.2.35'),
            'Tor 0.1.2': Version('0.1.2'),
            'Torr new_stuff': None,
            'new_stuff and stuff': None,
        }

        for v_line, expected in test_values.items():
            entry = RouterStatusEntryV3.create({'v': v_line})
            self.assertEqual(expected, entry.version)
            self.assertEqual(v_line, entry.version_line)

        # tries an invalid input
        expect_invalid_attr(self, {'v': 'Tor ugabuga'}, 'version')
예제 #11
0
    def test_parsing(self):
        """
    Tests parsing by the Version class constructor.
    """

        # valid versions with various number of compontents to the version

        version = Version("0.1.2.3-tag")
        self.assert_versions_match(version, 0, 1, 2, 3, "tag", None)

        version = Version("0.1.2.3")
        self.assert_versions_match(version, 0, 1, 2, 3, None, None)

        version = Version("0.1.2-tag")
        self.assert_versions_match(version, 0, 1, 2, None, "tag", None)

        version = Version("0.1.2")
        self.assert_versions_match(version, 0, 1, 2, None, None, None)

        # checks an empty tag
        version = Version("0.1.2.3-")
        self.assert_versions_match(version, 0, 1, 2, 3, "", None)

        version = Version("0.1.2-")
        self.assert_versions_match(version, 0, 1, 2, None, "", None)

        # check with extra informaton
        version = Version("0.1.2.3-tag (git-73ff13ab3cc9570d)")
        self.assert_versions_match(version, 0, 1, 2, 3, "tag",
                                   "git-73ff13ab3cc9570d")
        self.assertEqual("73ff13ab3cc9570d", version.git_commit)

        version = Version("0.1.2.3-tag ()")
        self.assert_versions_match(version, 0, 1, 2, 3, "tag", "")

        version = Version("0.1.2 (git-73ff13ab3cc9570d)")
        self.assert_versions_match(version, 0, 1, 2, None, None,
                                   "git-73ff13ab3cc9570d")

        # checks invalid version strings
        self.assertRaises(ValueError, stem.version.Version, "")
        self.assertRaises(ValueError, stem.version.Version, "1.2.3.4nodash")
        self.assertRaises(ValueError, stem.version.Version, "1.2.3.a")
        self.assertRaises(ValueError, stem.version.Version, "1.2.a.4")
        self.assertRaises(ValueError, stem.version.Version, "1x2x3x4")
        self.assertRaises(ValueError, stem.version.Version, "12.3")
        self.assertRaises(ValueError, stem.version.Version, "1.-2.3")
예제 #12
0
파일: version.py 프로젝트: Foxboron/stem
    def test_parsing(self):
        """
    Tests parsing by the Version class constructor.
    """

        # valid versions with various number of compontents to the version

        version = Version('0.1.2.3-tag')
        self.assert_versions_match(version, 0, 1, 2, 3, 'tag', None)

        version = Version('0.1.2.3')
        self.assert_versions_match(version, 0, 1, 2, 3, None, None)

        version = Version('0.1.2-tag')
        self.assert_versions_match(version, 0, 1, 2, None, 'tag', None)

        version = Version('0.1.2')
        self.assert_versions_match(version, 0, 1, 2, None, None, None)

        # checks an empty tag
        version = Version('0.1.2.3-')
        self.assert_versions_match(version, 0, 1, 2, 3, '', None)

        version = Version('0.1.2-')
        self.assert_versions_match(version, 0, 1, 2, None, '', None)

        # check with extra informaton
        version = Version('0.1.2.3-tag (git-73ff13ab3cc9570d)')
        self.assert_versions_match(version, 0, 1, 2, 3, 'tag',
                                   'git-73ff13ab3cc9570d')
        self.assertEqual('73ff13ab3cc9570d', version.git_commit)

        version = Version('0.1.2.3-tag ()')
        self.assert_versions_match(version, 0, 1, 2, 3, 'tag', '')

        version = Version('0.1.2 (git-73ff13ab3cc9570d)')
        self.assert_versions_match(version, 0, 1, 2, None, None,
                                   'git-73ff13ab3cc9570d')

        # checks invalid version strings
        self.assertRaises(ValueError, stem.version.Version, '')
        self.assertRaises(ValueError, stem.version.Version, '1.2.3.4nodash')
        self.assertRaises(ValueError, stem.version.Version, '1.2.3.a')
        self.assertRaises(ValueError, stem.version.Version, '1.2.a.4')
        self.assertRaises(ValueError, stem.version.Version, '1x2x3x4')
        self.assertRaises(ValueError, stem.version.Version, '12.3')
        self.assertRaises(ValueError, stem.version.Version, '1.-2.3')
예제 #13
0
    def test_nonversion_comparison(self):
        """
    Checks that we can be compared with other types.
    """

        test_version = Version("0.1.2.3")
        self.assertNotEqual(test_version, None)
        self.assertTrue(test_version > None)

        self.assertNotEqual(test_version, 5)
        self.assertTrue(test_version > 5)
예제 #14
0
    def test_requirements_greater_than(self):
        """
    Checks a VersionRequirements with a single greater_than rule.
    """

        requirements = stem.version._VersionRequirements()
        requirements.greater_than(Version("0.2.2.36"))

        self.assertTrue(Version("0.2.2.36") >= requirements)
        self.assertTrue(Version("0.2.2.37") >= requirements)
        self.assertTrue(Version("0.2.3.36") >= requirements)
        self.assertFalse(Version("0.2.2.35") >= requirements)
        self.assertFalse(Version("0.2.1.38") >= requirements)

        requirements = stem.version._VersionRequirements()
        requirements.greater_than(Version("0.2.2.36"), False)

        self.assertFalse(Version("0.2.2.35") >= requirements)
        self.assertFalse(Version("0.2.2.36") >= requirements)
        self.assertTrue(Version("0.2.2.37") >= requirements)
예제 #15
0
파일: version.py 프로젝트: Foxboron/stem
    def test_requirements_less_than(self):
        """
    Checks a VersionRequirements with a single less_than rule.
    """

        requirements = stem.version._VersionRequirements()
        requirements.less_than(Version('0.2.2.36'))

        self.assertTrue(Version('0.2.2.36') >= requirements)
        self.assertTrue(Version('0.2.2.35') >= requirements)
        self.assertTrue(Version('0.2.1.38') >= requirements)
        self.assertFalse(Version('0.2.2.37') >= requirements)
        self.assertFalse(Version('0.2.3.36') >= requirements)

        requirements = stem.version._VersionRequirements()
        requirements.less_than(Version('0.2.2.36'), False)

        self.assertFalse(Version('0.2.2.37') >= requirements)
        self.assertFalse(Version('0.2.2.36') >= requirements)
        self.assertTrue(Version('0.2.2.35') >= requirements)
예제 #16
0
  def test_versions(self):
    """
    Handles a variety of version inputs.
    """

    test_values = {
      'Tor 0.2.2.35': Version('0.2.2.35'),
      'Tor 0.1.2': Version('0.1.2'),
      'Torr new_stuff': None,
      'new_stuff and stuff': None,
    }

    for v_line, expected in test_values.items():
      entry = get_router_status_entry_v3({'v': v_line})
      self.assertEqual(expected, entry.version)
      self.assertEqual(v_line, entry.version_line)

    # tries an invalid input
    content = get_router_status_entry_v3({'v': 'Tor ugabuga'}, content = True)
    self._expect_invalid_attr(content, 'version')
예제 #17
0
    def test_requirements_less_than(self):
        """
    Checks a VersionRequirements with a single less_than rule.
    """

        requirements = stem.version.VersionRequirements()
        requirements.less_than(Version("0.2.2.36"))

        self.assertTrue(Version("0.2.2.36").meets_requirements(requirements))
        self.assertTrue(Version("0.2.2.35").meets_requirements(requirements))
        self.assertTrue(Version("0.2.1.38").meets_requirements(requirements))
        self.assertFalse(Version("0.2.2.37").meets_requirements(requirements))
        self.assertFalse(Version("0.2.3.36").meets_requirements(requirements))

        requirements = stem.version.VersionRequirements()
        requirements.less_than(Version("0.2.2.36"), False)

        self.assertFalse(Version("0.2.2.37").meets_requirements(requirements))
        self.assertFalse(Version("0.2.2.36").meets_requirements(requirements))
        self.assertTrue(Version("0.2.2.35").meets_requirements(requirements))
예제 #18
0
  def test_versions(self):
    """
    Handles a variety of version inputs.
    """

    test_values = {
      "Tor 0.2.2.35": Version("0.2.2.35"),
      "Tor 0.1.2": Version("0.1.2"),
      "Torr new_stuff": None,
      "new_stuff and stuff": None,
    }

    for v_line, expected in test_values.items():
      entry = get_router_status_entry_v3({'v': v_line})
      self.assertEquals(expected, entry.version)
      self.assertEquals(v_line, entry.version_line)

    # tries an invalid input
    content = get_router_status_entry_v3({'v': "Tor ugabuga"}, content = True)
    self._expect_invalid_attr(content, "version")
예제 #19
0
파일: version.py 프로젝트: Foxboron/stem
    def test_nonversion_comparison(self):
        """
    Checks that we can be compared with other types.

    In python 3 on only equality comparisons work, greater than and less than
    comparisons result in a TypeError.
    """

        test_version = Version('0.1.2.3')
        self.assertNotEqual(test_version, None)
        self.assertNotEqual(test_version, 5)
예제 #20
0
파일: version.py 프로젝트: Foxboron/stem
    def test_requirements_in_range(self):
        """
    Checks a VersionRequirements with a single in_range rule.
    """

        requirements = stem.version._VersionRequirements()
        requirements.in_range(Version('0.2.2.36'), Version('0.2.2.38'))

        self.assertFalse(Version('0.2.2.35') >= requirements)
        self.assertTrue(Version('0.2.2.36') >= requirements)
        self.assertTrue(Version('0.2.2.37') >= requirements)
        self.assertFalse(Version('0.2.2.38') >= requirements)

        # rule for 'anything in the 0.2.2.x series'
        requirements = stem.version._VersionRequirements()
        requirements.in_range(Version('0.2.2.0'), Version('0.2.3.0'))

        for index in range(0, 100):
            self.assertTrue(Version('0.2.2.%i' % index) >= requirements)
예제 #21
0
    def test_requirements_in_range(self):
        """
    Checks a VersionRequirements with a single in_range rule.
    """

        requirements = stem.version.VersionRequirements()
        requirements.in_range(Version("0.2.2.36"), Version("0.2.2.38"))

        self.assertFalse(Version("0.2.2.35").meets_requirements(requirements))
        self.assertTrue(Version("0.2.2.36").meets_requirements(requirements))
        self.assertTrue(Version("0.2.2.37").meets_requirements(requirements))
        self.assertFalse(Version("0.2.2.38").meets_requirements(requirements))

        # rule for 'anything in the 0.2.2.x series'
        requirements = stem.version.VersionRequirements()
        requirements.in_range(Version("0.2.2.0"), Version("0.2.3.0"))

        for index in xrange(0, 100):
            self.assertTrue(
                Version("0.2.2.%i" % index).meets_requirements(requirements))
예제 #22
0
    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())
예제 #23
0
    def tutorial_example():
      from stem.descriptor.remote import DescriptorDownloader
      from stem.version import Version

      downloader = DescriptorDownloader()
      count, with_contact = 0, 0

      print("Checking for outdated relays...\n")

      for desc in downloader.get_server_descriptors():
        if desc.tor_version < Version('0.2.3.0'):
          count += 1

          if desc.contact:
            print('  %-15s %s' % (desc.tor_version, desc.contact.decode("utf-8", "replace")))
            with_contact += 1

      print("\n%i outdated relays found, %i had contact information" % (count, with_contact))
예제 #24
0
    def run(self,
            do_onion=True,
            do_inet=True,
            tgen_model=None,
            tgen_client_conf=None,
            tgen_server_conf=None):
        '''
        only `tgen_server_conf.listen_port` are "public" and need to be opened on the firewall.
        if `tgen_client_conf.connect_port` != `tgen_server_conf.listen_port`, then you should have installed a forwarding rule in the firewall.
        all ports need to be unique though, and unique among multiple onionperf instances.

        here are some sane defaults:
        tgen_client_conf.listen_port=58888, tgen_client_conf.connect_port=8080, tgen_client_conf.tor_ctl_port=59050, tgen_client_conf.tor_socks_port=59000,
        tgen_server_conf.listen_port=8080, tgen_server_conf.tor_ctl_port=59051, tgen_server_conf.tor_socks_port=59001
        '''
        self.threads = []
        self.done_event = threading.Event()

        if tgen_client_conf is None:
            tgen_client_conf = TGenConf(listen_port=58888,
                                        connect_ip='0.0.0.0',
                                        connect_port=8080,
                                        tor_ctl_port=59050,
                                        tor_socks_port=59000)
        if tgen_server_conf is None:
            tgen_server_conf = TGenConf(listen_port=8080,
                                        tor_ctl_port=59051,
                                        tor_socks_port=59001)

        # if ctrl-c is pressed, shutdown child processes properly
        try:
            # make sure stem and Tor supports ephemeral HS (version >= 0.2.7.1-alpha)
            # and also the NEWNYM mode that clears descriptor cache (version >= 0.2.7.3-rc)
            if do_onion:
                try:
                    tor_version = get_system_tor_version(self.tor_bin_path)
                    if tor_version < Requirement.ADD_ONION or tor_version < Version(
                            '0.2.7.3-rc'):  # ADD_ONION is a stem 1.4.0 feature
                        logging.warning(
                            "OnionPerf in onion mode requires Tor version >= 0.2.7.3-rc, you have {0}, aborting"
                            .format(tor_version))
                        return
                except:
                    logging.warning(
                        "OnionPerf in onion mode requires stem version >= 1.4.0, you have {0}, aborting"
                        .format(stem_version))
                    return

            logging.info("Bootstrapping started...")
            logging.info(
                "Log files for the client and server processes will be placed in {0}"
                .format(self.datadir_path))

            general_writables = []
            tgen_client_writable, torctl_client_writable = None, None

            if do_onion or do_inet:
                tgen_model.port = tgen_server_conf.listen_port
                general_writables.append(self.__start_tgen_server(tgen_model))

            if do_onion:
                logging.info(
                    "Onion Service private keys will be placed in {0}".format(
                        self.privatedir_path))
                # one must not have an open socks port when running a single
                # onion service.  see tor's man page for more information.
                if self.single_onion:
                    tgen_server_conf.tor_socks_port = 0
                tor_writable, torctl_writable = self.__start_tor_server(
                    tgen_server_conf.tor_ctl_port,
                    tgen_server_conf.tor_socks_port, {
                        tgen_client_conf.connect_port:
                        tgen_server_conf.listen_port
                    })
                general_writables.append(tor_writable)
                general_writables.append(torctl_writable)

            if do_onion or do_inet:
                tor_writable, torctl_client_writable = self.__start_tor_client(
                    tgen_client_conf.tor_ctl_port,
                    tgen_client_conf.tor_socks_port)
                general_writables.append(tor_writable)

            server_urls = []
            if do_onion and self.hs_v3_service_id is not None:
                server_urls.append("{0}.onion:{1}".format(
                    self.hs_v3_service_id, tgen_client_conf.connect_port))
            if do_inet:
                connect_ip = tgen_client_conf.connect_ip if tgen_client_conf.connect_ip != '0.0.0.0' else util.get_ip_address(
                )
                server_urls.append("{0}:{1}".format(
                    connect_ip, tgen_client_conf.connect_port))
            tgen_model.servers = server_urls

            if do_onion or do_inet:
                assert len(server_urls) > 0

                tgen_model.port = tgen_client_conf.listen_port
                tgen_model.socks_port = tgen_client_conf.tor_socks_port
                tgen_client_writable = self.__start_tgen_client(tgen_model)

                self.__start_log_processors(general_writables,
                                            tgen_client_writable,
                                            torctl_client_writable)

                logging.info("Bootstrapping finished, entering heartbeat loop")
                time.sleep(1)
                while True:
                    if tgen_model.num_transfers:
                        # This function blocks until our TGen client process
                        # terminated on its own.
                        self.__wait_for_tgen_client()
                        break

                    if self.__is_alive():
                        logging.info(
                            "All helper processes seem to be alive :)")
                    else:
                        logging.warning(
                            "Some parallel components failed too many times or have died :("
                        )
                        logging.info(
                            "We are in a broken state, giving up and exiting now"
                        )
                        break

                    logging.info(
                        "Next main process heartbeat is in 1 hour (helper processes run on their own schedule)"
                    )
                    logging.info("press CTRL-C for graceful shutdown...")
                    time.sleep(3600)
            else:
                logging.info("No measurement mode set, nothing to do")

        except KeyboardInterrupt:
            logging.info(
                "Interrupt received, please wait for graceful shutdown")
            self.__is_alive()
        finally:
            logging.info("Cleaning up child processes now...")

            if self.hs_v3_service_id is not None:
                try:
                    with Controller.from_port(
                            port=self.hs_v3_control_port) as torctl:
                        torctl.authenticate()
                        torctl.remove_ephemeral_hidden_service(
                            self.hs_v3_service_id)
                except:
                    pass  # this fails to authenticate if tor proc is dead

#            logging.disable(logging.INFO)
            self.done_event.set()
            for t in self.threads:
                logging.info("Joining {0} thread...".format(t.getName()))
                t.join()
            time.sleep(1)
            #            logging.disable(logging.NOTSET)

            logging.info("Child processes terminated")
            logging.info("Child process cleanup complete!")
            logging.info("Exiting")
예제 #25
0
    def run(self,
            do_onion=True,
            do_inet=True,
            client_tgen_listen_port=58888,
            client_tgen_connect_ip='0.0.0.0',
            client_tgen_connect_port=8080,
            client_tor_ctl_port=59050,
            client_tor_socks_port=59000,
            server_tgen_listen_port=8080,
            server_tor_ctl_port=59051,
            server_tor_socks_port=59001):
        '''
        only `server_tgen_listen_port` are "public" and need to be opened on the firewall.
        if `client_tgen_connect_port` != `server_tgen_listen_port`, then you should have installed a forwarding rule in the firewall.
        all ports need to be unique though, and unique among multiple onionperf instances.

        here are some sane defaults:
        client_tgen_listen_port=58888, client_tgen_connect_port=8080, client_tor_ctl_port=59050, client_tor_socks_port=59000,
        server_tgen_listen_port=8080, server_tor_ctl_port=59051, server_tor_socks_port=59001
        '''
        self.threads = []
        self.done_event = threading.Event()

        # if ctrl-c is pressed, shutdown child processes properly
        try:
            # make sure stem and Tor supports ephemeral HS (version >= 0.2.7.1-alpha)
            # and also the NEWNYM mode that clears descriptor cache (version >= 0.2.7.3-rc)
            if do_onion:
                try:
                    tor_version = get_system_tor_version(self.tor_bin_path)
                    if tor_version < Requirement.ADD_ONION or tor_version < Version(
                            '0.2.7.3-rc'):  # ADD_ONION is a stem 1.4.0 feature
                        logging.warning(
                            "OnionPerf in onion mode requires Tor version >= 0.2.7.3-rc, you have {0}, aborting"
                            .format(tor_version))
                        return
                except:
                    logging.warning(
                        "OnionPerf in onion mode requires stem version >= 1.4.0, you have {0}, aborting"
                        .format(stem_version))
                    return

            logging.info("Bootstrapping started...")
            logging.info(
                "Log files for the client and server processes will be placed in {0}"
                .format(self.datadir_path))

            general_writables = []
            tgen_client_writable, torctl_client_writable = None, None

            if do_onion or do_inet:
                general_writables.append(
                    self.__start_tgen_server(server_tgen_listen_port))

            if do_onion:
                logging.info(
                    "Onion Service private keys will be placed in {0}".format(
                        self.privatedir_path))
                tor_writable, torctl_writable = self.__start_tor_server(
                    server_tor_ctl_port, server_tor_socks_port,
                    {client_tgen_connect_port: server_tgen_listen_port})
                general_writables.append(tor_writable)
                general_writables.append(torctl_writable)

            if do_onion or do_inet:
                tor_writable, torctl_client_writable = self.__start_tor_client(
                    client_tor_ctl_port, client_tor_socks_port)
                general_writables.append(tor_writable)

            server_urls = []
            if do_onion and self.hs_service_id is not None and self.hs_v3_service_id is not None:
                server_urls.append("{0}.onion:{1}".format(
                    self.hs_service_id, client_tgen_connect_port))
                server_urls.append("{0}.onion:{1}".format(
                    self.hs_v3_service_id, client_tgen_connect_port))
            if do_inet:
                connect_ip = client_tgen_connect_ip if client_tgen_connect_ip != '0.0.0.0' else util.get_ip_address(
                )
                server_urls.append("{0}:{1}".format(connect_ip,
                                                    client_tgen_connect_port))

            if do_onion or do_inet:
                assert len(server_urls) > 0

                tgen_client_writable = self.__start_tgen_client(
                    server_urls, client_tgen_listen_port,
                    client_tor_socks_port)

                self.__start_log_processors(general_writables,
                                            tgen_client_writable,
                                            torctl_client_writable)

                logging.info("Bootstrapping finished, entering heartbeat loop")
                time.sleep(1)
                if self.oneshot:
                    logging.info(
                        "Onionperf is running in Oneshot mode. It will download a 5M file and shut down gracefully..."
                    )
                while True:
                    # TODO add status update of some kind? maybe the number of files in the www directory?
                    # logging.info("Heartbeat: {0} downloads have completed successfully".format(self.__get_download_count(tgen_client_writable.filename)))
                    if self.oneshot:
                        downloads = 0
                        while True:
                            downloads = self.__get_download_count(
                                tgen_client_writable.filename)
                            if downloads >= 1:
                                logging.info(
                                    "Onionperf has downloaded a 5M file in oneshot mode, and will now shut down."
                                )
                                break
                        else:
                            continue
                        break

                    if self.__is_alive():
                        logging.info(
                            "All helper processes seem to be alive :)")
                    else:
                        logging.warning(
                            "Some parallel components failed too many times or have died :("
                        )
                        logging.info(
                            "We are in a broken state, giving up and exiting now"
                        )
                        break

                    logging.info(
                        "Next main process heartbeat is in 1 hour (helper processes run on their own schedule)"
                    )
                    logging.info("press CTRL-C for graceful shutdown...")
                    time.sleep(3600)
            else:
                logging.info("No measurement mode set, nothing to do")

        except KeyboardInterrupt:
            logging.info(
                "Interrupt received, please wait for graceful shutdown")
            self.__is_alive()
        finally:
            logging.info("Cleaning up child processes now...")

            if self.hs_service_id is not None:
                try:
                    with Controller.from_port(
                            port=self.hs_control_port) as torctl:
                        torctl.authenticate()
                        torctl.remove_ephemeral_hidden_service(
                            self.hs_service_id)
                except:
                    pass  # this fails to authenticate if tor proc is dead

            if self.hs_v3_service_id is not None:
                try:
                    with Controller.from_port(
                            port=self.hs_v3_control_port) as torctl:
                        torctl.authenticate()
                        torctl.remove_ephemeral_hidden_service(
                            self.hs_v3_service_id)
                except:
                    pass  # this fails to authenticate if tor proc is dead

#            logging.disable(logging.INFO)
            self.done_event.set()
            for t in self.threads:
                logging.info("Joining {0} thread...".format(t.getName()))
                t.join()
            time.sleep(1)
            #            logging.disable(logging.NOTSET)

            logging.info("Child processes terminated")
            logging.info("Child process cleanup complete!")
            logging.info("Exiting")
예제 #26
0
def NavigaTor(controller,
              num_circuits=1,
              num_rttprobes=1,
              num_ttfbprobes=1,
              num_bwprobes=1,
              probesleep=0,
              num_threads=1,
              output='probe_',
              network_protection=True):
    """
    Configure Tor client and start threads for probing the RTT and/or TTFB
    of Tor circuits.
        "controller": authenticated Tor Controller from stem.control.
        "num_circuits": number of circuits to be probed.
        "num_rttprobes": number of RTT probes to be taken for each circuit.
        "num_ttfbprobes": number of TTFB probes to be taken for each circuit.
        "num_bwprobes": number of bw probes to be taken for each circuit.
        "probesleep": number of seconds to wait between probes.
        "num_threads": number of threads to start that actually do the
                       probing.
        "output": prefix for output file(s).
        "network_protection": Anti-Hammering protection for the Tor network.
    """

    # RouterStatusEntryV3 support in Stem
    assert get_distribution('stem').version > '1.4.0', \
        'Stem module version must be greater then 1.4.0.'

    # socks5 + hostname support has been added in 7.21.7
    assert pycurl.version_info()[1] >= '7.21.7', \
        'pycurl version (%s) must be >= 7.21.7' % pycurl.version_info()[1]

    # Validate input parameters.
    assert isinstance(controller, Controller), \
        'Controller has wrong type: %s.' % type(controller)
    for i in num_circuits, num_rttprobes, num_ttfbprobes, num_bwprobes,\
            num_threads:
        assert isinstance(i, int), '%s has wrong type: %s.' % (i, type(i))
    # Maximum number of circuits that can be probed is limited by
    # the unique destination IP calculation. Currently there is no need to
    # raise this limit.
    max_circuits = 255 + 255 * 256 + 255 * pow(256, 2) - 1
    assert num_circuits in range(1, max_circuits), \
        'num_circuits is out of range: %d.' % (num_circuits)

    assert controller.get_version() > Version('0.2.3'), \
        ('Your tor version (%s) is too old. ' % controller.get_version() +
         'Tor version 0.2.3.x is required.')
    assert controller.get_version() < Version('0.2.4'), \
        ('Your tor version (%s) is too new. ' % controller.get_version() +
         'Tor version 0.2.3.x is required.')

    try:
        # Configure tor client
        controller.set_conf("__DisablePredictedCircuits", "1")
        controller.set_conf("__LeaveStreamsUnattached", "1")
        controller.set_conf("MaxClientCircuitsPending", "1024")
        # Workaround ticket 9543. 10s average for each RTT probe and
        # 10s for each TTFB probe should be enough.
        max_dirtiness = (num_rttprobes + num_ttfbprobes) * 10
        if int(controller.get_conf("MaxCircuitDirtiness")) < max_dirtiness:
            controller.set_conf("MaxCircuitDirtiness", str(max_dirtiness))

        # Close all non-internal circuits.
        for circ in controller.get_circuits():
            if not circ.build_flags or 'IS_INTERNAL' not in circ.build_flags:
                controller.close_circuit(circ.id)

        manager = _Manager(controller, num_circuits, num_rttprobes,
                           num_ttfbprobes, num_bwprobes, probesleep,
                           num_threads, output, network_protection)
        while True:
            manager.join(1)
            if not manager.is_alive():
                break

    except KeyboardInterrupt:
        pass

    finally:
        controller.reset_conf("__DisablePredictedCircuits")
        controller.reset_conf("__LeaveStreamsUnattached")
        controller.reset_conf("MaxCircuitDirtiness")
        controller.reset_conf("MaxClientCircuitsPending")
        controller.close()
예제 #27
0
from stem.descriptor.remote import DescriptorDownloader
from stem.version import Version

downloader = DescriptorDownloader()
count, with_contact = 0, 0

print("Checking for outdated relays...")
print("")

for desc in downloader.get_server_descriptors():
  if desc.tor_version < Version('0.2.3.0'):
    count += 1

    if desc.contact:
      print('  %-15s %s' % (desc.tor_version, desc.contact.decode("utf-8", "replace")))
      with_contact += 1

print("")
print("%i outdated relays found, %i had contact information" % (count, with_contact))