Loading crates/arti-client/examples/readme.rs 0 → 100644 +46 −0 Original line number Diff line number Diff line use anyhow::Result; use arti_client::{TorClient, TorClientConfig}; use tokio_crate as tokio; use futures::io::{AsyncReadExt, AsyncWriteExt}; #[tokio::main] async fn main() -> Result<()> { // Arti uses the `tracing` crate for logging. Install a handler for this, to print Arti's logs. tracing_subscriber::fmt::init(); // The client config includes things like where to store persistent Tor network state. // The "sane defaults" provided are the same as the Arti standalone application, and save data // to a conventional place depending on operating system (for example, ~/.local/share/arti // on Linux platforms) let config = TorClientConfig::sane_defaults()?; // Arti needs an async runtime handle to spawn async tasks. let rt = tor_rtcompat::tokio::current_runtime()?; eprintln!("connecting to Tor..."); // We now let the Arti client start and bootstrap a connection to the network. // (This takes a while to gather the necessary consensus state, etc.) let tor_client = TorClient::bootstrap(rt, config).await?; eprintln!("connecting to example.com..."); let mut stream = tor_client.connect(("example.com", 80), None).await?; eprintln!("sending request..."); stream .write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n") .await?; stream.flush().await?; eprintln!("reading response..."); let mut buf = Vec::new(); stream.read_to_end(&mut buf).await?; println!("{}", String::from_utf8_lossy(&buf)); Ok(()) } crates/arti-client/src/err.rs +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ use thiserror::Error; use tor_rtcompat::TimeoutError; /// An error originating from the tor-dirclient crate. /// Represents errors that can occur while doing Tor operations. #[derive(Error, Debug)] #[non_exhaustive] pub enum Error { Loading crates/arti-client/src/lib.rs +99 −15 Original line number Diff line number Diff line Loading @@ -24,24 +24,108 @@ //! general, are not the least bit stable. If you use this code, //! please expect your software to break on a regular basis. //! //! ## Design considerations, privacy considerations. //! //! As we build the APIs for this crate, we've been aiming for //! simplicity and safety: we want it to be as easy as possible to use //! `arti-client`, while trying to make certain kinds of privacy or security //! violation hard to write accidentally. //! //! Privacy isn't just a drop-in feature, however. There are still //! plenty of ways to accidentally leak information, even if you're //! anonymizing your connections over Tor. We'll try to document //! those in a user's guide at some point as Arti becomes more mature. //! //! # Using `arti-client` //! //! The `arti-client` crate provides an async Rust API. It is //! compatible with the `tokio` and `async_std` asynchronous backends. //! The main entry point for this crate is the [`TorClient`], an object that lets you make //! connections over the Tor network. //! //! Calling [`TorClient::bootstrap`] establishes a connection to the Tor network, pulling in //! necessary state about network consensus as required. This state gets persisted to the //! locations specified in the [`TorClientConfig`]. //! //! A client can then be used to make connections over Tor with [`TorClient::connect`], which //! accepts anything implementing [`IntoTorAddr`]. This returns a [`DataStream`], an anonymised //! TCP stream type that implements [`AsyncRead`](futures::io::AsyncRead) and //! [`AsyncWrite`](futures::io::AsyncWrite), as well as the Tokio versions of those traits if //! the `tokio` crate feature is enabled. //! //! The [`TorAddr`] type is intended to ensure that DNS lookups are done via the Tor network //! instead of locally. Doing local DNS resolution can leak information about which hostnames you're //! connecting to to your local DNS resolver (i.e. your ISP), so it's much better to let Arti //! do it for you to maintain privacy. //! //! If you really want to connect to a raw IP address and know what you're doing, take a look at //! [`TorAddr::dangerously_from`] -- but be careful! //! //! ## Example: making connections over Tor //! //! ```no_run //! # use anyhow::Result; //! # use arti_client::{TorClient, TorClientConfig}; //! # use tokio_crate as tokio; //! # #[tokio::main] //! # async fn main() -> Result<()> { //! // The client config includes things like where to store persistent Tor network state. //! let config = TorClientConfig::sane_defaults()?; //! // Arti needs a handle to an async runtime in order to spawn async tasks. //! // (See "Multiple runtime support" below.) //! let rt = tor_rtcompat::tokio::current_runtime()?; //! //! // Start the Arti client, and let it bootstrap a connection to the Tor network. //! // (This takes a while to gather the necessary consensus state, etc.) //! let tor_client = TorClient::bootstrap(rt, config).await?; //! //! // Initiate a connection over Tor to example.com, port 80. //! let mut stream = tor_client.connect(("example.com", 80), None).await?; //! //! use futures::io::{AsyncReadExt, AsyncWriteExt}; //! //! // Write out an HTTP request. //! stream //! .write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n") //! .await?; //! //! // IMPORTANT: Make sure the request was written. //! // Arti buffers data by default due to the design of the Tor protocol, so flushing the //! // buffer is usually required. //! stream.flush().await?; //! //! // Read and print the result. //! let mut buf = Vec::new(); //! stream.read_to_end(&mut buf).await?; //! //! println!("{}", String::from_utf8_lossy(&buf)); //! # //! # Ok(()) //! # } //! ``` //! //! ## More advanced usage //! //! This version of Arti includes basic support for "stream isolation": the ability to ensure that //! different TCP connections ('streams') go over different Tor circuits (and thus different exit //! nodes, making them originate from different IP addresses). //! //! This is useful to avoid deanonymising //! users by correlation: for example, you might want a Tor connection to your bank and a Tor //! connection to an online forum to use different circuits, to avoid the possibility of the two //! identities being linked by having the same source IP. //! //! Streams can be isolated in two ways: //! //! - by calling [`TorClient::isolated_client`], which returns a new [`TorClient`] whose streams //! will use a different circuit //! - by generating [`IsolationToken`]s, and passing them in via [`ConnectPrefs`] to //! [`TorClient::connect`]. //! //! # Multiple runtime support //! //! Arti uses the [`tor_rtcompat`] crate to support multiple asynchronous runtimes; currently, //! both [Tokio](https://tokio.rs) and [async-std](https://async.rs) are supported. //! //! Functions in this crate, like [`TorClient::bootstrap`], //! will expect a type that implements [`tor_rtcompat::Runtime`], which can be obtained: //! //! - for Tokio: //! - by calling [`tor_rtcompat::tokio::current_runtime`], if a Tokio reactor is already running //! - by calling [`tor_rtcompat::tokio::create_runtime`], to start a new reactor if one is not //! already running //! - by manually creating a [`TokioRuntimeHandle`](tor_rtcompat::tokio::TokioRuntimeHandle) from //! an existing Tokio runtime handle //! - for async-std: //! - by calling [`tor_rtcompat::async_std::current_runtime`], which will create a runtime or //! retrieve the existing one, if one has already been started //! //! TODO: Good examples here once the crate setup API is more simple. //! //! # Feature flags //! Loading Loading
crates/arti-client/examples/readme.rs 0 → 100644 +46 −0 Original line number Diff line number Diff line use anyhow::Result; use arti_client::{TorClient, TorClientConfig}; use tokio_crate as tokio; use futures::io::{AsyncReadExt, AsyncWriteExt}; #[tokio::main] async fn main() -> Result<()> { // Arti uses the `tracing` crate for logging. Install a handler for this, to print Arti's logs. tracing_subscriber::fmt::init(); // The client config includes things like where to store persistent Tor network state. // The "sane defaults" provided are the same as the Arti standalone application, and save data // to a conventional place depending on operating system (for example, ~/.local/share/arti // on Linux platforms) let config = TorClientConfig::sane_defaults()?; // Arti needs an async runtime handle to spawn async tasks. let rt = tor_rtcompat::tokio::current_runtime()?; eprintln!("connecting to Tor..."); // We now let the Arti client start and bootstrap a connection to the network. // (This takes a while to gather the necessary consensus state, etc.) let tor_client = TorClient::bootstrap(rt, config).await?; eprintln!("connecting to example.com..."); let mut stream = tor_client.connect(("example.com", 80), None).await?; eprintln!("sending request..."); stream .write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n") .await?; stream.flush().await?; eprintln!("reading response..."); let mut buf = Vec::new(); stream.read_to_end(&mut buf).await?; println!("{}", String::from_utf8_lossy(&buf)); Ok(()) }
crates/arti-client/src/err.rs +1 −1 Original line number Diff line number Diff line Loading @@ -3,7 +3,7 @@ use thiserror::Error; use tor_rtcompat::TimeoutError; /// An error originating from the tor-dirclient crate. /// Represents errors that can occur while doing Tor operations. #[derive(Error, Debug)] #[non_exhaustive] pub enum Error { Loading
crates/arti-client/src/lib.rs +99 −15 Original line number Diff line number Diff line Loading @@ -24,24 +24,108 @@ //! general, are not the least bit stable. If you use this code, //! please expect your software to break on a regular basis. //! //! ## Design considerations, privacy considerations. //! //! As we build the APIs for this crate, we've been aiming for //! simplicity and safety: we want it to be as easy as possible to use //! `arti-client`, while trying to make certain kinds of privacy or security //! violation hard to write accidentally. //! //! Privacy isn't just a drop-in feature, however. There are still //! plenty of ways to accidentally leak information, even if you're //! anonymizing your connections over Tor. We'll try to document //! those in a user's guide at some point as Arti becomes more mature. //! //! # Using `arti-client` //! //! The `arti-client` crate provides an async Rust API. It is //! compatible with the `tokio` and `async_std` asynchronous backends. //! The main entry point for this crate is the [`TorClient`], an object that lets you make //! connections over the Tor network. //! //! Calling [`TorClient::bootstrap`] establishes a connection to the Tor network, pulling in //! necessary state about network consensus as required. This state gets persisted to the //! locations specified in the [`TorClientConfig`]. //! //! A client can then be used to make connections over Tor with [`TorClient::connect`], which //! accepts anything implementing [`IntoTorAddr`]. This returns a [`DataStream`], an anonymised //! TCP stream type that implements [`AsyncRead`](futures::io::AsyncRead) and //! [`AsyncWrite`](futures::io::AsyncWrite), as well as the Tokio versions of those traits if //! the `tokio` crate feature is enabled. //! //! The [`TorAddr`] type is intended to ensure that DNS lookups are done via the Tor network //! instead of locally. Doing local DNS resolution can leak information about which hostnames you're //! connecting to to your local DNS resolver (i.e. your ISP), so it's much better to let Arti //! do it for you to maintain privacy. //! //! If you really want to connect to a raw IP address and know what you're doing, take a look at //! [`TorAddr::dangerously_from`] -- but be careful! //! //! ## Example: making connections over Tor //! //! ```no_run //! # use anyhow::Result; //! # use arti_client::{TorClient, TorClientConfig}; //! # use tokio_crate as tokio; //! # #[tokio::main] //! # async fn main() -> Result<()> { //! // The client config includes things like where to store persistent Tor network state. //! let config = TorClientConfig::sane_defaults()?; //! // Arti needs a handle to an async runtime in order to spawn async tasks. //! // (See "Multiple runtime support" below.) //! let rt = tor_rtcompat::tokio::current_runtime()?; //! //! // Start the Arti client, and let it bootstrap a connection to the Tor network. //! // (This takes a while to gather the necessary consensus state, etc.) //! let tor_client = TorClient::bootstrap(rt, config).await?; //! //! // Initiate a connection over Tor to example.com, port 80. //! let mut stream = tor_client.connect(("example.com", 80), None).await?; //! //! use futures::io::{AsyncReadExt, AsyncWriteExt}; //! //! // Write out an HTTP request. //! stream //! .write_all(b"GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n") //! .await?; //! //! // IMPORTANT: Make sure the request was written. //! // Arti buffers data by default due to the design of the Tor protocol, so flushing the //! // buffer is usually required. //! stream.flush().await?; //! //! // Read and print the result. //! let mut buf = Vec::new(); //! stream.read_to_end(&mut buf).await?; //! //! println!("{}", String::from_utf8_lossy(&buf)); //! # //! # Ok(()) //! # } //! ``` //! //! ## More advanced usage //! //! This version of Arti includes basic support for "stream isolation": the ability to ensure that //! different TCP connections ('streams') go over different Tor circuits (and thus different exit //! nodes, making them originate from different IP addresses). //! //! This is useful to avoid deanonymising //! users by correlation: for example, you might want a Tor connection to your bank and a Tor //! connection to an online forum to use different circuits, to avoid the possibility of the two //! identities being linked by having the same source IP. //! //! Streams can be isolated in two ways: //! //! - by calling [`TorClient::isolated_client`], which returns a new [`TorClient`] whose streams //! will use a different circuit //! - by generating [`IsolationToken`]s, and passing them in via [`ConnectPrefs`] to //! [`TorClient::connect`]. //! //! # Multiple runtime support //! //! Arti uses the [`tor_rtcompat`] crate to support multiple asynchronous runtimes; currently, //! both [Tokio](https://tokio.rs) and [async-std](https://async.rs) are supported. //! //! Functions in this crate, like [`TorClient::bootstrap`], //! will expect a type that implements [`tor_rtcompat::Runtime`], which can be obtained: //! //! - for Tokio: //! - by calling [`tor_rtcompat::tokio::current_runtime`], if a Tokio reactor is already running //! - by calling [`tor_rtcompat::tokio::create_runtime`], to start a new reactor if one is not //! already running //! - by manually creating a [`TokioRuntimeHandle`](tor_rtcompat::tokio::TokioRuntimeHandle) from //! an existing Tokio runtime handle //! - for async-std: //! - by calling [`tor_rtcompat::async_std::current_runtime`], which will create a runtime or //! retrieve the existing one, if one has already been started //! //! TODO: Good examples here once the crate setup API is more simple. //! //! # Feature flags //! Loading