Example #1
0
    def test_tor_connection_user_control_port(self):
        """
        Confirm we use a user-supplied control-port properly
        """

        config = TorConfig()
        config.OrPort = 1234
        config.ControlPort = 4321

        class Connector:
            def __call__(self, proto, trans):
                proto._set_valid_events('STATUS_CLIENT')
                proto.makeConnection(trans)
                proto.post_bootstrap.callback(proto)
                return proto.post_bootstrap

        def on_protocol(proto):
            proto.outReceived('Bootstrapped 90%\n')
            proto.outReceived('Bootstrapped 100%\n')

        trans = FakeProcessTransport()
        trans.protocol = self.protocol
        self.othertrans = trans
        creator = functools.partial(Connector(), self.protocol, self.transport)
        d = launch_tor(config, FakeReactor(self, trans, on_protocol), connection_creator=creator)

        def check_control_port(proto, tester):
            ## we just want to ensure launch_tor() didn't mess with
            ## the controlport we set
            tester.assertEquals(config.ControlPort, 4321)

        d.addCallback(check_control_port, self)
        d.addErrback(self.fail)
        return d
Example #2
0
    def test_tor_connection_user_data_dir(self):
        """
        Test that we don't delete a user-supplied data directory.
        """

        config = TorConfig()
        config.OrPort = 1234

        class Connector:
            def __call__(self, proto, trans):
                proto._set_valid_events('STATUS_CLIENT')
                proto.makeConnection(trans)
                proto.post_bootstrap.callback(proto)
                return proto.post_bootstrap

        def on_protocol(proto):
            proto.outReceived('Bootstrapped 90%\n')
            proto.outReceived('Bootstrapped 100%\n')

        my_dir = tempfile.mkdtemp(prefix='tortmp')
        config.DataDirectory = my_dir
        trans = FakeProcessTransport()
        trans.protocol = self.protocol
        self.othertrans = trans
        creator = functools.partial(Connector(), self.protocol, self.transport)
        d = launch_tor(config, FakeReactor(self, trans, on_protocol), connection_creator=creator)
        def still_have_data_dir(proto, tester):
            proto.cleanup()             # FIXME? not really unit-testy as this is sort of internal function
            tester.assertTrue(os.path.exists(my_dir))
            delete_file_or_tree(my_dir)
        d.addCallback(still_have_data_dir, self)
        d.addErrback(self.fail)
        return d
Example #3
0
    def test_parse_relative_path(self):
        # this makes sure we convert a relative path to absolute
        # hiddenServiceDir args. see Issue #77

        # make sure we have a valid thing from get_global_tor without
        # actually launching tor
        config = TorConfig()
        config.post_bootstrap = defer.succeed(config)
        from txtorcon import torconfig
        torconfig._global_tor_config = None
        get_global_tor(
            self.reactor,
            _tor_launcher=lambda react, config, prog: defer.succeed(config)
        )

        orig = os.path.realpath('.')
        try:
            with util.TempDir() as t:
                t = str(t)
                os.chdir(t)
                os.mkdir(os.path.join(t, 'foo'))
                hsdir = os.path.join(t, 'foo', 'blam')
                os.mkdir(hsdir)

                ep = serverFromString(
                    self.reactor,
                    'onion:88:localPort=1234:hiddenServiceDir=foo/blam'
                )
                self.assertEqual(
                    os.path.realpath(hsdir),
                    ep.hidden_service_dir
                )

        finally:
            os.chdir(orig)
Example #4
0
    def test_parse_user_path(self):
        # this makes sure we expand users and symlinks in
        # hiddenServiceDir args. see Issue #77

        # make sure we have a valid thing from get_global_tor without
        # actually launching tor
        config = TorConfig()
        config.post_bootstrap = defer.succeed(config)
        from txtorcon import torconfig
        torconfig._global_tor_config = None
        get_global_tor(
            self.reactor,
            _tor_launcher=lambda react, config, prog: defer.succeed(config)
        )
        ep = serverFromString(
            self.reactor,
            'onion:88:localPort=1234:hiddenServiceDir=~/blam/blarg'
        )
        # would be nice to have a fixed path here, but then would have
        # to run as a known user :/
        # maybe using the docker stuff to run integration tests better here?
        self.assertEqual(
            os.path.expanduser('~/blam/blarg'),
            ep.hidden_service_dir
        )
