State-Tracking Classes

build_tor_connection

txtorcon.build_tor_connection(connection, build_state=True, wait_for_proto=True, password_function=<function <lambda>>)

This is used to build a valid TorState (which has .protocol for the TorControlProtocol). For example:

from twisted.internet import reactor
from twisted.internet.endpoints import TCP4ClientEndpoint
import txtorcon

def example(state):
    print "Fully bootstrapped state:",state
    print "   with bootstrapped protocol:",state.protocol

d = txtorcon.build_tor_connection(TCP4ClientEndpoint(reactor,
                                                     "localhost",
                                                     9051))
d.addCallback(example)
reactor.run()
Parameters:
  • password_function – See txtorcon.TorControlProtocol
  • build_state – If True (the default) a TorState object will be built as well. If False, just a TorControlProtocol will be returned via the Deferred.
Returns:

a Deferred that fires with a TorControlProtocol or, if you specified build_state=True, a TorState. In both cases, the object has finished bootstrapping (i.e. TorControlProtocol.post_bootstrap or TorState.post_bootstap has fired, as needed)

build_local_tor_connection

txtorcon.build_local_tor_connection(reactor, host='127.0.0.1', port=9051, socket='/var/run/tor/control', *args, **kwargs)

This builds a connection to a local Tor, either via 127.0.0.1:9051 (which is tried first) or /var/run/tor/control (by default). See also build_tor_connection for other key-word arguments that are accepted here also.

Parameters:
  • host – An IP address to find Tor at. Corresponds to the ControlListenAddress torrc option.
  • port – The port to use with the address when trying to contact Tor. This corresponds to the ControlPort option in torrc (default is 9051).

TorState

class txtorcon.TorState(protocol, bootstrap=True)

Bases: object

This tracks the current state of Tor using a TorControlProtocol.

On setup it first queries the initial state of streams and circuits. It then asks for updates via the listeners. It requires an ITorControlProtocol instance. The control protocol doesn’t need to be bootstrapped yet. The Deferred .post_boostrap is driggered when the TorState instance is fully ready to go. The easiest way is to use the helper method txtorcon.build_tor_connection(). For details, see the implementation of that.

You may add an txtorcon.interface.IStreamAttacher to provide a custom mapping for Strams to Circuits (by default Tor picks by itself).

This is also a good example of the various listeners, and acts as an txtorcon.interface.ICircuitContainer and txtorcon.interface.IRouterContainer.

Variables:DO_NOT_ATTACH

Constant to return from an IAttacher indicating you don’t want to attach this stream at all.

classmethod from_protocol(protocol, **kw)

Create a new, boot-strapped TorState from a TorControlProtocol instance.

Returns:a Deferred that fires with a TorState instance
attacher = None

If set, provides txtorcon.interface.IStreamAttacher to attach new streams we hear about.

circuits = None

keys on id (integer)

streams = None

keys on id (integer)

all_routers = None

list of unique routers

routers = None

keys by hexid (string) and by unique names

routers_by_name = None

keys on name, value always list (many duplicate “Unnamed” routers, for example)

routers_by_hash = None

keys by hexid (string)

guards = None

potentially-usable as entry guards, I think? (any router with ‘Guard’ flag)

entry_guards = None

from GETINFO entry-guards, our current entry guards

unusable_entry_guards = None

list of entry guards we didn’t parse out

authorities = None

keys by name

cleanup = None

see set_attacher

undo_attacher()

Shouldn’t Tor handle this by turning this back to 0 if the controller that twiddled it disconnects?

set_attacher(attacher, myreactor)

Provide an txtorcon.interface.IStreamAttacher to associate streams to circuits. This won’t get turned on until after bootstrapping is completed. (‘__LeaveStreamsUnattached’ needs to be set to ‘1’ and the existing circuits list needs to be populated).

stream_close_reasons = {'REASON_EXITPOLICY': 4, 'REASON_TORPROTOCOL': 13, 'REASON_DONE': 6, 'REASON_CONNRESET': 12, 'REASON_RESOLVEFAILED': 2, 'REASON_RESOURCELIMIT': 11, 'REASON_NOROUTE': 8, 'REASON_NOTDIRECTORY': 14, 'REASON_HIBERNATING': 9, 'REASON_MISC': 1, 'REASON_TIMEOUT': 7, 'REASON_DESTROY': 5, 'REASON_INTERNAL': 10, 'REASON_CONNECTREFUSED': 3}
close_stream(stream, reason='REASON_MISC', **kwargs)

This sends a STREAMCLOSE command, using the specified reason (either an int or one of the 14 strings in section 6.3 of tor-spec.txt if the argument is a string). Any kwards are passed through as flags if they evaluated to true (e.g. “SomeFlag=True”). Currently there are none that Tor accepts.

