Controller

Controller is the main client that connects to Tor’s control port. It is used to send commands, read the corresponding replies and receive events from Tor.

Create and connect

class aiostem.controller.Controller[source]
classmethod from_path(path: str = '/var/run/tor/control') Controller[source]

Create a new controller for a local unix socket.

USE EXAMPLE:

async with Controller.from_path('/run/tor/control.sock') as controller:
    await controller.authenticate()
    ...
Parameters:

path (str, default: '/var/run/tor/control') – path to the unix socket on the file system.

Returns:

Controller – A controller for the target unix socket.

classmethod from_port(host: str = '127.0.0.1', port: int = 9051) Controller[source]

Create a new controller for a remote TCP host/port.

USE EXAMPLE:

async with Controller.from_port('10.0.0.1', 9051) as controller:
    await controller.authenticate('password')
    ...
Parameters:
  • host (str, default: '127.0.0.1') – ip address or hostname to the control host.

  • port (int, default: 9051) – TCP port to connect to.

Returns:

Controller – A controller for the target TCP host and port.

__init__(connector: ControlConnector) None[source]

Initialize a new controller from a provided ControlConnector.

Notes

You may want to alternatively use one of the following methods:
Parameters:

connector (ControlConnector) – the connector to the control socket.

async __aenter__() Self[source]

Enter Controller’s context, connect to the target.

Raises:

RuntimeError – when the context has already been entered.

Returns:

Self – A connected controller (the same exact instance).

async __aexit__(exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None) bool[source]

Exit the controller’s context and close the underlying socket.

Returns:

boolFalse to let any exception flow through the call stack.

Properties

class aiostem.controller.Controller[source]
property authenticated: bool

Tell whether we are correctly authenticated.

property connected: bool

Tell whether we are connected to the remote socket.

property entered: bool

Tell whether the context manager is entered.

Unauthenticated commands

class aiostem.controller.Controller[source]
async auth_challenge(nonce: bytes | str | None = None) ReplyAuthChallenge[source]

Start the authentication for SAFECOOKIE.

When no nonce is provided, once is generated and provided back in the reply. While this is obviously not part of the original reply from the server, it is added to the reply structure for convenience.

Warning

This method is not meant to be called by the end-user but is rather used internally by authenticate().

Note

This command can be sent while not authenticated (but only once).

Parameters:

nonce (bytes | str | None, default: None) – 32 random bytes (optional).

Returns:

ReplyAuthChallenge – An authentication challenge reply.

async authenticate(password: str | None = None) ReplyAuthenticate[source]

Authenticate to Tor’s controller.

Note

Available authentications are provided by protocol_info().

Important

Authentication methods are tried in the following order (when available):
  • NULL: authentication is automatically granted

  • HASHEDPASSWORD: password authentication (when a password is provided)

  • SAFECOOKIE: proof that we can read the cookie file

  • COOKIE: provide the content of the cookie file

Parameters:

password (str | None, default: None) – Optional password for method HASHEDPASSWORD.

Raises:

ControllerError – When no known authentication method was found.

Returns:

ReplyAuthenticate – The authentication reply (you should check the status here).

async protocol_info(version: int | None = None) ReplyProtocolInfo[source]

Get control protocol information from Tor.

This command is performed as part of the authentication process in order to find out all supported authentication methods (see AuthMethod).

The version is supposed to set to 1 but Tor currently does not care.

Note

The command result is cached when unauthenticated as we can only send this command once in this situation.

Parameters:

version (int | None, default: None) – Protocol version to ask for when provided.

Returns:

ReplyProtocolInfo – A completed protocol info reply from Tor.

async quit() ReplyQuit[source]

Tells the server to hang up on this controller connection.

Returns:

ReplyQuit – A simple quit reply where only the status is relevant.

Event management

aiostem.controller.EventCallbackType

Alias for event callbacks registered with Controller.add_event_handler().

alias of Callable[[Event], Awaitable[None] | None]

class aiostem.controller.Controller[source]
async add_event_handler(event: EventWord | EventWordInternal | str, callback: EventCallbackType) None[source]

Register a callback function to be called when an event message is received.

Notes

  • A special event DISCONNECT is handled internally by this library and can be registered here to be notified of any disconnection from the control socket.

  • Multiple callbacks can be set for a single event. If so, they are called in the order they were registered.

USE EXAMPLE:

def client_status_callback(event: EventStatusClient):
    print(event)

async with Controller.from_path('/run/tor/control.sock') as controller:
    await controller.authenticate()
    await controller.add_event_handler('STATUS_CLIENT', client_status_callback)
    ...
Parameters:
Raises:
Return type:

None

async del_event_handler(event: EventWord | EventWordInternal | str, callback: EventCallbackType) None[source]