Example #5
0
    def test_options_hidden(self):
        self.protocol.answers.append(
            'HiddenServiceDir=/fake/path\nHiddenServicePort=80 '
            '127.0.0.1:1234\nHiddenServiceDirGroupReadable=1\n'
        )

        conf = TorConfig(self.protocol)
        yield conf.post_bootstrap
        self.assertTrue(conf.post_bootstrap.called)
        self.assertTrue('HiddenServiceOptions' not in conf.config)
        self.assertTrue('HiddenServices' in conf.config)
        self.assertEqual(len(conf.HiddenServices), 1)

        self.assertTrue(not conf.needs_save())
        conf.hiddenservices.append(
            HiddenService(conf, '/some/dir', '80 127.0.0.1:2345', 'auth', 2, True)
        )
        conf.hiddenservices[0].ports.append('443 127.0.0.1:443')
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(len(self.protocol.sets), 9)
        self.assertEqual(self.protocol.sets[0], ('HiddenServiceDir', '/fake/path'))
        self.assertEqual(self.protocol.sets[1], ('HiddenServiceDirGroupReadable', '1'))
        self.assertEqual(self.protocol.sets[2], ('HiddenServicePort', '80 127.0.0.1:1234'))
        self.assertEqual(self.protocol.sets[3], ('HiddenServicePort', '443 127.0.0.1:443'))
        self.assertEqual(self.protocol.sets[4], ('HiddenServiceDir', '/some/dir'))
        self.assertEqual(self.protocol.sets[5], ('HiddenServiceDirGroupReadable', '1'))
        self.assertEqual(self.protocol.sets[6], ('HiddenServicePort', '80 127.0.0.1:2345'))
        self.assertEqual(self.protocol.sets[7], ('HiddenServiceVersion', '2'))
        self.assertEqual(self.protocol.sets[8], ('HiddenServiceAuthorizeClient', 'auth'))
Example #6
0
 def test_add_hidden_service_to_empty_config(self):
     conf = TorConfig()
     h = HiddenService(conf, '/fake/path', ['80 127.0.0.1:1234'], '', 3)
     conf.hiddenservices.append(h)
     self.assertEqual(len(conf.hiddenservices), 1)
     self.assertEqual(h, conf.hiddenservices[0])
     self.assertTrue(conf.needs_save())
Example #7
0
    def test_tor_connection_fails(self):
        """
        We fail to connect once, and then successfully connect --
        testing whether we're retrying properly on each Bootstrapped
        line from stdout.
        """

        config = TorConfig()
        config.OrPort = 1234
        config.SocksPort = 9999

        class Connector:
            count = 0

            def __call__(self, proto, trans):
                self.count += 1
                if self.count < 2:
                    return defer.fail(error.CannotListenError(None, None, None))

                proto._set_valid_events('STATUS_CLIENT')
                proto.makeConnection(trans)
                proto.post_bootstrap.callback(proto)
                return proto.post_bootstrap

        def on_protocol(proto):
            proto.outReceived('Bootstrapped 90%\n')
            proto.outReceived('Bootstrapped 100%\n')

        trans = FakeProcessTransport()
        trans.protocol = self.protocol
        self.othertrans = trans
        creator = functools.partial(Connector(), self.protocol, self.transport)
        d = launch_tor(config, FakeReactor(self, trans, on_protocol), connection_creator=creator, tor_binary='/bin/echo')
        d.addCallback(self.setup_complete_fails)
        return self.assertFailure(d, Exception)
Example #8
0
    def test_tor_produces_stderr_output(self):
        config = TorConfig()
        config.OrPort = 1234
        config.SocksPort = 9999

        def connector(proto, trans):
            proto._set_valid_events('STATUS_CLIENT')
            proto.makeConnection(trans)
            proto.post_bootstrap.callback(proto)
            return proto.post_bootstrap

        def on_protocol(proto):
            proto.errReceived('Something went horribly wrong!\n')

        trans = FakeProcessTransport()
        trans.protocol = self.protocol
        self.othertrans = trans
        fakeout = StringIO()
        fakeerr = StringIO()
        creator = functools.partial(connector, self.protocol, self.transport)
        d = launch_tor(config, FakeReactor(self, trans, on_protocol),
                       connection_creator=creator, tor_binary='/bin/echo',
                       stdout=fakeout, stderr=fakeerr)
        d.addCallback(self.fail)        # should't get callback
        d.addErrback(self.setup_fails_stderr, fakeout, fakeerr)
        self.assertFalse(self.protocol.on_disconnect)
        return d
Example #9
0
    def test_basic_launch(self):
        config = TorConfig()
        config.OrPort = 1234
        config.SocksPort = 9999

        def connector(proto, trans):
            proto._set_valid_events('STATUS_CLIENT')
            proto.makeConnection(trans)
            proto.post_bootstrap.callback(proto)
            return proto.post_bootstrap

        class OnProgress:
            def __init__(self, test, expected):
                self.test = test
                self.expected = expected

            def __call__(self, percent, tag, summary):
                self.test.assertEqual(self.expected[0], (percent, tag, summary))
                self.expected = self.expected[1:]
                self.test.assertTrue('"' not in summary)
                self.test.assertTrue(percent >= 0 and percent <= 100)            
            
        def on_protocol(proto):
            proto.outReceived('Bootstrapped 100%\n')
            proto.progress = OnProgress(self, [(90, 'circuit_create', 'Establishing a Tor circuit'),
                                               (100, 'done', 'Done')])

        trans = FakeProcessTransport()
        trans.protocol = self.protocol
        self.othertrans = trans
        creator = functools.partial(connector, self.protocol, self.transport)
        d = launch_tor(config, FakeReactor(self, trans, on_protocol), connection_creator=creator)
        d.addCallback(self.setup_complete_no_errors, config)
        return d
