Protocol and Helper Classes

connect

txtorcon.connect(*args, **kwargs)

(experimental; details may change) This connects to the given endpoint, presuming it is a Tor control connection and gives back a TorControlProtocol instance. This does not reconnect if the connection is dropped. This is the preferred entry point to control a running Tor; if you need to start a Tor see Launching Tor.

See txtorcon.TorState.from_protocol() to create a valid txtorcon.TorState instance from the connection.

Parameters:
  • endpoint – A Twisted IEndpoint, in practice either a TCP4ClientEndpoint or a UnixClientEndpoint. By default, Tor uses “tcp:localhost:9051” or “unix:/var/run/tor/control”.
  • password_function – This is only consulted if the Tor to which we connect does not have cookie authentication enabled. In that case, this function is called to request a password. It may return a Deferred.
Returns:

A Deferred that fires with a ready-to-use TorControlProtocol instance is returned, or Failure if a connection can’t be established.

TorControlProtocol

class txtorcon.TorControlProtocol(password_function=None)

Bases: twisted.protocols.basic.LineOnlyReceiver

This is the main class that talks to a Tor and implements the “raw” procotol.

This instance does not track state; see txtorcon.TorState for the current state of all Circuits, Streams and Routers.

txtorcon.TorState.build_circuit() allows you to build custom circuits.

txtorcon.TorControlProtocol.add_event_listener() can be used to listen for specific events.

To see how circuit and stream listeners are used, see txtorcon.TorState, which is also the place to go if you wish to add your own stream or circuit listeners.

Parameters:password_function – A zero-argument callable which returns a password (or Deferred). It is only called if the Tor doesn’t have COOKIE authentication turned on. Tor’s default is COOKIE.
password_function = None

If set, a callable to query for a password to use for authentication to Tor (default is to use COOKIE, however). May return Deferred.

version = None

Version of Tor we’ve connected to.

is_owned = None

If not None, this is the PID of the Tor process we own (TAKEOWNERSHIP, etc).

events = None

events we’ve subscribed to (keyed by name like “GUARD”, “STREAM”)

valid_events = None

all valid events (name -> Event instance)

valid_signals = None

A list of all valid signals we accept from Tor

on_disconnect = None

This Deferred is triggered when the connection is closed. If there was an error, the errback is called instead.

post_bootstrap = None

This Deferred is triggered when we’re done setting up (authentication, getting information from Tor). You will want to use this to do things with the TorControlProtocol class when it’s set up, like:

def setup_complete(proto):
    print "Setup complete, attached to Tor version",proto.version

def setup(proto):
    proto.post_bootstrap.addCallback(setup_complete)

ep = TCP4ClientEndpoint(reactor, "localhost", 9051)
ep.connect(TorProtocolFactory())
d.addCallback(setup)

See the helper method txtorcon.build_tor_connection().

start_debug()
stop_debug()
graphviz_data()
get_info_raw(*args)

Mostly for internal use; gives you the raw string back from the GETINFO command. See getinfo

get_info_incremental(key, line_cb)

Mostly for internal use; calls GETINFO for a single key and calls line_cb with each line received, as it is received.

See getinfo

get_info(*args)

Uses GETINFO to obtain informatoin from Tor.

Parameters:args

should be a list or tuple of strings which are valid information keys. For valid keys, see control-spec.txt from torspec.

Todo

make some way to automagically obtain valid keys, either from running Tor or parsing control-spec

Returns:a Deferred which will callback with a dict containing the keys you asked for. If you want to avoid the parsing into a dict, you can use get_info_raw instead.
get_conf(*args)

Uses GETCONF to obtain configuration values from Tor.

Parameters:args – any number of strings which are keys to get. To get all valid configuraiton names, you can call: get_info('config/names')
Returns:a Deferred which callbacks with one or many configuration values (depends on what you asked for). See control-spec for valid keys (you can also use TorConfig which will come set up with all the keys that are valid). The value will be a dict.

Note that Tor differentiates between an empty value and a default value; in the raw protocol one looks like ‘250 MyFamily’ versus ‘250 MyFamily=’ where the latter is set to the empty string and the former is a default value. We differentiate these by setting the value in the dict to DEFAULT_VALUE for the default value case, or an empty string otherwise.

get_conf_raw(*args)

Same as get_conf, except that the results are not parsed into a dict

set_conf(*args)

set configuration values. see control-spec for valid keys. args is treated as a list containing name then value pairs. For example, set_conf('foo', 'bar') will (attempt to) set the key ‘foo’ to value ‘bar’.

Returns:a Deferred that will callback with the response (‘OK’) or errback with the error code and message (e.g. "552 Unrecognized option: Unknown option 'foo'.  Failing.")
signal(nm)

Issues a signal to Tor. See control-spec or txtorcon.TorControlProtocol.valid_signals for which ones are available and their return values.

Returns:a Deferred which callbacks with Tor’s response (OK or something like 552 Unrecognized signal code "foo").
add_event_listener(evt, callback)
Parameters:evt – event name, see also

:var:`txtorcon.TorControlProtocol.events` .keys()

