Tracking and Changing Live Tor State¶
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
andtxtorcon.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
-
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
keys by name
-
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.You are Strongly Encouraged to not use this API directly, and instead use
txtorcon.Circuit.stream_via()
ortxtorcon.Circuit.web_agent()
instead. If you do need to use this API, it’s an error if you call either of the other two methods.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_CONNECTREFUSED': 3, 'REASON_CONNRESET': 12, 'REASON_DESTROY': 5, 'REASON_DONE': 6, 'REASON_EXITPOLICY': 4, 'REASON_HIBERNATING': 9, 'REASON_INTERNAL': 10, 'REASON_MISC': 1, 'REASON_NOROUTE': 8, 'REASON_NOTDIRECTORY': 14, 'REASON_RESOLVEFAILED': 2, 'REASON_RESOURCELIMIT': 11, 'REASON_TIMEOUT': 7, 'REASON_TORPROTOCOL': 13}¶
-
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
-
on_circuit_new
(callback)¶ - Parameters
callback – will be called (with ‘circuit’ instance) when a CIRC NEW event happens
-
on_circuit_launched
(callback)¶ - Parameters
callback – will be called (with ‘circuit’ instance) when a CIRC LAUNCHED event happens
-
on_circuit_extend
(callback)¶ - Parameters
callback – will be called (with ‘circuit’ and ‘router’ instances) when a CIRC EXTENDED event happens
-
on_circuit_built
(callback)¶ - Parameters
callback – will be called (with ‘circuit’ instance) when a CIRC BUILT event happens
-
on_circuit_closed
(callback)¶ - Parameters
callback – will be called (with ‘circuit’ instance, and arbitrary kwargs) when a CIRC CLOSED event happens
-
on_circuit_failed
(callback)¶ - Parameters
callback – will be called (with ‘circuit’ instance, and arbitrary kwargs) when a CIRC FAILED event happens
-
add_circuit_listener
(icircuitlistener)¶ Adds a new instance of
txtorcon.interface.ICircuitListener
which will receive updates for all existing and new circuits.
-
on_stream_new
(callback)¶ - Parameters
callback – will be called (with ‘stream’ instance) when a STREAM NEW event happens.
-
on_stream_succeeded
(callback)¶ - Parameters
callback – will be called (with ‘stream’ instance) when a STREAM SUCCEEDED event happens.
-
on_stream_attach
(callback)¶ - Parameters
callback – will be called (with ‘stream’ and ‘circuit’ instances) when a stream is attached to a circuit
-
on_stream_detach
(callback)¶ - Parameters
callback – will be called (with ‘stream’ instance and arbitrary kwargs) when a STREAM DETACHED happens
-
on_stream_closed
(callback)¶ - Parameters
callback – will be called (with ‘stream’ instance and arbitrary kwargs) when a STREAM CLOSED event happens.
-
on_stream_failed
(callback)¶ - Parameters
callback – will be called (with ‘stream’ instance and arbitrary kwargs) when a STREAM FAILED event happens.
-
add_stream_listener
(istreamlistener)¶ Adds a new instance of
txtorcon.interface.IStreamListener
which will receive updates for all existing and new streams.
-
build_circuit
(routers=None, using_guards=True, purpose=None)¶ 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
= {'ADDRMAP': '_addr_map', 'CIRC': '_circuit_update', 'NEWCONSENSUS': '_update_network_status', 'STREAM': '_stream_update'}¶
-
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. For most purposes, you’ll want to look at GENERAL circuits only. 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
id – The ID of this circuit, a number (or None if unset).
- Parameters
routercontainer – should implement
txtorcon.interface.IRouterContainer
.
-
property
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.
If the circuit will never hit BUILT (e.g. it is abandoned by Tor before it gets to BUILT) you will receive an errback
-
when_closed
()¶ Returns a Deferred that callback()’s (with this Circuit instance) when this circuit hits CLOSED or FAILED.
-
web_agent
(reactor, socks_endpoint, pool=None)¶ - Parameters
socks_endpoint – create one with
txtorcon.TorConfig.create_socks_endpoint()
. Can be a Deferred.pool – passed on to the Agent (as
pool=
)
-
stream_via
(reactor, host, port, socks_endpoint, use_tls=False)¶ This returns an IStreamClientEndpoint that will connect to the given
host
,port
via Tor – and via this parciular circuit.We match the streams up using their source-ports, so even if there are many streams in-flight to the same destination they will align correctly. For example, to cause a stream to go to
torproject.org:443
via a particular circuit:@inlineCallbacks def main(reactor): circ = yield torstate.build_circuit() # lets Tor decide the path yield circ.when_built() tor_ep = circ.stream_via(reactor, 'torproject.org', 443) # 'factory' is for your protocol proto = yield tor_ep.connect(factory)
Note that if you’re doing client-side Web requests, you probably want to use treq or
Agent
directly so calltxtorcon.Circuit.web_agent()
instead.- Parameters
socks_endpoint – should be a Deferred firing a valid IStreamClientEndpoint pointing at a Tor SOCKS port (or an IStreamClientEndpoint already).
-
property
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 oftxtorcon.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.
-
property
unique_name
¶ has the hex id if this router’s name is not unique, or its name otherwise
-
property
modified
¶ This is the time of ‘the publication time of its most recent descriptor’ (in UTC).
See also dir-spec.txt.
-
update
(name, idhash, orhash, modified, ip, orport, dirport)¶
-
get_location
()¶ Returns a Deferred that fires with a NetLocation object for this router.
-
property
location
¶ A NetLocation instance with some GeoIP or pygeoip information about location, asn, city (if available).
Deprecated in txtorcon 18.0.0.
-
property
flags
¶ A list of all the flags for this Router, each one an all-lower-case string.
-
property
bandwidth
¶ The reported bandwidth of this Router.
-
get_onionoo_details
(agent)¶ Requests the ‘details’ document from onionoo.torproject.org via the given twisted.web.iweb.IAgent – you can get a suitable instance to pass here by calling either
txtorcon.Tor.web_agent()
ortxtorcon.Circuit.web_agent()
.
-
property
policy
¶ Port policies for this Router. :return: a string describing the policy
-
accepts_port
(port)¶ Query whether this Router will accept the given port.
-
property