Example #10
0
 def test_hidden_service_parse_error(self):
     conf = TorConfig(FakeControlProtocol(['config/names=']))
     try:
         conf._setup_hidden_services('''FakeHiddenServiceKey=foo''')
         self.fail()
     except RuntimeError, e:
         self.assertTrue('parse' in str(e))
Example #11
0
 def _do_launch_tor(self):
     tconfig = TorConfig()
     #tconfig.ControlPort = allocate_tcp_port() # defaults to 9052
     tconfig.SocksPort = allocate_tcp_port()
     socks_desc = "tcp:127.0.0.1:%d" % tconfig.SocksPort
     # this could take tor_binary=
     tproto = yield launch_tor(tconfig, self._reactor)
     returnValue((tproto, tconfig, socks_desc))
Example #12
0
    def test_set_wrong_object(self):
        conf = TorConfig(self.protocol)

        try:
            conf.log = ('this', 'is', 'a', 'tuple')
            self.fail()
        except ValueError, e:
            self.assertTrue('Not valid' in str(e))
Example #13
0
    def test_log_set_slice(self):
        conf = TorConfig(self.protocol)

        conf.log[0:1] = ['info file /tmp/foo.log']
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(self.protocol.sets[0], ('Log', 'info file /tmp/foo.log'))
Example #14
0
    def test_log_set_index(self):
        conf = TorConfig(self.protocol)

        conf.log[0] = 'info file /tmp/foo.log'
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertTrue(self.protocol.sets[0] == ('Log', 'info file /tmp/foo.log'))
Example #15
0
    def test_iterate_torconfig(self):
        cfg = TorConfig()
        cfg.FooBar = 'quux'
        cfg.save()
        cfg.Quux = 'blimblam'

        keys = sorted([k for k in cfg])

        self.assertEqual(['FooBar', 'Quux'], keys)
Example #16
0
 def test_boolean_parse_error(self):
     self.protocol.answers.append('config/names=\nfoo Boolean')
     self.protocol.answers.append({'foo': 'bar'})
     cfg = TorConfig(self.protocol)
     self.assertEqual(cfg.get_type('foo'), torconfig.Boolean)
     errs = self.flushLoggedErrors(ValueError)
     self.assertEqual(len(errs), 1)
     ## dunno if asserting strings in messages is a good idea...
     self.assertTrue('invalid literal' in errs[0].getErrorMessage())
Example #17
0
    def test_log_set_capital(self):
        conf = TorConfig(self.protocol)

        conf.Log.append('info file /tmp/foo.log')
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(self.protocol.sets[0], ('Log', 'notice file /var/log/tor/notices.log'))
        self.assertEqual(self.protocol.sets[1], ('Log', 'info file /tmp/foo.log'))
Example #18
0
 def test_multiple_orports(self):
     self.protocol.post_bootstrap = None
     self.protocol.answers.append('config/names=\nOrPort CommaList')
     self.protocol.answers.append({'OrPort': '1234'})
     conf = TorConfig(self.protocol)
     conf.OrPort = ['1234', '4321']
     conf.save()
     self.assertEqual(self.protocol.sets, [('OrPort', '1234'),
                                           ('OrPort', '4321')])
Example #19
0
    def test_log_set_remove(self):
        conf = TorConfig(self.protocol)

        self.assertEqual(len(conf.log), 1)
        conf.log.remove('notice file /var/log/tor/notices.log')
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(len(conf.log), 0)
        self.assertEqual(len(self.protocol.sets), 0)
Example #20
0
 def test_multiple_append(self):
     conf = TorConfig()
     h0 = HiddenService(conf, '/fake/path', ['80 127.0.0.1:1234'], '', 3)
     h1 = HiddenService(conf, '/fake/path', ['90 127.0.0.1:4321'], '', 3)
     conf.hiddenservices.append(h0)
     conf.hiddenservices.append(h1)
     self.assertEqual(len(conf.hiddenservices), 2)
     self.assertEqual(h0, conf.hiddenservices[0])
     self.assertEqual(h1, conf.hiddenservices[1])
     self.assertTrue(conf.needs_save())
Example #21
0
    def test_get_type(self):
        self.protocol.answers.append(
            'config/names=\nSomethingExciting CommaList\nHiddenServices Dependant'
        )
        self.protocol.answers.append({'SomethingExciting': 'a,b'})
        conf = TorConfig(self.protocol)

        from txtorcon.torconfig import HiddenService
        self.assertEqual(conf.get_type('SomethingExciting'), CommaList)
        self.assertEqual(conf.get_type('HiddenServices'), HiddenService)
Example #22
0
    def test_log_set_pop(self):
        conf = TorConfig(self.protocol)

        self.assertEqual(len(conf.log), 1)
        conf.log.pop()
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(len(conf.log), 0)
        self.assertEqual(len(self.protocol.sets), 0)
