pub struct Controller { /* private fields */ }Expand description
A high-level interface for interacting with Tor’s control protocol.
The Controller provides the primary API for controlling a Tor process.
It wraps a ControlSocket and provides
typed methods for common operations like authentication, circuit management,
and event subscription.
§Conceptual Role
The Controller is the main entry point for most stem-rs users. It handles:
- Protocol message formatting and parsing
- Response validation and error handling
- Asynchronous event buffering
- Connection lifecycle management
§What This Type Does NOT Do
- Direct relay communication (use
client::Relay) - Descriptor parsing (use
descriptormodule) - Exit policy evaluation (use
ExitPolicy)
§Invariants
- The underlying socket connection is valid while the Controller exists
- After successful authentication, the controller is ready for commands
- Events received during command execution are buffered for later retrieval
§Thread Safety
Controller is Send but not Sync. For concurrent access from multiple
tasks, wrap in Arc<Mutex<Controller>>:
use std::sync::Arc;
use tokio::sync::Mutex;
use stem_rs::controller::Controller;
let controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
let shared = Arc::new(Mutex::new(controller));
// Clone Arc for each task
let c1 = shared.clone();
tokio::spawn(async move {
let mut ctrl = c1.lock().await;
// Use controller...
});§Example
use stem_rs::controller::Controller;
use stem_rs::Signal;
// Connect and authenticate
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(Some("my_password")).await?;
// Query information
let version = controller.get_version().await?;
let circuits = controller.get_circuits().await?;
// Send signal
controller.signal(Signal::Newnym).await?;§Security
- Passwords are not stored after authentication
- Cookie files are read with minimal permissions
- SAFECOOKIE uses secure random nonces
§See Also
from_port: Connect via TCPfrom_socket_file: Connect via Unix socketauthenticate: Authenticate with Tor
Implementations§
Source§impl Controller
impl Controller
Sourcepub async fn from_port(addr: SocketAddr) -> Result<Self, Error>
pub async fn from_port(addr: SocketAddr) -> Result<Self, Error>
Creates a new Controller connected to a TCP control port.
Establishes a TCP connection to Tor’s control port at the specified
address. The connection is unauthenticated; call authenticate
before issuing commands.
§Arguments
addr- The socket address of Tor’s control port (e.g.,127.0.0.1:9051)
§Errors
Returns Error::Socket if:
- The connection is refused (Tor not running or port incorrect)
- Network is unreachable
- Connection times out
§Example
use stem_rs::controller::Controller;
// Connect to default control port
let controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
// Connect to custom port
let controller = Controller::from_port("127.0.0.1:9151".parse()?).await?;§See Also
from_socket_file: Connect via Unix socketauthenticate: Authenticate after connecting
Sourcepub async fn from_socket_file(path: &Path) -> Result<Self, Error>
pub async fn from_socket_file(path: &Path) -> Result<Self, Error>
Creates a new Controller connected to a Unix domain socket.
Establishes a connection to Tor’s control socket at the specified file path. This is typically more secure than TCP as it doesn’t expose the control interface to the network.
§Arguments
path- Path to Tor’s control socket file (e.g.,/var/run/tor/control)
§Errors
Returns Error::Socket if:
- The socket file doesn’t exist
- Permission denied accessing the socket
- The socket is not a valid Unix domain socket
§Example
use std::path::Path;
use stem_rs::controller::Controller;
// Connect to Tor's Unix control socket
let controller = Controller::from_socket_file(
Path::new("/var/run/tor/control")
).await?;§Platform Support
Unix domain sockets are only available on Unix-like systems (Linux, macOS, BSD).
On Windows, use from_port instead.
§See Also
from_port: Connect via TCPauthenticate: Authenticate after connecting
Sourcepub async fn authenticate(
&mut self,
password: Option<&str>,
) -> Result<(), Error>
pub async fn authenticate( &mut self, password: Option<&str>, ) -> Result<(), Error>
Authenticates with the Tor control interface.
Attempts authentication using the best available method. If password
is provided, PASSWORD authentication is attempted. Otherwise, the method
is auto-detected from PROTOCOLINFO.
§Authentication Methods
Methods are tried in this order:
- NONE - If control port is open (no auth required)
- SAFECOOKIE - Preferred for local connections
- COOKIE - Fallback for older Tor versions
- PASSWORD - If password is provided
§Arguments
password- Optional password for PASSWORD authentication
§Preconditions
- Socket must be connected (not closed)
- No prior successful authentication on this connection
§Postconditions
- On success: Controller is authenticated and ready for commands
- On failure: Connection state is undefined; reconnect recommended
§Errors
Returns Error::Authentication with specific reason:
AuthError::NoMethods- No compatible auth methods availableAuthError::IncorrectPassword- PASSWORD auth failedAuthError::CookieUnreadable- Cannot read cookie fileAuthError::IncorrectCookie- COOKIE auth failedAuthError::ChallengeFailed- SAFECOOKIE challenge failed
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
// Auto-detect authentication method
controller.authenticate(None).await?;
// Or use password authentication
controller.authenticate(Some("my_password")).await?;§Security
- Passwords are cleared from memory after use
- Cookie comparison uses constant-time algorithm
- SAFECOOKIE nonces are cryptographically random
§See Also
Sourcepub async fn get_info(&mut self, key: &str) -> Result<String, Error>
pub async fn get_info(&mut self, key: &str) -> Result<String, Error>
Queries Tor for information using the GETINFO command.
GETINFO retrieves various pieces of information from Tor. The available keys depend on Tor’s version and configuration.
§Arguments
key- The information key to query (e.g., “version”, “circuit-status”)
§Common Keys
| Key | Description |
|---|---|
version | Tor version string |
process/pid | Tor process ID |
circuit-status | Active circuit information |
stream-status | Active stream information |
address | Best guess at external IP address |
fingerprint | Relay fingerprint (if running as relay) |
config-file | Path to torrc file |
§Errors
Returns Error::OperationFailed if:
- The key is unrecognized
- The information is not available
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Query Tor version
let version = controller.get_info("version").await?;
println!("Tor version: {}", version);
// Query external IP address
let address = controller.get_info("address").await?;
println!("External IP: {}", address);§See Also
get_version: Typed version queryget_pid: Typed PID query
Sourcepub async fn get_version(&mut self) -> Result<Version, Error>
pub async fn get_version(&mut self) -> Result<Version, Error>
Retrieves the Tor version as a parsed Version object.
This is a convenience wrapper around get_info("version")
that parses the version string into a structured Version type.
§Errors
Returns an error if:
- The GETINFO command fails
- The version string cannot be parsed
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let version = controller.get_version().await?;
println!("Tor version: {}", version);
// Version supports comparison
// if version >= Version::parse("0.4.0.0")? { ... }§See Also
Version: Version type with comparison support
Sourcepub async fn get_pid(&mut self) -> Result<u32, Error>
pub async fn get_pid(&mut self) -> Result<u32, Error>
Retrieves the process ID of the Tor process.
This is a convenience wrapper around get_info("process/pid")
that parses the PID into a u32.
§Errors
Returns an error if:
- The GETINFO command fails
- The PID string cannot be parsed as a number
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let pid = controller.get_pid().await?;
println!("Tor PID: {}", pid);Sourcepub async fn get_conf(&mut self, key: &str) -> Result<Vec<String>, Error>
pub async fn get_conf(&mut self, key: &str) -> Result<Vec<String>, Error>
Retrieves the value(s) of a Tor configuration option.
Uses the GETCONF command to query Tor’s current configuration.
Some options can have multiple values, so this returns a Vec<String>.
§Arguments
key- The configuration option name (e.g., “SocksPort”, “ExitPolicy”)
§Errors
Returns Error::OperationFailed if:
- The configuration option is unrecognized
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Get SOCKS port configuration
let socks_ports = controller.get_conf("SocksPort").await?;
for port in socks_ports {
println!("SOCKS port: {}", port);
}§See Also
set_conf: Set a configuration optionreset_conf: Reset to default value
Sourcepub async fn set_conf(&mut self, key: &str, value: &str) -> Result<(), Error>
pub async fn set_conf(&mut self, key: &str, value: &str) -> Result<(), Error>
Sets a Tor configuration option.
Uses the SETCONF command to change Tor’s configuration at runtime.
The change takes effect immediately but is not persisted to the torrc
file unless you call save_conf.
§Arguments
key- The configuration option namevalue- The new value for the option
§Value Escaping
Values containing spaces or quotes are automatically escaped. You don’t need to handle quoting yourself.
§Errors
Returns Error::OperationFailed if:
- The configuration option is unrecognized
- The value is invalid for this option
- The option cannot be changed at runtime
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Change bandwidth rate
controller.set_conf("BandwidthRate", "1 MB").await?;
// Enable a feature
controller.set_conf("SafeLogging", "1").await?;§See Also
get_conf: Get current configurationreset_conf: Reset to default value
Sourcepub async fn reset_conf(&mut self, key: &str) -> Result<(), Error>
pub async fn reset_conf(&mut self, key: &str) -> Result<(), Error>
Resets a Tor configuration option to its default value.
Uses the RESETCONF command to restore a configuration option to its default value as if it were not set in the torrc file.
§Arguments
key- The configuration option name to reset
§Errors
Returns Error::OperationFailed if:
- The configuration option is unrecognized
- The option cannot be reset at runtime
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Reset bandwidth rate to default
controller.reset_conf("BandwidthRate").await?;§See Also
Sourcepub async fn save_conf(&mut self, force: bool) -> Result<(), Error>
pub async fn save_conf(&mut self, force: bool) -> Result<(), Error>
Saves the current configuration to the torrc file.
This persists any configuration changes made via set_conf
to Tor’s configuration file, so they survive restarts.
§Arguments
force- Iftrue, overwrite the configuration even if it includes a%includeclause. This is ignored if Tor doesn’t support it.
§Errors
Returns Error::OperationFailed if:
- Tor is unable to save the configuration file (e.g., permission denied)
- The configuration file contains
%includeandforceisfalse
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Change a configuration option
controller.set_conf("BandwidthRate", "1 MB").await?;
// Save to torrc
controller.save_conf(false).await?;
// Force save even with %include
controller.save_conf(true).await?;§See Also
Sourcepub async fn signal(&mut self, signal: Signal) -> Result<(), Error>
pub async fn signal(&mut self, signal: Signal) -> Result<(), Error>
Sends a signal to the Tor process.
Signals control various aspects of Tor’s behavior, from requesting new circuits to initiating shutdown.
§Arguments
signal- The signal to send (seeSignal)
§Available Signals
| Signal | Description |
|---|---|
Reload | Reload configuration (SIGHUP) |
Shutdown | Controlled shutdown |
Dump | Write statistics to disk |
Debug | Switch to debug logging |
Halt | Immediate shutdown (SIGTERM) |
Newnym | Request new circuits |
ClearDnsCache | Clear DNS cache |
Heartbeat | Trigger heartbeat log |
Active | Wake from dormant mode |
Dormant | Enter dormant mode |
§Errors
Returns Error::OperationFailed if:
- The signal is not recognized
- The signal cannot be sent (e.g., rate-limited NEWNYM)
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
use stem_rs::Signal;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Request new identity (new circuits)
controller.signal(Signal::Newnym).await?;
// Reload configuration
controller.signal(Signal::Reload).await?;
// Clear DNS cache
controller.signal(Signal::ClearDnsCache).await?;§Rate Limiting
The Newnym signal is rate-limited by Tor to prevent abuse. If called
too frequently, Tor may delay the signal or return an error.
§See Also
Signal: Signal enumeration
Sourcepub async fn get_circuits(&mut self) -> Result<Vec<Circuit>, Error>
pub async fn get_circuits(&mut self) -> Result<Vec<Circuit>, Error>
Retrieves information about all active circuits.
Returns a list of all circuits currently known to Tor, including their status and path information.
§Errors
Returns an error if:
- The GETINFO command fails
- The circuit status cannot be parsed
§Example
use stem_rs::controller::Controller;
use stem_rs::CircStatus;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let circuits = controller.get_circuits().await?;
for circuit in circuits {
if circuit.status == CircStatus::Built {
println!("Circuit {} is ready with {} hops",
circuit.id, circuit.path.len());
}
}§See Also
Circuit: Circuit information structurenew_circuit: Create a new circuitclose_circuit: Close a circuit
Sourcepub async fn new_circuit(
&mut self,
path: Option<&[&str]>,
) -> Result<CircuitId, Error>
pub async fn new_circuit( &mut self, path: Option<&[&str]>, ) -> Result<CircuitId, Error>
Creates a new circuit, optionally with a specified path.
If no path is specified, Tor will select relays automatically based on its path selection algorithm. If a path is provided, Tor will attempt to build a circuit through those specific relays.
§Arguments
path- Optional list of relay fingerprints or nicknames for the circuit path
§Path Specification
Relays can be specified by:
- Fingerprint:
$9695DFC35FFEB861329B9F1AB04C46397020CE31 - Nickname:
MyRelay - Fingerprint with nickname:
$9695DFC35FFEB861329B9F1AB04C46397020CE31~MyRelay
§Errors
Returns Error::OperationFailed if:
- A specified relay is unknown or unavailable
- The path is invalid (e.g., too short)
- Circuit creation fails
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Create circuit with automatic path selection
let circuit_id = controller.new_circuit(None).await?;
println!("Created circuit: {}", circuit_id);
// Create circuit with specific path
let path = &["$AAAA...", "$BBBB...", "$CCCC..."];
let circuit_id = controller.new_circuit(Some(path)).await?;§See Also
extend_circuit: Extend an existing circuitclose_circuit: Close a circuitget_circuits: List active circuits
Sourcepub async fn extend_circuit(
&mut self,
id: &CircuitId,
path: &[&str],
) -> Result<(), Error>
pub async fn extend_circuit( &mut self, id: &CircuitId, path: &[&str], ) -> Result<(), Error>
Extends an existing circuit by adding additional hops.
Adds one or more relays to an existing circuit. The circuit must be in a state that allows extension (typically BUILT or EXTENDED).
§Arguments
id- The circuit ID to extendpath- List of relay fingerprints or nicknames to add
§Errors
Returns Error::InvalidArguments if:
- The path is empty
Returns Error::CircuitExtensionFailed if:
- The circuit doesn’t exist
- The circuit is in a state that doesn’t allow extension
- A specified relay is unknown or unavailable
- The extension fails for any other reason
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Create a circuit and extend it
let circuit_id = controller.new_circuit(None).await?;
controller.extend_circuit(&circuit_id, &["$DDDD..."]).await?;§See Also
new_circuit: Create a new circuitclose_circuit: Close a circuit
Sourcepub async fn close_circuit(&mut self, id: &CircuitId) -> Result<(), Error>
pub async fn close_circuit(&mut self, id: &CircuitId) -> Result<(), Error>
Closes an existing circuit.
Tears down the specified circuit, closing all streams attached to it.
§Arguments
id- The circuit ID to close
§Errors
Returns Error::OperationFailed if:
- The circuit doesn’t exist
- The circuit is already closed
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Create and then close a circuit
let circuit_id = controller.new_circuit(None).await?;
controller.close_circuit(&circuit_id).await?;§See Also
new_circuit: Create a new circuitget_circuits: List active circuits
Sourcepub async fn get_streams(&mut self) -> Result<Vec<Stream>, Error>
pub async fn get_streams(&mut self) -> Result<Vec<Stream>, Error>
Retrieves information about all active streams.
Returns a list of all streams currently known to Tor, including their status, target, and circuit attachment.
§Errors
Returns an error if:
- The GETINFO command fails
- The stream status cannot be parsed
§Example
use stem_rs::controller::Controller;
use stem_rs::StreamStatus;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let streams = controller.get_streams().await?;
for stream in streams {
println!("Stream {} -> {}:{} ({:?})",
stream.id, stream.target_host, stream.target_port, stream.status);
}§See Also
Stream: Stream information structureattach_stream: Attach a stream to a circuitclose_stream: Close a stream
Sourcepub async fn attach_stream(
&mut self,
stream_id: &StreamId,
circuit_id: &CircuitId,
) -> Result<(), Error>
pub async fn attach_stream( &mut self, stream_id: &StreamId, circuit_id: &CircuitId, ) -> Result<(), Error>
Attaches a stream to a specific circuit.
Manually attaches a stream to a circuit. This is typically used when you want to control which circuit a stream uses, rather than letting Tor choose automatically.
§Arguments
stream_id- The stream to attachcircuit_id- The circuit to attach the stream to
§Preconditions
- The stream must be in a state that allows attachment (typically NEW)
- The circuit must be BUILT
- The circuit’s exit policy must allow the stream’s target
§Errors
Returns Error::OperationFailed if:
- The stream doesn’t exist
- The circuit doesn’t exist
- The stream is not in an attachable state
- The circuit cannot handle the stream’s target
§Example
use stem_rs::controller::{Controller, CircuitId, StreamId};
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Attach stream 1 to circuit 5
let stream_id = StreamId::new("1");
let circuit_id = CircuitId::new("5");
controller.attach_stream(&stream_id, &circuit_id).await?;§See Also
get_streams: List active streamsclose_stream: Close a stream
Sourcepub async fn close_stream(
&mut self,
id: &StreamId,
reason: Option<u8>,
) -> Result<(), Error>
pub async fn close_stream( &mut self, id: &StreamId, reason: Option<u8>, ) -> Result<(), Error>
Closes an existing stream.
Terminates the specified stream with an optional reason code.
§Arguments
id- The stream ID to closereason- Optional reason code (defaults to 1 = MISC if not specified)
§Reason Codes
Common reason codes include:
- 1: MISC (miscellaneous)
- 2: RESOLVEFAILED (DNS resolution failed)
- 3: CONNECTREFUSED (connection refused)
- 4: EXITPOLICY (exit policy violation)
- 5: DESTROY (circuit destroyed)
- 6: DONE (stream finished normally)
- 7: TIMEOUT (connection timeout)
§Errors
Returns Error::OperationFailed if:
- The stream doesn’t exist
- The stream is already closed
- Tor returns an error response
§Example
use stem_rs::controller::{Controller, StreamId};
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Close stream with default reason
let stream_id = StreamId::new("1");
controller.close_stream(&stream_id, None).await?;
// Close stream with specific reason (DONE)
controller.close_stream(&stream_id, Some(6)).await?;§See Also
get_streams: List active streamsattach_stream: Attach a stream to a circuit
Sourcepub async fn map_address(
&mut self,
from: &str,
to: &str,
) -> Result<HashMap<String, String>, Error>
pub async fn map_address( &mut self, from: &str, to: &str, ) -> Result<HashMap<String, String>, Error>
Maps one address to another for Tor connections.
Creates an address mapping so that connections to the from address
are redirected to the to address. This is useful for creating
virtual addresses or redirecting traffic.
§Arguments
from- The source address to map fromto- The destination address to map to
§Returns
Returns a HashMap containing the established mappings. The keys are
the source addresses and values are the destination addresses.
§Errors
Returns Error::OperationFailed if:
- The address format is invalid
- The mapping cannot be created
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Map a hostname to a .onion address
let mappings = controller.map_address(
"www.example.com",
"exampleonion.onion"
).await?;
for (from, to) in mappings {
println!("{} -> {}", from, to);
}Sourcepub async fn set_events(&mut self, events: &[EventType]) -> Result<(), Error>
pub async fn set_events(&mut self, events: &[EventType]) -> Result<(), Error>
Subscribes to asynchronous events from Tor.
Configures which event types Tor should send to this controller.
Events are received via recv_event.
§Arguments
events- List of event types to subscribe to
§Event Types
Common event types include:
EventType::Circ- Circuit status changesEventType::Stream- Stream status changesEventType::Bw- Bandwidth usageEventType::Notice- Notice-level log messagesEventType::Warn- Warning-level log messages
§Errors
Returns Error::OperationFailed if:
- An event type is not recognized
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
use stem_rs::EventType;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Subscribe to circuit and bandwidth events
controller.set_events(&[EventType::Circ, EventType::Bw]).await?;
// Receive events
loop {
let event = controller.recv_event().await?;
println!("Received event: {:?}", event);
}§Clearing Subscriptions
To stop receiving events, call with an empty slice:
controller.set_events(&[]).await?; // Clear all subscriptions§See Also
recv_event: Receive subscribed eventsEventType: Available event typesevents: Event parsing module
Sourcepub async fn recv_event(&mut self) -> Result<ParsedEvent, Error>
pub async fn recv_event(&mut self) -> Result<ParsedEvent, Error>
Receives the next asynchronous event from Tor.
Blocks until an event is available. Events must first be subscribed
to using set_events.
§Event Buffering
Events that arrive while waiting for command responses are automatically buffered and returned by subsequent calls to this method.
§Errors
Returns Error::Protocol if:
- The received message is not an event (status code != 650)
Returns Error::Socket if:
- The connection is closed
- A network error occurs
§Example
use stem_rs::controller::Controller;
use stem_rs::EventType;
use stem_rs::events::ParsedEvent;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Subscribe to bandwidth events
controller.set_events(&[EventType::Bw]).await?;
// Receive and process events
loop {
match controller.recv_event().await? {
ParsedEvent::Bandwidth(bw) => {
println!("Bandwidth: {} read, {} written", bw.read, bw.written);
}
other => println!("Other event: {:?}", other),
}
}§See Also
set_events: Subscribe to eventsParsedEvent: Event types
Sourcepub async fn msg(&mut self, command: &str) -> Result<String, Error>
pub async fn msg(&mut self, command: &str) -> Result<String, Error>
Sends a raw command to Tor and returns the response.
This is a low-level method for sending arbitrary control protocol
commands. For most use cases, prefer the typed methods like
get_info, signal, etc.
§Arguments
command- The raw command string to send
§Errors
Returns Error::OperationFailed if:
- Tor returns an error response
Returns Error::Socket if:
- The connection is closed
- A network error occurs
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Send a raw GETINFO command
let response = controller.msg("GETINFO version").await?;
println!("Raw response: {}", response);§See Also
Creates an ephemeral hidden service.
Unlike file-based hidden services, ephemeral services don’t touch disk and are the recommended way to create hidden services programmatically.
§Arguments
ports- Mapping of virtual ports to local targets (e.g.,[(80, "127.0.0.1:8080")])key_type- Type of key:"NEW"to generate,"RSA1024", or"ED25519-V3"key_content- Key content or type to generate ("BEST","RSA1024","ED25519-V3")flags- Optional flags like"Detach","DiscardPK","BasicAuth","MaxStreamsCloseCircuit"
§Returns
Returns an AddOnionResponse containing:
service_id: The onion address (without.onionsuffix)private_key: The private key (unlessDiscardPKflag was set)private_key_type: The key type (e.g.,"ED25519-V3")
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Create a v3 hidden service mapping port 80 to local port 8080
let response = controller.create_ephemeral_hidden_service(
&[(80, "127.0.0.1:8080")],
"NEW",
"ED25519-V3",
&[],
).await?;
println!("Hidden service: {}.onion", response.service_id);§See Also
remove_ephemeral_hidden_service: Remove the service
Removes an ephemeral hidden service.
Discontinues a hidden service that was created with
create_ephemeral_hidden_service.
§Arguments
service_id- The onion address without the.onionsuffix
§Returns
Returns true if the service was removed, false if it wasn’t running.
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Create and then remove a hidden service
let response = controller.create_ephemeral_hidden_service(
&[(80, "127.0.0.1:8080")],
"NEW",
"BEST",
&[],
).await?;
controller.remove_ephemeral_hidden_service(&response.service_id).await?;Sourcepub async fn load_conf(&mut self, config_text: &str) -> Result<(), Error>
pub async fn load_conf(&mut self, config_text: &str) -> Result<(), Error>
Loads configuration text as if it were read from the torrc.
This allows dynamically configuring Tor without modifying the torrc file. The configuration text is processed as if it were part of the torrc.
§Arguments
config_text- The configuration text to load
§Errors
Returns Error::InvalidRequest if:
- The configuration text contains invalid options
- The configuration text has syntax errors
Returns Error::InvalidArguments if:
- An unknown configuration option is specified
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Load configuration
controller.load_conf("MaxCircuitDirtiness 600").await?;§See Also
Sourcepub async fn drop_guards(&mut self, reset_timeouts: bool) -> Result<(), Error>
pub async fn drop_guards(&mut self, reset_timeouts: bool) -> Result<(), Error>
Drops guard nodes and optionally resets circuit timeouts.
This forces Tor to drop its current guard nodes and select new ones. Optionally, circuit build timeout counters can also be reset.
§Arguments
reset_timeouts- Iftrue, also reset circuit build timeout counters
§Errors
Returns Error::OperationFailed if:
- Tor returns an error response
reset_timeoutsistruebut Tor version doesn’t support DROPTIMEOUTS
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
// Drop guards only
controller.drop_guards(false).await?;
// Drop guards and reset timeouts
controller.drop_guards(true).await?;Sourcepub async fn repurpose_circuit(
&mut self,
circuit_id: &CircuitId,
purpose: CircuitPurpose,
) -> Result<(), Error>
pub async fn repurpose_circuit( &mut self, circuit_id: &CircuitId, purpose: CircuitPurpose, ) -> Result<(), Error>
Changes a circuit’s purpose.
Currently, two purposes are recognized: “general” and “controller”.
§Arguments
circuit_id- The ID of the circuit to repurposepurpose- The new purpose for the circuit
§Errors
Returns Error::InvalidRequest if:
- The circuit doesn’t exist
- The purpose is invalid
§Example
use stem_rs::controller::{Controller, CircuitId, CircuitPurpose};
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let circuit_id = CircuitId::new("5");
controller.repurpose_circuit(&circuit_id, CircuitPurpose::Controller).await?;Sourcepub async fn enable_feature(&mut self, features: &[&str]) -> Result<(), Error>
pub async fn enable_feature(&mut self, features: &[&str]) -> Result<(), Error>
Enables controller features that are disabled by default.
Once enabled, a feature cannot be disabled and a new control connection must be opened to get a connection with the feature disabled.
§Arguments
features- List of feature names to enable
§Errors
Returns Error::InvalidArguments if:
- An unrecognized feature is specified
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
controller.enable_feature(&["VERBOSE_NAMES"]).await?;Sourcepub async fn get_listeners(
&mut self,
listener_type: ListenerType,
) -> Result<Vec<(String, u16)>, Error>
pub async fn get_listeners( &mut self, listener_type: ListenerType, ) -> Result<Vec<(String, u16)>, Error>
Gets the addresses and ports where Tor is listening for connections.
Returns a list of (address, port) tuples for the specified listener type.
§Arguments
listener_type- The type of listener to query
§Errors
Returns Error::OperationFailed if:
- The GETINFO command fails
Returns Error::Protocol if:
- The response format is unexpected
§Example
use stem_rs::controller::{Controller, ListenerType};
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let listeners = controller.get_listeners(ListenerType::Socks).await?;
for (addr, port) in listeners {
println!("SOCKS listener: {}:{}", addr, port);
}§See Also
get_ports: Get just the port numbers
Sourcepub async fn get_ports(
&mut self,
listener_type: ListenerType,
) -> Result<HashSet<u16>, Error>
pub async fn get_ports( &mut self, listener_type: ListenerType, ) -> Result<HashSet<u16>, Error>
Gets just the port numbers where Tor is listening for connections.
Returns a set of unique port numbers for the specified listener type.
This is a convenience method that extracts just the ports from
get_listeners.
§Arguments
listener_type- The type of listener to query
§Example
use stem_rs::controller::{Controller, ListenerType};
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let ports = controller.get_ports(ListenerType::Socks).await?;
for port in ports {
println!("SOCKS port: {}", port);
}§See Also
get_listeners: Get addresses and ports
Sourcepub async fn get_user(&mut self) -> Result<String, Error>
pub async fn get_user(&mut self) -> Result<String, Error>
Gets the user Tor is running as.
§Errors
Returns Error::OperationFailed if:
- The information is not available
- Tor returns an error response
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let user = controller.get_user().await?;
println!("Tor is running as: {}", user);Sourcepub async fn get_start_time(&mut self) -> Result<f64, Error>
pub async fn get_start_time(&mut self) -> Result<f64, Error>
Gets the Unix timestamp when Tor started.
Calculates the start time by subtracting the uptime from the current time.
§Errors
Returns an error if:
- The uptime cannot be determined
- The uptime value is invalid
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let start_time = controller.get_start_time().await?;
println!("Tor started at: {}", start_time);§See Also
get_uptime: Get how long Tor has been running
Sourcepub async fn get_uptime(&mut self) -> Result<f64, Error>
pub async fn get_uptime(&mut self) -> Result<f64, Error>
Gets how long Tor has been running in seconds.
§Errors
Returns an error if:
- The GETINFO command fails
- The uptime value cannot be parsed
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let uptime = controller.get_uptime().await?;
println!("Tor has been running for {} seconds", uptime);§See Also
get_start_time: Get when Tor started
Sourcepub async fn get_protocolinfo(&mut self) -> Result<ProtocolInfo, Error>
pub async fn get_protocolinfo(&mut self) -> Result<ProtocolInfo, Error>
Gets protocol information including authentication methods.
Returns information about the Tor control protocol version, the Tor version, and available authentication methods.
§Errors
Returns Error::Parse if:
- The PROTOCOLINFO response cannot be parsed
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
let info = controller.get_protocolinfo().await?;
println!("Protocol version: {}", info.protocol_version);
println!("Tor version: {}", info.tor_version);
println!("Auth methods: {:?}", info.auth_methods);Sourcepub async fn get_accounting_stats(&mut self) -> Result<AccountingStats, Error>
pub async fn get_accounting_stats(&mut self) -> Result<AccountingStats, Error>
Gets accounting statistics for bandwidth limiting.
Returns statistics about Tor’s accounting status when AccountingMax is set in the torrc.
§Errors
Returns Error::OperationFailed if:
- Accounting is not enabled
- The GETINFO commands fail
§Example
use stem_rs::controller::Controller;
let mut controller = Controller::from_port("127.0.0.1:9051".parse()?).await?;
controller.authenticate(None).await?;
let stats = controller.get_accounting_stats().await?;
println!("Status: {}", stats.status);
println!("Read: {} bytes", stats.read_bytes);
println!("Written: {} bytes", stats.written_bytes);