1
//! Implements a usable view of Tor network parameters.
2
//!
3
//! The Tor consensus document contains a number of 'network
4
//! parameters', which are integer-valued items voted on by the
5
//! directory authorities.  They are used to tune the behavior of
6
//! numerous aspects of the network.
7
//! A set of Tor network parameters
8
//!
9
//! The Tor consensus document contains a number of 'network
10
//! parameters', which are integer-valued items voted on by the
11
//! directory authorities.  These parameters are used to tune the
12
//! behavior of numerous aspects of the network.
13
//!
14
//! This type differs from
15
//! [`NetParams`](tor_netdoc::doc::netstatus::NetParams) in that it
16
//! only exposes a set of parameters recognized by arti.  In return
17
//! for this restriction, it makes sure that the values it gives are
18
//! in range, and provides default values for any parameters that are
19
//! missing.
20

            
21
use tor_units::{
22
    BoundedInt32, IntegerDays, IntegerMilliseconds, IntegerMinutes, IntegerSeconds, Percentage,
23
    SendMeVersion,
24
};
25

            
26
/// Upper limit for channel padding timeouts
27
///
28
/// This is just a safety catch which might help prevent integer overflow,
29
/// and also might prevent a client getting permanently stuck in a state
30
/// where it ought to send padding but never does.
31
///
32
/// The actual value is stolen from C Tor as per
33
///   <https://gitlab.torproject.org/tpo/core/arti/-/merge_requests/586#note_2813638>
34
/// pending an update to the specifications
35
///   <https://gitlab.torproject.org/tpo/core/torspec/-/issues/120>
36
pub const CHANNEL_PADDING_TIMEOUT_UPPER_BOUND: i32 = 60_000;
37

            
38
/// An object that can be constructed from an i32, with saturating semantics.
39
pub trait FromInt32Saturating {
40
    /// Construct an instance of this object from `val`.
41
    ///
42
    /// If `val` is too low, treat it as the lowest value that would be
43
    /// valid.  If `val` is too high, treat it as the highest value that
44
    /// would be valid.
45
    fn from_saturating(val: i32) -> Self;
46

            
47
    /// Try to construct an instance of this object from `val`.
48
    ///
49
    /// If `val` is out of range, return an error instead.
50
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
51
    where
52
        Self: Sized;
53
}
54

            
55
impl FromInt32Saturating for i32 {
56
    fn from_saturating(val: i32) -> Self {
57
        val
58
    }
59

            
60
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
61
    where
62
        Self: Sized,
63
    {
64
        Ok(val)
65
    }
66
}
67
impl<const L: i32, const H: i32> FromInt32Saturating for BoundedInt32<L, H> {
68
51
    fn from_saturating(val: i32) -> Self {
69
51
        Self::saturating_new(val)
70
51
    }
71

            
72
14143
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
73
14143
    where
74
14143
        Self: Sized,
75
14143
    {
76
14143
        Self::checked_new(val)
77
14143
    }
78
}
79
impl<T: Copy + Into<f64> + FromInt32Saturating> FromInt32Saturating for Percentage<T> {
80
4
    fn from_saturating(val: i32) -> Self {
81
4
        Self::new(T::from_saturating(val))
82
4
    }
83

            
84
1106
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
85
1106
    where
86
1106
        Self: Sized,
87
1106
    {
88
1106
        Ok(Self::new(T::from_checked(val)?))
89
1106
    }
90
}
91
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMilliseconds<T> {
92
    fn from_saturating(val: i32) -> Self {
93
        Self::new(T::from_saturating(val))
94
    }
95

            
96
824
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
97
824
    where
98
824
        Self: Sized,
99
824
    {
100
824
        Ok(Self::new(T::from_checked(val)?))
101
824
    }
102
}
103
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerSeconds<T> {
104
    fn from_saturating(val: i32) -> Self {
105
        Self::new(T::from_saturating(val))
106
    }
107

            
108
102
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
109
102
    where
110
102
        Self: Sized,
111
102
    {
112
102
        Ok(Self::new(T::from_checked(val)?))
113
102
    }
114
}
115
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMinutes<T> {
116
    fn from_saturating(val: i32) -> Self {
117
        Self::new(T::from_saturating(val))
118
    }
119

            
120
4
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
121
4
    where
122
4
        Self: Sized,
123
4
    {
124
4
        Ok(Self::new(T::from_checked(val)?))
125
4
    }
126
}
127
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerDays<T> {
128
    fn from_saturating(val: i32) -> Self {
129
        Self::new(T::from_saturating(val))
130
    }
131

            
132
6
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
133
6
    where
134
6
        Self: Sized,
135
6
    {
136
6
        Ok(Self::new(T::from_checked(val)?))
137
6
    }
138
}
139
impl FromInt32Saturating for SendMeVersion {
140
    fn from_saturating(val: i32) -> Self {
141
        Self::new(val.clamp(0, 255) as u8)
142
    }
143

            
144
10
    fn from_checked(val: i32) -> Result<Self, tor_units::Error>
145
10
    where
146
10
        Self: Sized,
147
10
    {
148
10
        let val = BoundedInt32::<0, 255>::checked_new(val)?;
149
10
        Ok(Self::new(val.get() as u8))
150
10
    }
151
}
152

            
153
/// A macro to help us declare the net parameters object.  It lets us
154
/// put the information about each parameter in just one place, even
155
/// though it will later get split between the struct declaration, the
156
/// Default implementation, and the implementation of
157
/// `saturating_update_override`.
158
macro_rules! declare_net_parameters {
159
    {
160
        $(#[$s_meta:meta])* $s_v:vis struct $s_name:ident {
161
            $(
162
                $(#[$p_meta:meta])* $p_v:vis
163
                    $p_name:ident : $p_type:ty
164
                    = ($p_dflt:expr) from $p_string:literal
165
            ),*
166
            $( , )?
167
        }
168
    } =>
169
    {
170
        $(#[$s_meta])* $s_v struct $s_name {
171
            $(
172
                $(#[$p_meta])* $p_v $p_name : $p_type
173
            ),*
174
        }
175

            
176
        impl $s_name {
177
            /// Try to construct an instance of with its default values.
178
            ///
179
            /// (This should always succeed, unless one of the default values
180
            /// is out-of-bounds for the type.)
181
13787
            fn default_values() -> Result<Self, tor_units::Error> {
182
                Ok(Self {
183
13787
                    $( $p_name : $p_dflt.try_into()? ),*
184
                })
185
13787
            }
186
            /// Replace the current value for the parameter identified in the
187
            /// consensus with `key` with a new value `val`.
188
            ///
189
            /// Uses saturating semantics if the new value is out-of-range.
190
            ///
191
            /// Returns true if the key was recognized, and false otherwise.
192
14161
            fn set_saturating(&mut self, key: &str, val: i32) -> bool {
193
14161
                match key {
194
8
                    $( $p_string => self.$p_name = {
195
                        type T = $p_type;
196
                        match T::from_checked(val) {
197
                            Ok(v) => v,
198
                            Err(e) => {
199
                                tracing::warn!("For key {key}, clamping out of range value: {e:?}");
200
                                T::from_saturating(val)
201
                            }
202
                        }
203
                    }, )*
204
8
                    _ => return false,
205
                }
206
14153
                true
207
14161
            }
208
        }
209
    }
210
}
211

            
212
declare_net_parameters! {
213

            
214
/// This structure holds recognized configuration parameters. All values are type-safe,
215
/// and where applicable clamped to be within range.
216
#[derive(Clone, Debug)]
217
#[non_exhaustive]
218
pub struct NetParameters {
219
    /// A weighting factor for bandwidth calculations
220
    pub bw_weight_scale: BoundedInt32<1, { i32::MAX }> = (10_000)
221
        from "bwweightscale",
222
    /// If true, do not attempt to learn circuit-build timeouts at all.
223
    pub cbt_learning_disabled: BoundedInt32<0, 1> = (0)
224
        from "cbtdisabled",
225
    /// Number of histograms bins to consider when estimating Xm for a
226
    /// Pareto-based circuit timeout estimator.
227
    pub cbt_num_xm_modes: BoundedInt32<1, 20> = (10)
228
        from "cbtnummodes",
229
    /// How many recent circuit success/timeout statuses do we remember
230
    /// when trying to tell if our circuit timeouts are too low?
231
    pub cbt_success_count: BoundedInt32<3, 1_000> = (20)
232
        from "cbtrecentcount",
233
    /// How many timeouts (in the last `cbt_success_count` observations)
234
    /// indicates that our circuit timeouts are too low?
235
    pub cbt_max_timeouts: BoundedInt32<3, 10_000> = (18)
236
        from "cbtmaxtimeouts",
237
    /// Smallest number of circuit build times we have to view in order to use
238
    /// our Pareto-based circuit timeout estimator.
239
    pub cbt_min_circs_for_estimate: BoundedInt32<1, 10_000> = (100)
240
        from "cbtmincircs",
241
    /// Quantile to use when determining the correct circuit timeout value
242
    /// with our Pareto estimator.
243
    ///
244
    /// (We continue building circuits after this timeout, but only
245
    /// for build-time measurement purposes.)
246
    pub cbt_timeout_quantile: Percentage<BoundedInt32<10, 99>> = (80)
247
        from "cbtquantile",
248
    /// Quantile to use when determining when to abandon circuits completely
249
    /// with our Pareto estimator.
250
    pub cbt_abandon_quantile: Percentage<BoundedInt32<10, 99>> = (99)
251
        from "cbtclosequantile",
252
    /// Lowest permissible timeout value for Pareto timeout estimator.
253
    pub cbt_min_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (10)
254
        from "cbtmintimeout",
255
    /// Timeout value to use for our Pareto timeout estimator when we have
256
    /// no initial estimate.
257
    pub cbt_initial_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (60_000)
258
        from "cbtinitialtimeout",
259
    /// When we don't have a good build-time estimate yet, how long
260
    /// (in seconds) do we wait between trying to launch build-time
261
    /// testing circuits through the network?
262
    pub cbt_testing_delay: IntegerSeconds<BoundedInt32<1, { i32::MAX }>> = (10)
263
        from "cbttestfreq",
264
    /// How many circuits can be open before we will no longer
265
    /// consider launching testing circuits to learn average build
266
    /// times?
267
    pub cbt_max_open_circuits_for_testing: BoundedInt32<0, 14> = (10)
268
        from "cbtmaxopencircs",
269

            
270
    /// Specifies which congestion control algorithm clients should use.
271
    /// Current values are 0 for the fixed window algorithm and 2 for Vegas.
272
    ///
273
    /// TODO: Flip this to 2 once CC circuit negotiation and Flow Control is in which would be the
274
    /// same default as C-tor. Reason is that we can't have it to 2 for now else it makes the
275
    /// consensus download fails.
276
    pub cc_alg: BoundedInt32<0, 2> = (0)
277
        from "cc_alg",
278

            
279
    /// Vegas only. This parameter defines the integer number of 'cc_sendme_inc' multiples
280
    /// of gap allowed between inflight and cwnd, to still declare the cwnd full.
281
    pub cc_cwnd_full_gap: BoundedInt32<0, { i16::MAX as i32 }> = (4444)
282
        from "cc_cwnd_full_gap",
283
    /// Vegas only. This parameter defines a low watermark in percent.
284
    pub cc_cwnd_full_minpct: Percentage<BoundedInt32<0, 100>> = (25)
285
        from "cc_cwnd_full_minpct",
286
    /// Vegas only. This parameter governs how often a cwnd must be full.
287
    pub cc_cwnd_full_per_cwnd: BoundedInt32<0, 1> = (1)
288
        from "cc_cwnd_full_per_cwnd",
289

            
290
    /// Initial congestion window for new congestion control Tor clients.
291
    pub cc_cwnd_init: BoundedInt32<31, 10_000> = (4 * 31)
292
        from "cc_cwnd_init",
293
    /// Percentage of the current congestion window to increment by during slow start,
294
    /// every congestion window.
295
    pub cc_cwnd_inc_pct_ss: Percentage<BoundedInt32<1, 500>> = (50)
296
        from "cc_cwnd_inc_pct_ss",
297
    /// How much to increment the congestion window by during steady state,
298
    /// every congestion window.
299
    pub cc_cwnd_inc: BoundedInt32<1, 1000> = (31)
300
        from "cc_cwnd_inc",
301
    /// How often we update our congestion window, per cwnd worth of packets.
302
    /// (For example, if this is 2, we will update the window twice every window.)
303
    pub cc_cwnd_inc_rate: BoundedInt32<1, 250> = (1)
304
        from "cc_cwnd_inc_rate",
305
    /// The minimum allowed congestion window.
306
    pub cc_cwnd_min: BoundedInt32<31, 1000> = (31)
307
        from "cc_cwnd_min",
308
    /// The maximum allowed congestion window.
309
    pub cc_cwnd_max: BoundedInt32<500, { i32::MAX }> = (i32::MAX)
310
        from "cc_cwnd_max",
311

            
312
    /// This specifies the N in N-EWMA smoothing of RTT and BDP estimation,
313
    /// as a percent of the number of SENDME acks in a congestion window.
314
    ///
315
    /// A percentage over 100% indicates smoothing with more than one
316
    /// congestion window's worth of SENDMEs.
317
    pub cc_ewma_cwnd_pct: Percentage<BoundedInt32<1, 255>> = (50)
318
        from "cc_ewma_cwnd_pct",
319
    /// This specifies the max N in N_EWMA smoothing of RTT and BDP estimation.
320
    pub cc_ewma_max: BoundedInt32<2, { i32::MAX }> = (10)
321
        from "cc_ewma_max",
322
    /// This specifies the N in N_EWMA smoothing of RTT during Slow Start.
323
    pub cc_ewma_ss: BoundedInt32<2, { i32::MAX }> = (2)
324
        from "cc_ewma_ss",
325
    /// Describes a percentile average between RTT_min and RTT_current_ewma,
326
    /// for use to reset RTT_min, when the congestion window hits cwnd_min.
327
    pub cc_rtt_reset_pct: Percentage<BoundedInt32<0, 100>> = (100)
328
        from "cc_rtt_reset_pct",
329
    /// Specifies how many cells a SENDME acks.
330
    pub cc_sendme_inc: BoundedInt32<1, 254> = (31)
331
        from "cc_sendme_inc",
332
    /// This parameter provides a hard-max on the congestion window in Slow Start.
333
    pub cc_ss_max: BoundedInt32<500, { i32::MAX }> = (5000)
334
        from "cc_ss_max",
335

            
336
    /// Vegas alpha parameter for an Exit circuit.
337
    pub cc_vegas_alpha_exit: BoundedInt32<0, 1000> = (3 * 62)
338
        from "cc_vegas_alpha_exit",
339
    /// Vegas beta parameter for an Exit circuit.
340
    pub cc_vegas_beta_exit: BoundedInt32<0, 1000> = (4 * 62)
341
        from "cc_vegas_beta_exit",
342
    /// Vegas delta parameter for an Exit circuit.
343
    pub cc_vegas_delta_exit: BoundedInt32<0, 1000> = (5 * 62)
344
        from "cc_vegas_delta_exit",
345
    /// Vegas gamma parameter for an Exit circuit.
346
    pub cc_vegas_gamma_exit: BoundedInt32<0, 1000> = (3 * 62)
347
        from "cc_vegas_gamma_exit",
348

            
349
    /// Vegas alpha parameter for an Onion circuit.
350
    pub cc_vegas_alpha_onion: BoundedInt32<0, 1000> = (3 * 62)
351
        from "cc_vegas_alpha_onion",
352
    /// Vegas beta parameter for an Onion circuit.
353
    pub cc_vegas_beta_onion: BoundedInt32<0, 1000> = (6 * 62)
354
        from "cc_vegas_beta_onion",
355
    /// Vegas delta parameter for an Onion circuit.
356
    pub cc_vegas_delta_onion: BoundedInt32<0, 1000> = (7 * 62)
357
        from "cc_vegas_delta_onion",
358
    /// Vegas gamma parameter for an Onion circuit.
359
    pub cc_vegas_gamma_onion: BoundedInt32<0, 1000> = (4 * 62)
360
        from "cc_vegas_gamma_onion",
361

            
362
    /// Parameter for Exit circuit that describe the the RFC3742 'cap', after which
363
    /// congestion window increments are reduced. The MAX disables RFC3742.
364
    pub cc_vegas_sscap_exit: BoundedInt32<100, { i32::MAX }> = (600)
365
        from "cc_sscap_exit",
366
    /// Parameter for Onion circuit that describe the the RFC3742 'cap', after which
367
    /// congestion window increments are reduced. The MAX disables RFC3742.
368
    pub cc_vegas_sscap_onion: BoundedInt32<100, { i32::MAX }> = (475)
369
        from "cc_sscap_onion",
370

            
371
    /// The maximum cell window size?
372
    pub circuit_window: BoundedInt32<100, 1000> = (1_000)
373
        from "circwindow",
374
    /// The decay parameter for circuit priority
375
    pub circuit_priority_half_life: IntegerMilliseconds<BoundedInt32<1, { i32::MAX }>> = (30_000)
376
        from "CircuitPriorityHalflifeMsec",
377
    /// Whether to perform circuit extensions by Ed25519 ID
378
    pub extend_by_ed25519_id: BoundedInt32<0, 1> = (0)
379
        from "ExtendByEd25519ID",
380

            
381
    /// If we have excluded so many possible guards that the
382
    /// available fraction is below this threshold, we should use a different
383
    /// guard sample.
384
    pub guard_meaningful_restriction: Percentage<BoundedInt32<1,100>> = (20)
385
        from "guard-meaningful-restriction-percent",
386

            
387
    /// We should warn the user if they have excluded so many guards
388
    /// that the available fraction is below this threshold.
389
    pub guard_extreme_restriction: Percentage<BoundedInt32<1,100>> = (1)
390
        from "guard-extreme-restriction-percent",
391

            
392
    /// How long should we keep an unconfirmed guard (one we have not
393
    /// contacted) before removing it from the guard sample?
394
    pub guard_lifetime_unconfirmed: IntegerDays<BoundedInt32<1, 3650>> = (120)
395
        from "guard-lifetime-days",
396

            
397
    /// How long should we keep a _confirmed_ guard (one we have contacted)
398
    /// before removing it from the guard sample?
399
    pub guard_lifetime_confirmed: IntegerDays<BoundedInt32<1, 3650>> = (60)
400
        from "guard-confirmed-min-lifetime-days",
401

            
402
    /// If all circuits have failed for this interval, then treat the internet
403
    /// as "probably down", and treat any guard failures in that interval
404
    /// as unproven.
405
    pub guard_internet_likely_down: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (600)
406
        from "guard-internet-likely-down-interval",
407
    /// Largest number of guards that a client should try to maintain in
408
    /// a sample of possible guards.
409
    pub guard_max_sample_size: BoundedInt32<1, {i32::MAX}> = (60)
410
        from "guard-max-sample-size",
411
    /// Largest fraction of guard bandwidth on the network that a client
412
    /// should try to remain in a sample of possible guards.
413
    pub guard_max_sample_threshold: Percentage<BoundedInt32<1,100>> = (20)
414
        from "guard-max-sample-threshold",
415

            
416
    /// If the client ever has fewer than this many guards in their sample,
417
    /// after filtering out unusable guards, they should try to add more guards
418
    /// to the sample (if allowed).
419
    pub guard_filtered_min_sample_size: BoundedInt32<1,{i32::MAX}> = (20)
420
        from "guard-min-filtered-sample-size",
421

            
422
    /// The number of confirmed guards that the client should treat as
423
    /// "primary guards".
424
    pub guard_n_primary: BoundedInt32<1,{i32::MAX}> = (3)
425
        from "guard-n-primary-guards",
426
    /// The number of primary guards that the client should use in parallel.
427
    /// Other primary guards won't get used unless earlier ones are down.
428
    pub guard_use_parallelism: BoundedInt32<1, {i32::MAX}> = (1)
429
        from "guard-n-primary-guards-to-use",
430
    /// The number of primary guards that the client should use in
431
    /// parallel.  Other primary directory guards won't get used
432
    /// unless earlier ones are down.
433
    pub guard_dir_use_parallelism: BoundedInt32<1, {i32::MAX}> = (3)
434
        from "guard-n-primary-dir-guards-to-use",
435

            
436
    /// When trying to confirm nonprimary guards, if a guard doesn't
437
    /// answer for more than this long in seconds, treat any lower-
438
    /// priority guards as possibly usable.
439
    pub guard_nonprimary_connect_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (15)
440
        from "guard-nonprimary-guard-connect-timeout",
441
    /// When trying to confirm nonprimary guards, if a guard doesn't
442
    /// answer for more than _this_ long in seconds, treat it as down.
443
    pub guard_nonprimary_idle_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (600)
444
        from "guard-nonprimary-guard-idle-timeout",
445
    /// If a guard has been unlisted in the consensus for at least this
446
    /// long, remove it from the consensus.
447
    pub guard_remove_unlisted_after: IntegerDays<BoundedInt32<1,3650>> = (20)
448
        from "guard-remove-unlisted-guards-after-days",
449

            
450

            
451
    /// The minimum threshold for circuit patch construction
452
    pub min_circuit_path_threshold: Percentage<BoundedInt32<25, 95>> = (60)
453
        from "min_paths_for_circs_pct",
454

            
455
    /// Channel padding, low end of random padding interval, milliseconds
456
    ///
457
    /// `nf_ito` stands for "netflow inactive timeout".
458
    pub nf_ito_low: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (1500)
459
        from "nf_ito_low",
460
    /// Channel padding, high end of random padding interval, milliseconds
461
    pub nf_ito_high: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9500)
462
        from "nf_ito_high",
463
    /// Channel padding, low end of random padding interval (reduced padding) milliseconds
464
    pub nf_ito_low_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9000)
465
        from "nf_ito_low_reduced",
466
    /// Channel padding, high end of random padding interval (reduced padding) , milliseconds
467
    pub nf_ito_high_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (14000)
468
        from "nf_ito_high_reduced",
469

            
470
    /// The minimum sendme version to accept.
471
    pub sendme_accept_min_version: SendMeVersion = (0)
472
        from "sendme_accept_min_version",
473
    /// The minimum sendme version to transmit.
474
    pub sendme_emit_min_version: SendMeVersion = (0)
475
        from "sendme_emit_min_version",
476

            
477
    /// How long should never-used client circuits stay available,
478
    /// in the steady state?
479
    pub unused_client_circ_timeout: IntegerSeconds<BoundedInt32<60, 86_400>> = (30*60)
480
        from "nf_conntimeout_clients",
481
    /// When we're learning circuit timeouts, how long should never-used client
482
    /// circuits stay available?
483
    pub unused_client_circ_timeout_while_learning_cbt: IntegerSeconds<BoundedInt32<10, 60_000>> = (3*60)
484
        from "cbtlearntimeout",
485

            
486
    /// Lower bound on the number of INTRODUCE2 cells to allow per introduction
487
    /// circuit before the service decides to rotate to a new introduction
488
    /// circuit.
489
    pub hs_introcirc_requests_min: BoundedInt32<0, {i32::MAX}> = (16384)
490
        from "hs_intro_min_introduce2",
491

            
492
    /// Upper bound on the number of INTRODUCE2 cells to allow per introduction
493
    /// circuit before the service decides to rotate to a new introduction
494
    /// circuit.
495
    pub hs_introcirc_requests_max: BoundedInt32<0, {i32::MAX}> = (32768)
496
        from "hs_intro_max_introduce2",
497

            
498
    /// Lower bound on the lifetime of an introduction point.
499
    pub hs_intro_min_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (18 * 60 * 60)
500
        from "hs_intro_min_lifetime",
501

            
502
    /// Upper bound on the lifetime of an introduction point.
503
    pub hs_intro_max_lifetime: IntegerSeconds<BoundedInt32<0, {i32::MAX}>> = (24 * 60 * 60)
504
        from "hs_intro_max_lifetime",
505

            
506
    /// Number of "extra" introduction points that an onion service is allowed
507
    /// to open based on demand.
508
    pub hs_intro_num_extra_intropoints: BoundedInt32<0, 128> = (2)
509
        from "hs_intro_num_extra",
510

            
511
    /// Largest number of allowable relay cells received
512
    /// in reply to an hsdir download attempt.
513
    pub hsdir_dl_max_reply_cells: BoundedInt32<2, 2304> = (110)
514
        from "hsdir_dl_max_reply_cells",
515

            
516
    /// Largest number of allowable relay cells received
517
    /// in reply to an hsdir upload attempt.
518
    pub hsdir_ul_max_reply_cells: BoundedInt32<2, 1024> = (8)
519
        from "hsdir_ul_max_reply_cells",
520

            
521
    /// The duration of a time period, as used in the onion service directory
522
    /// protocol.
523
    ///
524
    /// During each "time period", each onion service gets a different blinded
525
    /// ID, and the hash ring gets a new layout.
526
    pub hsdir_timeperiod_length: IntegerMinutes<BoundedInt32<5, 14400>> = (1440)
527
        from "hsdir_interval",
528

            
529
    /// The number of positions at the hash ring where an onion service
530
    /// descriptor should be stored.
531
    pub hsdir_n_replicas: BoundedInt32<1, 16> = (2)
532
        from "hsdir_n_replicas",
533

            
534
    /// The number of HSDir instances, at each position in the hash ring, that
535
    /// should be considered when downloading an onion service descriptor.
536
    pub hsdir_spread_fetch: BoundedInt32<1, 128> = (3)
537
        from "hsdir_spread_fetch",
538

            
539
    /// The number of HSDir instances, at each position in the hash ring, that
540
    /// should be considered when uploading an onion service descriptor.
541
    pub hsdir_spread_store: BoundedInt32<1,128> = (4)
542
        from "hsdir_spread_store",
543

            
544
    /// Largest allowable v3 onion service size (in bytes).
545
    pub hsdir_max_desc_size: BoundedInt32<1, {i32::MAX}> = (50_000)
546
        from "HSV3MaxDescriptorSize",
547

            
548
    /// Largest number of failures to rendezvous that an onion service should
549
    /// allow for a request.
550
    pub hs_service_rendezvous_failures_max: BoundedInt32<1, 10> = (2)
551
        from "hs_service_max_rdv_failures",
552

            
553
    /// If set to 1, introduction points use the INTRODUCE1 rate limiting
554
    /// defense when no `DosParams` are sent.
555
    ///
556
    /// See <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSDefense>
557
    pub hs_intro_dos_enabled: BoundedInt32<0, 1> = (0)
558
        from "HiddenServiceEnableIntroDoSDefense",
559

            
560
    /// Default _rate_ value for an introduction point to use for INTRODUCE1 rate
561
    /// limiting when no `DosParams` value is sent, in messages per second.
562
    ///
563
    /// See
564
    /// <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSBurstPerSec>
565
    pub hs_intro_dos_max_burst: BoundedInt32<0, {i32::MAX}> = (200)
566
        from "HiddenServiceEnableIntroDoSBurstPerSec",
567

            
568
    /// Default _burst_ value for an introduction point to use for INTRODUCE1 rate
569
    /// limiting when no `DosParams` value is sent.
570
    ///
571
    /// See
572
    /// <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSRatePerSec>
573
    pub hs_intro_dos_rate: BoundedInt32<0, {i32::MAX}> = (25)
574
        from  "HiddenServiceEnableIntroDoSRatePerSec",
575

            
576
    /// Maximum Proof-of-Work V1 effort clients should send. Services will cap higher efforts to
577
    /// this value.
578
    ///
579
    /// See
580
    /// <https://spec.torproject.org/proposals/362-update-pow-control-loop.html>
581
    // TODO POW: Make u32, or change spec.
582
    pub hs_pow_v1_max_effort: BoundedInt32<0, {i32::MAX}> = (10_000)
583
        from "HiddenServiceProofOfWorkV1MaxEffort",
584

            
585
    /// The maximum age for items in the onion service intro queue, when Proof-of-Work V1 is
586
    /// enabled.
587
    ///
588
    /// See
589
    /// <https://spec.torproject.org/proposals/362-update-pow-control-loop.html>
590
    pub hs_pow_v1_service_intro_timeout: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (300)
591
        from "HiddenServiceProofOfWorkV1ServiceIntroTimeoutSeconds",
592

            
593
    /// The default Proof-of-Work V1 decay adjustment value.
594
    ///
595
    /// See
596
    /// <https://spec.torproject.org/proposals/362-update-pow-control-loop.html>
597
    pub hs_pow_v1_default_decay_adjustment: Percentage<BoundedInt32<0, 99>> = (0)
598
        from "HiddenServiceProofOfWorkV1ServiceDefaultDecayAdjustment",
599

            
600
    /// The type of vanguards to use by default when building onion service circuits:
601
    ///
602
    /// ```text
603
    ///    0: No vanguards.
604
    ///    1: Lite vanguards.
605
    ///    2: Full vanguards.
606
    /// ```
607
    ///
608
    /// See
609
    /// <https://spec.torproject.org/param-spec.html#vanguards>
610
    pub vanguards_enabled: BoundedInt32<0, 2> = (1)
611
        from "vanguards-enabled",
612

            
613
    /// If higher than `vanguards-enabled`,
614
    /// and we are running an onion service,
615
    /// we use this level for all our onion service circuits:
616
    ///
617
    /// ```text
618
    ///    0: No vanguards.
619
    ///    1: Lite vanguards.
620
    ///    2: Full vanguards.
621
    /// ```
622
    ///
623
    /// See
624
    /// <https://spec.torproject.org/param-spec.html#vanguards>
625
    pub vanguards_hs_service: BoundedInt32<0, 2> = (2)
626
        from "vanguards-hs-service",
627

            
628
    /// The number of vanguards in the L2 vanguard set.
629
    ///
630
    /// See
631
    /// <https://spec.torproject.org/param-spec.html#vanguards>
632
    pub guard_hs_l2_number: BoundedInt32<1, {i32::MAX}> = (4)
633
        from  "guard-hs-l2-number",
634

            
635
    /// The minimum lifetime of L2 vanguards.
636
    ///
637
    /// See
638
    /// <https://spec.torproject.org/param-spec.html#vanguards>
639
    pub guard_hs_l2_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (86400)
640
        from  "guard-hs-l2-lifetime-min",
641

            
642
    /// The maximum lifetime of L2 vanguards.
643
    ///
644
    /// See
645
    /// <https://spec.torproject.org/param-spec.html#vanguards>
646
    pub guard_hs_l2_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (1036800)
647
        from  "guard-hs-l2-lifetime-max",
648

            
649
    /// The number of vanguards in the L3 vanguard set.
650
    ///
651
    /// See
652
    /// <https://spec.torproject.org/param-spec.html#vanguards>
653
    pub guard_hs_l3_number: BoundedInt32<1, {i32::MAX}> = (8)
654
        from  "guard-hs-l3-number",
655

            
656
    /// The minimum lifetime of L3 vanguards.
657
    ///
658
    /// See
659
    /// <https://spec.torproject.org/param-spec.html#vanguards>
660
    pub guard_hs_l3_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (3600)
661
        from  "guard-hs-l3-lifetime-min",
662

            
663
    /// The maximum lifetime of L3 vanguards.
664
    ///
665
    /// See
666
    /// <https://spec.torproject.org/param-spec.html#vanguards>
667
    pub guard_hs_l3_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (172800)
668
        from  "guard-hs-l3-lifetime-max",
669

            
670
    /// The KIST to use by default when building inter-relay channels:
671
    ///
672
    /// ```text
673
    ///    0: No KIST.
674
    ///    1: KIST using TCP_NOTSENT_LOWAT.
675
    /// ```
676
    ///
677
    // TODO(KIST): add this to param spec
678
    // TODO(KIST): make this default to 1 (KIST with TCP_NOTSENT_LOWAT)
679
    // when we're confident it behaves correctly in conjunction with cc
680
    pub kist_enabled: BoundedInt32<0, 1> = (0)
681
        from "kist-enabled",
682

            
683
    /// If `kist_enabled` is `1` (KIST using TCP_NOTSENT_LOWAT),
684
    /// the TCP_NOTSENT_LOWAT value to set for each channel.
685
    ///
686
    /// If `kist_enabled` is `0` (disabled),
687
    /// the TCP_NOTSENT_LOWAT option is set to 0xFFFFFFFF (u32::MAX).
688
    ///
689
    // TODO(KIST): technically, this should be a u32, not an i32.
690
    // However, because we're using it to limit the amount of unsent data in TCP sockets,
691
    // it's unlikely we're ever going to want to set this to a high value,
692
    // so an upper bound of i32::MAX is good enough for our purposes.
693
    pub kist_tcp_notsent_lowat: BoundedInt32<1, {i32::MAX}> = (1)
694
        from  "kist-tcp-notsent-lowat",
695

            
696
    /// If true, we use lists of family members
697
    /// when making decisions about which relays belong to the same family.
698
    pub use_family_lists: BoundedInt32<0,1> = (1)
699
        from "use-family-lists",
700

            
701
    /// If true, we use lists of family IDs
702
    /// when making decisions about which relays belong to the same family.
703
    pub use_family_ids: BoundedInt32<0,1> = (1)
704
        from "use-family-ids",
705
}
706

            
707
}
708

            
709
impl Default for NetParameters {
710
13787
    fn default() -> Self {
711
13787
        NetParameters::default_values().expect("Default parameters were out-of-bounds")
712
13787
    }
713
}
714

            
715
// This impl is a bit silly, but it makes the `params` method on NetDirProvider
716
// work out.
717
impl AsRef<NetParameters> for NetParameters {
718
405
    fn as_ref(&self) -> &NetParameters {
719
405
        self
720
405
    }
721
}
722

            
723
impl NetParameters {
724
    /// Construct a new NetParameters from a given list of key=value parameters.
725
    ///
726
    /// Unrecognized parameters are ignored.
727
994
    pub fn from_map(p: &tor_netdoc::doc::netstatus::NetParams<i32>) -> Self {
728
994
        let mut params = NetParameters::default();
729
994
        let unrecognized = params.saturating_update(p.iter());
730
994
        for u in unrecognized {
731
            tracing::debug!("Ignored unrecognized net param: {u}");
732
        }
733
994
        params
734
994
    }
735

            
736
    /// Replace a list of parameters, using the logic of
737
    /// `set_saturating`.
738
    ///
739
    /// Return a vector of the parameter names we didn't recognize.
740
18896
    pub(crate) fn saturating_update<'a, S>(
741
18896
        &mut self,
742
18896
        iter: impl Iterator<Item = (S, &'a i32)>,
743
18896
    ) -> Vec<S>
744
18896
    where
745
18896
        S: AsRef<str>,
746
18896
    {
747
18896
        let mut unrecognized = Vec::new();
748
33057
        for (k, v) in iter {
749
14161
            if !self.set_saturating(k.as_ref(), *v) {
750
8
                unrecognized.push(k);
751
14153
            }
752
        }
753
18896
        unrecognized
754
18896
    }
755
}
756

            
757
#[cfg(test)]
758
#[allow(clippy::many_single_char_names)]
759
#[allow(clippy::cognitive_complexity)]
760
mod test {
761
    // @@ begin test lint list maintained by maint/add_warning @@
762
    #![allow(clippy::bool_assert_comparison)]
763
    #![allow(clippy::clone_on_copy)]
764
    #![allow(clippy::dbg_macro)]
765
    #![allow(clippy::mixed_attributes_style)]
766
    #![allow(clippy::print_stderr)]
767
    #![allow(clippy::print_stdout)]
768
    #![allow(clippy::single_char_pattern)]
769
    #![allow(clippy::unwrap_used)]
770
    #![allow(clippy::unchecked_duration_subtraction)]
771
    #![allow(clippy::useless_vec)]
772
    #![allow(clippy::needless_pass_by_value)]
773
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
774
    use super::*;
775
    use std::string::String;
776

            
777
    #[test]
778
    fn empty_list() {
779
        let mut x = NetParameters::default();
780
        let y = Vec::<(&String, &i32)>::new();
781
        let u = x.saturating_update(y.into_iter());
782
        assert!(u.is_empty());
783
    }
784

            
785
    #[test]
786
    fn unknown_parameter() {
787
        let mut x = NetParameters::default();
788
        let mut y = Vec::<(&String, &i32)>::new();
789
        let k = &String::from("This_is_not_a_real_key");
790
        let v = &456;
791
        y.push((k, v));
792
        let u = x.saturating_update(y.into_iter());
793
        assert_eq!(u, vec![&String::from("This_is_not_a_real_key")]);
794
    }
795

            
796
    // #[test]
797
    // fn duplicate_parameter() {}
798

            
799
    #[test]
800
    fn single_good_parameter() {
801
        let mut x = NetParameters::default();
802
        let mut y = Vec::<(&String, &i32)>::new();
803
        let k = &String::from("min_paths_for_circs_pct");
804
        let v = &54;
805
        y.push((k, v));
806
        let z = x.saturating_update(y.into_iter());
807
        assert!(z.is_empty());
808
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
809
    }
810

            
811
    #[test]
812
    fn multiple_good_parameters() {
813
        let mut x = NetParameters::default();
814
        let mut y = Vec::<(&String, &i32)>::new();
815
        let k = &String::from("min_paths_for_circs_pct");
816
        let v = &54;
817
        y.push((k, v));
818
        let k = &String::from("circwindow");
819
        let v = &900;
820
        y.push((k, v));
821
        let z = x.saturating_update(y.into_iter());
822
        assert!(z.is_empty());
823
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
824
        assert_eq!(x.circuit_window.get(), 900);
825
    }
826

            
827
    #[test]
828
    fn good_out_of_range() {
829
        let mut x = NetParameters::default();
830
        let mut y = Vec::<(&String, &i32)>::new();
831
        let k = &String::from("sendme_accept_min_version");
832
        let v = &30;
833
        y.push((k, v));
834
        let k = &String::from("min_paths_for_circs_pct");
835
        let v = &255;
836
        y.push((k, v));
837
        let z = x.saturating_update(y.into_iter());
838
        assert!(z.is_empty());
839
        assert_eq!(x.sendme_accept_min_version.get(), 30);
840
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
841
    }
842

            
843
    #[test]
844
    fn good_invalid_rep() {
845
        let mut x = NetParameters::default();
846
        let mut y = Vec::<(&String, &i32)>::new();
847
        let k = &String::from("sendme_accept_min_version");
848
        let v = &30;
849
        y.push((k, v));
850
        let k = &String::from("min_paths_for_circs_pct");
851
        let v = &9000;
852
        y.push((k, v));
853
        let z = x.saturating_update(y.into_iter());
854
        assert!(z.is_empty());
855
        assert_eq!(x.sendme_accept_min_version.get(), 30);
856
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
857
    }
858

            
859
    // #[test]
860
    // fn good_duplicate() {}
861
    #[test]
862
    fn good_unknown() {
863
        let mut x = NetParameters::default();
864
        let mut y = Vec::<(&String, &i32)>::new();
865
        let k = &String::from("sendme_accept_min_version");
866
        let v = &30;
867
        y.push((k, v));
868
        let k = &String::from("not_a_real_parameter");
869
        let v = &9000;
870
        y.push((k, v));
871
        let z = x.saturating_update(y.into_iter());
872
        assert_eq!(z, vec![&String::from("not_a_real_parameter")]);
873
        assert_eq!(x.sendme_accept_min_version.get(), 30);
874
    }
875

            
876
    #[test]
877
    fn from_consensus() {
878
        let mut p = NetParameters::default();
879
        let mut mp: std::collections::HashMap<String, i32> = std::collections::HashMap::new();
880
        mp.insert("bwweightscale".to_string(), 70);
881
        mp.insert("min_paths_for_circs_pct".to_string(), 45);
882
        mp.insert("im_a_little_teapot".to_string(), 1);
883
        mp.insert("circwindow".to_string(), 99999);
884
        mp.insert("ExtendByEd25519ID".to_string(), 1);
885

            
886
        let z = p.saturating_update(mp.iter());
887
        assert_eq!(z, vec![&String::from("im_a_little_teapot")]);
888

            
889
        assert_eq!(p.bw_weight_scale.get(), 70);
890
        assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 45);
891
        let b_val: bool = p.extend_by_ed25519_id.into();
892
        assert!(b_val);
893
    }
