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)

Bases: object

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() or txtorcon.connect()

quit(**kwargs)

Closes the control connection, and if we launched this Tor instance we’ll send it a TERM and wait until it exits.

process

An object implementing twisted.internet.interfaces.IProcessProtocol if this Tor instance was launched, or None.

protocol

The TorControlProtocol instance that is communicating with this Tor instance.

version
get_config(**kwargs)
Returns:a Deferred that fires with a TorConfig instance. This instance represents up-to-date configuration of the tor instance (even if another controller is connected). If you call this more than once you’ll get the same TorConfig back.
web_agent(pool=None, socks_endpoint=None)
Parameters:
  • socks_endpoint – If None (the default), a suitable SOCKS port is chosen from our config (or added). If supplied, should be a Deferred which fires an IStreamClientEndpoint (e.g. the return-value from txtorcon.TorConfig.socks_endpoint()) or an immediate IStreamClientEndpoint You probably don’t need to mess with this.
  • pool – passed on to the Agent (as pool=)
dns_resolve(**kwargs)
Parameters:hostname – a string
Returns:a Deferred that calbacks with the hostname as looked-up via Tor (or errback). This uses Tor’s custom extension to the SOCKS5 protocol.
dns_resolve_ptr(**kwargs)
Parameters:ip – a string, like “127.0.0.1”
Returns:a Deferred that calbacks with the IP address as looked-up via Tor (or errback). This uses Tor’s custom extension to the SOCKS5 protocol.
add_onion_authentication(**kwargs)

Add a client-side authentication token for a particular Onion service.

remove_onion_authentication(**kwargs)

Remove a token for an onion host

Returns:True if successful, False if there wasn’t a token for that host.
onion_authentication(onion_host, token)

(Python3 only!) This returns an async context-manager that will add and remove onion authentication. For example, inside an async def method that’s had ensureDeferred called on it:

async with tor.onion_authentication("timaq4ygg2iegci7.onion", "seekrit token"):
    agent = tor.web_agent()
    resp = await agent.request(b'GET', "http://timaq4ygg2iegci7.onion/")
    body = await readBody(resp)
# after the "async with" the token will be removed from Tor's configuration

Under the hood, this just uses the add_onion_authentication and remove_onion_authentication methods so on Python2 you can use those together with try/finally to get the same effect.

stream_via(host, port, tls=False, socks_endpoint=None)

This returns an IStreamClientEndpoint instance that will use this Tor (via SOCKS) to visit the (host, port) indicated.

Parameters:
  • host – The host to connect to. You MUST pass host-names to this. If you absolutely know that you’ve not leaked DNS (e.g. you save IPs in your app’s configuration or similar) then you can pass an IP.
  • port – Port to connect to.
  • tls – If True, it will wrap the return endpoint in one that does TLS (default: False).
  • socks_endpoint – Normally not needed (default: None) but you can pass an IStreamClientEndpoint directed at one of the local Tor’s SOCKS5 ports (e.g. created with txtorcon.TorConfig.create_socks_endpoint()). Can be a Deferred.
create_authenticated_onion_endpoint(port, auth, private_key=None, version=None)

WARNING: API subject to change

When creating an authenticated Onion service a token is created for each user. For ‘stealth’ authentication, the hostname is also different for each user. The difference between this method and txtorcon.Tor.create_onion_endpoint() is in this case the “onion_service” instance implements txtorcon.IAuthenticatedOnionClients.

Returns:

an object that implements IStreamServerEndpoint, which will create an “ephemeral” Onion service when .listen() is called. This uses the ADD_ONION Tor control-protocol command. The object returned from .listen() will be a :class:TorOnionListeningPort``; its .onion_service attribute will be a txtorcon.IAuthenticatedOnionClients instance.

Parameters:
  • port – the port to listen publically on the Tor network on (e.g. 80 for a Web server)
  • private_key – if not None (the default), this should be the same blob of key material that you received from the txtorcon.IOnionService object during a previous run (i.e. from the .provate_key attribute).
  • version – if not None, a specific version of service to use; version=3 is Proposition 224 and version=2 is the older 1024-bit key based implementation.
  • auth – a AuthBasic or AuthStealth instance
create_onion_endpoint(port, private_key=None, version=None)

WARNING: API subject to change

Returns:

an object that implements IStreamServerEndpoint, which will create an “ephemeral” Onion service when .listen() is called. This uses the ADD_ONION tor control-protocol command. The object returned from .listen() will be a :class:TorOnionListeningPort``; its .onion_service attribute will be a txtorcon.IOnionService instance.

Parameters:
  • port – the port to listen publically on the Tor network on (e.g. 80 for a Web server)
  • private_key – if not None (the default), this should be the same blob of key material that you received from the txtorcon.IOnionService object during a previous run (i.e. from the .private_key attribute).
  • version – if not None, a specific version of service to use; version=3 is Proposition 224 and version=2 is the older 1024-bit key based implementation.
create_filesystem_onion_endpoint(port, hs_dir, group_readable=False, version=None)

