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 permantently 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

            
48
impl FromInt32Saturating for i32 {
49
    fn from_saturating(val: i32) -> Self {
50
        val
51
    }
52
}
53
impl<const L: i32, const H: i32> FromInt32Saturating for BoundedInt32<L, H> {
54
11533
    fn from_saturating(val: i32) -> Self {
55
11533
        Self::saturating_new(val)
56
11533
    }
57
}
58
impl<T: Copy + Into<f64> + FromInt32Saturating> FromInt32Saturating for Percentage<T> {
59
746
    fn from_saturating(val: i32) -> Self {
60
746
        Self::new(T::from_saturating(val))
61
746
    }
62
}
63
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMilliseconds<T> {
64
824
    fn from_saturating(val: i32) -> Self {
65
824
        Self::new(T::from_saturating(val))
66
824
    }
67
}
68
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerSeconds<T> {
69
12
    fn from_saturating(val: i32) -> Self {
70
12
        Self::new(T::from_saturating(val))
71
12
    }
72
}
73
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerMinutes<T> {
74
4
    fn from_saturating(val: i32) -> Self {
75
4
        Self::new(T::from_saturating(val))
76
4
    }
77
}
78
impl<T: FromInt32Saturating + TryInto<u64>> FromInt32Saturating for IntegerDays<T> {
79
6
    fn from_saturating(val: i32) -> Self {
80
6
        Self::new(T::from_saturating(val))
81
6
    }
82
}
83
impl FromInt32Saturating for SendMeVersion {
84
10
    fn from_saturating(val: i32) -> Self {
85
10
        Self::new(val.clamp(0, 255) as u8)
86
10
    }
87
}
88

            
89
/// A macro to help us declare the net parameters object.  It lets us
90
/// put the information about each parameter in just one place, even
91
/// though it will later get split between the struct declaration, the
92
/// Default implementation, and the implementation of
93
/// `saturating_update_override`.
94
macro_rules! declare_net_parameters {
95
    {
96
        $(#[$s_meta:meta])* $s_v:vis struct $s_name:ident {
97
            $(
98
                $(#[$p_meta:meta])* $p_v:vis
99
                    $p_name:ident : $p_type:ty
100
                    = ($p_dflt:expr) from $p_string:literal
101
            ),*
102
            $( , )?
103
        }
104
    } =>
105
    {
106
        $(#[$s_meta])* $s_v struct $s_name {
107
            $(
108
                $(#[$p_meta])* $p_v $p_name : $p_type
109
            ),*
110
        }
111

            
112
        impl $s_name {
113
            /// Try to construct an instance of with its default values.
114
            ///
115
            /// (This should always succeed, unless one of the default values
116
            /// is out-of-bounds for the type.)
117
11942
            fn default_values() -> Result<Self, tor_units::Error> {
118
                Ok(Self {
119
11942
                    $( $p_name : $p_dflt.try_into()? ),*
120
                })
121
11942
            }
122
            /// Replace the current value for the parameter identified in the
123
            /// consensus with `key` with a new value `val`.
124
            ///
125
            /// Uses saturating semantics if the new value is out-of-range.
126
            ///
127
            /// Returns true if the key was recognized, and false otherwise.
128
11551
            fn set_saturating(&mut self, key: &str, val: i32) -> bool {
129
11551
                match key {
130
8
                    $( $p_string => self.$p_name = {
131
                        type T = $p_type;
132
                        T::from_saturating(val)
133
                    }, )*
134
8
                    _ => return false,
135
                }
136
11543
                true
137
11551
            }
138
        }
139
    }
140
}
141

            
142
declare_net_parameters! {
143

            
144
/// This structure holds recognized configuration parameters. All values are type-safe,
145
/// and where applicable clamped to be within range.
146
#[derive(Clone, Debug)]
147
#[non_exhaustive]
148
pub struct NetParameters {
149
    /// A weighting factor for bandwidth calculations
150
    pub bw_weight_scale: BoundedInt32<1, { i32::MAX }> = (10_000)
151
        from "bwweightscale",
152
    /// If true, do not attempt to learn circuit-build timeouts at all.
153
    pub cbt_learning_disabled: BoundedInt32<0, 1> = (0)
154
        from "cbtdisabled",
155
    /// Number of histograms bins to consider when estimating Xm for a
156
    /// Pareto-based circuit timeout estimator.
157
    pub cbt_num_xm_modes: BoundedInt32<1, 20> = (10)
158
        from "cbtnummodes",
159
    /// How many recent circuit success/timeout statuses do we remember
160
    /// when trying to tell if our circuit timeouts are too low?
161
    pub cbt_success_count: BoundedInt32<3, 1_000> = (20)
162
        from "cbtrecentcount",
163
    /// How many timeouts (in the last `cbt_success_count` observations)
164
    /// indicates that our circuit timeouts are too low?
165
    pub cbt_max_timeouts: BoundedInt32<3, 10_000> = (18)
166
        from "cbtmaxtimeouts",
167
    /// Smallest number of circuit build times we have to view in order to use
168
    /// our Pareto-based circuit timeout estimator.
169
    pub cbt_min_circs_for_estimate: BoundedInt32<1, 10_000> = (100)
170
        from "cbtmincircs",
171
    /// Quantile to use when determining the correct circuit timeout value
172
    /// with our Pareto estimator.
173
    ///
174
    /// (We continue building circuits after this timeout, but only
175
    /// for build-time measurement purposes.)
176
    pub cbt_timeout_quantile: Percentage<BoundedInt32<10, 99>> = (80)
177
        from "cbtquantile",
178
    /// Quantile to use when determining when to abandon circuits completely
179
    /// with our Pareto estimator.
180
    pub cbt_abandon_quantile: Percentage<BoundedInt32<10, 99>> = (99)
181
        from "cbtclosequantile",
182
    /// Lowest permissible timeout value for Pareto timeout estimator.
183
    pub cbt_min_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (10)
184
        from "cbtmintimeout",
185
    /// Timeout value to use for our Pareto timeout estimator when we have
186
    /// no initial estimate.
187
    pub cbt_initial_timeout: IntegerMilliseconds<BoundedInt32<10, { i32::MAX }>> = (60_000)
188
        from "cbtinitialtimeout",
189
    /// When we don't have a good build-time estimate yet, how long
190
    /// (in seconds) do we wait between trying to launch build-time
191
    /// testing circuits through the network?
192
    pub cbt_testing_delay: IntegerSeconds<BoundedInt32<1, { i32::MAX }>> = (10)
193
        from "cbttestfreq",
194
    /// How many circuits can be open before we will no longer
195
    /// consider launching testing circuits to learn average build
196
    /// times?
197
    pub cbt_max_open_circuits_for_testing: BoundedInt32<0, 14> = (10)
198
        from "cbtmaxopencircs",
199

            
200
    /// Specifies which congestion control algorithm clients should use.
201
    /// Current values are 0 for the fixed window algorithm and 2 for Vegas.
202
    ///
203
    /// TODO: Flip this to 2 once CC circuit negotiation and Flow Control is in which would be the
204
    /// same default as C-tor. Reason is that we can't have it to 2 for now else it makes the
205
    /// consensus download fails.
206
    pub cc_alg: BoundedInt32<0, 2> = (0)
207
        from "cc_alg",
208

            
209
    /// Vegas only. This parameter defines the integer number of 'cc_sendme_inc' multiples
210
    /// of gap allowed between inflight and cwnd, to still declare the cwnd full.
211
    pub cc_cwnd_full_gap: BoundedInt32<0, { i16::MAX as i32 }> = (4444)
212
        from "cc_cwnd_full_gap",
213
    /// Vegas only. This parameter defines a low watermark in percent.
214
    pub cc_cwnd_full_minpct: Percentage<BoundedInt32<0, 100>> = (25)
215
        from "cc_cwnd_full_minpct",
216
    /// Vegas only. This parameter governs how often a cwnd must be full.
217
    pub cc_cwnd_full_per_cwnd: BoundedInt32<0, 1> = (1)
218
        from "cc_cwnd_full_per_cwnd",
219

            
220
    /// Initial congestion window for new congestion control Tor clients.
221
    pub cc_cwnd_init: BoundedInt32<31, 10_000> = (4 * 31)
222
        from "cc_cwnd_init",
223
    /// Percentage of the current congestion window to increment by during slow start,
224
    /// every congestion window.
225
    pub cc_cwnd_inc_pct_ss: Percentage<BoundedInt32<1, 500>> = (50)
226
        from "cc_cwnd_inc_pct_ss",
227
    /// How much to increment the congestion window by during steady state,
228
    /// every congestion window.
229
    pub cc_cwnd_inc: BoundedInt32<1, 1000> = (31)
230
        from "cc_cwnd_inc",
231
    /// How often we update our congestion window, per cwnd worth of packets.
232
    /// (For example, if this is 2, we will update the window twice every window.)
233
    pub cc_cwnd_inc_rate: BoundedInt32<1, 250> = (1)
234
        from "cc_cwnd_inc_rate",
235
    /// The minimum allowed congestion window.
236
    pub cc_cwnd_min: BoundedInt32<31, 1000> = (31)
237
        from "cc_cwnd_min",
238
    /// The maximum allowed congestion window.
239
    pub cc_cwnd_max: BoundedInt32<500, { i32::MAX }> = (i32::MAX)
240
        from "cc_cwnd_max",
241

            
242
    /// This specifies the N in N-EWMA smoothing of RTT and BDP estimation,
243
    /// as a percent of the number of SENDME acks in a congestion window.
244
    ///
245
    /// A percentage over 100% indicates smoothing with more than one
246
    /// congestion window's worth of SENDMEs.
247
    pub cc_ewma_cwnd_pct: Percentage<BoundedInt32<1, 255>> = (50)
248
        from "cc_ewma_cwnd_pct",
249
    /// This specifies the max N in N_EWMA smoothing of RTT and BDP estimation.
250
    pub cc_ewma_max: BoundedInt32<2, { i32::MAX }> = (10)
251
        from "cc_ewma_max",
252
    /// This specifies the N in N_EWMA smoothing of RTT during Slow Start.
253
    pub cc_ewma_ss: BoundedInt32<2, { i32::MAX }> = (2)
254
        from "cc_ewma_ss",
255
    /// Describes a percentile average between RTT_min and RTT_current_ewma,
256
    /// for use to reset RTT_min, when the congestion window hits cwnd_min.
257
    pub cc_rtt_reset_pct: Percentage<BoundedInt32<0, 100>> = (100)
258
        from "cc_rtt_reset_pct",
259
    /// Specifies how many cells a SENDME acks.
260
    pub cc_sendme_inc: BoundedInt32<1, 254> = (31)
261
        from "cc_sendme_inc",
262
    /// This parameter provides a hard-max on the congestion window in Slow Start.
263
    pub cc_ss_max: BoundedInt32<500, { i32::MAX }> = (5000)
264
        from "cc_ss_max",
265

            
266
    /// Vegas alpha parameter for an Exit circuit.
267
    pub cc_vegas_alpha_exit: BoundedInt32<0, 1000> = (3 * 62)
268
        from "cc_vegas_alpha_exit",
269
    /// Vegas beta parameter for an Exit circuit.
270
    pub cc_vegas_beta_exit: BoundedInt32<0, 1000> = (4 * 62)
271
        from "cc_vegas_beta_exit",
272
    /// Vegas delta parameter for an Exit circuit.
273
    pub cc_vegas_delta_exit: BoundedInt32<0, 1000> = (5 * 62)
274
        from "cc_vegas_delta_exit",
275
    /// Vegas gamma parameter for an Exit circuit.
276
    pub cc_vegas_gamma_exit: BoundedInt32<0, 1000> = (3 * 62)
277
        from "cc_vegas_gamma_exit",
278

            
279
    /// Vegas alpha parameter for an Onion circuit.
280
    pub cc_vegas_alpha_onion: BoundedInt32<0, 1000> = (3 * 62)
281
        from "cc_vegas_alpha_onion",
282
    /// Vegas beta parameter for an Onion circuit.
283
    pub cc_vegas_beta_onion: BoundedInt32<0, 1000> = (6 * 62)
284
        from "cc_vegas_beta_onion",
285
    /// Vegas delta parameter for an Onion circuit.
286
    pub cc_vegas_delta_onion: BoundedInt32<0, 1000> = (7 * 62)
287
        from "cc_vegas_delta_onion",
288
    /// Vegas gamma parameter for an Onion circuit.
289
    pub cc_vegas_gamma_onion: BoundedInt32<0, 1000> = (4 * 62)
290
        from "cc_vegas_gamma_onion",
291

            
292
    /// Parameter for Exit circuit that describe the the RFC3742 'cap', after which
293
    /// congestion window increments are reduced. The MAX disables RFC3742.
294
    pub cc_vegas_sscap_exit: BoundedInt32<100, { i32::MAX }> = (600)
295
        from "cc_sscap_exit",
296
    /// Parameter for Onion circuit that describe the the RFC3742 'cap', after which
297
    /// congestion window increments are reduced. The MAX disables RFC3742.
298
    pub cc_vegas_sscap_onion: BoundedInt32<100, { i32::MAX }> = (475)
299
        from "cc_sscap_onion",
300

            
301
    /// The maximum cell window size?
302
    pub circuit_window: BoundedInt32<100, 1000> = (1_000)
303
        from "circwindow",
304
    /// The decay parameter for circuit priority
305
    pub circuit_priority_half_life: IntegerMilliseconds<BoundedInt32<1, { i32::MAX }>> = (30_000)
306
        from "CircuitPriorityHalflifeMsec",
307
    /// Whether to perform circuit extensions by Ed25519 ID
308
    pub extend_by_ed25519_id: BoundedInt32<0, 1> = (0)
309
        from "ExtendByEd25519ID",
310

            
311
    /// If we have excluded so many possible guards that the
312
    /// available fraction is below this threshold, we should use a different
313
    /// guard sample.
314
    pub guard_meaningful_restriction: Percentage<BoundedInt32<1,100>> = (20)
315
        from "guard-meaningful-restriction-percent",
316

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

            
322
    /// How long should we keep an unconfirmed guard (one we have not
323
    /// contacted) before removing it from the guard sample?
324
    pub guard_lifetime_unconfirmed: IntegerDays<BoundedInt32<1, 3650>> = (120)
325
        from "guard-lifetime-days",
326

            
327
    /// How long should we keep a _confirmed_ guard (one we have contacted)
328
    /// before removing it from the guard sample?
329
    pub guard_lifetime_confirmed: IntegerDays<BoundedInt32<1, 3650>> = (60)
330
        from "guard-confirmed-min-lifetime-days",
331

            
332
    /// If all circuits have failed for this interval, then treat the internet
333
    /// as "probably down", and treat any guard failures in that interval
334
    /// as unproven.
335
    pub guard_internet_likely_down: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (600)
336
        from "guard-internet-likely-down-interval",
337
    /// Largest number of guards that a client should try to maintain in
338
    /// a sample of possible guards.
339
    pub guard_max_sample_size: BoundedInt32<1, {i32::MAX}> = (60)
340
        from "guard-max-sample-size",
341
    /// Largest fraction of guard bandwidth on the network that a client
342
    /// should try to remain in a sample of possible guards.
343
    pub guard_max_sample_threshold: Percentage<BoundedInt32<1,100>> = (20)
344
        from "guard-max-sample-threshold",
345

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

            
352
    /// The number of confirmed guards that the client should treat as
353
    /// "primary guards".
354
    pub guard_n_primary: BoundedInt32<1,{i32::MAX}> = (3)
355
        from "guard-n-primary-guards",
356
    /// The number of primary guards that the client should use in parallel.
357
    /// Other primary guards won't get used unless earlier ones are down.
358
    pub guard_use_parallelism: BoundedInt32<1, {i32::MAX}> = (1)
359
        from "guard-n-primary-guards-to-use",
360
    /// The number of primary guards that the client should use in
361
    /// parallel.  Other primary directory guards won't get used
362
    /// unless earlier ones are down.
363
    pub guard_dir_use_parallelism: BoundedInt32<1, {i32::MAX}> = (3)
364
        from "guard-n-primary-dir-guards-to-use",
365

            
366
    /// When trying to confirm nonprimary guards, if a guard doesn't
367
    /// answer for more than this long in seconds, treat any lower-
368
    /// priority guards as possibly usable.
369
    pub guard_nonprimary_connect_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (15)
370
        from "guard-nonprimary-guard-connect-timeout",
371
    /// When trying to confirm nonprimary guards, if a guard doesn't
372
    /// answer for more than _this_ long in seconds, treat it as down.
373
    pub guard_nonprimary_idle_timeout: IntegerSeconds<BoundedInt32<1,{i32::MAX}>> = (600)
374
        from "guard-nonprimary-guard-idle-timeout",
375
    /// If a guard has been unlisted in the consensus for at least this
376
    /// long, remove it from the consensus.
377
    pub guard_remove_unlisted_after: IntegerDays<BoundedInt32<1,3650>> = (20)
378
        from "guard-remove-unlisted-guards-after-days",
379

            
380

            
381
    /// The minimum threshold for circuit patch construction
382
    pub min_circuit_path_threshold: Percentage<BoundedInt32<25, 95>> = (60)
383
        from "min_paths_for_circs_pct",
384

            
385
    /// Channel padding, low end of random padding interval, milliseconds
386
    ///
387
    /// `nf_ito` stands for "netflow inactive timeout".
388
    pub nf_ito_low: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (1500)
389
        from "nf_ito_low",
390
    /// Channel padding, high end of random padding interval, milliseconds
391
    pub nf_ito_high: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9500)
392
        from "nf_ito_high",
393
    /// Channel padding, low end of random padding interval (reduced padding) milliseconds
394
    pub nf_ito_low_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (9000)
395
        from "nf_ito_low_reduced",
396
    /// Channel padding, high end of random padding interval (reduced padding) , milliseconds
397
    pub nf_ito_high_reduced: IntegerMilliseconds<BoundedInt32<0, CHANNEL_PADDING_TIMEOUT_UPPER_BOUND>> = (14000)
398
        from "nf_ito_high_reduced",
399

            
400
    /// The minimum sendme version to accept.
401
    pub sendme_accept_min_version: SendMeVersion = (0)
402
        from "sendme_accept_min_version",
403
    /// The minimum sendme version to transmit.
404
    pub sendme_emit_min_version: SendMeVersion = (0)
405
        from "sendme_emit_min_version",
406

            
407
    /// How long should never-used client circuits stay available,
408
    /// in the steady state?
409
    pub unused_client_circ_timeout: IntegerSeconds<BoundedInt32<60, 86_400>> = (30*60)
410
        from "nf_conntimeout_clients",
411
    /// When we're learning circuit timeouts, how long should never-used client
412
    /// circuits stay available?
413
    pub unused_client_circ_timeout_while_learning_cbt: IntegerSeconds<BoundedInt32<10, 60_000>> = (3*60)
414
        from "cbtlearntimeout",
415

            
416
    /// Lower bound on the number of INTRODUCE2 cells to allow per introduction
417
    /// circuit before the service decides to rotate to a new introduction
418
    /// circuit.
419
    pub hs_introcirc_requests_min: BoundedInt32<0, {i32::MAX}> = (16384)
420
        from "hs_intro_min_introduce2",
421

            
422
    /// Upper bound on the number of INTRODUCE2 cells to allow per introduction
423
    /// circuit before the service decides to rotate to a new introduction
424
    /// circuit.
425
    pub hs_introcirc_requests_max: BoundedInt32<0, {i32::MAX}> = (32768)
426
        from "hs_intro_max_introduce2",
427

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

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

            
436
    /// Number of "extra" introduction points that an onion service is allowed
437
    /// to open based on demand.
438
    pub hs_intro_num_extra_intropoints: BoundedInt32<0, 128> = (2)
439
        from "hs_intro_num_extra",
440

            
441
    /// The duration of a time period, as used in the onion service directory
442
    /// protocol.
443
    ///
444
    /// During each "time period", each onion service gets a different blinded
445
    /// ID, and the hash ring gets a new layout.
446
    pub hsdir_timeperiod_length: IntegerMinutes<BoundedInt32<30, 14400>> = (1440)
447
        from "hsdir_interval",
448

            
449
    /// The number of positions at the hash ring where an onion service
450
    /// descriptor should be stored.
451
    pub hsdir_n_replicas: BoundedInt32<1, 16> = (2)
452
        from "hsdir_n_replicas",
453

            
454
    /// The number of HSDir instances, at each position in the hash ring, that
455
    /// should be considered when downloading an onion service descriptor.
456
    pub hsdir_spread_fetch: BoundedInt32<1, 128> = (3)
457
        from "hsdir_spread_fetch",
458

            
459
    /// The number of HSDir instances, at each position in the hash ring, that
460
    /// should be considered when uploading an onion service descriptor.
461
    pub hsdir_spread_store: BoundedInt32<1,128> = (4)
462
        from "hsdir_spread_store",
463

            
464
    /// Largest allowable v3 onion service size (in bytes).
465
    pub hsdir_max_desc_size: BoundedInt32<1, {i32::MAX}> = (50_000)
466
        from "HSV3MaxDescriptorSize",
467

            
468
    /// Largest number of failures to rendezvous that an onion service should
469
    /// allow for a request.
470
    pub hs_service_rendezvous_failures_max: BoundedInt32<1, 10> = (2)
471
        from "hs_service_max_rdv_failures",
472

            
473
    /// If set to 1, introduction points use the INTRODUCE1 rate limiting
474
    /// defense when no `DosParams` are sent.
475
    ///
476
    /// See <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSDefense>
477
    pub hs_intro_dos_enabled: BoundedInt32<0, 1> = (0)
478
        from "HiddenServiceEnableIntroDoSDefense",
479

            
480
    /// Default _rate_ value for an introduction point to use for INTRODUCE1 rate
481
    /// limiting when no `DosParams` value is sent, in messages per second.
482
    ///
483
    /// See
484
    /// <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSBurstPerSec>
485
    pub hs_intro_dos_max_burst: BoundedInt32<0, {i32::MAX}> = (200)
486
        from "HiddenServiceEnableIntroDoSBurstPerSec",
487

            
488
    /// Default _burst_ value for an introduction point to use for INTRODUCE1 rate
489
    /// limiting when no `DosParams` value is sent.
490
    ///
491
    /// See
492
    /// <https://spec.torproject.org/param-spec.html#HiddenServiceEnableIntroDoSRatePerSec>
493
    pub hs_intro_dos_rate: BoundedInt32<0, {i32::MAX}> = (25)
494
        from  "HiddenServiceEnableIntroDoSRatePerSec",
495

            
496
    /// The type of vanguards to use by default when building onion service circuits:
497
    ///
498
    /// ```text
499
    ///    0: No vanguards.
500
    ///    1: Lite vanguards.
501
    ///    2: Full vanguards.
502
    /// ```
503
    ///
504
    /// See
505
    /// <https://spec.torproject.org/param-spec.html#vanguards>
506
    pub vanguards_enabled: BoundedInt32<0, 2> = (1)
507
        from "vanguards-enabled",
508

            
509
    /// If higher than `vanguards-enabled`,
510
    /// and we are running an onion service,
511
    /// we use this level for all our onion service circuits:
512
    ///
513
    /// ```text
514
    ///    0: No vanguards.
515
    ///    1: Lite vanguards.
516
    ///    2: Full vanguards.
517
    /// ```
518
    ///
519
    /// See
520
    /// <https://spec.torproject.org/param-spec.html#vanguards>
521
    pub vanguards_hs_service: BoundedInt32<0, 2> = (2)
522
        from "vanguards-hs-service",
523

            
524
    /// The number of vanguards in the L2 vanguard set.
525
    ///
526
    /// See
527
    /// <https://spec.torproject.org/param-spec.html#vanguards>
528
    pub guard_hs_l2_number: BoundedInt32<1, {i32::MAX}> = (4)
529
        from  "guard-hs-l2-number",
530

            
531
    /// The minimum lifetime of L2 vanguards.
532
    ///
533
    /// See
534
    /// <https://spec.torproject.org/param-spec.html#vanguards>
535
    pub guard_hs_l2_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (86400)
536
        from  "guard-hs-l2-lifetime-min",
537

            
538
    /// The maximum lifetime of L2 vanguards.
539
    ///
540
    /// See
541
    /// <https://spec.torproject.org/param-spec.html#vanguards>
542
    pub guard_hs_l2_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (1036800)
543
        from  "guard-hs-l2-lifetime-max",
544

            
545
    /// The number of vanguards in the L3 vanguard set.
546
    ///
547
    /// See
548
    /// <https://spec.torproject.org/param-spec.html#vanguards>
549
    pub guard_hs_l3_number: BoundedInt32<1, {i32::MAX}> = (8)
550
        from  "guard-hs-l3-number",
551

            
552
    /// The minimum lifetime of L3 vanguards.
553
    ///
554
    /// See
555
    /// <https://spec.torproject.org/param-spec.html#vanguards>
556
    pub guard_hs_l3_lifetime_min: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (3600)
557
        from  "guard-hs-l3-lifetime-min",
558

            
559
    /// The maximum lifetime of L3 vanguards.
560
    ///
561
    /// See
562
    /// <https://spec.torproject.org/param-spec.html#vanguards>
563
    pub guard_hs_l3_lifetime_max: IntegerSeconds<BoundedInt32<1, {i32::MAX}>> = (172800)
564
        from  "guard-hs-l3-lifetime-max",
565

            
566
    /// The KIST to use by default when building inter-relay channels:
567
    ///
568
    /// ```text
569
    ///    0: No KIST.
570
    ///    1: KIST using TCP_NOTSENT_LOWAT.
571
    /// ```
572
    ///
573
    // TODO(KIST): add this to param spec
574
    // TODO(KIST): make this default to 1 (KIST with TCP_NOTSENT_LOWAT)
575
    // when we're confident it behaves correctly in conjunction with cc
576
    pub kist_enabled: BoundedInt32<0, 1> = (0)
577
        from "kist-enabled",
578

            
579
    /// If `kist_enabled` is `1` (KIST using TCP_NOTSENT_LOWAT),
580
    /// the TCP_NOTSENT_LOWAT value to set for each channel.
581
    ///
582
    /// If `kist_enabled` is `0` (disabled),
583
    /// the TCP_NOTSENT_LOWAT option is set to 0xFFFFFFFF (u32::MAX).
584
    ///
585
    // TODO(KIST): technically, this should be a u32, not an i32.
586
    // However, because we're using it to limit the amount of unsent data in TCP sockets,
587
    // it's unlikely we're ever going to want to set this to a high value,
588
    // so an upper bound of i32::MAX is good enough for our purposes.
589
    pub kist_tcp_notsent_lowat: BoundedInt32<1, {i32::MAX}> = (1)
590
        from  "kist-tcp-notsent-lowat",
591

            
592
    /// If true, we use lists of family members
593
    /// when making decisions about which relays belong to the same family.
594
    pub use_family_lists: BoundedInt32<0,1> = (1)
595
        from "use-family-lists",
596

            
597
    /// If true, we use lists of family IDs
598
    /// when making decisions about which relays belong to the same family.
599
    pub use_family_ids: BoundedInt32<0,1> = (1)
600
        from "use-family-ids",
601
}
602

            
603
}
604

            
605
impl Default for NetParameters {
606
11942
    fn default() -> Self {
607
11942
        NetParameters::default_values().expect("Default parameters were out-of-bounds")
608
11942
    }
609
}
610

            
611
// This impl is a bit silly, but it makes the `params` method on NetDirProvider
612
// work out.
613
impl AsRef<NetParameters> for NetParameters {
614
360
    fn as_ref(&self) -> &NetParameters {
615
360
        self
616
360
    }
617
}
618

            
619
impl NetParameters {
620
    /// Construct a new NetParameters from a given list of key=value parameters.
621
    ///
622
    /// Unrecognized parameters are ignored.
623
724
    pub fn from_map(p: &tor_netdoc::doc::netstatus::NetParams<i32>) -> Self {
624
724
        let mut params = NetParameters::default();
625
724
        let _ = params.saturating_update(p.iter());
626
724
        params
627
724
    }
628

            
629
    /// Replace a list of parameters, using the logic of
630
    /// `set_saturating`.
631
    ///
632
    /// Return a vector of the parameter names we didn't recognize.
633
15746
    pub(crate) fn saturating_update<'a, S>(
634
15746
        &mut self,
635
15746
        iter: impl Iterator<Item = (S, &'a i32)>,
636
15746
    ) -> Vec<S>
637
15746
    where
638
15746
        S: AsRef<str>,
639
15746
    {
640
15746
        let mut unrecognized = Vec::new();
641
27297
        for (k, v) in iter {
642
11551
            if !self.set_saturating(k.as_ref(), *v) {
643
8
                unrecognized.push(k);
644
11543
            }
645
        }
646
15746
        unrecognized
647
15746
    }
648
}
649

            
650
#[cfg(test)]
651
#[allow(clippy::many_single_char_names)]
652
#[allow(clippy::unwrap_used)]
653
#[allow(clippy::cognitive_complexity)]
654
mod test {
655
    // @@ begin test lint list maintained by maint/add_warning @@
656
    #![allow(clippy::bool_assert_comparison)]
657
    #![allow(clippy::clone_on_copy)]
658
    #![allow(clippy::dbg_macro)]
659
    #![allow(clippy::mixed_attributes_style)]
660
    #![allow(clippy::print_stderr)]
661
    #![allow(clippy::print_stdout)]
662
    #![allow(clippy::single_char_pattern)]
663
    #![allow(clippy::unwrap_used)]
664
    #![allow(clippy::unchecked_duration_subtraction)]
665
    #![allow(clippy::useless_vec)]
666
    #![allow(clippy::needless_pass_by_value)]
667
    //! <!-- @@ end test lint list maintained by maint/add_warning @@ -->
668
    use super::*;
669
    use std::string::String;
670

            
671
    #[test]
672
    fn empty_list() {
673
        let mut x = NetParameters::default();
674
        let y = Vec::<(&String, &i32)>::new();
675
        let u = x.saturating_update(y.into_iter());
676
        assert!(u.is_empty());
677
    }
678

            
679
    #[test]
680
    fn unknown_parameter() {
681
        let mut x = NetParameters::default();
682
        let mut y = Vec::<(&String, &i32)>::new();
683
        let k = &String::from("This_is_not_a_real_key");
684
        let v = &456;
685
        y.push((k, v));
686
        let u = x.saturating_update(y.into_iter());
687
        assert_eq!(u, vec![&String::from("This_is_not_a_real_key")]);
688
    }
689

            
690
    // #[test]
691
    // fn duplicate_parameter() {}
692

            
693
    #[test]
694
    fn single_good_parameter() {
695
        let mut x = NetParameters::default();
696
        let mut y = Vec::<(&String, &i32)>::new();
697
        let k = &String::from("min_paths_for_circs_pct");
698
        let v = &54;
699
        y.push((k, v));
700
        let z = x.saturating_update(y.into_iter());
701
        assert!(z.is_empty());
702
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
703
    }
704

            
705
    #[test]
706
    fn multiple_good_parameters() {
707
        let mut x = NetParameters::default();
708
        let mut y = Vec::<(&String, &i32)>::new();
709
        let k = &String::from("min_paths_for_circs_pct");
710
        let v = &54;
711
        y.push((k, v));
712
        let k = &String::from("circwindow");
713
        let v = &900;
714
        y.push((k, v));
715
        let z = x.saturating_update(y.into_iter());
716
        assert!(z.is_empty());
717
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 54);
718
        assert_eq!(x.circuit_window.get(), 900);
719
    }
720

            
721
    #[test]
722
    fn good_out_of_range() {
723
        let mut x = NetParameters::default();
724
        let mut y = Vec::<(&String, &i32)>::new();
725
        let k = &String::from("sendme_accept_min_version");
726
        let v = &30;
727
        y.push((k, v));
728
        let k = &String::from("min_paths_for_circs_pct");
729
        let v = &255;
730
        y.push((k, v));
731
        let z = x.saturating_update(y.into_iter());
732
        assert!(z.is_empty());
733
        assert_eq!(x.sendme_accept_min_version.get(), 30);
734
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
735
    }
736

            
737
    #[test]
738
    fn good_invalid_rep() {
739
        let mut x = NetParameters::default();
740
        let mut y = Vec::<(&String, &i32)>::new();
741
        let k = &String::from("sendme_accept_min_version");
742
        let v = &30;
743
        y.push((k, v));
744
        let k = &String::from("min_paths_for_circs_pct");
745
        let v = &9000;
746
        y.push((k, v));
747
        let z = x.saturating_update(y.into_iter());
748
        assert!(z.is_empty());
749
        assert_eq!(x.sendme_accept_min_version.get(), 30);
750
        assert_eq!(x.min_circuit_path_threshold.as_percent().get(), 95);
751
    }
752

            
753
    // #[test]
754
    // fn good_duplicate() {}
755
    #[test]
756
    fn good_unknown() {
757
        let mut x = NetParameters::default();
758
        let mut y = Vec::<(&String, &i32)>::new();
759
        let k = &String::from("sendme_accept_min_version");
760
        let v = &30;
761
        y.push((k, v));
762
        let k = &String::from("not_a_real_parameter");
763
        let v = &9000;
764
        y.push((k, v));
765
        let z = x.saturating_update(y.into_iter());
766
        assert_eq!(z, vec![&String::from("not_a_real_parameter")]);
767
        assert_eq!(x.sendme_accept_min_version.get(), 30);
768
    }
769

            
770
    #[test]
771
    fn from_consensus() {
772
        let mut p = NetParameters::default();
773
        let mut mp: std::collections::HashMap<String, i32> = std::collections::HashMap::new();
774
        mp.insert("bwweightscale".to_string(), 70);
775
        mp.insert("min_paths_for_circs_pct".to_string(), 45);
776
        mp.insert("im_a_little_teapot".to_string(), 1);
777
        mp.insert("circwindow".to_string(), 99999);
778
        mp.insert("ExtendByEd25519ID".to_string(), 1);
779

            
780
        let z = p.saturating_update(mp.iter());
781
        assert_eq!(z, vec![&String::from("im_a_little_teapot")]);
782

            
783
        assert_eq!(p.bw_weight_scale.get(), 70);
784
        assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 45);
785
        let b_val: bool = p.extend_by_ed25519_id.into();
786
        assert!(b_val);
787
    }