Example #23
0
def get_tor_config():
    tor_config = TorConfig()
    if config.tor.control_port is None:
        config.tor.control_port = int(randomFreePort())
    if config.tor.socks_port is None:
        config.tor.socks_port = int(randomFreePort())

    tor_config.ControlPort = config.tor.control_port
    tor_config.SocksPort = config.tor.socks_port

    if config.tor.data_dir:
        data_dir = os.path.expanduser(config.tor.data_dir)
        # We only use the Tor data dir specified in the config file if
        # 1. It is not locked (i.e. another process is using it)
        # 2. We have write permissions to it
        data_dir_usable = is_tor_data_dir_usable(data_dir)
        try:
            mkdir_p(data_dir)
        except OSError as ose:
            if ose.errno == errno.EACCESS:
                data_dir_usable = False
            else:
                raise
        if data_dir_usable:
            tor_config.DataDirectory = data_dir

    if config.tor.bridges:
        tor_config.UseBridges = 1
        if config.advanced.obfsproxy_binary:
            tor_config.ClientTransportPlugin = (
                'obfs2,obfs3 exec %s managed' %
                config.advanced.obfsproxy_binary
            )
        bridges = []
        with open(config.tor.bridges) as f:
            for bridge in f:
                if 'obfs' in bridge:
                    if config.advanced.obfsproxy_binary:
                        bridges.append(bridge.strip())
                else:
                    bridges.append(bridge.strip())
        tor_config.Bridge = bridges

    if config.tor.torrc:
        for i in config.tor.torrc.keys():
            setattr(tor_config, i, config.tor.torrc[i])

    if os.geteuid() == 0:
        tor_config.User = pwd.getpwuid(os.geteuid()).pw_name

    tor_config.save()
    log.debug("Setting control port as %s" % tor_config.ControlPort)
    log.debug("Setting SOCKS port as %s" % tor_config.SocksPort)
    return tor_config
Example #24
0
    def startTor(self):
        """ Starts Tor
        Launches a Tor with :param: socks_port :param: control_port
        :param: tor_binary set in ooniprobe.conf
        """
        log.msg("Starting Tor...")

        from txtorcon import TorConfig

        tor_config = TorConfig()
        if config.tor.control_port is None:
            config.tor.control_port = int(randomFreePort())
        if config.tor.socks_port is None:
            config.tor.socks_port = int(randomFreePort())

        tor_config.ControlPort = config.tor.control_port
        tor_config.SocksPort = config.tor.socks_port

        if config.tor.data_dir:
            data_dir = os.path.expanduser(config.tor.data_dir)

            if not os.path.exists(data_dir):
                log.msg("%s does not exist. Creating it." % data_dir)
                os.makedirs(data_dir)
            tor_config.DataDirectory = data_dir

        if config.tor.bridges:
            tor_config.UseBridges = 1
            if config.advanced.obfsproxy_binary:
                tor_config.ClientTransportPlugin = (
                    'obfs2,obfs3 exec %s managed' %
                    config.advanced.obfsproxy_binary
                )
            bridges = []
            with open(config.tor.bridges) as f:
                for bridge in f:
                    if 'obfs' in bridge:
                        if config.advanced.obfsproxy_binary:
                            bridges.append(bridge.strip())
                    else:
                        bridges.append(bridge.strip())
            tor_config.Bridge = bridges

        if config.tor.torrc:
            for i in config.tor.torrc.keys():
                setattr(tor_config, i, config.tor.torrc[i])

        if os.geteuid() == 0:
            tor_config.User = pwd.getpwuid(os.geteuid()).pw_name

        tor_config.save()
        log.debug("Setting control port as %s" % tor_config.ControlPort)
        log.debug("Setting SOCKS port as %s" % tor_config.SocksPort)
        return start_tor(tor_config)
Example #25
0
class CreateSocksEndpointTests(unittest.TestCase):

    def setUp(self):
        self.reactor = Mock()
        self.config = TorConfig()
        self.config.SocksPort = []
        self.config.bootstrap = defer.succeed(self.config)

    @defer.inlineCallbacks
    def test_create_default_no_ports(self):
        with self.assertRaises(Exception) as ctx:
            yield self.config.create_socks_endpoint(self.reactor, None)
        self.assertTrue('no SocksPorts configured' in str(ctx.exception))

    @defer.inlineCallbacks
    def test_create_default(self):
        self.config.SocksPort = ['9150']
        ep = yield self.config.create_socks_endpoint(self.reactor, None)

        factory = Mock()
        ep.connect(factory)
        self.assertEqual(1, len(self.reactor.mock_calls))
        call = self.reactor.mock_calls[0]
        self.assertEqual('connectTCP', call[0])
        self.assertEqual('127.0.0.1', call[1][0])
        self.assertEqual(9150, call[1][1])

    @defer.inlineCallbacks
    def test_create_tcp(self):
        ep = yield self.config.create_socks_endpoint(
            self.reactor, "9050",
        )

        factory = Mock()
        ep.connect(factory)
        self.assertEqual(1, len(self.reactor.mock_calls))
        call = self.reactor.mock_calls[0]
        self.assertEqual('connectTCP', call[0])
        self.assertEqual('127.0.0.1', call[1][0])
        self.assertEqual(9050, call[1][1])

    @defer.inlineCallbacks
    def test_create_error_on_save(self):
        self.config.SocksPort = []

        def boom(*args, **kw):
            raise TorProtocolError(551, "Something bad happened")

        with patch.object(TorConfig, 'save', boom):
            with self.assertRaises(Exception) as ctx:
                yield self.config.create_socks_endpoint(self.reactor, 'unix:/foo')
        err = str(ctx.exception)
        self.assertTrue('error from Tor' in err)
        self.assertTrue('specific ownership/permissions requirements' in err)