close_circuit(circid, **kwargs)

This sends a CLOSECIRCUIT command, using any keyword arguments passed as the Flags (currently, that is just ‘IfUnused’ which means to only close the circuit when it is no longer used by any streams).

Parameters:circid – Either a circuit-id (int) or a Circuit instance
Returns:a Deferred which callbacks with the result of queuing the command to Tor (usually “OK”). If you want to instead know when the circuit is actually-gone, see Circuit.close
add_circuit_listener(icircuitlistener)
add_stream_listener(istreamlistener)
build_circuit(routers=None, using_guards=True)

Builds a circuit consisting of exactly the routers specified, in order. This issues an EXTENDCIRCUIT call to Tor with all the routers specified.

Parameters:
  • routers – a list of Router instances which is the path desired. To allow Tor to choose the routers itself, pass None (the default) for routers.
  • using_guards – A warning is issued if the first router isn’t in self.entry_guards.
Returns:

A Deferred that will callback with a Circuit instance (with the .id member being valid, and probably nothing else).

DO_NOT_ATTACH = <object object>
event_map = {'CIRC': <function _circuit_update at 0x7f6356b24500>, 'NS': <function _update_network_status at 0x7f6356b24410>, 'ADDRMAP': <function _addr_map at 0x7f6356b245f0>, 'STREAM': <function _stream_update at 0x7f6356b24578>, 'NEWCONSENSUS': <function _update_network_status at 0x7f6356b24410>}

event_map used by add_events to map event_name -> unbound method

find_circuit(circid)

ICircuitContainer API

router_from_id(routerid)

IRouterContainer API

stream_new(stream)

IStreamListener: a new stream has been created

stream_succeeded(stream)

IStreamListener: stream has succeeded

stream_attach(stream, circuit)

IStreamListener: the stream has been attached to a circuit. It seems you get an attach to None followed by an attach to real circuit fairly frequently. Perhaps related to __LeaveStreamsUnattached?

stream_detach(stream, **kw)

IStreamListener

stream_closed(stream, **kw)

IStreamListener: stream has been closed (won’t be in controller’s list anymore)

stream_failed(stream, **kw)

IStreamListener: stream failed for some reason (won’t be in controller’s list anymore)

circuit_launched(circuit)

ICircuitListener API

circuit_extend(circuit, router)

ICircuitListener API

circuit_built(circuit)

ICircuitListener API

circuit_new(circuit)

ICircuitListener API

circuit_destroy(circuit)

Used by circuit_closed and circuit_failed (below)

circuit_closed(circuit, **kw)

ICircuitListener API

circuit_failed(circuit, **kw)

ICircuitListener API

Circuit

class txtorcon.Circuit(routercontainer)

Bases: object

Used by txtorcon.TorState to represent one of Tor’s circuits.

This is kept up-to-date by the :class`txtorcon.TorState` that owns it, and individual circuits can be listened to for updates (or listen to every one using txtorcon.TorState.add_circuit_listener())

Variables:
  • path – contains a list of txtorcon.Router objects representing the path this Circuit takes. Mostly this will be 3 or 4 routers long. Note that internally Tor uses single-hop paths for some things. See also the purpose instance-variable.
  • streams – contains a list of Stream objects representing all streams currently attached to this circuit.
  • state

    contains a string from Tor describing the current state of the stream. From control-spec.txt section 4.1.1, these are:

    • LAUNCHED: circuit ID assigned to new circuit
    • BUILT: all hops finished, can now accept streams
    • EXTENDED: one more hop has been completed
    • FAILED: circuit closed (was not built)
    • CLOSED: circuit closed (was built)
  • purpose

    The reason this circuit was built. Values can currently be one of (but see control-spec.txt 4.1.1):

    • GENERAL
    • HS_CLIENT_INTRO
    • HS_CLIENT_REND
    • HS_SERVICE_INTRO
    • HS_SERVICE_REND
    • TESTING
    • CONTROLLER

For most purposes, you’ll want to look at GENERAL circuits only.

Variables:id – The ID of this circuit, a number (or None if unset).
Parameters:routercontainer – should implement

txtorcon.interface.IRouterContainer.

is_built
when_built()

Returns a Deferred that is callback()’d (with this Circuit instance) when this circuit hits BUILT.

If it’s already BUILT when this is called, you get an already-successful Deferred; otherwise, the state must change to BUILT.

time_created
listen(listener)
unlisten(listener)
close(**kw)

This asks Tor to close the underlying circuit object. See txtorcon.torstate.TorState.close_circuit() for details.