788

            
789
    #[test]
790
    fn all_parameters() {
791
        use std::time::Duration;
792
        let mut p = NetParameters::default();
793
        let mp = [
794
            ("bwweightscale", 10),
795
            ("cbtdisabled", 1),
796
            ("cbtnummodes", 11),
797
            ("cbtrecentcount", 12),
798
            ("cbtmaxtimeouts", 13),
799
            ("cbtmincircs", 5),
800
            ("cbtquantile", 61),
801
            ("cbtclosequantile", 15),
802
            ("cbtlearntimeout", 1900),
803
            ("cbtmintimeout", 2020),
804
            ("cbtinitialtimeout", 2050),
805
            ("cbttestfreq", 110),
806
            ("cbtmaxopencircs", 14),
807
            ("circwindow", 999),
808
            ("CircuitPriorityHalflifeMsec", 222),
809
            ("guard-lifetime-days", 36),
810
            ("guard-confirmed-min-lifetime-days", 37),
811
            ("guard-internet-likely-down-interval", 38),
812
            ("guard-max-sample-size", 39),
813
            ("guard-max-sample-threshold", 40),
814
            ("guard-min-filtered-sample-size", 41),
815
            ("guard-n-primary-guards", 42),
816
            ("guard-n-primary-guards-to-use", 43),
817
            ("guard-n-primary-dir-guards-to-use", 44),
818
            ("guard-nonprimary-guard-connect-timeout", 45),
819
            ("guard-nonprimary-guard-idle-timeout", 46),
820
            ("guard-remove-unlisted-guards-after-days", 47),
821
            ("guard-meaningful-restriction-percent", 12),
822
            ("guard-extreme-restriction-percent", 3),
823
            ("ExtendByEd25519ID", 0),
824
            ("min_paths_for_circs_pct", 51),
825
            ("nf_conntimeout_clients", 606),
826
            ("nf_ito_low", 1_000),
827
            ("nf_ito_high", 20_000),
828
            ("nf_ito_low_reduced", 3_000),
829
            ("nf_ito_high_reduced", 40_000),
830
            ("sendme_accept_min_version", 31),
831
            ("sendme_emit_min_version", 32),
832
        ];
833
        let ignored = p.saturating_update(mp.iter().map(|(a, b)| (a, b)));
834
        assert!(ignored.is_empty());
835

            
836
        assert_eq!(p.bw_weight_scale.get(), 10);
837
        assert!(bool::from(p.cbt_learning_disabled));
838
        assert_eq!(p.cbt_num_xm_modes.get(), 11);
839
        assert_eq!(p.cbt_success_count.get(), 12);
840
        assert_eq!(p.cbt_max_timeouts.get(), 13);
841
        assert_eq!(p.cbt_min_circs_for_estimate.get(), 5);
842
        assert_eq!(p.cbt_timeout_quantile.as_percent().get(), 61);
843
        assert_eq!(p.cbt_abandon_quantile.as_percent().get(), 15);
844
        assert_eq!(p.nf_ito_low.as_millis().get(), 1_000);
845
        assert_eq!(p.nf_ito_high.as_millis().get(), 20_000);
846
        assert_eq!(p.nf_ito_low_reduced.as_millis().get(), 3_000);
847
        assert_eq!(p.nf_ito_high_reduced.as_millis().get(), 40_000);
848
        assert_eq!(
849
            Duration::try_from(p.unused_client_circ_timeout_while_learning_cbt).unwrap(),
850
            Duration::from_secs(1900)
851
        );
852
        assert_eq!(
853
            Duration::try_from(p.cbt_min_timeout).unwrap(),
854
            Duration::from_millis(2020)
855
        );
856
        assert_eq!(
857
            Duration::try_from(p.cbt_initial_timeout).unwrap(),
858
            Duration::from_millis(2050)
859
        );
860
        assert_eq!(
861
            Duration::try_from(p.cbt_testing_delay).unwrap(),
862
            Duration::from_secs(110)
863
        );
864
        assert_eq!(p.cbt_max_open_circuits_for_testing.get(), 14);
865
        assert_eq!(p.circuit_window.get(), 999);
866
        assert_eq!(
867
            Duration::try_from(p.circuit_priority_half_life).unwrap(),
868
            Duration::from_millis(222)
869
        );
870
        assert!(!bool::from(p.extend_by_ed25519_id));
871
        assert_eq!(p.min_circuit_path_threshold.as_percent().get(), 51);
872
        assert_eq!(
873
            Duration::try_from(p.unused_client_circ_timeout).unwrap(),
874
            Duration::from_secs(606)
875
        );
876
        assert_eq!(p.sendme_accept_min_version.get(), 31);
877
        assert_eq!(p.sendme_emit_min_version.get(), 32);
878

            
879
        assert_eq!(
880
            Duration::try_from(p.guard_lifetime_unconfirmed).unwrap(),
881
            Duration::from_secs(86400 * 36)
882
        );
883
        assert_eq!(
884
            Duration::try_from(p.guard_lifetime_confirmed).unwrap(),
885
            Duration::from_secs(86400 * 37)
886
        );
887
        assert_eq!(
888
            Duration::try_from(p.guard_internet_likely_down).unwrap(),
889
            Duration::from_secs(38)
890
        );
891
        assert_eq!(p.guard_max_sample_size.get(), 39);
892
        assert_eq!(p.guard_max_sample_threshold.as_percent().get(), 40);
893
        assert_eq!(p.guard_filtered_min_sample_size.get(), 41);
894
        assert_eq!(p.guard_n_primary.get(), 42);
895
        assert_eq!(p.guard_use_parallelism.get(), 43);
896
        assert_eq!(p.guard_dir_use_parallelism.get(), 44);
897
        assert_eq!(
898
            Duration::try_from(p.guard_nonprimary_connect_timeout).unwrap(),
899
            Duration::from_secs(45)
900
        );
901
        assert_eq!(
902
            Duration::try_from(p.guard_nonprimary_idle_timeout).unwrap(),
903
            Duration::from_secs(46)
904
        );
905
        assert_eq!(
906
            Duration::try_from(p.guard_remove_unlisted_after).unwrap(),
907
            Duration::from_secs(86400 * 47)
908
        );
909
        assert_eq!(p.guard_meaningful_restriction.as_percent().get(), 12);
910
        assert_eq!(p.guard_extreme_restriction.as_percent().get(), 3);
911
    }
912
}