Example #26
0
    def test_proper_sets(self):
        self.protocol.answers.append('config/names=\nLog LineList')
        self.protocol.answers.append({'Log': 'foo'})

        conf = TorConfig(self.protocol)
        conf.log.append('bar')
        conf.save()

        self.assertEqual(len(self.protocol.sets), 2)
        self.assertEqual(self.protocol.sets[0], ('Log', 'foo'))
        self.assertEqual(self.protocol.sets[1], ('Log', 'bar'))
Example #27
0
 def test_parse_via_plugin(self):
     # make sure we have a valid thing from get_global_tor without actually launching tor
     config = TorConfig()
     config.post_bootstrap = defer.succeed(config)
     from txtorcon import torconfig
     torconfig._global_tor_config = None
     get_global_tor(self.reactor,
                    _tor_launcher=lambda react, config, prog: defer.succeed(config))
     ep = serverFromString(self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=/foo/bar')
     self.assertEqual(ep.public_port, 88)
     self.assertEqual(ep.local_port, 1234)
     self.assertEqual(ep.hidden_service_dir, '/foo/bar')
Example #28
0
    def test_save_boolean_with_strange_values(self):
        self.protocol.answers.append('config/names=\nfoo Boolean\nbar Boolean')
        self.protocol.answers.append({'foo': '0'})
        self.protocol.answers.append({'bar': '1'})

        conf = TorConfig(self.protocol)
        # save some non-boolean value
        conf.foo = "Something True"
        conf.bar = 0
        conf.save()
        self.assertEqual(set(self.protocol.sets),
                         set([('foo', 1), ('bar', 0)]))
Example #29
0
    def test_log_set_insert(self):
        conf = TorConfig(self.protocol)

        self.assertEqual(len(conf.log), 1)
        conf.log.insert(0, 'info file /tmp/foo')
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(len(conf.log), 2)
        self.assertEqual(len(self.protocol.sets), 2)
        self.assertEqual(self.protocol.sets[1], ('Log', 'notice file /var/log/tor/notices.log'))
        self.assertEqual(self.protocol.sets[0], ('Log', 'info file /tmp/foo'))
Example #30
0
    def test_log_set_extend(self):
        conf = TorConfig(self.protocol)

        self.assertTrue(len(conf.log) == 1)
        conf.log.extend(['info file /tmp/foo'])
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertTrue(len(conf.log) == 2)
        self.assertTrue(len(self.protocol.sets) == 2)
        self.assertTrue(self.protocol.sets[0] == ('Log', 'notice file /var/log/tor/notices.log'))
        self.assertTrue(self.protocol.sets[1] == ('Log', 'info file /tmp/foo'))
Example #31
0
    def test_ephemeral_extra_kwargs(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)

        with self.assertRaises(ValueError) as ctx:
            EphemeralOnionService(
                config,
                ports=["80 127.0.0.1:80"],
                ver=2,
                something_funny="foo",
            )
        self.assertIn(
            "Unknown kwarg",
            str(ctx.exception),
        )
Example #32
0
    def test_ephemeral_auth_stealth(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralAuthenticatedOnionService.create(
                Mock(),
                config,
                ports=["80 127.0.0.1:80"],
                auth=AuthStealth(["steve", "carol"]),
            )
        self.assertIn(
            "Tor does not yet support",
            str(ctx.exception),
        )
Example #33
0
    def test_ephemeral_auth_unknown(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralAuthenticatedOnionService.create(
                Mock(),
                config,
                ports=["80 127.0.0.1:80"],
                auth=["carol", "steve"],
            )
        self.assertIn(
            "'auth' should be an AuthBasic or AuthStealth instance",
            str(ctx.exception),
        )
Example #34
0
    def test_filesystem_wrong_ports(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)

        with self.assertRaises(ValueError) as ctx:
            yield FilesystemOnionService.create(
                Mock(),
                config,
                "/dev/null",
                ports="80 127.0.0.1:80",
            )
        self.assertIn(
            "'ports' must be a list of strings",
            str(ctx.exception)
        )
Example #35
0
    def test_explicit_data_dir(self, ftb):
        with util.TempDir() as tmp:
            d = str(tmp)
            with open(os.path.join(d, 'hostname'), 'w') as f:
                f.write('public')

            config = TorConfig(self.protocol)
            ep = TCPHiddenServiceEndpoint(self.reactor, config, 123, d)

            # make sure listen() correctly configures our hidden-serivce
            # with the explicit directory we passed in above
            yield ep.listen(NoOpProtocolFactory())

            self.assertEqual(1, len(config.HiddenServices))
            self.assertEqual(config.HiddenServices[0].dir, d)
            self.assertEqual(config.HiddenServices[0].hostname, 'public')
Example #36
0
    def test_ephemeral_v3_no_key(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)

        # returns a Deferred we're ignoring
        EphemeralOnionService.create(
            Mock(),
            config,
            ports=["80 127.0.0.1:80"],
            detach=True,
            version=3,
        )

        cmd, d = protocol.commands[0]
        self.assertEqual(u"ADD_ONION NEW:ED25519-V3 Port=80,127.0.0.1:80 Flags=Detach", cmd)
        d.callback("PrivateKey={}\nServiceID={}".format(_test_private_key_blob, _test_onion_id))
Example #37
0
    def test_ephemeral_ports_no_spaces(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)
        privkey = 'a' * 32

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralOnionService.create(
                Mock(),
                config,
                ports=["80:127.0.0.1:80"],
                private_key=privkey,
            )
        self.assertIn(
            "exactly one space",
            str(ctx.exception)
        )
Example #38
0
    def test_ephemeral_ports_not_a_list(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)
        privkey = 'a' * 32

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralOnionService.create(
                Mock(),
                config,
                ports="80 127.0.0.1:80",
                private_key=privkey,
            )
        self.assertIn(
            "'ports' must be a list of strings",
            str(ctx.exception)
        )
Example #39
0
    def test_ephemeral_ports_not_an_int(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)
        privkey = 'a' * 32

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralOnionService.create(
                Mock(),
                config,
                ports=["web 127.0.0.1:80"],
                private_key=privkey,
            )
        self.assertIn(
            "external port isn't an int",
            str(ctx.exception)
        )
Example #40
0
    def test_ephemeral_ports_non_local(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)
        privkey = 'a' * 32

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralOnionService.create(
                Mock(),
                config,
                ports=["80 8.8.8.8:80"],
                private_key=privkey,
            )
        self.assertIn(
            "should be a local address",
            str(ctx.exception)
        )
Example #41
0
    def test_create_torrc(self):
        config = TorConfig()
        config.SocksPort = 1234
        config.hiddenservices = [
            HiddenService(config, '/some/dir', '80 127.0.0.1:1234', 'auth', 2)
        ]
        config.Log = ['80 127.0.0.1:80', '90 127.0.0.1:90']
        config.save()
        torrc = config.create_torrc()
        self.assertEqual(
            torrc, '''HiddenServiceDir /some/dir
HiddenServicePort 80 127.0.0.1:1234
HiddenServiceVersion 2
HiddenServiceAuthorizeClient auth
Log 80 127.0.0.1:80
Log 90 127.0.0.1:90
SocksPort 1234
''')
Example #42
0
    def test_log_set_index(self):
        conf = TorConfig(self.protocol)

        conf.log[0] = 'info file /tmp/foo.log'
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(
            self.protocol.sets[0],
            ('Log', 'info file /tmp/foo.log')
        )
Example #43
0
    def test_old_tor_version(self):
        protocol = FakeControlProtocol([])
        protocol.version = "0.1.2.3"
        config = TorConfig(protocol)
        hsdir = self.mktemp()

        def my_progress(a, b, c):
            pass

        eph_d = FilesystemOnionService.create(
            Mock(),
            config,
            hsdir,
            ports=["80 127.0.0.1:80"],
            progress=my_progress,
        )
        yield eph_d
Example #44
0
    def test_set_multiple(self):
        self.protocol.answers.append('config/names=\nAwesomeKey String\nOK')
        self.protocol.answers.append({'AwesomeKey': 'foo'})

        conf = TorConfig(self.protocol)
        conf.awesomekey
        conf.awesomekey = 'baz'
        self.assertTrue(conf.needs_save())
        conf.awesomekey = 'nybble'
        conf.awesomekey = 'pac man'

        conf.save()

        self.assertEqual(len(self.protocol.sets), 1)
        self.assertEqual(self.protocol.sets[0], ('AwesomeKey', 'pac man'))
Example #45
0
    def test_log_set_slice(self):
        conf = TorConfig(self.protocol)

        conf.log[0:1] = ['info file /tmp/foo.log']
        self.assertTrue(conf.needs_save())
        conf.save()

        self.assertEqual(1, len(self.protocol.sets))
        self.assertEqual(
            self.protocol.sets[0],
            ('Log', 'info file /tmp/foo.log')
        )
Example #46
0
    def test_save_boolean_with_strange_values(self):
        self.protocol.answers.append('config/names=\nfoo Boolean\nbar Boolean')
        self.protocol.answers.append({'foo': '0'})
        self.protocol.answers.append({'bar': '1'})

        conf = TorConfig(self.protocol)
        # save some non-boolean value
        conf.foo = "Something True"
        conf.bar = 0
        conf.save()
        self.assertEqual(set(self.protocol.sets),
                         set([('foo', 1), ('bar', 0)]))
Example #47
0
    def test_unknown_version(self):
        protocol = FakeControlProtocol([])
        protocol.version = "0.1.1.1"
        config = TorConfig(protocol)
        hsdir = self.mktemp()
        os.mkdir(hsdir)

        hs = yield FilesystemOnionService.create(
            Mock(),
            config,
            hsdir=hsdir,
            ports=["80 127.0.0.1:4321"],
            version=99,
        )

        with self.assertRaises(RuntimeError) as ctx:
            hs.private_key
        self.assertIn("Don't know how to load", str(ctx.exception))
Example #48
0
    def test_ephemeral_v3_wrong_key_type(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)
        privkey = 'RSA1024:{}'.format('a' * 32)

        with self.assertRaises(ValueError) as ctx:
            yield EphemeralOnionService.create(
                Mock(),
                config,
                ports=["80 127.0.0.1:80"],
                detach=True,
                version=3,
                private_key=privkey,
            )
        self.assertIn(
            "but private key isn't",
            str(ctx.exception),
        )
Example #49
0
    def test_single_client(self):
        # FIXME test without crapping on filesystem
        self.protocol.answers.append('HiddenServiceDir=/fake/path\n')
        d = tempfile.mkdtemp()

        try:
            with open(os.path.join(d, 'hostname'), 'w') as f:
                f.write('gobledegook\n')

            conf = TorConfig(self.protocol)
            hs = HiddenService(conf, d, [])

            self.assertEqual(1, len(hs.clients))
            self.assertEqual('default', hs.clients[0][0])
            self.assertEqual('gobledegook', hs.clients[0][1])

        finally:
            shutil.rmtree(d, ignore_errors=True)
Example #50
0
    def test_onion_keys(self):
        self.protocol.answers.append('HiddenServiceDir=/fake/path\n')
        d = tempfile.mkdtemp()

        try:
            with open(os.path.join(d, 'hostname'), 'w') as f:
                f.write('public')
            with open(os.path.join(d, 'private_key'), 'w') as f:
                f.write('private')

            conf = TorConfig(self.protocol)
            hs = HiddenService(conf, d, [])

            self.assertEqual(hs.hostname, 'public')
            self.assertEqual(hs.private_key, 'private')

        finally:
            shutil.rmtree(d, ignore_errors=True)
Example #51
0
    def test_save_boolean(self):
        self.protocol.answers.append('config/names=\nfoo Boolean\nbar Boolean')
        self.protocol.answers.append({'foo': '0'})
        self.protocol.answers.append({'bar': '1'})

        conf = TorConfig(self.protocol)

        # save some boolean value
        conf.foo = True
        conf.bar = False
        conf.save()
        self.assertEqual(set(self.protocol.sets),
                         set([('foo', 1), ('bar', 0)]))
Example #52
0
    def test_create_torrc(self):
        config = TorConfig()
        config.SocksPort = 1234
        config.hiddenservices = [
            HiddenService(config, '/some/dir', '80 127.0.0.1:1234',
                          'auth', 2, True)
        ]
        config.Log = ['80 127.0.0.1:80', '90 127.0.0.1:90']
        config.save()
        torrc = config.create_torrc()
        lines = torrc.split('\n')
        lines.sort()
        torrc = '\n'.join(lines).strip()
        self.assertEqual(torrc, '''HiddenServiceAuthorizeClient auth
HiddenServiceDir /some/dir
HiddenServicePort 80 127.0.0.1:1234
HiddenServiceVersion 2
Log 80 127.0.0.1:80
Log 90 127.0.0.1:90
SocksPort 1234''')
Example #53
0
    def test_read_boolean_after_save(self):
        self.protocol.answers.append('config/names=\nfoo Boolean\nbar Boolean')
        self.protocol.answers.append({'foo': '0'})
        self.protocol.answers.append({'bar': '1'})

        conf = TorConfig(self.protocol)

        # save some boolean value
        conf.foo = True
        conf.bar = False
        conf.save()
        self.assertTrue(conf.foo is True, msg="foo not True: %s" % conf.foo)
        self.assertTrue(conf.bar is False, msg="bar not False: %s" % conf.bar)
Example #54
0
    def test_explicit_data_dir(self):
        d = tempfile.mkdtemp()
        try:
            with open(os.path.join(d, 'hostname'), 'w') as f:
                f.write('public')

            config = TorConfig(self.protocol)
            ep = TCPHiddenServiceEndpoint(self.reactor, config, 123, d)

            # make sure listen() correctly configures our hidden-serivce
            # with the explicit directory we passed in above
            port = yield ep.listen(NoOpProtocolFactory())

            self.assertEqual(1, len(config.HiddenServices))
            self.assertEqual(config.HiddenServices[0].dir, d)
            self.assertEqual(config.HiddenServices[0].hostname, 'public')

        finally:
            shutil.rmtree(d, ignore_errors=True)
Example #55
0
    def test_conf_changed_parsed(self):
        '''
        Create a configuration which holds boolean types. These types
        have to be parsed as booleans.
        '''
        protocol = FakeControlProtocol([])
        protocol.answers.append('config/names=\nFoo Boolean\nBar Boolean')
        protocol.answers.append({'Foo': '0'})
        protocol.answers.append({'Bar': '1'})

        config = TorConfig(protocol)
        # Initial value is not tested here
        protocol.events['CONF_CHANGED']('Foo=1\nBar=0')

        msg = "Foo is not True: %r" % config.Foo
        self.assertTrue(config.Foo is True, msg=msg)

        msg = "Foo is not False: %r" % config.Bar
        self.assertTrue(config.Bar is False, msg=msg)
Example #56
0
def startTor():
    def updates(prog, tag, summary):
        print("%d%%: %s" % (prog, summary))

    torconfig = TorConfig()
    torconfig.SocksPort = config.main.socks_port
    if config.main.tor2webmode:
        torconfig.Tor2webMode = 1
        torconfig.CircuitBuildTimeout = 60
    torconfig.save()
    if config.main.tor_binary is not None:
        d = launch_tor(torconfig, reactor,
                       tor_binary=config.main.tor_binary,
                       progress_updates=updates)
    else:
        d = launch_tor(torconfig, reactor, progress_updates=updates)
    d.addCallback(setupCollector)
    d.addErrback(txSetupFailed)
Example #57
0
    def test_ephemeral_v3_non_anonymous(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)

        # returns a Deferred we're ignoring
        EphemeralOnionService.create(
            Mock(),
            config,
            ports=[(80, "192.168.1.2:80")],
            version=3,
            detach=True,
            single_hop=True,
        )

        cmd, d = protocol.commands[0]
        self.assertEqual(
            u"ADD_ONION NEW:ED25519-V3 Port=80,192.168.1.2:80 Flags=Detach,NonAnonymous",
            cmd)
        d.callback("PrivateKey={}\nServiceID={}".format(
            _test_private_key_blob, _test_onion_id))
Example #58
0
 def _try_control_port(self, control_port):
     NOPE = (None, None, None)
     ep = clientFromString(self._reactor, control_port)
     try:
         tproto = yield build_tor_connection(ep, build_state=False)
         # now wait for bootstrap
         tconfig = yield TorConfig.from_protocol(tproto)
     except (ValueError, ConnectError):
         returnValue(NOPE)
     socks_ports = list(tconfig.SocksPort)
     socks_port = socks_ports[0]  # TODO: when might there be multiple?
     # I've seen "9050", and "unix:/var/run/tor/socks WorldWritable"
     pieces = socks_port.split()
     p = pieces[0]
     if p == DEFAULT_VALUE:
         socks_desc = "tcp:127.0.0.1:9050"
     elif re.search('^\d+$', p):
         socks_desc = "tcp:127.0.0.1:%s" % p
     else:
         socks_desc = p
     returnValue((tproto, tconfig, socks_desc))
Example #59
0
    def test_dir_ioerror(self):
        protocol = FakeControlProtocol([])
        config = TorConfig(protocol)
        hsdir = self.mktemp()
        os.mkdir(hsdir)
        with open(join(hsdir, "hostname"), "w") as f:
            f.write("{}.onion".format(_test_onion_id))

        hs_d = FilesystemOnionService.create(
            Mock(),
            config,
            hsdir=hsdir,
            ports=["80 127.0.0.1:4321"],
        )

        # arrange HS_DESC callbacks so we get the hs instance back
        cb = protocol.events['HS_DESC']
        cb('UPLOAD {} UNKNOWN hsdir0'.format(_test_onion_id))
        cb('UPLOADED {} UNKNOWN hsdir0'.format(_test_onion_id))

        hs = yield hs_d
        self.assertIs(None, hs.private_key)
Example #60
0
def setupCollector(tor_process_protocol, datadir):
    def setup_complete(port):
        #XXX: drop some other noise about what API are available on this machine
        print("Exposed collector Tor hidden service on httpo://%s"
              % port.onion_uri)

    torconfig = TorConfig(tor_process_protocol.tor_protocol)
    public_port = 80
    # XXX there is currently a bug in txtorcon that prevents data_dir from
    # being passed properly. Details on the bug can be found here:
    # https://github.com/meejah/txtorcon/pull/22

    #XXX: set up the various API endpoints, if configured and enabled
    #XXX: also set up a separate keyed hidden service for collectors to push their status to, if the bouncer is enabled
    hs_endpoint = TCPHiddenServiceEndpoint(reactor, torconfig, public_port,
                                           data_dir=os.path.join(datadir, 'collector'))
    d = hs_endpoint.listen(ooniBackend)
    
    d.addCallback(setup_complete)
    d.addErrback(txSetupFailed)

    return tor_process_protocol