Add a listener to an Event object. This may be called multiple times for the same event. If it’s the first listener, a new SETEVENTS call will be initiated to Tor.

Currently the callback is any callable that takes a single argument, that is the text collected for the event from the tor control protocol.

For more information on the events supported, see control-spec section 4.1

Note

this is a low-level interface; if you want to follow circuit or stream creation etc. see TorState and methods like add_circuit_listener

Return:None

Todo

need an interface for the callback show how to tie in Stem parsing if you want

remove_event_listener(evt, cb)
protocolinfo()
Returns:a Deferred which will give you PROTOCOLINFO; see control-spec
authenticate(passphrase)

Call the AUTHENTICATE command.

quit()

Sends the QUIT command, which asks Tor to hang up on this controller connection.

If you’ve taken ownership of the Tor to which you’re connected, this should also cause it to exit. Otherwise, it won’t.

queue_command(cmd, arg=None)

returns a Deferred which will fire with the response data when we get it

Note that basically every request is ultimately funelled through this command.

lineReceived(line)

twisted.protocols.basic.LineOnlyReceiver API

connectionMade()

Protocol API

connectionLost(reason)

Protocol API

TorProtocolFactory

class txtorcon.TorProtocolFactory(password_function=<function <lambda>>)

Bases: object

Builds TorControlProtocol objects. Implements IProtocolFactory for Twisted interaction.

If your running Tor doesn’t support COOKIE authentication, then you should supply a password callback.

Builds protocols to talk to a Tor client on the specified address. For example:

ep = TCP4ClientEndpoint(reactor, "localhost", 9051)
ep.connect(TorProtocolFactory())
reactor.run()

By default, COOKIE authentication is used if available.

Parameters:password_function – If supplied, this is a zero-argument method that returns a password (or a Deferred). By default, it returns None. This is only queried if the Tor we connect to doesn’t support (or hasn’t enabled) COOKIE authentication.
doStart()

twisted.internet.interfaces.IProtocolFactory API

doStop()

twisted.internet.interfaces.IProtocolFactory API

buildProtocol(addr)

twisted.internet.interfaces.IProtocolFactory API

TorProcessProtocol

class txtorcon.TorProcessProtocol(connection_creator, progress_updates=None, config=None, ireactortime=None, timeout=None, kill_on_stderr=True, stdout=None, stderr=None)

Bases: twisted.internet.protocol.ProcessProtocol

This will read the output from a Tor process and attempt a connection to its control port when it sees any ‘Bootstrapped’ message on stdout. You probably don’t need to use this directly except as the return value from the txtorcon.launch_tor() method. tor_protocol contains a valid txtorcon.TorControlProtocol instance by that point.

connection_creator is a callable that should return a Deferred that callbacks with a txtorcon.TorControlProtocol; see txtorcon.launch_tor() for the default one which is a functools.partial that will call connect(TorProtocolFactory()) on an appropriate twisted.internet.endpoints.TCP4ClientEndpoint

Parameters:
  • connection_creator – A no-parameter callable which returns a Deferred which promises a IStreamClientEndpoint. If this is None, we do NOT attempt to connect to the underlying Tor process.
  • progress_updates – A callback which received progress updates with three args: percent, tag, summary
  • config – a TorConfig object to connect to the TorControlProtocl from the launched tor (should it succeed)
  • ireactortime – An object implementing IReactorTime (i.e. a reactor) which needs to be supplied if you pass a timeout.
  • timeout – An int representing the timeout in seconds. If we are unable to reach 100% by this time we will consider the setting up of Tor to have failed. Must supply ireactortime if you supply this.
  • kill_on_stderr – When True, kill subprocess if we receive anything on stderr
  • stdout – Anything subprocess writes to stdout is sent to .write() on this
  • stderr – Anything subprocess writes to stderr is sent to .write() on this