Unregister a previously registered callback function.

Parameters:
Return type:

None

async set_events(events: Set[EventWord]) ReplySetEvents[source]

Set the list of events that we subscribe to.

Warning

This method should not probably be called by the end-user. Please see add_event_handler() instead.

Parameters:

events (Set[EventWord]) – a set of events to subscribe to.

Returns:

ReplySetEvents – A simple setevents reply where only the status is relevant.

Configuration commands

class aiostem.controller.Controller[source]
async get_conf(*args: str) ReplyGetConf[source]

Request the value of zero or move configuration variable(s).

Note that you can request the same key multiple times, and some configuration entries can provide multiple values. When any of this happens, the result dictionary provides a Sequence of strings as its value.

Parameters:

args (str) – A list of configuration variables to request.

Returns:

ReplyGetConf – A reply containing the corresponding values (when successful).

async load_conf(text: str) ReplyLoadConf[source]

Upload and replace the content of a config file.

This command allows a controller to upload the text of a config file to Tor over the control port. This config file is then loaded as if it had been read from disk.

Returns:

ReplyLoadConf – A simple reply with only a status.

async reset_conf(items: Mapping[str, MutableSequence[int | str] | int | str | None]) ReplyResetConf[source]

Change or reset configuration entries on the remote server.

Notes

  • When None is provided, all values are reset to their default.

  • When list, multiple values are assigned.

Parameters:

items (Mapping[str, MutableSequence[int | str] | int | str | None]) – a map of configuration entries to apply or reset.

Returns:

ReplyResetConf – A simple resetconf reply where only the status is relevant.

async save_conf(*, force: bool = False) ReplySaveConf[source]

Instructs the server to write out its configuration options into torrc.

If %include is used on torrc, SAVECONF will not write the configuration to disk. When set, the configuration will be overwritten even if %include is used. You can find out whether this flag is needed using config-can-saveconf on CommandGetInfo.

Keyword Arguments:

force – force write the configuration to disk.

Returns:

ReplySaveConf – A simple reply with only a status.

async set_conf(items: Mapping[str, MutableSequence[int | str] | int | str | None]) ReplySetConf[source]

Change configuration entries on the remote server.

Notes

  • When None is provided, all values are removed.

  • When list, multiple values are assigned.

Parameters:

items (Mapping[str, MutableSequence[int | str] | int | str | None]) – a map of new configuration entries to apply or clear.

Returns:

ReplySetConf – A simple setconf reply where only the status is relevant.

Hidden services commands

class aiostem.controller.Controller[source]
async add_onion(key: Ed25519PrivateKey | RSAPrivateKey | OnionServiceNewKeyStruct | str, ports: Sequence[VirtualPortTarget | str], *, client_auth: Sequence[HsDescClientAuth] = [], client_auth_v3: Sequence[X25519PublicKey] = [], flags: Set[OnionServiceFlags] = frozenset({}), generate_locally: bool = True, max_streams: int | None = None, pow_defenses_enabled: bool | None = None, pow_queue_rate: int | None = None, pow_queue_burst: int | None = None) ReplyAddOnion[source]

Create a new onion service.

This can either be created from an existing private key or ask Tor generate a new one. You must provide at least one port for this command to succeed.

Parameters:
Keyword Arguments:
  • client_auth – List of authorized clients (for V2 onions).

  • client_auth_v3 – List of authorized clients (for V3 onions).

  • flags – Set of additional flags attached to this service.

  • generate_locally – Generate onion keys locally instead (default).

  • max_streams – Optional max number of streams attached to the rendezvous circuit.

  • pow_defenses_enabled – Enable PoW defenses for this onion service.

  • pow_queue_rate – Optional rate of rendezvous requests from the priority queue.

  • pow_queue_burst – Optional maximum burst size for rendezvous requests.

Returns:

ReplyAddOnion – The reply from the Tor server.

async del_onion(address: ~typing.Annotated[~typing.Annotated[~aiostem.structures.HiddenServiceAddressV2, ~pydantic.types.Tag(tag=<HiddenServiceVersion.ONION_V2: 2>)] | ~typing.Annotated[~aiostem.structures.HiddenServiceAddressV3, ~pydantic.types.Tag(tag=<HiddenServiceVersion.ONION_V3: 3>)], ~pydantic.types.Discriminator(discriminator=~aiostem.structures._discriminate_hidden_service_version, custom_error_type=None, custom_error_message=None, custom_error_context=None)] | str) ReplyDelOnion[source]

Request the deletion of a hidden service we control.

Parameters:

address (HiddenServiceAddressV2 | HiddenServiceAddressV3 | str) – The hidden service address to delete.

Return type:

ReplyDelOnion

Returnse