WARNING: API subject to change

Returns:

an object that implements IStreamServerEndpoint. When the .listen() method is called, the endpoint will create an Onion service whose keys are on disk when .listen() is called. The object returned from .listen() will be a :class:TorOnionListeningPort``; its .onion_service attribute will be a txtorcon.IOnionService instance.

Parameters:
  • port – the port to listen publically on the Tor network on (e.g. 80 for a Web server)
  • hs_dir – the directory in which keys are stored for this service.
  • group_readable – controls the Tor HiddenServiceDirGroupReadable which will either set (or not) group read-permissions on the hs_dir.
  • version – if not None, a specific version of service to use; version=3 is Proposition 224 and version=2 is the older 1024-bit key based implementation. The default is version 3.
create_filesystem_authenticated_onion_endpoint(port, hs_dir, auth, group_readable=False, version=None)

WARNING: API subject to change

Returns:

an object that implements IStreamServerEndpoint. When the .listen() method is called, the endpoint will create an Onion service whose keys are on disk when .listen() is called. The object returned from .listen() will be a :class:TorOnionListeningPort``; its .onion_service attribute will be a txtorcon.IOnionService instance.

Parameters:
  • port – the port to listen publically on the Tor network on (e.g. 80 for a Web server)
  • hs_dir – the directory in which keys are stored for this service.
  • auth – instance of txtorcon.AuthBasic or txtorcon.AuthStealth controlling the type of authentication to use.
  • group_readable – controls the Tor HiddenServiceDirGroupReadable which will either set (or not) group read-permissions on the hs_dir.
  • version – if not None, a specific version of service to use; version=3 is Proposition 224 and version=2 is the older 1024-bit key based implementation. The default is version 3.
create_state(**kwargs)

returns a Deferred that fires with a ready-to-go txtorcon.TorState instance.

is_ready(**kwargs)
Returns:a Deferred that fires with True if this Tor is non-dormant and ready to go. This will return True if GETINFO dormant is false or if GETINFO status/enough-dir-info is true or if GETINFO status/circuit-established true.
become_ready(**kwargs)

Make sure Tor is no longer dormant.

If Tor is currently dormant, it is woken up by doing a DNS request for torproject.org

create_onion_service(**kwargs)

Create a new Onion service

This method will create a new Onion service, returning (via Deferred) an instance that implements IOnionService. (To create authenticated onion services, see XXX). This method awaits at least one upload of the Onion service’s ‘descriptor’ to the Tor network – this can take from 30s to a couple minutes.

Parameters:
  • private_key

    None, txtorcon.DISCARD or a key-blob retained from a prior run

    Passing None means a new one will be created. It can be retrieved from the .private_key property of the returned object. You must retain this key yourself (and pass it in to this method in the future) if you wish to keep the same .onion domain when re-starting your program.

    Passing txtorcon.DISCARD means txtorcon will never learn the private key from Tor and so there will be no way to re-create an Onion Service on the same address after Tor exits.

  • version – The latest Tor releases support ‘Proposition 224’ (version 3) services. These are the default.
  • progress – if provided, a function that takes 3 arguments: (percent_done, tag, description) which may be called any number of times to indicate some progress has been made.
  • await_all_uploads – if False (the default) then we wait until at least one upload of our Descriptor to a Directory Authority has completed; if True we wait until all have completed.
create_filesystem_onion_service(**kwargs)

Create a new Onion service stored on disk

This method will create a new Onion service, returning (via Deferred) an instance that implements IOnionService. (To create authenticated onion services, see XXX). This method awaits at least one upload of the Onion service’s ‘descriptor’ to the Tor network – this can take from 30s to a couple minutes.

Parameters:
  • ports – a collection of ports to advertise; these are forwarded locally on a random port. Each entry may instead be a 2-tuple, which chooses an explicit local port.
  • onion_service_dir

    a path to an Onion Service directory.

    Tor will write a hostname file in this directory along with the private keys for the service (if they do not already exist). You do not need to retain the private key yourself.

  • version – which kind of Onion Service to create. The default is 3 which are the Proposition 224 services. Version 2 are the previous services. There are no other valid versions currently.
  • group_readable – if True, Tor creates the directory with group read permissions. The default is False.
  • progress – if provided, a function that takes 3 arguments: (percent_done, tag, description) which may be called any number of times to indicate some progress has been made.

connect

controller.connect(**kwargs)

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(**kwargs)

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: the txtorcon.TorConfig instance, create endpoints, create txtorcon.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 (respecting TMP) and is deleted when this tor is shut down (you therefore probably want to supply the data_directory= kwarg);
  • a random, currently-unused local TCP port is used as the SocksPort (specify socks_port= if you want your own). If you want no SOCKS listener at all, pass socks_port=0
  • we set __OwningControllerProcess and call TAKEOWNERSHIP 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. If None (the default), we create a tempdir for this and delete it on exit. It is recommended you pass something here.
  • 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:

  1. 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).