def startTor(): def updates(prog, tag, summary): print("%d%%: %s" % (prog, summary)) tempfile.tempdir = os.path.join(_repo_dir, 'tmp') if not os.path.isdir(tempfile.gettempdir()): os.makedirs(tempfile.gettempdir()) _temp_dir = tempfile.mkdtemp() torconfig = TorConfig() torconfig.SocksPort = config.main.socks_port if config.main.tor2webmode: torconfig.Tor2webMode = 1 torconfig.CircuitBuildTimeout = 60 if config.main.tor_datadir is None: log.warn("Option 'tor_datadir' in oonib.conf is unspecified!") log.msg("Creating tmp directory in current directory for datadir.") log.debug("Using %s" % _temp_dir) datadir = _temp_dir else: datadir = config.main.tor_datadir torconfig.DataDirectory = datadir 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, datadir) if ooniBouncer: d.addCallback(setupBouncer, datadir) d.addErrback(txSetupFailed)
def test_no_tor_binary(self): """FIXME: do I really need all this crap in here?""" from txtorcon import torconfig oldone = torconfig.find_tor_binary self.transport = proto_helpers.StringTransport() config = TorConfig() d = None 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 try: self.protocol = FakeControlProtocol([]) torconfig.find_tor_binary = lambda: None trans = FakeProcessTransport() trans.protocol = self.protocol self.othertrans = trans creator = functools.partial(Connector(), self.protocol, self.transport) try: d = launch_tor(config, FakeReactor(self, trans, lambda x: None), connection_creator=creator) self.fail() except TorNotFound: pass # success! finally: torconfig.find_tor_binary = oldone return d
def _start(self): self.status = "Starting" # should more tightly follow state of tor process, see the txtrocon.torstate. sadly it doesn't yet parse ipv6 descriptors #XXX TODO: fix this #XXX: I really don't know if we should catch Exceptions this way try: tp = txtorcon.launch_tor( self.config, reactor, tor_binary=hc.TOR_BINARY, progress_updates=self._setup_updates) # calls reactor.run() def _setup_complete(self): self.status = "Running" tp.addCallback(reactor.fireSystemEvent, 'bootstrap', self) #XXX: can we do like this ? #XXX: is this post bootstrap or what? tp.addErrback(self._setup_failed) def _bootstrap_complete(): # do some things after bootstrap # e.g. provide a way to alert the BridgeManager # that this bridge has completed bootstrap reactor.fireSystemEvent('bootstrap') # figure out how to pass reference to instance in systemEvent tp.post_bootstrap = _bootstrap_complete except Exception: #XXX: must catch specifc exceptions!!! self.status = "Failed" # could we get the process exit status? raise return None return tp
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') 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)
def _create_my_own_tor(self): _start_launch = self._timing.add_event("launch tor") start = time.time() config = self.config = txtorcon.TorConfig() if 0: # The default is for launch_tor to create a tempdir itself, and # delete it when done. We only need to set a DataDirectory if we # want it to be persistent. import tempfile datadir = tempfile.mkdtemp() config.DataDirectory = datadir #config.ControlPort = allocate_tcp_port() # defaults to 9052 #print("setting config.ControlPort to", config.ControlPort) config.SocksPort = allocate_tcp_port() self._tor_socks_port = config.SocksPort print("setting config.SocksPort to", config.SocksPort) tpp = yield txtorcon.launch_tor(config, self._reactor, #tor_binary= ) # gives a TorProcessProtocol with .tor_protocol self._tor_protocol = tpp.tor_protocol print("tp:", self._tor_protocol) print("elapsed:", time.time() - start) self._timing.finish_event(_start_launch) returnValue(True)
def _launch_tor(self): return launch_tor(self.tor_config, reactor, tor_binary=config.advanced.tor_binary, progress_updates=self._progress_updates, stdout=self.tor_output, timeout=self.timeout, stderr=self.tor_output)
def main(reactor, tor_binary): config = txtorcon.TorConfig() config.ORPort = 0 config.SOCKSPort = 0 config.Tor2WebMode = 1 # leaving ControlPort unset; launch_tor will choose one print "Launching tor...", tor_binary try: yield txtorcon.launch_tor( config, reactor, tor_binary=tor_binary, stdout=sys.stdout ) print "success! We support Tor2Web mode" except RuntimeError as e: print "There was a problem:", str(e) print "We do NOT support Tor2Web mode" return print "quitting in 5 seconds" reactor.callLater(5, lambda: reactor.stop()) yield Deferred() # wait forever because we never .callback()
def test_tor_connection_default_control_port(self): """ Confirm a default control-port is set if not user-supplied. """ config = TorConfig() 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): ## ensure ControlPort was set to a default value tester.assertEquals(config.ControlPort, 9052) d.addCallback(check_control_port, self) d.addErrback(self.fail) return d
def main(reactor): config = txtorcon.TorConfig() config.OrPort = 1234 config.SocksPort = 9999 try: yield txtorcon.launch_tor(config, reactor, stdout=stdout) except RuntimeError as e: print "Error:", e return proto = config.protocol print "Connected to Tor version", proto.version state = yield txtorcon.TorState.from_protocol(proto) print "This Tor has PID", state.tor_pid print "This Tor has the following %d Circuits:" % len(state.circuits) for c in state.circuits.values(): print c print "Changing our config (SOCKSPort=9876)" config.SOCKSPort = 9876 yield config.save() print "Querying to see it changed:" socksport = yield proto.get_conf("SOCKSPort") print "SOCKSPort", socksport
def main(launch_tor=False): log.startLogging(sys.stdout) control_port = 9051 if launch_tor: control_port = 9151 config = txtorcon.TorConfig() config.ControlPort = control_port config.SocksPort = 0 d = txtorcon.launch_tor(config, reactor, progress_updates=progress) ## launch_tor returns a TorProcessProtocol ## ...so we grab out the TorControlProtocol instance in order ## to simply use the same callback on "d" below d.addCallback(lambda pp: pp.tor_protocol) else: ## if build_state=True, then we get a TorState() object back d = txtorcon.build_tor_connection((reactor, '127.0.0.1', control_port), build_state=False) d.addCallback(setup_complete).addErrback(an_error) try: reactor.run() except KeyboardInterrupt: pass # ctrl+c
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)
def main(progress_updates=updates, data_directory=None): """ Start logging, apaf services, and tor. :param progress_updates: a callback fired during tor's bootstrap. :ret: a twisted Deferred object for setting up callbacks in case of sucess/errors. """ ## start the logger. ## log.startLogging(sys.stdout) torconfig = txtorcon.TorConfig() ## start apaf. ## panel.start_panel(torconfig) core.start_services(torconfig) torconfig.HiddenServices = [x.hs for x in apaf.hiddenservices] torconfig.save() ## start tor. ## try: return txtorcon.launch_tor( torconfig, reactor, progress_updates=progress_updates, data_directory=data_directory, tor_binary=config.tor_binary, ) except OSError as exc: print >> sys.stderr, "Failing to launch tor executable (%s)" % ecx sys.exit(1) # return error status.
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 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.fail) # should't get callback d.addErrback(self.setup_fails_stderr) return d
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') 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, tor_binary='/bin/echo') 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
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
def start_tor(torconfig): d = txtorcon.launch_tor(torconfig, reactor, progress_updates=updates, tor_binary=tor_binary) d.addCallback(setup_complete) d.addErrback(setup_failed)
def test_tor_connection_default_control_port(self): """ Confirm a default control-port is set if not user-supplied. """ config = TorConfig() 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, tor_binary='/bin/echo') def check_control_port(proto, tester): ## ensure ControlPort was set to a default value tester.assertEquals(config.ControlPort, 9052) d.addCallback(check_control_port, self) d.addErrback(self.fail) return d
def main(reactor): config = txtorcon.TorConfig() config.ORPort = 0 config.SocksPort = 9998 try: os.mkdir('tor-data') except OSError: pass config.DataDirectory = './tor-data' try: process = yield txtorcon.launch_tor( config, reactor, progress_updates=progress ) except Exception as e: print("Error launching tor:", e) return protocol = process.tor_protocol print("Tor has launched.") print("Protocol:", protocol) info = yield protocol.get_info('traffic/read', 'traffic/written') print(info) # explicitly stop tor by either disconnecting our protocol or the # Twisted IProcessProtocol (or just exit our program) print("Killing our tor, PID={pid}".format(pid=process.transport.pid)) yield process.transport.signalProcess('TERM')
def _connect(self, reactor, update_status): # create a new Tor config = self.config = txtorcon.TorConfig() if self._data_directory: # The default is for launch_tor to create a tempdir itself, and # delete it when done. We only need to set a DataDirectory if we # want it to be persistent. This saves some startup time, because # we cache the descriptors from last time. On one of my hosts, # this reduces connect from 20s to 15s. if not os.path.exists(self._data_directory): # tor will mkdir this, but txtorcon wants to chdir to it # before spawning the tor process, so (for now) we need to # mkdir it ourselves. TODO: txtorcon should take # responsibility for this. os.mkdir(self._data_directory) config.DataDirectory = self._data_directory #config.ControlPort = allocate_tcp_port() # defaults to 9052 config.SocksPort = allocate_tcp_port() socks_desc = "tcp:127.0.0.1:%d" % config.SocksPort self._socks_desc = socks_desc # stash for tests socks_endpoint = clientFromString(reactor, socks_desc) with add_context(update_status, "launching Tor"): tpp = yield txtorcon.launch_tor(config, reactor, tor_binary=self._tor_binary) #print "launched" # gives a TorProcessProtocol with .tor_protocol self._tor_protocol = tpp.tor_protocol returnValue(socks_endpoint)
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, tor_binary='/bin/echo') 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
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
def main(progress_updates=updates, data_directory=None): """ Start logging, apaf services, and tor. :param progress_updates: a callback fired during tor's bootstrap. :ret: a twisted Deferred object for setting up callbacks in case of sucess/errors. """ ## start the logger. ## log.startLogging(sys.stdout) torconfig = txtorcon.TorConfig() ## start apaf. ## panel.start_panel(torconfig) core.start_services(torconfig) torconfig.HiddenServices = [x.hs for x in apaf.hiddenservices] torconfig.save() ## start tor. ## try: return txtorcon.launch_tor(torconfig, reactor, progress_updates=progress_updates, data_directory=data_directory, tor_binary=config.tor_binary, ) except OSError as exc: print >> sys.stderr, "Failing to launch tor executable (%s)" % ecx sys.exit(1) # return error status.
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
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
def test_full_tor_connection(self): def getTransport(address): """ If the address of the bridge starts with a valid c identifier then we consider it to be a bridge. Returns: The transport_name if it's a transport. None if it's not a obfsproxy bridge. """ transport_name = address.split(' ')[0] transport_name_chars = string.ascii_letters + string.digits if all(c in transport_name_chars for c in transport_name): return transport_name else: return None config = txtorcon.TorConfig() config.ControlPort = random.randint(2**14, 2**16) config.SocksPort = random.randint(2**14, 2**16) transport_name = getTransport(self.bridge) if transport_name and self.pyobfsproxy_bin: config.ClientTransportPlugin = "%s exec %s managed" % (transport_name, self.pyobfsproxy_bin) self.report['transport_name'] = transport_name self.report['bridge_address'] = self.bridge.split(' ')[1] elif transport_name and not self.pyobfsproxy_bin: log.err("Unable to test bridge because pyobfsproxy is not installed") self.report['success'] = None return else: self.report['bridge_address'] = self.bridge.split(' ')[0] config.Bridge = self.bridge config.UseBridges = 1 config.save() def updates(prog, tag, summary): log.msg("%s: %s%%" % (self.bridge, prog)) self.report['tor_progress'] = int(prog) self.report['tor_progress_tag'] = tag self.report['tor_progress_summary'] = summary d = txtorcon.launch_tor(config, reactor, timeout=self.timeout, progress_updates=updates) @d.addCallback def setup_complete(proto): try: proto.transport.signalProcess('TERM') except error.ProcessExitedAlready: proto.transport.loseConnection() log.msg("Successfully connected to %s" % self.bridge) self.report['success'] = True @d.addErrback def setup_failed(failure): log.msg("Failed to connect to %s" % self.bridge) self.report['success'] = False return d
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))
def startTor(torconfig): def updates(prog, tag, summary): print("%d%%: %s" % (prog, summary)) if config.main.socks_port: torconfig.SocksPort = config.main.socks_port if config.main.control_port: torconfig.ControlPort = config.main.control_port if config.main.tor2webmode: torconfig.Tor2webMode = 1 torconfig.CircuitBuildTimeout = 60 if config.main.tor_datadir is None: temporary_data_dir = tempfile.mkdtemp() log.warn("Option 'tor_datadir' in oonib.conf is unspecified!") log.warn("Using %s" % temporary_data_dir) torconfig.DataDirectory = temporary_data_dir else: if os.path.exists(config.main.tor_datadir): torconfig.DataDirectory = os.path.abspath(config.main.tor_datadir) else: raise Exception tor_log_file = os.path.join(torconfig.DataDirectory, "tor.log") torconfig.Log = ["notice stdout", "notice file %s" % tor_log_file] torconfig.save() if not hasattr(torconfig, 'ControlPort'): control_port = int(randomFreePort()) torconfig.ControlPort = control_port config.main.control_port = control_port if not hasattr(torconfig, 'SocksPort'): socks_port = int(randomFreePort()) torconfig.SocksPort = socks_port config.main.socks_port = socks_port 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) return d
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)
def run_tor(self): def progress(percent, tag, summary): ticks = int((percent/100.0) * 10.0) prog = (ticks * '#') + ((10 - ticks) * '.') print '%s %s' % (prog, summary) config = txtorcon.TorConfig() config.SocksPort = self.conf.tor.socks_port config.ControlPort = self.conf.tor.control_port d = txtorcon.launch_tor(config, reactor, progress_updates=progress) return d
def startTor(): def updates(prog, tag, summary): print "%d%%: %s" % (prog, summary) torconfig = txtorcon.TorConfig() torconfig.SocksPort = 9055 torconfig.save() d = txtorcon.launch_tor(torconfig, reactor, progress_updates=updates) d.addCallback(setupCollector) d.addErrback(txSetupFailed)
def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "c:hp:t", [ "control_port=", "help", "port", "launch_tor" ]) except getopt.GetoptError as err: print str(err) usage() sys.exit(2) for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-c", "--control_port"): options.control_port = int(a) elif o in ("-t", "--launch_tor"): options.launch_tor = True elif o in ("-p", "--port"): options.port = int(a) else: assert False, "unhandled option" log.startLogging(sys.stdout) if options.launch_tor: config = txtorcon.TorConfig() config.ControlPort = options.control_port config.SocksPort = 0 d = txtorcon.launch_tor(config, reactor, progress_updates=progress) # launch_tor returns a TorProcessProtocol # ...so we grab out the TorControlProtocol instance in order # to simply use the same callback on "d" below d.addCallback(lambda pp: pp.tor_protocol) else: # if build_state=True, then we get a TorState() object back d = txtorcon.build_tor_connection((reactor, '127.0.0.1', options.control_port), build_state=False) d.addCallback(setup_complete).addErrback(an_error) try: reactor.run() except KeyboardInterrupt: pass # ctrl+c
def startTor(self, torconfig): def updates(prog, tag, summary): print("%d%%: %s" % (prog, summary)) torconfig.SocksPort = config.main.socks_port if config.main.tor2webmode: torconfig.Tor2webMode = 1 torconfig.CircuitBuildTimeout = 60 if config.main.tor_datadir is None: self.temporary_data_dir = tempfile.mkdtemp() log.warn("Option 'tor_datadir' in oonib.conf is unspecified!") log.warn("Using %s" % self.temporary_data_dir) torconfig.DataDirectory = self.temporary_data_dir else: torconfig.DataDirectory = config.main.tor_datadir 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) return d
def startTor(): def updates(prog, tag, summary): print "%d%%: %s" % (prog, summary) torconfig = txtorcon.TorConfig() torconfig.SocksPort = 9055 if config.main.tor2webmode: torconfig.Tor2webMode = 1 torconfig.save() d = txtorcon.launch_tor(torconfig, reactor, tor_binary=config.main.tor_binary, progress_updates=updates) d.addCallback(setupCollector) d.addErrback(txSetupFailed)
def start_mock_apaf(tor, *services): """ Start the apaf for testing purposes. XXX. how to handle cleanup? Currently the reactor is left unclean :ret: None. """ torconfig = txtorcon.TorConfig() ## start apaf. ## panel.start_panel(torconfig) for service in services: service = imp.load_module( service, *imp.find_module(service, [config.services_dir]) ).ServiceDescriptor torconfig.HiddenServices = [x.hs for x in apaf.hiddenservices] torconfig.save() if tor: txtorcon.launch_tor(torconfig, reactor, progress_updates=progress_updates, tor_binary=config.tor_binary)
def test_full_tor_connection(self): config = txtorcon.TorConfig() config.ControlPort = net.randomFreePort() config.SocksPort = net.randomFreePort() config.DataDirectory = self.tor_datadir log.msg( "Connecting to tor %s" % (onion.tor_details['version'])) config.log = ['notice stdout', 'notice file %s' % self.tor_logfile] config.save() def updates(prog, tag, summary): log.msg("Progress is at: %s%%" % (prog)) self.report['tor_progress'] = int(prog) self.report['tor_progress_tag'] = tag self.report['tor_progress_summary'] = summary d = txtorcon.launch_tor(config, reactor, tor_binary=onion.find_tor_binary(), timeout=self.timeout, progress_updates=updates) @d.addCallback def setup_complete(proto): try: proto.transport.signalProcess('TERM') except error.ProcessExitedAlready: proto.transport.loseConnection() log.msg("Successfully connected to Tor") self.report['success'] = True @d.addErrback def setup_failed(failure): log.msg("Failed to connect to Tor") self.report['success'] = False self.report['error'] = 'timeout-reached' return @d.addCallback def write_log(_): with open(self.tor_logfile) as f: self.report['tor_log'] = f.read() os.remove(self.tor_logfile) try: shutil.rmtree(self.tor_datadir) except: pass return d
def test_full_tor_connection(self): config = txtorcon.TorConfig() config.ControlPort = net.randomFreePort() config.SocksPort = net.randomFreePort() config.DataDirectory = self.tor_datadir log.msg("Connecting to tor %s" % (onion.tor_details['version'])) config.log = ['notice stdout', 'notice file %s' % self.tor_logfile] config.save() def updates(prog, tag, summary): log.msg("Progress is at: %s%%" % (prog)) self.report['tor_progress'] = int(prog) self.report['tor_progress_tag'] = tag self.report['tor_progress_summary'] = summary d = txtorcon.launch_tor(config, reactor, tor_binary=onion.find_tor_binary(), timeout=self.timeout, progress_updates=updates) @d.addCallback def setup_complete(proto): try: proto.transport.signalProcess('TERM') except error.ProcessExitedAlready: proto.transport.loseConnection() log.msg("Successfully connected to Tor") self.report['success'] = True @d.addErrback def setup_failed(failure): log.msg("Failed to connect to Tor") self.report['success'] = False self.report['error'] = 'timeout-reached' return @d.addCallback def write_log(_): with open(self.tor_logfile) as f: self.report['tor_log'] = f.read() os.remove(self.tor_logfile) try: shutil.rmtree(self.tor_datadir) except: pass return d
def spawn(self, on_finish=None): """ Spawns a new isntance of tor process """ tor_config = txtorcon.TorConfig() tor_config.SOCKSPort = config.Application().tor_socks_port tor_config.ControlPort = config.Application().tor_control_port d = txtorcon.launch_tor( tor_config, reactor, progress_updates=self.updates, timeout=60) d.addCallback(functools.partial(self.setup_complete, tor_config)) d.addErrback(self.setup_failed) if on_finish is not None: self.on_finish = on_finish
def create(self, config): ''' Create a new tor process. :param config: a :class:`txtorcon.TorConfig` object. ''' self.connected = False if getattr(config, "ControlPort", 0) == 0: raise ValueError("ControlPort has to be set to a non-zero value.") self.control_port = config.ControlPort self.host = "127.0.0.1" defered = txtorcon.launch_tor(config=config, reactor=reactor) defered.addCallback(self._process_success) defered.addErrback(self._process_failed) defered.addErrback(self._fatal_error)
def _launch_tor(reactor, tor_executable, private_dir, txtorcon): # TODO: handle default tor-executable # TODO: it might be a good idea to find exactly which Tor we used, # and record it's absolute path into tahoe.cfg . This would protect # us against one Tor being on $PATH at create-node time, but then a # different Tor being present at node startup. OTOH, maybe we don't # need to worry about it. tor_config = txtorcon.TorConfig() tor_config.DataDirectory = data_directory(private_dir) if True: # unix-domain control socket tor_config.ControlPort = "unix:" + os.path.join( private_dir, "tor.control") tor_control_endpoint_desc = tor_config.ControlPort else: # we allocate a new TCP control port each time tor_config.ControlPort = allocate_tcp_port() tor_control_endpoint_desc = "tcp:127.0.0.1:%d" % tor_config.ControlPort tor_config.SOCKSPort = allocate_tcp_port() tpp = yield txtorcon.launch_tor( tor_config, reactor, tor_binary=tor_executable, # can be useful when debugging; mirror Tor's output to ours # stdout=sys.stdout, # stderr=sys.stderr, ) # now tor is launched and ready to be spoken to # as a side effect, we've got an ITorControlProtocol ready to go tor_control_proto = tpp.tor_protocol # How/when to shut down the new process? for normal usage, the child # tor will exit when it notices its parent (us) quit. Unit tests will # mock out txtorcon.launch_tor(), so there will never be a real Tor # process. So I guess we don't need to track the process. # If we do want to do anything with it, we can call tpp.quit() # (because it's a TorProcessProtocol) which returns a Deferred # that fires when Tor has actually exited. returnValue((tor_control_endpoint_desc, tor_control_proto))
def test_launch_with_timeout(self): config = TorConfig() config.OrPort = 1234 config.SocksPort = 9999 timeout = 5 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') trans = FakeProcessTransportNeverBootstraps() trans.protocol = self.protocol self.othertrans = trans creator = functools.partial(connector, self.protocol, self.transport) react = FakeReactor(self, trans, on_protocol) d = launch_tor(config, react, connection_creator=creator, timeout=timeout, tor_binary='/bin/echo') rtn = self.assertFailure(d, RuntimeError, "Timed out waiting for Tor to launch.") # FakeReactor is a task.Clock subclass and +1 just to be sure react.advance(timeout + 1) return rtn
def _launch_tor(reactor, tor_executable, private_dir, txtorcon): # TODO: handle default tor-executable # TODO: it might be a good idea to find exactly which Tor we used, # and record it's absolute path into tahoe.cfg . This would protect # us against one Tor being on $PATH at create-node time, but then a # different Tor being present at node startup. OTOH, maybe we don't # need to worry about it. tor_config = txtorcon.TorConfig() tor_config.DataDirectory = data_directory(private_dir) if True: # unix-domain control socket tor_config.ControlPort = "unix:" + os.path.join(private_dir, "tor.control") tor_control_endpoint_desc = tor_config.ControlPort else: # we allocate a new TCP control port each time tor_config.ControlPort = allocate_tcp_port() tor_control_endpoint_desc = "tcp:127.0.0.1:%d" % tor_config.ControlPort tor_config.SOCKSPort = allocate_tcp_port() tpp = yield txtorcon.launch_tor( tor_config, reactor, tor_binary=tor_executable, # can be useful when debugging; mirror Tor's output to ours # stdout=sys.stdout, # stderr=sys.stderr, ) # now tor is launched and ready to be spoken to # as a side effect, we've got an ITorControlProtocol ready to go tor_control_proto = tpp.tor_protocol # How/when to shut down the new process? for normal usage, the child # tor will exit when it notices its parent (us) quit. Unit tests will # mock out txtorcon.launch_tor(), so there will never be a real Tor # process. So I guess we don't need to track the process. # If we do want to do anything with it, we can call tpp.quit() # (because it's a TorProcessProtocol) which returns a Deferred # that fires when Tor has actually exited. returnValue((tor_control_endpoint_desc, tor_control_proto))
def get_global_tor(reactor): global _global_tor_config global _global_tor_lock yield _global_tor_lock.acquire() try: if _global_tor_config is None: _global_tor_config = _configTor() # start Tor launching def updates(prog, tag, summary): log.msg("%d%%: %s" % (prog, summary)) yield launch_tor(_global_tor_config, reactor, progress_updates=updates, tor_binary=config.main.tor_binary) yield _global_tor_config.post_bootstrap defer.returnValue(_global_tor_config) finally: _global_tor_lock.release()
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, tor_binary='/bin/echo') d.addCallback(self.setup_complete_no_errors, config) return d
def main(progress_updates=updates, data_directory=None, connection_creator=None): """ Start logging, apaf services, and tor. :param progress_updates: a callback fired during tor's bootstrap. :ret: a twisted Deferred object for setting up callbacks in case of sucess/errors. XXX: for versions of txtorcon greater that 0.6 it is possible to set the data_directory argument directly in the toconfig, and removing from launch_tor. See issue #15 of txtorcon and #40 of APAF. """ ## start the logger. ## log.startLogging(sys.stdout) torconfig = txtorcon.TorConfig() if data_directory is not None: config.DataDirectory = data_directory ## start apaf. ## panel.start_panel(torconfig) core.start_services(torconfig) # torconfig.DataDirectory = data_directory torconfig.HiddenServices = [x.hs for x in apaf.hiddenservices] torconfig.save() ## start tor. ## try: return txtorcon.launch_tor(torconfig, reactor, progress_updates=progress_updates, tor_binary=config.tor_binary, connection_creator=connection_creator) except OSError as exc: print >> sys.stderr, "Failing to launch tor executable (%s)" % ecx sys.exit(1) # return error status.
def main(reactor, tor_binary): config = txtorcon.TorConfig() config.ORPort = 0 config.SOCKSPort = 0 config.Tor2WebMode = 1 # leaving ControlPort unset; launch_tor will choose one print("Launching tor...", tor_binary) try: yield txtorcon.launch_tor(config, reactor, tor_binary=tor_binary, stdout=sys.stdout) print("success! We support Tor2Web mode") except RuntimeError as e: print("There was a problem:", str(e)) print("We do NOT support Tor2Web mode") return print("quitting in 5 seconds") reactor.callLater(5, lambda: reactor.stop()) yield Deferred() # wait forever because we never .callback()
def test_launch_tor_fails(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.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)
def test_launch_tor_fails(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.outReceived('Bootstrapped 90%\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.setup_complete_fails, fakeout, fakeerr) self.flushLoggedErrors(RuntimeError) return d