High Level API¶
This is the recommended API. See the Programming Guide for “prose” documentation of these (and other) APIs.
Tor¶
- class txtorcon.Tor(reactor, control_protocol, _tor_config=None, _process_proto=None, _non_anonymous=None)¶
I represent a single instance of Tor and act as a Builder/Factory for several useful objects you will probably want. There are two ways to create a Tor instance:
txtorcon.connect()
to connect to a Tor that is already running (e.g. Tor Browser Bundle, a system Tor, …).txtorcon.launch()
to launch a fresh Tor instance
The stable API provided by this class is
txtorcon.interface.ITor
If you desire more control, there are “lower level” APIs which are the very ones used by this class. However, this “highest level” API should cover many use-cases:
import txtorcon @inlineCallbacks def main(reactor): # tor = yield txtorcon.connect(UNIXClientEndpoint(reactor, "/var/run/tor/control")) tor = yield txtorcon.launch(reactor) onion_ep = tor.create_onion_endpoint(port=80) port = yield onion_ep.listen(Site()) print(port.getHost())
don’t instantiate this class yourself – instead use the factory methods
txtorcon.launch()
ortxtorcon.connect()
connect¶
- controller.connect(control_endpoint=None, password_function=None)¶
Creates a
txtorcon.Tor
instance by connecting to an already-running tor’s control port. For example, a common default tor uses is UNIXClientEndpoint(reactor, ‘/var/run/tor/control’) or TCP4ClientEndpoint(reactor, ‘localhost’, 9051)If only password authentication is available in the tor we connect to, the
password_function
is called (if supplied) to retrieve a valid password. This function can return a Deferred.For example:
import txtorcon from twisted.internet.task import react from twisted.internet.defer import inlineCallbacks @inlineCallbacks def main(reactor): tor = yield txtorcon.connect( TCP4ClientEndpoint(reactor, "localhost", 9051) ) state = yield tor.create_state() for circuit in state.circuits: print(circuit)
- Parameters:
control_endpoint – None, an IStreamClientEndpoint to connect to, or a Sequence of IStreamClientEndpoint instances to connect to. If None, a list of defaults are tried.
password_function – See
txtorcon.TorControlProtocol
- Returns:
a Deferred that fires with a
txtorcon.Tor
instance
launch¶
- controller.launch(progress_updates=None, control_port=None, data_directory=None, socks_port=None, non_anonymous_mode=None, stdout=None, stderr=None, timeout=None, tor_binary=None, user=None, connection_creator=None, kill_on_stderr=True, _tor_config=None)¶
launches a new Tor process, and returns a Deferred that fires with a new
txtorcon.Tor
instance. From this instance, you can create or get any “interesting” instances you need: thetxtorcon.TorConfig
instance, create endpoints, createtxtorcon.TorState
instance(s), etc.Note that there is NO way to pass in a config; we only expost a couple of basic Tor options. If you need anything beyond these, you can access the
TorConfig
instance (via.config
) and make any changes there, reflecting them in tor with.config.save()
.You can igore all the options and safe defaults will be provided. However, it is recommended to pass data_directory especially if you will be starting up Tor frequently, as it saves a bunch of time (and bandwidth for the directory authorities). “Safe defaults” means:
a tempdir for a
DataDirectory
is used (respectingTMP
) and is deleted when this tor is shut down (you therefore probably want to supply thedata_directory=
kwarg);a random, currently-unused local TCP port is used as the
SocksPort
(specifysocks_port=
if you want your own). If you want no SOCKS listener at all, passsocks_port=0
we set
__OwningControllerProcess
and callTAKEOWNERSHIP
so that if our control connection goes away, tor shuts down (see control-spec 3.23).the launched Tor will use
COOKIE
authentication.
- Parameters:
reactor – a Twisted IReactorCore implementation (usually twisted.internet.reactor)
progress_updates – a callback which gets progress updates; gets 3 args: percent, tag, summary (FIXME make an interface for this).
data_directory – set as the
DataDirectory
option to Tor, this is where tor keeps its state information (cached relays, etc); starting with an already-populated state directory is a lot faster. IfNone
(the default), we create a tempdir for this and delete it on exit. It is recommended you pass something here.non_anonymous_mode – sets the Tor options HiddenServiceSingleHopMode and HiddenServiceNonAnonymousMode to 1 and un-sets any SOCKSPort config, thus putting this Tor client into “non-anonymous mode” which allows starting so-called Single Onion services – which use single-hop circuits to rendezvous points. See WARNINGs in Tor manual! Also you need Tor 0.3.4.1 or later (e.g. any 0.3.5.* or newer) for this to work properly.
stdout – a file-like object to which we write anything that Tor prints on stdout (just needs to support write()).
stderr – a file-like object to which we write anything that Tor prints on stderr (just needs .write()). Note that we kill Tor off by default if anything appears on stderr; pass “kill_on_stderr=False” if you don’t want this behavior.
tor_binary – path to the Tor binary to run. If None (the default), we try to find the tor binary.
kill_on_stderr – When True (the default), if Tor prints anything on stderr we kill off the process, close the TorControlProtocol and raise an exception.
connection_creator – is mostly available to ease testing, so you probably don’t want to supply this. If supplied, it is a callable that should return a Deferred that delivers an IProtocol or ConnectError. See twisted.internet.interfaces.IStreamClientEndpoint.connect Note that this parameter is ignored if config.ControlPort == 0
- Returns:
a Deferred which callbacks with
txtorcon.Tor
instance, from which you can retrieve the TorControlProtocol instance via the.protocol
property.
HACKS:
It’s hard to know when Tor has both (completely!) written its authentication cookie file AND is listening on the control port. It seems that waiting for the first ‘bootstrap’ message on stdout is sufficient. Seems fragile…and doesn’t work 100% of the time, so FIXME look at Tor source.
XXX this “User” thing was, IIRC, a feature for root-using scripts (!!) that were going to launch tor, but where tor would drop to a different user. Do we still want to support this? Probably relevant to Docker (where everything is root! yay!)
User
: if this exists, we attempt to set ownership of the tempdir to this user (but only if our effective UID is 0).