A safe, practical, robust, and configurable Rust crate for interfacing with the Tor control protocol.
- 🔒 Safe - No unsafe code, comprehensive error handling
- 🔧 Configurable - Multiple authentication methods, flexible connection options
- 🚀 Async - Built on Tokio for efficient async I/O
- 📦 Complete - Implements all major Tor control commands
- 🔐 Secure Authentication - Supports NULL, password, cookie, and SAFECOOKIE methods
Add this to your Cargo.toml:
[dependencies]
tor-controller = "0.1.1"use tor_controller::{TorClient, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Connect to the default control port (127.0.0.1:9051)
let mut client = TorClient::connect_default().await?;
// Auto-authenticate using the best available method
client.auto_authenticate().await?;
// Get Tor version
let version = client.get_version().await?;
println!("Connected to Tor {}", version);
// Request a new identity (new circuits)
client.new_identity().await?;
println!("New identity requested");
Ok(())
}The crate supports all Tor authentication methods:
client.authenticate(&AuthCredential::None).await?;client.authenticate(&AuthCredential::Password("secret".to_string())).await?;client.authenticate(&AuthCredential::CookieFile(
"/run/tor/control.authcookie".to_string()
)).await?;client.authenticate(&AuthCredential::SafeCookie {
cookie_path: "/run/tor/control.authcookie".to_string(),
}).await?;// Automatically detect and use the best available method
client.auto_authenticate().await?;// Get a configuration value
if let Some(socks_port) = client.get_conf("SocksPort").await? {
println!("SOCKS port: {}", socks_port);
}
// Set configuration
client.set_conf("MaxCircuitDirtiness", "300").await?;
// Save configuration to disk
client.save_conf(false).await?;use tor_controller::{Signal, CircuitId};
// Request new identity (new circuits)
client.signal(Signal::NewNym).await?;
// Get circuit status
let circuits = client.get_circuit_status().await?;
for circuit in circuits {
println!("Circuit {}: {:?}", circuit.id.0, circuit.status);
}
// Close a circuit
client.close_circuit(CircuitId(12345), false).await?;// Create a new onion service
let service = client.add_onion(
&[(80, Some("127.0.0.1:8080"))], // Virtual port 80 -> local 8080
None, // Generate new key
&[], // No flags
).await?;
println!("Service address: {}", service.address);
if let Some(key) = service.private_key {
println!("Private key: {}", key);
}
// Delete the service when done
client.del_onion(&service.address.service_id()).await?;use tor_controller::EventType;
// Subscribe to events
client.set_events(&[EventType::Circ, EventType::Stream, EventType::Bw]).await?;
// Read events
loop {
let event = client.read_event().await?;
match event {
Event::Circuit(circ) => println!("Circuit {}: {:?}", circ.id.0, circ.status),
Event::Bandwidth(bw) => println!("Bandwidth: {} down, {} up", bw.read, bw.written),
_ => println!("Other event: {:?}", event),
}
}// Get Tor version
let version = client.get_version().await?;
println!("Tor version: {}", version);
// Get arbitrary info
let traffic = client.get_info("traffic/read").await?;
println!("Traffic read: {} bytes", traffic);use tor_controller::Signal;
// Request new identity
client.signal(Signal::NewNym).await?;
// Reload configuration
client.signal(Signal::Reload).await?;
// Clear DNS cache
client.signal(Signal::ClearDnsCache).await?;
// Initiate graceful shutdown
client.signal(Signal::Shutdown).await?;All operations return Result<T, TorControlError>:
use tor_controller::TorControlError;
match client.authenticate(&credential).await {
Ok(()) => println!("Authenticated!"),
Err(TorControlError::AuthenticationFailed(msg)) => {
eprintln!("Auth failed: {}", msg);
}
Err(TorControlError::ConnectionClosed) => {
eprintln!("Connection was closed");
}
Err(e) => eprintln!("Error: {}", e),
}To enable the control port in Tor, add to your torrc:
# Enable control port on TCP
ControlPort 9051
# Or use a Unix socket
#ControlSocket /run/tor/control
# Authentication options:
# No authentication (not recommended for production)
#CookieAuthentication 0
# Cookie authentication (recommended)
CookieAuthentication 1
# Or password authentication
#HashedControlPassword <hashed-password>
Generate a hashed password with:
tor --hash-password "your-password"| Feature | Default | Description |
|---|---|---|
tokio-runtime |
✓ | Enable async support using Tokio |
This crate implements Tor Control Protocol version 1 as specified in the Tor Control Specification.
The version number (0.1.1.0) corresponds to the Tor version where the control protocol was last significantly changed, ensuring compatibility with modern Tor daemons.
MIT License - see LICENSE for details.
Contributions are welcome! Please feel free to submit a Pull Request.