1
//! Configuration logic for launching a circuit manager.
2
//!
3
//! # Semver note
4
//!
5
//! Most types in this module are re-exported by `arti-client`.
6

            
7
use tor_basic_utils::humantime_serde_option;
8
use tor_config::ConfigBuildError;
9

            
10
use derive_builder::Builder;
11
use serde::Deserialize;
12

            
13
use std::time::Duration;
14

            
15
/// Rules for building paths over the network.
16
///
17
/// This type is immutable once constructed.  To build one, use
18
/// [`PathConfigBuilder`], or deserialize it from a string.
19
///
20
/// You may change the PathConfig on a running Arti client.  Doing so changes
21
/// paths that are constructed in the future, and prevents requests from being
22
/// attached to existing circuits, if the configuration has become more
23
/// restrictive.
24
195
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
25
#[builder(build_fn(error = "ConfigBuildError"))]
26
5
#[builder(derive(Deserialize))]
27
#[serde(deny_unknown_fields)]
28
pub struct PathConfig {
29
    /// Set the length of a bit-prefix for a default IPv4 subnet-family.
30
    ///
31
    /// Any two relays will be considered to belong to the same family if their
32
    /// IPv4 addresses share at least this many initial bits.
33
    #[builder(default = "ipv4_prefix_default()")]
34
    #[serde(default = "ipv4_prefix_default")]
35
    ipv4_subnet_family_prefix: u8,
36

            
37
    /// Set the length of a bit-prefix for a default IPv6 subnet-family.
38
    ///
39
    /// Any two relays will be considered to belong to the same family if their
40
    /// IPv6 addresses share at least this many initial bits.
41
    #[builder(default = "ipv6_prefix_default()")]
42
    #[serde(default = "ipv6_prefix_default")]
43
    ipv6_subnet_family_prefix: u8,
44
}
45

            
46
/// Default value for ipv4_subnet_family_prefix.
47
152
fn ipv4_prefix_default() -> u8 {
48
152
    16
49
152
}
50
/// Default value for ipv6_subnet_family_prefix.
51
152
fn ipv6_prefix_default() -> u8 {
52
152
    32
53
152
}
54

            
55
impl PathConfig {
56
    /// Return a new [`PathConfigBuilder`].
57
2
    pub fn builder() -> PathConfigBuilder {
58
2
        PathConfigBuilder::default()
59
2
    }
60
    /// Return a subnet configuration based on these rules.
61
3094
    pub fn subnet_config(&self) -> tor_netdir::SubnetConfig {
62
3094
        tor_netdir::SubnetConfig::new(
63
3094
            self.ipv4_subnet_family_prefix,
64
3094
            self.ipv6_subnet_family_prefix,
65
3094
        )
66
3094
    }
67

            
68
    /// Return true if this configuration is at least as permissive as `other`.
69
    ///
70
    /// In other words, in other words, return true if every circuit permitted
71
    /// by `other` would also be permitted by this configuration.
72
6
    pub(crate) fn at_least_as_permissive_as(&self, other: &Self) -> bool {
73
6
        self.ipv4_subnet_family_prefix >= other.ipv4_subnet_family_prefix
74
4
            && self.ipv6_subnet_family_prefix >= other.ipv6_subnet_family_prefix
75
6
    }
76
}
77

            
78
impl Default for PathConfig {
79
11
    fn default() -> PathConfig {
80
11
        PathConfigBuilder::default()
81
11
            .build()
82
11
            .expect("unusable hardwired defaults")
83
11
    }
84
}
85

            
86
/// Configuration for preemptive circuits.
87
///
88
/// Preemptive circuits are built ahead of time, to anticipate client need. This
89
/// object configures the way in which this demand is anticipated and in which
90
/// these circuits are constructed.
91
///
92
/// This type is immutable once constructed. To create an object of this type,
93
/// use [`PreemptiveCircuitConfigBuilder`].
94
///
95
/// Except as noted, this configuration can be changed on a running Arti client.
96
214
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
97
#[builder(build_fn(error = "ConfigBuildError"))]
98
10
#[builder(derive(Deserialize))]
99
#[serde(deny_unknown_fields)]
100
pub struct PreemptiveCircuitConfig {
101
    /// If we have at least this many available circuits, we suspend
102
    /// construction of preemptive circuits. whether our available circuits
103
    /// support our predicted exit ports or not.
104
    #[builder(default = "default_preemptive_threshold()")]
105
    #[serde(default = "default_preemptive_threshold")]
106
    pub(crate) disable_at_threshold: usize,
107

            
108
    /// At startup, which exit ports should we expect that the client will want?
109
    ///
110
    /// (Over time, new ports are added to the predicted list, in response to
111
    /// what the client has actually requested.)
112
    ///
113
    /// This value cannot be changed on a running Arti client, because doing so
114
    /// would be meaningless.
115
    #[builder(default = "default_preemptive_ports()")]
116
    #[serde(default = "default_preemptive_ports")]
117
    pub(crate) initial_predicted_ports: Vec<u16>,
118

            
119
    /// After we see the client request a connection to a new port, how long
120
    /// should we predict that the client will still want to have circuits
121
    /// available for that port?
122
    #[builder(default = "default_preemptive_duration()")]
123
    #[serde(with = "humantime_serde", default = "default_preemptive_duration")]
124
    #[builder(attrs(serde(with = "humantime_serde_option")))]
125
    pub(crate) prediction_lifetime: Duration,
126

            
127
    /// How many available circuits should we try to have, at minimum, for each
128
    /// predicted exit port?
129
    #[builder(default = "default_preemptive_min_exit_circs_for_port()")]
130
    #[serde(default = "default_preemptive_min_exit_circs_for_port")]
131
    pub(crate) min_exit_circs_for_port: usize,
132
}
133

            
134
/// Configuration for circuit timeouts, expiration, and so on.
135
///
136
/// This type is immutable once constructed. To create an object of this type,
137
/// use [`CircuitTimingBuilder`].
138
///
139
/// You can change the CircuitTiming on a running Arti client.  Doing
140
/// so _should_ affect the expiration times of all circuits that are
141
/// not currently expired, and the request timing of all _future_
142
/// requests.  However, there are currently bugs: see bug
143
/// [#263](https://gitlab.torproject.org/tpo/core/arti/-/issues/263).
144
193
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
145
#[builder(build_fn(error = "ConfigBuildError"))]
146
12
#[builder(derive(Deserialize))]
147
#[serde(deny_unknown_fields)]
148
pub struct CircuitTiming {
149
    /// How long after a circuit has first been used should we give
150
    /// it out for new requests?
151
    #[builder(default = "default_max_dirtiness()")]
152
    #[serde(with = "humantime_serde", default = "default_max_dirtiness")]
153
    #[builder(attrs(serde(with = "humantime_serde_option")))]
154
    pub(crate) max_dirtiness: Duration,
155

            
156
    /// When a circuit is requested, we stop retrying new circuits
157
    /// after this much time.
158
    // TODO: Impose a maximum or minimum?
159
    #[builder(default = "default_request_timeout()")]
160
    #[serde(with = "humantime_serde", default = "default_request_timeout")]
161
    #[builder(attrs(serde(with = "humantime_serde_option")))]
162
    pub(crate) request_timeout: Duration,
163

            
164
    /// When a circuit is requested, we stop retrying new circuits after
165
    /// this many attempts.
166
    // TODO: Impose a maximum or minimum?
167
    #[builder(default = "default_request_max_retries()")]
168
    #[serde(default = "default_request_max_retries")]
169
    pub(crate) request_max_retries: u32,
170

            
171
    /// When waiting for requested circuits, wait at least this long
172
    /// before using a suitable-looking circuit launched by some other
173
    /// request.
174
    #[builder(default = "default_request_loyalty()")]
175
    #[serde(with = "humantime_serde", default = "default_request_loyalty")]
176
    #[builder(attrs(serde(with = "humantime_serde_option")))]
177
    pub(crate) request_loyalty: Duration,
178
}
179

            
180
/// Return default threshold
181
186
fn default_preemptive_threshold() -> usize {
182
186
    12
183
186
}
184

            
185
/// Return default target ports
186
182
fn default_preemptive_ports() -> Vec<u16> {
187
182
    vec![80, 443]
188
182
}
189

            
190
/// Return default duration
191
182
fn default_preemptive_duration() -> Duration {
192
182
    Duration::from_secs(60 * 60)
193
182
}
194

            
195
/// Return minimum circuits for an exit port
196
186
fn default_preemptive_min_exit_circs_for_port() -> usize {
197
186
    2
198
186
}
199

            
200
/// Return the default value for `max_dirtiness`.
201
150
fn default_max_dirtiness() -> Duration {
202
150
    Duration::from_secs(60 * 10)
203
150
}
204

            
205
/// Return the default value for `request_timeout`.
206
151
fn default_request_timeout() -> Duration {
207
151
    Duration::from_secs(60)
208
151
}
209

            
210
/// Return the default value for `request_max_retries`.
211
151
fn default_request_max_retries() -> u32 {
212
151
    32
213
151
}
214

            
215
/// Return the default request loyalty timeout.
216
151
fn default_request_loyalty() -> Duration {
217
151
    Duration::from_millis(50)
218
151
}
219

            
220
// NOTE: it seems that `unwrap` may be safe because of builder defaults
221
// check `derive_builder` documentation for details
222
// https://docs.rs/derive_builder/0.10.2/derive_builder/#default-values
223
#[allow(clippy::unwrap_used)]
224
impl Default for CircuitTiming {
225
10
    fn default() -> Self {
226
10
        CircuitTimingBuilder::default().build().unwrap()
227
10
    }
228
}
229

            
230
impl CircuitTiming {
231
    /// Return a new [`CircuitTimingBuilder`]
232
    pub fn builder() -> CircuitTimingBuilder {
233
        CircuitTimingBuilder::default()
234
    }
235
}
236

            
237
impl Default for PreemptiveCircuitConfig {
238
28
    fn default() -> Self {
239
28
        PreemptiveCircuitConfigBuilder::default()
240
28
            .build()
241
28
            .expect("preemptive circuit defaults")
242
28
    }
243
}
244

            
245
impl PreemptiveCircuitConfig {
246
    /// Return a new [`PreemptiveCircuitConfigBuilder`]
247
4
    pub fn builder() -> PreemptiveCircuitConfigBuilder {
248
4
        PreemptiveCircuitConfigBuilder::default()
249
4
    }
250
}
251

            
252
/// Configuration for a circuit manager.
253
///
254
/// This configuration includes information about how to build paths
255
/// on the Tor network, and rules for timeouts and retries on Tor
256
/// circuits.
257
///
258
/// This type is immutable once constructed.  To create an object of
259
/// this type, use [`CircMgrConfigBuilder`], or deserialize it from a
260
/// string.  (Arti generally uses Toml for configuration, but you can
261
/// use other formats if you prefer.)
262
28
#[derive(Debug, Clone, Builder, Default, Eq, PartialEq)]
263
#[builder(build_fn(error = "ConfigBuildError"))]
264
pub struct CircMgrConfig {
265
    /// Override the default required distance for two relays to share
266
    /// the same circuit.
267
    #[builder(default)]
268
    pub(crate) path_rules: PathConfig,
269

            
270
    /// Timing and retry information related to circuits themselves.
271
    #[builder(default)]
272
    pub(crate) circuit_timing: CircuitTiming,
273

            
274
    /// Information related to preemptive circuits.
275
    #[builder(default)]
276
    pub(crate) preemptive_circuits: PreemptiveCircuitConfig,
277
}
278

            
279
impl CircMgrConfig {
280
    /// Return a new [`CircMgrConfigBuilder`].
281
    pub fn builder() -> CircMgrConfigBuilder {
282
        CircMgrConfigBuilder::default()
283
    }
284
}
285

            
286
#[cfg(test)]
287
mod test {
288
    #![allow(clippy::unwrap_used)]
289
    use super::*;
290

            
291
    #[test]
292
    fn path_config() {
293
        let pc1 = PathConfig::default();
294
        // Because these configurations consider _fewer_ nodes to be in the same
295
        // families, they are _more_ permissive about what circuits we can
296
        // build.
297
        let pc2 = PathConfig::builder()
298
            .ipv4_subnet_family_prefix(32)
299
            .build()
300
            .unwrap();
301
        let pc3 = PathConfig::builder()
302
            .ipv6_subnet_family_prefix(128)
303
            .build()
304
            .unwrap();
305

            
306
        assert!(pc2.at_least_as_permissive_as(&pc1));
307
        assert!(pc3.at_least_as_permissive_as(&pc1));
308
        assert!(pc1.at_least_as_permissive_as(&pc1));
309
        assert!(!pc1.at_least_as_permissive_as(&pc2));
310
        assert!(!pc1.at_least_as_permissive_as(&pc3));
311
        assert!(!pc3.at_least_as_permissive_as(&pc2));
312
    }
313
}