Variables:
  • tor_protocol – The TorControlProtocol instance connected to the Tor this ProcessProtocol>` is speaking to. Will be valid when the connected_cb callback runs.
  • connected_cb – Triggered when the Tor process we represent is fully bootstrapped
quit()

This will terminate (with SIGTERM) the underlying Tor process.

Returns:a Deferred that callback()’s (with None) when the process has actually exited.
outReceived(data)

ProcessProtocol API

timeout_expired()

A timeout was supplied during setup, and the time has run out.

errReceived(data)

ProcessProtocol API

cleanup()

Clean up my temporary files.

processExited(reason)
processEnded(status)

ProcessProtocol API

progress(percent, tag, summary)

Can be overridden or monkey-patched if you want to get progress updates yourself.

tor_connection_failed(failure)
status_client(arg)
tor_connected(proto)
protocol_bootstrapped(proto)

TCPHiddenServiceEndpoint

class txtorcon.TCPHiddenServiceEndpoint(reactor, config, public_port, hidden_service_dir=None, local_port=None, stealth_auth=None)

Bases: object

This represents something listening on an arbitrary local port that has a Tor configured with a Hidden Service pointing at it. TCP4ServerEndpoint is used under the hood to do the local listening.

There are three main ways to use this class, and you are encouraged to use the @classmethod ways of creating instances: system_tor, global_tor, and private_tor

  1. system_tor(...) connects to an already-started tor on the endpoint you specify; stricly speaking not a “system” tor since you could have spawned it some other way. See Tor bug 11291 however.
  2. global_tor(...) refers to a single possible Tor instance per python process. So the first call to this launches a new Tor, and subsequent calls re-use the existing Tor (that is, add more hidden services to it).
  3. private_tor(...) launches a new Tor instance no matter what, so it will have just the one hidden serivce on it.

If you need to set configuration options that are not reflected in any of the method signatures above, you’ll have to construct an instance of this class yourself (i.e. with a TorConfig instance you’ve created).

No matter how you came by your instance, calling listen() on it causes Tor to be launched or connected-to, your hidden service to be added, checks that the descriptor is uploaded and you get a Deferred with an IListeningPort whose getHost() will return a txtorcon.TorOnionAddress. The port object will also implement txtorcon.IHiddenService so you can get the locally-listening address and hidden serivce directory:

endpoint = ...
port = yield endpoint.listen(...)
uri = port.getHost().onion_uri
port = port.getHost().onion_port
addr = IHiddenService(port).local_address
hsdir = IHiddenService(port).hidden_service_dir

returns (via Deferred) an object that implements twisted.internet.interfaces.IStreamServerEndpoint

Variables:
  • onion_uri – the public key, like timaq4ygg2iegci7.onion which came from the hidden_service_dir’s hostname file
  • onion_private_key – the contents of hidden_service_dir/private_key
  • hiddenServiceDir – the data directory, either passed in or created with tempfile.mkstemp
Parameters:
  • reactortwisted.internet.interfaces.IReactorTCP provider
  • configtxtorcon.TorConfig instance (doesn’t need to be bootstrapped) or a Deferred. Note that save() will be called on this at least once. FIXME should I just accept a TorControlProtocol instance instead, and create my own TorConfig?
  • public_port – The port number we will advertise in the hidden serivces directory.
  • local_port – The port number we will perform our local tcp listen on and receive incoming connections from the tor process.
  • hidden_service_dir – If not None, point to a HiddenServiceDir directory (i.e. with “hostname” and “private_key” files in it). If not provided, one is created with temp.mkstemp() AND DELETED when the reactor shuts down.
  • stealth_auth – A list of strings, one name for each stealth authenticator you want. Like: ['alice', 'bob']
  • endpoint_generator – A callable that generates a new instance of something that implements IServerEndpoint (by default TCP4ServerEndpoint)
classmethod system_tor(reactor, control_endpoint, public_port, hidden_service_dir=None, local_port=None)

This returns a TCPHiddenServiceEndpoint connected to the endpoint you specify in control_endpoint. After connecting, a single hidden service is added. The endpoint can be a Unix socket if Tor’s ControlSocket option was used (instead of ControlPort).

Note

If Tor bug #11291 is not yet fixed, this won’t work if you only have Group access. XXX FIXME re-test

classmethod global_tor(reactor, public_port, hidden_service_dir=None, local_port=None, control_port=None, stealth_auth=None)

This returns a TCPHiddenServiceEndpoint connected to a txtorcon global Tor instance. The first time you call this, a new Tor will be launched. Subsequent calls will re-use the same connection (in fact, the very same TorControlProtocol and TorConfig instances). If the options you pass are incompatible with an already-launched Tor, RuntimeError will be thrown.

It’s probably best to not specify any option besides public_port, hidden_service_dir, and maybe local_port unless you have a specific need to.

You can also access this global txtorcon instance via :method:`txtorcon.get_global_tor` (which is precisely what this method uses to get it).

All keyword options have defaults (e.g. random ports, or tempdirs).

Parameters:stealth_auth – None, or a list of strings – one for each stealth authenticator you require.
classmethod private_tor(reactor, public_port, hidden_service_dir=None, local_port=None, control_port=None)

This returns a TCPHiddenServiceEndpoint that’s always connected to its own freshly-launched Tor instance. All keyword options have defaults (e.g. random ports, or tempdirs).

retries = None

for IProgressProvider to add_progress_listener

onion_uri
onion_private_key
add_progress_listener(listener)

IProgressProvider API

listen(*args, **kwargs)

Implement IStreamServerEndpoint.

Returns a Deferred that delivers an twisted.internet.interfaces.IListeningPort implementation.

This port can also be adapted to two other interfaces:

txtorcon.IHiddenService so you can get the onion_uri and onion_private_key members (these correspond to “hostname” and “private_key” from the HiddenServiceDir Tor is using).

txtorcon.IProgressProvider can provide you progress updates while Tor is launched. Note that Tor is not always launched when calling this listen() method.

At this point, Tor will have fully started up and successfully accepted the hidden service’s config.

FIXME TODO: also listen for an INFO-level Tor message (does exist, #tor-dev says) that indicates the hidden service’s descriptor is published.

It is “connection_dir_client_reached_eof(): Uploaded rendezvous descriptor (status 200 (“Service descriptor (v2) stored”))” at INFO level.