1
1
//! Implementations for the core Tor protocol
2
//!
3
//! # Overview
4
//!
5
//! The `tor-proto` crate lies at the core of
6
//! [Arti](https://gitlab.torproject.org/tpo/core/arti/), a project to
7
//! implement [Tor](https://www.torproject.org/) in Rust.
8
//! Most people shouldn't use this crate directly,
9
//! since its APIs are needlessly low-level for most purposes, and it is
10
//! easy to misuse them in an insecure or privacy-violating way.
11
//!
12
//! Most people should use the [`arti-client`] crate instead.  This crate is
13
//! of interest mainly for those that want to access the Tor protocols at
14
//! a low level.
15
//!
16
//! ## Core concepts
17
//!
18
//! At its essence, Tor makes connections called "channels" to other
19
//! Tor instances.  These channels are implemented using TLS.  Each of
20
//! these channels multiplexes a number of anonymized multihop
21
//! "circuits" that act as reliable transports for "relay messages"
22
//! that are sent between clients and the different relays on the
23
//! circuits.  Finally, each circuit multiplexes a number of "streams",
24
//! each corresponding roughly to an application-level request.
25
//!
26
//! This crate implements the logic, protocols, and cryptography that
27
//! implement these [`channel::Channel`]s, [`circuit::ClientCirc`]s, and
28
//! [`stream::DataStream`]s.  It uses rust async code and future-related
29
//! traits, and is intended to work with (nearly) any executor
30
//! implementation that complies with the futures API.  It should also
31
//! work with nearly any TLS implementation that exposes AsyncRead and
32
//! AsyncWrite traits.
33
//!
34
//! ## Not in this crate
35
//!
36
//! This crate does _not_ implement higher level protocols, like onion
37
//! services or the Tor directory protocol, that are based on the Tor
38
//! protocol here.  Nor does it decide _when_, _how_, or _where_ to
39
//! build channels and circuits: that's the role of higher-level crates.
40
//!
41
//! This crate also has no support for timeouts, so every network
42
//! operation here has the potential to block the current task
43
//! indefinitely.  Timeouts are another necessary piece that gets
44
//! added at a higher level.
45
//!
46
//! In order to create channels and circuits, you'll need to know
47
//! about some Tor relays, and expose their information via
48
//! [`tor_linkspec::ChanTarget`] and [`tor_linkspec::CircTarget`].
49
//! Currently, the [`tor-netdir`] crate is the easiest way to do so.
50
//!
51
//! For an example of this crate in action, see the [`arti-client`]
52
//! library, or the `arti` CLI.
53
//!
54
//! # Design notes
55
//!
56
//! This crate's APIs are structured to explicitly avoid any usage of
57
//! an asynchronous runtime: It doesn't launch tasks or include
58
//! timeouts.  Those are done at a higher level in Arti, via the
59
//! [`tor-rtcompat`] crate.
60
//!
61
//! To the extent possible, this crate avoids doing public-key
62
//! cryptography in the same functions it uses for network activity.
63
//! This makes it easier for higher-level code to parallelize or yield
64
//! around public-key operations.
65
//!
66
//! # Limitations
67
//!
68
//! This is all a work in progress, and will need severe refactoring
69
//! before it's done.
70
//!
71
//! This is a client-only implementation; there is no support the
72
//! operations that Relays need.
73
//!
74
//! There are too many missing features to list.
75
//!
76
//! There isn't enough documentation or examples.
77
//!
78
//! This crate was my first attempt to use async in rust, and is probably
79
//! pretty kludgy.
80
//!
81
//! I bet that there are deadlocks somewhere in this code.  I fixed
82
//! all the ones I could find or think of, but it would be great to
83
//! find a good way to eliminate every lock that we have.
84

            
85
#![deny(missing_docs)]
86
#![warn(noop_method_call)]
87
#![deny(unreachable_pub)]
88
#![warn(clippy::all)]
89
#![deny(clippy::await_holding_lock)]
90
#![deny(clippy::cargo_common_metadata)]
91
#![deny(clippy::cast_lossless)]
92
#![deny(clippy::checked_conversions)]
93
#![warn(clippy::cognitive_complexity)]
94
#![deny(clippy::debug_assert_with_mut_call)]
95
#![deny(clippy::exhaustive_enums)]
96
#![deny(clippy::exhaustive_structs)]
97
#![deny(clippy::expl_impl_clone_on_copy)]
98
#![deny(clippy::fallible_impl_from)]
99
#![deny(clippy::implicit_clone)]
100
#![deny(clippy::large_stack_arrays)]
101
#![warn(clippy::manual_ok_or)]
102
#![deny(clippy::missing_docs_in_private_items)]
103
#![deny(clippy::missing_panics_doc)]
104
#![warn(clippy::needless_borrow)]
105
#![warn(clippy::needless_pass_by_value)]
106
#![warn(clippy::option_option)]
107
#![warn(clippy::rc_buffer)]
108
#![deny(clippy::ref_option_ref)]
109
#![warn(clippy::semicolon_if_nothing_returned)]
110
#![warn(clippy::trait_duplication_in_bounds)]
111
#![deny(clippy::unnecessary_wraps)]
112
#![warn(clippy::unseparated_literal_suffix)]
113
#![deny(clippy::unwrap_used)]
114

            
115
pub mod channel;
116
pub mod circuit;
117
mod crypto;
118
pub mod stream;
119
mod util;
120

            
121
pub use util::err::Error;
122

            
123
/// A vector of bytes that gets cleared when it's dropped.
124
type SecretBytes = zeroize::Zeroizing<Vec<u8>>;
125

            
126
/// A Result type for this crate.
127
pub type Result<T> = std::result::Result<T, Error>;
128

            
129
/// Timestamp object that we update whenever we get incoming traffic.
130
///
131
/// Used to implement [`time_since_last_incoming_traffic`]
132
static LAST_INCOMING_TRAFFIC: util::ts::OptTimestamp = util::ts::OptTimestamp::new();
133

            
134
/// Called whenever we receive incoming traffic.
135
///
136
/// Used to implement [`time_since_last_incoming_traffic`]
137
#[inline]
138
153
pub(crate) fn note_incoming_traffic() {
139
153
    LAST_INCOMING_TRAFFIC.update();
140
153
}
141

            
142
/// Return the amount of time since we last received "incoming traffic".
143
///
144
/// This is a global counter, and is subject to interference from
145
/// other users of the `tor_proto`.  Its only permissible use is for
146
/// checking how recently we have been definitely able to receive
147
/// incoming traffic.
148
///
149
/// When enabled, this timestamp is updated whenever we receive a valid
150
/// cell, and whenever we complete a channel handshake.
151
///
152
/// Returns `None` if we never received "incoming traffic".
153
5355
pub fn time_since_last_incoming_traffic() -> Option<std::time::Duration> {
154
5355
    LAST_INCOMING_TRAFFIC.time_since_update().map(Into::into)
155
5355
}