894

            
895
    #[test]
896
    fn all_parameters() {
897
        use std::time::Duration;
898
        let mut p = NetParameters::default();
899
        let mp = [
900
            ("bwweightscale", 10),
901
            ("cbtdisabled", 1),
902
            ("cbtnummodes", 11),
903
            ("cbtrecentcount", 12),
904
            ("cbtmaxtimeouts", 13),
905
            ("cbtmincircs", 5),
906
            ("cbtquantile", 61),
907
            ("cbtclosequantile", 15),
908
            ("cbtlearntimeout", 1900),
909
            ("cbtmintimeout", 2020),
910
            ("cbtinitialtimeout", 2050),
911
            ("cbttestfreq", 110),
912
            ("cbtmaxopencircs", 14),
913
            ("circwindow", 999),
914
            ("CircuitPriorityHalflifeMsec", 222),
915
            ("guard-lifetime-days", 36),
916
            ("guard-confirmed-min-lifetime-days", 37),
917
            ("guard-internet-likely-down-interval", 38),
918
            ("guard-max-sample-size", 39),
919
            ("guard-max-sample-threshold", 40),
920
            ("guard-min-filtered-sample-size", 41),
921
            ("guard-n-primary-guards", 42),
922
            ("guard-n-primary-guards-to-use", 43),
923
            ("guard-n-primary-dir-guards-to-use", 44),
924
            ("guard-nonprimary-guard-connect-timeout", 45),
925
            ("guard-nonprimary-guard-idle-timeout", 46),
926
            ("guard-remove-unlisted-guards-after-days", 47),
927
            ("guard-meaningful-restriction-percent", 12),
928
            ("guard-extreme-restriction-percent", 3),
929
            ("ExtendByEd25519ID", 0),
930
            ("min_paths_for_circs_pct", 51),
931
            ("nf_conntimeout_clients", 606),
932
            ("nf_ito_low", 1_000),
933
            ("nf_ito_high", 20_000),
934
            ("nf_ito_low_reduced", 3_000),
935
            ("nf_ito_high_reduced", 40_000),
936
            ("sendme_accept_min_version", 31),
937
            ("sendme_emit_min_version", 32),
938
        ];
939
        let ignored = p.saturating_update(mp.iter().map(|(a, b)| (a, b)));
940
        assert!(ignored.is_empty());
941

            
942
        assert_eq!(p.bw_weight_scale.get(), 10);
943
        assert!(bool::from(p.cbt_learning_disabled));
944
        assert_eq!(p.cbt_num_xm_modes.get(), 11);
945
        assert_eq!(p.cbt_success_count.get(), 12);
946
        assert_eq!(p.cbt_max_timeouts.get(), 13);
947
        assert_eq!(p.cbt_min_circs_for_estimate.get(), 5);
948
        assert_eq!(p.cbt_timeout_quantile.as_percent().get(), 61);
949
        assert_eq!(p.cbt_abandon_quantile.as_percent().get(), 15);
950
        assert_eq!(p.nf_ito_low.as_millis().get(), 1_000);
951
        assert_eq!(p.nf_ito_high.as_millis().get(), 20_000);
952
        assert_eq!(p.nf_ito_low_reduced.as_millis().get(), 3_000);
953
        assert_eq!(p.nf_ito_high_reduced.as_millis().get(), 40_000);
954
        assert_eq!(
955
            Duration::try_from(p.unused_client_circ_timeout_while_learning_cbt).unwrap(),
956
            Duration::from_secs(1900)
957
        );
958
        assert_eq!(
959
            Duration::try_from(p.cbt_min_timeout).unwrap(),
960
            Duration::from_millis(2020)
961
        );
962
        assert_eq!(
963
            Duration::try_from(p.cbt_initial_timeout).unwrap(),
964
            Duration::from_millis(2050)
965
        );
966
        assert_eq!(
967
            Duration::try_from(p.cbt_testing_delay).unwrap(),
968
            Duration::from_secs(110)
969
        );
970
        assert_eq!(p.cbt_max_open_circuits_for_testing.get(), 14);
971
        assert_eq!(p.circuit_window.get(), 999);
972
        assert_eq!(
973
            Duration::try_from(p.circuit_priority_half_life).unwrap(),
974
            Duration::from_millis(222)
975
        );
976
        assert!(!bool::from(p.extend_by_ed25519_id));
977
        assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 51);