You may pass keyword arguments to take care of any Flags Tor accepts for the CLOSECIRCUIT command. Currently, this is only “IfUnused”. So for example: circ.close(IfUnused=True)

Returns:Deferred which callbacks with this Circuit instance

ONLY after Tor has confirmed it is gone (not simply that the CLOSECIRCUIT command has been queued). This could be a while if you included IfUnused.

age(now=None)

Returns an integer which is the difference in seconds from ‘now’ to when this circuit was created.

Returns None if there is no created-time.

update(args)
maybe_call_closing_deferred()

Used internally to callback on the _closing_deferred if it exists.

update_path(path)

There are EXTENDED messages which don’t include any routers at all, and any of the EXTENDED messages may have some arbitrary flags in them. So far, they’re all upper-case and none start with $ luckily. The routers in the path should all be LongName-style router names (this depends on them starting with $).

For further complication, it’s possible to extend a circuit to a router which isn’t in the consensus. nickm via #tor thought this might happen in the case of hidden services choosing a rendevouz point not in the current consensus.

Stream

class txtorcon.Stream(circuitcontainer, addrmap=None)

Bases: object

Represents an active stream in Tor’s state (txtorcon.TorState).

Variables:
  • circuit – Streams will generally be attached to circuits pretty quickly. If they are attached, circuit will be a txtorcon.Circuit instance or None if this stream isn’t yet attached to a circuit.
  • state
    Tor’s idea of the stream’s state, one of:
    • NEW: New request to connect
    • NEWRESOLVE: New request to resolve an address
    • REMAP: Address re-mapped to another
    • SENTCONNECT: Sent a connect cell along a circuit
    • SENTRESOLVE: Sent a resolve cell along a circuit
    • SUCCEEDED: Received a reply; stream established
    • FAILED: Stream failed and not retriable
    • CLOSED: Stream closed
    • DETACHED: Detached from circuit; still retriable
  • target_host – Something like www.example.com – the host the stream is destined for.
  • target_port – The port the stream will exit to.
  • target_addr – Target address, looked up (usually) by Tor (e.g. 127.0.0.1).
  • id – The ID of this stream, a number (or None if unset).
Parameters:

circuitcontainer – an object which implements

interface.ICircuitContainer

id = None

An int, Tor’s ID for this txtorcon.Circuit

state = None

A string, Tor’s idea of the state of this txtorcon.Stream

target_host = None

Usually a hostname, but sometimes an IP address (e.g. when we query existing state from Tor)

target_addr = None

If available, the IP address we’re connecting to (if None, see target_host instead).

target_port = None

The port we’re connecting to.

circuit = None

If we’ve attached to a txtorcon.Circuit, this will be an instance of txtorcon.Circuit (otherwise None).

listeners = None

A list of all connected txtorcon.interface.IStreamListener instances.

source_addr = None

If available, the address from which this Stream originated (e.g. local process, etc). See get_process() also.

source_port = None

If available, the port from which this Stream originated. See get_process() also.

flags = None

All flags from last update to this Stream. str->str

listen(listen)

Attach an txtorcon.interface.IStreamListener to this stream.

See also txtorcon.TorState.add_stream_listener() to listen to all streams.

Parameters:listen – something that knows

txtorcon.interface.IStreamListener

unlisten(listener)
close(**kw)

This asks Tor to close the underlying stream object. See txtorcon.interface.ITorControlProtocol.close_stream() for details.

Although Tor currently takes no flags, it allows you to; any keyword arguments are passed through as flags.

NOTE that the callback delivered from this method only callbacks after the underlying stream is really destroyed (not just when the CLOSESTREAM command has successfully completed).

update(args)
maybe_call_closing_deferred()

Used internally to callback on the _closing_deferred if it exists.

Router

class txtorcon.Router(controller)

Bases: object

Represents a Tor Router, including location.

The controller you pass in is really only used to do get_info calls for ip-to-country/IP in case the txtorcon.util.NetLocation stuff fails to find a country.

After an .update() call, the id_hex attribute contains a hex-encoded long hash (suitable, for example, to use in a GETINFO ns/id/* call).

After setting the policy property you may call accepts_port() to find out if the router will accept a given port. This works with the reject or accept based policies.

unique_name

has the hex id if this router’s name is not unique, or its name otherwise

modified
update(name, idhash, orhash, modified, ip, orport, dirport)
location

A NetLocation instance with some GeoIP or pygeoip information about location, asn, city (if available).

flags

A list of all the flags for this Router, each one an all-lower-case string.

bandwidth

The reported bandwidth of this Router.

policy

Port policies for this Router. :return: a string describing the policy

accepts_port(port)

Query whether this Router will accept the given port.