Expand description
Tor for Rust: make HTTP requests over the Tor network, and host onion services.
hypertor is a thin, honest layer over two mature pieces of software:
arti, the Tor Project’s Rust
implementation of Tor, and hyper, the HTTP stack
reqwest is built on. It supplies the seam between them and the ergonomics
on top; it implements no Tor protocol and no HTTP protocol of its own.
§Making requests
use hypertor::TorClient;
#[tokio::main]
async fn main() -> hypertor::Result<()> {
let client = TorClient::new().await?;
let body = client
.get("https://check.torproject.org/api/ip")?
.send()
.await?
.error_for_status()?
.text()?;
println!("{body}");
Ok(())
}.onion addresses work the same way, and never touch an exit relay:
let response = client.get("http://example.onion/api")?.send().await?;§Hosting an onion service
use hypertor::{OnionApp, ServeResponse};
pub async fn run() -> hypertor::Result<()> {
let app = OnionApp::new()
.get("/", |_req| async { ServeResponse::text("hello") });
let service = app.serve("my-service").await?;
println!("{}", service.onion_address());
service.wait().await
}§What hypertor adds over wiring arti and hyper together yourself
- Connection pooling that actually pools. The Tor connector plugs into hyper’s pooling client, so a warm circuit is reused across requests rather than paying seconds of circuit setup every time.
- Circuit isolation as a first-class concept.
IsolationLevelandIsolationTokenlet you decide explicitly which of your activities may be linked to one another. - Redirects that do not betray you. Credentials are stripped across
origins, and a redirect from a
.onionout to clearnet is refused unless you opt in. SeeRedirectPolicy. - No local DNS, ever. Hostnames are resolved by the exit relay. A Tor integration that resolves names locally leaks every site you visit.
- Bodies that stream in both directions.
Body::from_fileuploads without buffering;send_streamingdownloads without buffering. Decompression happens incrementally, so the size limit bounds a decompression bomb instead of discovering one. - Errors that do not leak. Hostnames in
Errorare scrubbed when displayed, because error messages end up in logs. - Onion services that are not distinguishable. A hosted service accepts
only
BEGINstreams for the virtual ports it publishes, which is what every other implementation does — behaving differently is itself a fingerprint.
§What hypertor does not do
It is not an anonymity system in its own right, and no library can be. Tor protects the network path; it cannot protect you from an application that logs in with your real identity, from timing patterns in your own traffic, or from anything running on a compromised machine. Read the Tor Project’s guidance before relying on this for anything that matters.
It also keeps no cookie jar, deliberately. A jar shared across requests
would relink activities that IsolationLevel exists to keep apart — the
separation would still hold at the network layer while the application layer
gave the correlation away for free. Set Cookie yourself, and its scope is
yours to choose.
§Feature flags
| Feature | Default | What it adds |
|---|---|---|
client | yes | TorClient and the HTTP client stack |
rustls | yes | TLS via rustls — one fingerprint on every platform |
native-tls | no | TLS via the OS stack; leaks your platform, see tls |
server | no | OnionService and OnionApp |
pow | no | Equi-X proof-of-work; pulls in LGPL-3.0 crates |
socks | no | SocksProxy, a local SOCKS5 front-end |
ws | no | TorWebSocket |
static-sqlite | no | link SQLite statically; needed on Windows |
full is client + server + socks + ws + rustls. It deliberately excludes
pow, so a default build stays entirely permissively licensed.
There is no python feature. The bindings are a separate, unpublished crate
(bindings/python in the repository) that consumes this one through its
public API, so a Rust dependency on hypertor never pulls in pyo3.
Re-exports§
pub use config::Config;pub use config::ConfigBuilder;pub use config::DEFAULT_USER_AGENT;pub use config::TlsConfig;pub use config::TlsVersion;pub use error::Error;pub use error::Result;pub use isolation::IsolatedSession;pub use isolation::IsolationLevel;pub use isolation::IsolationToken;pub use redirect::RedirectAction;pub use redirect::RedirectPolicy;pub use stream::TorStream;pub use body::Body;pub use body::Encoding;pub use client::TorClient;pub use client::TorClientBuilder;pub use request::RequestBuilder;pub use response::Response;pub use response::Streaming;pub use onion_service::OnionService;pub use onion_service::OnionServiceBuilder;pub use onion_service::OnionServiceConfig;pub use onion_service::OnionStream;pub use serve::OnionApp;pub use serve::Request as ServeRequest;pub use serve::Response as ServeResponse;pub use serve::ServingApp;pub use socks::SocksConfig;pub use socks::SocksProxy;pub use websocket::Close as WsClose;pub use websocket::Message as WsMessage;pub use websocket::Receiver as WsReceiver;pub use websocket::Sender as WsSender;pub use websocket::TorWebSocket;pub use websocket::TorWebSocketBuilder;
Modules§
- body
- Request bodies, and response body decoding.
- client
- The Tor HTTP client.
- config
- Client configuration.
- error
- Typed errors for hypertor.
- isolation
- Circuit isolation.
- onion_
service - Hosting onion services.
- prelude
- The common imports, in one line.
- redirect
- Redirect handling.
- request
- Building and sending requests.
- response
- HTTP responses.
- serve
- A small HTTP framework for onion services.
- socks
- A local SOCKS5 proxy that routes traffic over Tor.
- stream
- A Tor stream, optionally wrapped in TLS.
- tls
- TLS for clearnet targets reached through a Tor exit relay.
- websocket
- WebSocket over Tor.
Enums§
- Vanguard
Mode - Vanguard mode, re-exported from arti.
Constants§
- VERSION
- The version of this crate.