978
        assert_eq!(
979
            Duration::try_from(p.unused_client_circ_timeout).unwrap(),
980
            Duration::from_secs(606)
981
        );
982
        assert_eq!(p.sendme_accept_min_version.get(), 31);
983
        assert_eq!(p.sendme_emit_min_version.get(), 32);
984

            
985
        assert_eq!(
986
            Duration::try_from(p.guard_lifetime_unconfirmed).unwrap(),
987
            Duration::from_secs(86400 * 36)
988
        );
989
        assert_eq!(
990
            Duration::try_from(p.guard_lifetime_confirmed).unwrap(),
991
            Duration::from_secs(86400 * 37)
992
        );
993
        assert_eq!(
994
            Duration::try_from(p.guard_internet_likely_down).unwrap(),
995
            Duration::from_secs(38)
996
        );
997
        assert_eq!(p.guard_max_sample_size.get(), 39);
998
        assert_eq!(p.guard_max_sample_threshold.as_percent().get(), 40);
999
        assert_eq!(p.guard_filtered_min_sample_size.get(), 41);
        assert_eq!(p.guard_n_primary.get(), 42);
        assert_eq!(p.guard_use_parallelism.get(), 43);
        assert_eq!(p.guard_dir_use_parallelism.get(), 44);
        assert_eq!(
            Duration::try_from(p.guard_nonprimary_connect_timeout).unwrap(),
            Duration::from_secs(45)
        );
        assert_eq!(
            Duration::try_from(p.guard_nonprimary_idle_timeout).unwrap(),
            Duration::from_secs(46)
        );
        assert_eq!(
            Duration::try_from(p.guard_remove_unlisted_after).unwrap(),
            Duration::from_secs(86400 * 47)
        );
        assert_eq!(p.guard_meaningful_restriction.as_percent().get(), 12);
        assert_eq!(p.guard_extreme_restriction.as_percent().get(), 3);
    }
}