summaryrefslogtreecommitdiff
path: root/crates/arti-client/src/lib.rs
blob: 470d965c79feb5366b9a629cd67c12b606843d73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
//! High-level functionality for accessing the Tor network as a client.
//!
//! # Overview
//!
//! The `arti-client` crate aims to provide a safe, easy-to-use API for
//! applications that want to use Tor network to anonymize their
//! traffic.  It hides most of the underlying detail, letting other
//! crates decide how exactly to use the Tor crate.
//!
//! This crate is part of
//! [Arti](https://gitlab.torproject.org/tpo/core/arti/), a project to
//! implement [Tor](https://www.torproject.org/) in Rust.
//! It is the highest-level library crate in
//! Arti, and the one that nearly all client-only programs should use.
//! Most of its functionality is provided by lower-level crates in Arti.
//!
//! ## ⚠ Warnings ⚠
//!
//! Note that Arti is a work in progress; although we've tried to
//! write all the critical security components, you probably shouldn't
//! use Arti in production until it's a bit more mature.
//!
//! Also note that all of the APIs for this crate, and for Arti in
//! general, are not the least bit stable.  If you use this code,
//! please expect your software to break on a regular basis.
//!
//! # Using `arti-client`
//!
//! 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 anonymized
//! 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 configuration describes how to connect to the Tor network,
//! // and what directories to use for storing persistent state.
//! let config = TorClientConfig::default();
//! // Arti needs a handle to an async runtime in order to spawn tasks and use the
//! // network. (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 directory information.
//! // It uses cached information when possible.)
//! 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)).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, 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 deanonymizing
//! 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
//!
//!
//! # Feature flags
//!
//! `tokio` -- (Default) Build with support for the Tokio backend.
//!
//! `async-std` -- Build with support for the `async_std` backend.
//!
//! `static` -- Link with static versions of your system dependencies,
//! including sqlite and/or openssl.
//!
//! `experimental-api` -- Build with experimental, unstable API support.
//! Note that these APIs are NOT covered by semantic versioning guarantees:
//! we might break them or remove them between patch versions.

#![deny(missing_docs)]
#![warn(noop_method_call)]
#![deny(unreachable_pub)]
#![deny(clippy::all)]
#![deny(clippy::await_holding_lock)]
#![deny(clippy::cargo_common_metadata)]
#![deny(clippy::cast_lossless)]
#![deny(clippy::checked_conversions)]
#![warn(clippy::clone_on_ref_ptr)]
#![warn(clippy::cognitive_complexity)]
#![deny(clippy::debug_assert_with_mut_call)]
#![deny(clippy::exhaustive_enums)]
#![deny(clippy::exhaustive_structs)]
#![deny(clippy::expl_impl_clone_on_copy)]
#![deny(clippy::fallible_impl_from)]
#![deny(clippy::implicit_clone)]
#![deny(clippy::large_stack_arrays)]
#![warn(clippy::manual_ok_or)]
#![deny(clippy::missing_docs_in_private_items)]
#![deny(clippy::missing_panics_doc)]
#![warn(clippy::needless_borrow)]
#![warn(clippy::needless_pass_by_value)]
#![warn(clippy::option_option)]
#![warn(clippy::rc_buffer)]
#![deny(clippy::ref_option_ref)]
#![warn(clippy::semicolon_if_nothing_returned)]
#![warn(clippy::trait_duplication_in_bounds)]
#![deny(clippy::unnecessary_wraps)]
#![warn(clippy::unseparated_literal_suffix)]
#![deny(clippy::unwrap_used)]

mod address;
mod client;

pub mod config;

pub use address::{DangerouslyIntoTorAddr, IntoTorAddr, TorAddr, TorAddrError};
pub use client::{ConnectPrefs, TorClient};
pub use config::TorClientConfig;

pub use tor_circmgr::IsolationToken;
pub use tor_proto::stream::DataStream;

mod err;
pub use err::Error;

/// Alias for the [`Result`] type used by the `arti_client` crate.
pub type Result<T> = std::result::Result<T, Error>;