A simple del_onion reply where only the status is relevant.

async hs_fetch(address: ~typing.Annotated[~typing.Annotated[~aiostem.structures.HiddenServiceAddressV2, ~pydantic.types.Tag(tag=<HiddenServiceVersion.ONION_V2: 2>)] | ~typing.Annotated[~aiostem.structures.HiddenServiceAddressV3, ~pydantic.types.Tag(tag=<HiddenServiceVersion.ONION_V3: 3>)], ~pydantic.types.Discriminator(discriminator=~aiostem.structures._discriminate_hidden_service_version, custom_error_type=None, custom_error_message=None, custom_error_context=None)] | str, servers: ~collections.abc.Sequence[~aiostem.structures.LongServerName | str] = []) ReplyHsFetch[source]

Request a hidden service descriptor fetch.

The result does not contain the descriptor, which is provided asynchronously through events such as HS_DESC or HS_DESC_CONTENT.

Parameters:
Returns:

ReplyHsFetch – A simple hsfetch reply where only the status is relevant.

async hs_post(descriptor: str, *, address: HiddenServiceAddressV3 | str | None = None, servers: Sequence[LongServerName | str] = []) ReplyHsPost[source]

Ask Tor to upload the provided descriptor.

Important

address is mandatory when uploading a v3 descriptor.

Warning

When an invalid descriptor is provided and no address is provided, tor does not provide an answer to this command, make sure to wrap this function call with a timeout!

Parameters:

descriptor (str) – The descriptor content to upload.

Keyword Arguments:
  • address – For v3 only, the hidden service address.

  • servers – List of servers to upload the descriptor to.

Returns:

ReplyHsPost – A simple reply where only the status is relevant.

async onion_client_auth_add(address: HiddenServiceAddressV3 | str, key: X25519PrivateKey, *, flags: Set[OnionClientAuthFlags] = frozenset({}), nickname: str | None = None) ReplyOnionClientAuthAdd[source]

Add a new client authorization for an existing hidden service.

Parameters:
Keyword Arguments:
  • flags – Set of additional flags.

  • nickname – Client name associated with the provided key.

Returns:

ReplyOnionClientAuthAdd – A simple reply where only the status is relevant.

async onion_client_auth_remove(address: HiddenServiceAddressV3 | str) ReplyOnionClientAuthRemove[source]

Remove a client authorization for an existing hidden service.

Parameters:

address (HiddenServiceAddressV3 | str) – Onion service address to remove a client authorization from.

Returns:

ReplyOnionClientAuthRemove – A simple reply where only the status is relevant.

async onion_client_auth_view(address: HiddenServiceAddressV3 | str | None = None) ReplyOnionClientAuthView[source]

List authorization clients for the provided hidden service or all services.

Parameters:

address (HiddenServiceAddressV3 | str | None, default: None) – Optional onion service address to list authorization for.

Returns:

ReplyOnionClientAuthView – A simple reply where only the status is relevant.

Streams and circuits

class aiostem.controller.Controller[source]
async close_circuit(circuit: int, *, if_unused: bool = False) ReplyCloseCircuit[source]

Tell the server to close the specified circuit.

Parameters:

circuit (int) – The circuit identifier to close.

Keyword Arguments:

if_unused – Close the circuit only if it is unused.

Returns:

ReplyCloseCircuit – A simple reply where only the status is relevant.

async extend_circuit(circuit: int, servers: Sequence[LongServerName | str], *, purpose: CircuitPurpose | str | None = None) ReplyExtendCircuit[source]

Extend the provided circuit to the provided servers.

Parameters:
  • circuit (int) – The circuit identifier to extend to (0 for a new circuit).

  • servers (Sequence[LongServerName | str]) – List of servers to extend the circuit to.

Keyword Arguments:

purpose – Optional circuit purpose.

Returns:

ReplyExtendCircuit – A circuit reply containing the circuit number.

async set_circuit_purpose(circuit: int, purpose: CircuitPurpose | str) ReplySetCircuitPurpose[source]

Change the circuit purpose.

Parameters:
  • circuit (int) – The circuit identifier to change the purpose.

  • purpose (CircuitPurpose | str) – New purpose for the provided circuit.

Returns:

ReplySetCircuitPurpose – A simple reply with only a status.

async attach_stream(stream: int, circuit: int, *, hop: int | None = None) ReplyAttachStream[source]

Inform the server that the specified stream should be associated with a circuit.

Parameters:
  • stream (int) – The stream to associate to the provided circuit.

  • circuit (int) – The circuit identifier to attach the stream onto.

Keyword Arguments:

hop – When specified, Tor choose the HopNumth hop in the circuit as the exit node.

Returns:

ReplyAttachStream – A simple reply where only the status is relevant.

async close_stream(stream: int, reason: StreamCloseReasonInt) ReplyCloseStream[source]

Tell the server to close the specified stream.

Parameters:
  • stream (int) – The stream identifier to close.

  • reason (StreamCloseReasonInt) – The provided reason why this stream should be closed.

Returns:

ReplyCloseStream – A simple reply where only the status is relevant.

async redirect_stream(stream: int, address: AnyHost, *, port: int | None = None) ReplyRedirectStream[source]

Tell the server to change the exit address on the specified stream.

Parameters:
  • stream (int) – The stream identifier to redirect.

  • address (AnyHost) – Destination address to redirect it to.

Keyword Arguments:

port – Optional port to redirect the stream to.

Returns:

ReplyRedirectStream – A simple reply where only the status is relevant.

async post_descriptor(descriptor: str, *, cache: bool | None = None, purpose: DescriptorPurpose | None = None) ReplyPostDescriptor[source]

Inform the server about a new router descriptor.

Parameters:

descriptor (str) – The router descriptor content.

Keyword Arguments:
  • cache – Whether to cache the provided descriptor internally.

  • purpose – The purpose of the descriptor (default is GENERAL).

Returns:

ReplyPostDescriptor – A simple reply where only the status is relevant.

async drop_guards() ReplyDropGuards[source]

Tell the server to drop all guard nodes.

Warning

Do not invoke this command lightly; it can increase vulnerability to tracking attacks over time.

Returns:

ReplyDropGuards – A simple drop-guards reply where only the status is relevant.

async drop_timeouts() ReplyDropTimeouts[source]

Tells the server to drop all circuit build times.

Warning

Do not invoke this command lightly; it can increase vulnerability to tracking attacks over time.

Note

Tor also emits the BUILDTIMEOUT_SET RESET event right after the reply.

Returns:

ReplyDropTimeouts – A simple drop-timeouts reply where only the status is relevant.

Control commands

class aiostem.controller.Controller[source]
async drop_ownership() ReplyDropOwnership[source]

Relinquish ownership of this control connection.

Hint

This ownership can be taken using take_ownership().

Returns:

ReplyDropOwnership – A simple drop-ownership reply where only the status is relevant.

async take_ownership() ReplyTakeOwnership[source]

Instructs Tor to shut down when this control connection is closed.

Hint

This ownership can be dropped with drop_ownership().

Returns:

ReplyTakeOwnership – A simple take-ownership reply where only the status is relevant.

async map_address(addresses: Mapping[AnyHost, AnyHost]) ReplyMapAddress[source]

Map provided addresses with their replacement.

The client tells the server that future SOCKS requests for connections to any original address provided here should be replaced with a connection to the specified replacement address.

The client may decline to provide a replacement address and instead provide a special address. This means that the server should choose the original address itself.

  • For IPv4: 0.0.0.0

  • For IPv6: ::0

  • For hostname: .

Mapping values can be read using get_info() with address-mappings/control.

Parameters:

addresses (Mapping[AnyHost, AnyHost]) – A map of addresses to remap on socks requests.

Returns:

ReplyMapAddress – A list of individual replies for each map request.

Note that some values can be rejected and others can be accepted, which means that you should check each individual value.

async resolve(addresses: Sequence[AnyHost], *, reverse: bool = False) ReplyResolve[source]

Launch a remote hostname lookup request for every specified request.

Note

The result is not provided along with the reply here but can be caught using the ADDRMAP.

Parameters:

addresses (Sequence[AnyHost]) – List of addresses to launch a resolve request for.

Keyword Arguments:

reverse – Whether to perform a reverse DNS lookup.

Returns:

ReplyResolve – A simple resolve reply where only the status is relevant.

async get_info(*args: str) ReplyGetInfo[source]

Request for Tor daemon information.

Note that you can request the same key multiple times. When this happens, the result dictionary provides a Sequence of strings as its value.

Parameters:

args (str) – A list of information data to request.

Returns:

ReplyGetInfo – A reply containing the corresponding values (when successful).

async signal(signal: Signal | str) ReplySignal[source]

Send a signal to the controller.

Parameters:

signal (Signal | str) – name of the signal to send.

Returns:

ReplySignal – A simple signal reply where only the status is relevant.

Generic request

class aiostem.controller.Controller[source]
async request(command: Command) Message[source]

Send any kind of command to the controller.

This method is the underlying call of any other command.

It can be used to send custom subclass of Command, and get the raw Message corresponding to the response. This Message can then be parsed by an appropriate Reply.

Important

A single command can run at any time due to an internal lock.

Parameters:

command (Command) – The command we want to send to Tor.

Raises:

ControllerError – When the controller is not connected.

Returns:

Message – The corresponding reply message from the remote daemon.