1
//! Types and functions to configure a Tor client.
2
//!
3
//! Some of these are re-exported from lower-level crates.
4
//!
5
//! # ⚠ Stability Warning ⚠
6
//!
7
//! The design of this structure, and of the configuration system for
8
//! Arti, is likely to change significantly before the release of Arti
9
//! 1.0.0. The layout of options within this structure is also likely
10
//! to change. For more information see ticket [#285].
11
//!
12
//! [#285]: https://gitlab.torproject.org/tpo/core/arti/-/issues/285
13

            
14
use derive_builder::Builder;
15
use serde::Deserialize;
16
use std::collections::HashMap;
17
use std::path::Path;
18
use std::path::PathBuf;
19
use std::time::Duration;
20
pub use tor_basic_utils::humantime_serde_option;
21
pub use tor_config::{CfgPath, ConfigBuildError, Reconfigure};
22

            
23
/// Types for configuring how Tor circuits are built.
24
pub mod circ {
25
    pub use tor_circmgr::{
26
        CircMgrConfig, CircMgrConfigBuilder, CircuitTiming, CircuitTimingBuilder, PathConfig,
27
        PathConfigBuilder, PreemptiveCircuitConfig, PreemptiveCircuitConfigBuilder,
28
    };
29
}
30

            
31
/// Types for configuring how Tor accesses its directory information.
32
pub mod dir {
33
    pub use tor_dirmgr::{
34
        Authority, AuthorityBuilder, DirMgrConfig, DirMgrConfigBuilder, DownloadSchedule,
35
        DownloadScheduleConfig, DownloadScheduleConfigBuilder, FallbackDir, FallbackDirBuilder,
36
        NetworkConfig, NetworkConfigBuilder,
37
    };
38
}
39

            
40
/// Configuration for client behavior relating to addresses.
41
///
42
/// This type is immutable once constructed. To create an object of this type,
43
/// use [`ClientAddrConfigBuilder`].
44
///
45
/// You can replace this configuration on a running Arti client.  Doing so will
46
/// affect new streams and requests, but will have no effect on existing streams
47
/// and requests.
48
62
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
49
#[builder(build_fn(error = "ConfigBuildError"))]
50
3
#[builder(derive(Deserialize))]
51
#[serde(deny_unknown_fields)]
52
pub struct ClientAddrConfig {
53
    /// Should we allow attempts to make Tor connections to local addresses?
54
    ///
55
    /// This option is off by default, since (by default) Tor exits will
56
    /// always reject connections to such addresses.
57
    #[builder(default)]
58
    #[serde(default)]
59
    pub(crate) allow_local_addrs: bool,
60
}
61

            
62
/// Configuration for client behavior relating to stream connection timeouts
63
///
64
/// This type is immutable once constructed. To create an object of this type,
65
/// use [`StreamTimeoutConfigBuilder`].
66
///
67
/// You can replace this configuration on a running Arti client.  Doing so will
68
/// affect new streams and requests, but will have no effect on existing streams
69
/// and requests—even those that are currently waiting.
70
53
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
71
#[builder(build_fn(error = "ConfigBuildError"))]
72
10
#[builder(derive(Deserialize))]
73
#[serde(deny_unknown_fields)]
74
#[non_exhaustive]
75
pub struct StreamTimeoutConfig {
76
    /// How long should we wait before timing out a stream when connecting
77
    /// to a host?
78
    #[builder(default = "default_connect_timeout()")]
79
    #[serde(with = "humantime_serde", default = "default_connect_timeout")]
80
    #[builder(attrs(serde(with = "humantime_serde_option")))]
81
    pub(crate) connect_timeout: Duration,
82

            
83
    /// How long should we wait before timing out when resolving a DNS record?
84
    #[builder(default = "default_dns_resolve_timeout()")]
85
    #[serde(with = "humantime_serde", default = "default_dns_resolve_timeout")]
86
    #[builder(attrs(serde(with = "humantime_serde_option")))]
87
    pub(crate) resolve_timeout: Duration,
88

            
89
    /// How long should we wait before timing out when resolving a DNS
90
    /// PTR record?
91
    #[builder(default = "default_dns_resolve_ptr_timeout()")]
92
    #[serde(with = "humantime_serde", default = "default_dns_resolve_ptr_timeout")]
93
    #[builder(attrs(serde(with = "humantime_serde_option")))]
94
    pub(crate) resolve_ptr_timeout: Duration,
95
}
96

            
97
// NOTE: it seems that `unwrap` may be safe because of builder defaults
98
// check `derive_builder` documentation for details
99
// https://docs.rs/derive_builder/0.10.2/derive_builder/#default-values
100
#[allow(clippy::unwrap_used)]
101
impl Default for ClientAddrConfig {
102
9
    fn default() -> Self {
103
9
        ClientAddrConfigBuilder::default().build().unwrap()
104
9
    }
105
}
106

            
107
impl ClientAddrConfig {
108
    /// Return a new [`ClientAddrConfigBuilder`].
109
    pub fn builder() -> ClientAddrConfigBuilder {
110
        ClientAddrConfigBuilder::default()
111
    }
112
}
113

            
114
#[allow(clippy::unwrap_used)]
115
impl Default for StreamTimeoutConfig {
116
    fn default() -> Self {
117
        StreamTimeoutConfigBuilder::default().build().unwrap()
118
    }
119
}
120

            
121
impl StreamTimeoutConfig {
122
    /// Return a new [`StreamTimeoutConfigBuilder`].
123
    pub fn builder() -> StreamTimeoutConfigBuilder {
124
        StreamTimeoutConfigBuilder::default()
125
    }
126
}
127

            
128
/// Return the default stream timeout
129
44
fn default_connect_timeout() -> Duration {
130
44
    Duration::new(10, 0)
131
44
}
132

            
133
/// Return the default resolve timeout
134
44
fn default_dns_resolve_timeout() -> Duration {
135
44
    Duration::new(10, 0)
136
44
}
137

            
138
/// Return the default PTR resolve timeout
139
44
fn default_dns_resolve_ptr_timeout() -> Duration {
140
44
    Duration::new(10, 0)
141
44
}
142

            
143
/// Configuration for where information should be stored on disk.
144
///
145
/// By default, cache information will be stored in `${ARTI_CACHE}`, and
146
/// persistent state will be stored in `${ARTI_LOCAL_DATA}`.  That means that
147
/// _all_ programs using these defaults will share their cache and state data.
148
/// If that isn't what you want,  you'll need to override these directories.
149
///
150
/// On unix, the default directories will typically expand to `~/.cache/arti`
151
/// and `~/.local/share/arti/` respectively, depending on the user's
152
/// environment. Other platforms will also use suitable defaults. For more
153
/// information, see the documentation for [`CfgPath`].
154
///
155
/// This section is for read/write storage.
156
///
157
/// You cannot change this section on a running Arti client.
158
53
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
159
#[serde(deny_unknown_fields)]
160
#[builder(build_fn(error = "ConfigBuildError"))]
161
5
#[builder(derive(Deserialize))]
162
pub struct StorageConfig {
163
    /// Location on disk for cached directory information.
164
    #[builder(setter(into), default = "default_cache_dir()")]
165
    #[serde(default = "default_cache_dir")]
166
    cache_dir: CfgPath,
167
    /// Location on disk for less-sensitive persistent state information.
168
    #[builder(setter(into), default = "default_state_dir()")]
169
    #[serde(default = "default_state_dir")]
170
    state_dir: CfgPath,
171
}
172

            
173
/// Return the default cache directory.
174
32
fn default_cache_dir() -> CfgPath {
175
32
    CfgPath::new("${ARTI_CACHE}".to_owned())
176
32
}
177

            
178
/// Return the default state directory.
179
32
fn default_state_dir() -> CfgPath {
180
32
    CfgPath::new("${ARTI_LOCAL_DATA}".to_owned())
181
32
}
182

            
183
impl Default for StorageConfig {
184
    fn default() -> Self {
185
        Self::builder().build().expect("Default builder failed")
186
    }
187
}
188

            
189
impl StorageConfig {
190
    /// Return a new StorageConfigBuilder.
191
    pub fn builder() -> StorageConfigBuilder {
192
        StorageConfigBuilder::default()
193
    }
194

            
195
    /// Try to expand `state_dir` to be a path buffer.
196
2
    pub(crate) fn expand_state_dir(&self) -> Result<PathBuf, ConfigBuildError> {
197
2
        self.state_dir
198
2
            .path()
199
2
            .map_err(|e| ConfigBuildError::Invalid {
200
                field: "state_dir".to_owned(),
201
                problem: e.to_string(),
202
2
            })
203
2
    }
204
    /// Try to expand `cache_dir` to be a path buffer.
205
2
    pub(crate) fn expand_cache_dir(&self) -> Result<PathBuf, ConfigBuildError> {
206
2
        self.cache_dir
207
2
            .path()
208
2
            .map_err(|e| ConfigBuildError::Invalid {
209
                field: "cache_dir".to_owned(),
210
                problem: e.to_string(),
211
2
            })
212
2
    }
213
}
214

            
215
/// Configuration for system resources used by Tor.
216
///
217
/// You cannot change this section on a running Arti client.
218
89
#[derive(Deserialize, Debug, Clone, Builder, Eq, PartialEq)]
219
#[serde(deny_unknown_fields)]
220
#[builder(build_fn(error = "ConfigBuildError"))]
221
3
#[builder(derive(Deserialize))]
222
#[non_exhaustive]
223
pub struct SystemConfig {
224
    /// Maximum number of file descriptors we should launch with
225
    #[builder(setter(into), default = "default_max_files()")]
226
    #[serde(default = "default_max_files")]
227
    pub max_files: u64,
228
}
229

            
230
/// Return the default maximum number of file descriptors to launch with.
231
80
fn default_max_files() -> u64 {
232
80
    16384
233
80
}
234

            
235
impl Default for SystemConfig {
236
18
    fn default() -> Self {
237
18
        Self::builder().build().expect("Default builder failed")
238
18
    }
239
}
240

            
241
impl SystemConfig {
242
    /// Return a new SystemConfigBuilder.
243
18
    pub fn builder() -> SystemConfigBuilder {
244
18
        SystemConfigBuilder::default()
245
18
    }
246
}
247

            
248
/// A configuration used to bootstrap a [`TorClient`](crate::TorClient).
249
///
250
/// In order to connect to the Tor network, Arti needs to know a few
251
/// well-known directory caches on the network, and the public keys of the
252
/// network's directory authorities.  It also needs a place on disk to
253
/// store persistent state and cached directory information. (See [`StorageConfig`]
254
/// for default directories.)
255
///
256
/// Most users will create a TorClientConfig by running
257
/// [`TorClientConfig::default`].
258
///
259
/// If you need to override the locations where Arti stores its
260
/// information, you can make a TorClientConfig with
261
/// [`TorClientConfigBuilder::from_directories`].
262
///
263
/// Finally, you can get fine-grained control over the members of a a
264
/// TorClientConfig using [`TorClientConfigBuilder`].
265
///
266
/// # ⚠ Stability Warning ⚠
267
///
268
/// The design of this structure, and of the configuration system for
269
/// Arti, is likely to change significantly before the release of Arti
270
/// 1.0.0. The layout of options within this structure is also likely
271
/// to change. For more information see ticket [#285].
272
///
273
/// [#285]: https://gitlab.torproject.org/tpo/core/arti/-/issues/285
274
4
#[derive(Clone, Debug, Eq, PartialEq)]
275
pub struct TorClientConfig {
276
    /// Information about the Tor network we want to connect to.
277
    tor_network: dir::NetworkConfig,
278

            
279
    /// Directories for storing information on disk
280
    pub(crate) storage: StorageConfig,
281

            
282
    /// Information about when and how often to download directory information
283
    download_schedule: dir::DownloadScheduleConfig,
284

            
285
    /// Facility to override network parameters from the values set in the
286
    /// consensus.
287
    override_net_params: HashMap<String, i32>,
288

            
289
    /// Information about how to build paths through the network.
290
    path_rules: circ::PathConfig,
291

            
292
    /// Information about preemptive circuits.
293
    preemptive_circuits: circ::PreemptiveCircuitConfig,
294

            
295
    /// Information about how to retry and expire circuits and request for circuits.
296
    circuit_timing: circ::CircuitTiming,
297

            
298
    /// Rules about which addresses the client is willing to connect to.
299
    pub(crate) address_filter: ClientAddrConfig,
300

            
301
    /// Information about timing out client requests.
302
    pub(crate) stream_timeouts: StreamTimeoutConfig,
303

            
304
    /// Information about system resources
305
    pub system: SystemConfig,
306
}
307

            
308
impl Default for TorClientConfig {
309
31
    fn default() -> Self {
310
31
        Self::builder()
311
31
            .build()
312
31
            .expect("Could not build TorClientConfig from default configuration.")
313
31
    }
314
}
315

            
316
impl TorClientConfig {
317
    /// Return a new TorClientConfigBuilder.
318
32
    pub fn builder() -> TorClientConfigBuilder {
319
32
        TorClientConfigBuilder::default()
320
32
    }
321

            
322
    /// Build a DirMgrConfig from this configuration.
323
2
    pub(crate) fn get_dirmgr_config(&self) -> Result<dir::DirMgrConfig, ConfigBuildError> {
324
2
        let mut dircfg = dir::DirMgrConfigBuilder::default();
325
2
        dircfg.network_config(self.tor_network.clone());
326
2
        dircfg.schedule_config(self.download_schedule.clone());
327
2
        dircfg.cache_path(self.storage.expand_cache_dir()?);
328
2
        for (k, v) in &self.override_net_params {
329
            dircfg.override_net_param(k.clone(), *v);
330
        }
331
2
        dircfg.build()
332
2
    }
333

            
334
    /// Return a [`CircMgrConfig`](circ::CircMgrConfig) object based on the user's selected
335
    /// configuration.
336
2
    pub(crate) fn get_circmgr_config(&self) -> Result<circ::CircMgrConfig, ConfigBuildError> {
337
2
        let mut builder = circ::CircMgrConfigBuilder::default();
338
2
        builder
339
2
            .path_rules(self.path_rules.clone())
340
2
            .circuit_timing(self.circuit_timing.clone())
341
2
            .build()
342
2
    }
343
}
344

            
345
/// Builder object used to construct a [`TorClientConfig`].
346
///
347
/// Unlike other builder types in Arti, this builder works by exposing an
348
/// inner builder for each section in the [`TorClientConfig`].
349
47
#[derive(Clone, Default, Deserialize)]
350
pub struct TorClientConfigBuilder {
351
    /// Inner builder for the `tor_network` section.
352
    #[serde(default)]
353
    tor_network: dir::NetworkConfigBuilder,
354
    /// Inner builder for the `storage` section.
355
    #[serde(default)]
356
    storage: StorageConfigBuilder,
357
    /// Inner builder for the `download_schedule` section.
358
    #[serde(default)]
359
    download_schedule: dir::DownloadScheduleConfigBuilder,
360
    /// Inner builder for the `override_net_params` section.
361
    #[serde(default)]
362
    override_net_params: HashMap<String, i32>,
363
    /// Inner builder for the `path_rules` section.
364
    #[serde(default)]
365
    path_rules: circ::PathConfigBuilder,
366
    /// Inner builder for the `circuit_timing` section.
367
    #[serde(default)]
368
    preemptive_circuits: circ::PreemptiveCircuitConfigBuilder,
369
    /// Inner builder for the `circuit_timing` section.
370
    #[serde(default)]
371
    circuit_timing: circ::CircuitTimingBuilder,
372
    /// Inner builder for the `address_filter` section.
373
    #[serde(default)]
374
    address_filter: ClientAddrConfigBuilder,
375
    /// Inner builder for the `stream_timeouts` section.
376
    #[serde(default)]
377
    stream_timeouts: StreamTimeoutConfigBuilder,
378
    /// Inner builder for the `system` section.
379
    #[serde(default)]
380
    system: SystemConfigBuilder,
381
}
382

            
383
impl TorClientConfigBuilder {
384
    /// Construct a [`TorClientConfig`] from this builder.
385
53
    pub fn build(&self) -> Result<TorClientConfig, ConfigBuildError> {
386
53
        let tor_network = self
387
53
            .tor_network
388
53
            .build()
389
53
            .map_err(|e| e.within("tor_network"))?;
390
53
        let storage = self.storage.build().map_err(|e| e.within("storage"))?;
391
53
        let download_schedule = self
392
53
            .download_schedule
393
53
            .build()
394
53
            .map_err(|e| e.within("download_schedule"))?;
395
53
        let override_net_params = self.override_net_params.clone();
396
53
        let path_rules = self
397
53
            .path_rules
398
53
            .build()
399
53
            .map_err(|e| e.within("path_rules"))?;
400
53
        let preemptive_circuits = self
401
53
            .preemptive_circuits
402
53
            .build()
403
53
            .map_err(|e| e.within("preemptive_circuits"))?;
404
53
        let circuit_timing = self
405
53
            .circuit_timing
406
53
            .build()
407
53
            .map_err(|e| e.within("circuit_timing"))?;
408
53
        let address_filter = self
409
53
            .address_filter
410
53
            .build()
411
53
            .map_err(|e| e.within("address_filter"))?;
412
53
        let stream_timeouts = self
413
53
            .stream_timeouts
414
53
            .build()
415
53
            .map_err(|e| e.within("stream_timeouts"))?;
416
53
        let system = self.system.build().map_err(|e| e.within("system"))?;
417

            
418
53
        Ok(TorClientConfig {
419
53
            tor_network,
420
53
            storage,
421
53
            download_schedule,
422
53
            override_net_params,
423
53
            path_rules,
424
53
            preemptive_circuits,
425
53
            circuit_timing,
426
53
            address_filter,
427
53
            stream_timeouts,
428
53
            system,
429
53
        })
430
53
    }
431

            
432
    /// Returns a `TorClientConfigBuilder` using the specified state and cache directories.
433
    ///
434
    /// All other configuration options are set to their defaults.
435
2
    pub fn from_directories<P, Q>(state_dir: P, cache_dir: Q) -> Self
436
2
    where
437
2
        P: AsRef<Path>,
438
2
        Q: AsRef<Path>,
439
2
    {
440
2
        let mut builder = Self::default();
441
2
        builder
442
2
            .storage()
443
2
            .cache_dir(CfgPath::from_path(cache_dir))
444
2
            .state_dir(CfgPath::from_path(state_dir));
445
2
        builder
446
2
    }
447

            
448
    /// Return a mutable reference to a
449
    /// [`NetworkConfigBuilder`](dir::NetworkConfigBuilder)
450
    /// to use in configuring the underlying Tor network.
451
    ///
452
    /// Most programs shouldn't need to alter this configuration: it's only for
453
    /// cases when you need to use a nonstandard set of Tor directory authorities
454
    /// and fallback caches.
455
10
    pub fn tor_network(&mut self) -> &mut dir::NetworkConfigBuilder {
456
10
        &mut self.tor_network
457
10
    }
458

            
459
    /// Return a mutable reference to a [`StorageConfigBuilder`].
460
    ///
461
    /// This section is used to configure the locations where Arti should
462
    /// store files on disk.
463
12
    pub fn storage(&mut self) -> &mut StorageConfigBuilder {
464
12
        &mut self.storage
465
12
    }
466

            
467
    /// Return a mutable reference to a
468
    /// [`DownloadScheduleConfigBuilder`](dir::DownloadScheduleConfigBuilder).
469
    ///
470
    /// This section is used to override Arti's schedule when attempting and
471
    /// retrying to download directory objects.
472
10
    pub fn download_schedule(&mut self) -> &mut dir::DownloadScheduleConfigBuilder {
473
10
        &mut self.download_schedule
474
10
    }
475

            
476
    /// Return a mutable reference to a [`HashMap`] of network parameters
477
    /// that should be used to override those specified in the consensus
478
    /// directory.
479
    ///
480
    /// This section should not usually be used for anything but testing:
481
    /// if you find yourself needing to configure an override here for
482
    /// production use, please consider opening a feature request for it
483
    /// instead.
484
    ///
485
    /// For a complete list of Tor's defined network parameters (not all of
486
    /// which are yet supported by Arti), see
487
    /// [`path-spec.txt`](https://gitlab.torproject.org/tpo/core/torspec/-/blob/main/param-spec.txt).
488
10
    pub fn override_net_params(&mut self) -> &mut HashMap<String, i32> {
489
10
        &mut self.override_net_params
490
10
    }
491

            
492
    /// Return a mutable reference to a [`PathConfigBuilder`](circ::PathConfigBuilder).
493
    ///
494
    /// This section is used to override Arti's rules for selecting which
495
    /// relays should be used in a given circuit.
496
10
    pub fn path_rules(&mut self) -> &mut circ::PathConfigBuilder {
497
10
        &mut self.path_rules
498
10
    }
499

            
500
    /// Return a mutable reference to a [`PreemptiveCircuitConfigBuilder`](circ::PreemptiveCircuitConfigBuilder).
501
    ///
502
    /// This section overrides Arti's rules for preemptive circuits.
503
9
    pub fn preemptive_circuits(&mut self) -> &mut circ::PreemptiveCircuitConfigBuilder {
504
9
        &mut self.preemptive_circuits
505
9
    }
506

            
507
    /// Return a mutable reference to a [`CircuitTimingBuilder`](circ::CircuitTimingBuilder).
508
    ///
509
    /// This section overrides Arti's rules for deciding how long to use
510
    /// circuits, and when to give up on attempts to launch them.
511
10
    pub fn circuit_timing(&mut self) -> &mut circ::CircuitTimingBuilder {
512
10
        &mut self.circuit_timing
513
10
    }
514

            
515
    /// Return a mutable reference to a [`StreamTimeoutConfigBuilder`].
516
    ///
517
    /// This section overrides Arti's rules for deciding how long a stream
518
    /// request (that is, an attempt to connect or resolve) should wait
519
    /// for a response before deciding that the stream has timed out.
520
    pub fn stream_timeouts(&mut self) -> &mut StreamTimeoutConfigBuilder {
521
        &mut self.stream_timeouts
522
    }
523

            
524
    /// Return a mutable reference to a [`ClientAddrConfigBuilder`].
525
    ///
526
    /// This section controls which addresses Arti is willing to launch connections
527
    /// to over the Tor network.  Any addresses rejected by this section cause
528
    /// stream attempts to fail before any traffic is sent over the network.
529
10
    pub fn address_filter(&mut self) -> &mut ClientAddrConfigBuilder {
530
10
        &mut self.address_filter
531
10
    }
532

            
533
    /// Return a mutable reference to a [`SystemConfigBuilder`].
534
    ///
535
    /// This section is used to configure the system resources used by Arti.
536
    pub fn system(&mut self) -> &mut SystemConfigBuilder {
537
        &mut self.system
538
    }
539
}
540

            
541
#[cfg(test)]
542
mod test {
543
    #![allow(clippy::unwrap_used)]
544
    use super::*;
545

            
546
    #[test]
547
    fn defaults() {
548
        let dflt = TorClientConfig::default();
549
        let b2 = TorClientConfigBuilder::default();
550
        let dflt2 = b2.build().unwrap();
551
        assert_eq!(&dflt, &dflt2);
552
    }
553

            
554
    #[test]
555
    fn builder() {
556
        use tor_dirmgr::DownloadSchedule;
557
        let sec = std::time::Duration::from_secs(1);
558

            
559
        let auth = dir::Authority::builder()
560
            .name("Fred")
561
            .v3ident([22; 20].into())
562
            .build()
563
            .unwrap();
564
        let fallback = dir::FallbackDir::builder()
565
            .rsa_identity([23; 20].into())
566
            .ed_identity([99; 32].into())
567
            .orports(vec!["127.0.0.7:7".parse().unwrap()])
568
            .build()
569
            .unwrap();
570

            
571
        let mut bld = TorClientConfig::builder();
572
        bld.tor_network()
573
            .authorities(vec![auth])
574
            .fallback_caches(vec![fallback]);
575
        bld.storage()
576
            .cache_dir(CfgPath::new("/var/tmp/foo".to_owned()))
577
            .state_dir(CfgPath::new("/var/tmp/bar".to_owned()));
578
        bld.download_schedule()
579
            .retry_certs(DownloadSchedule::new(10, sec, 3))
580
            .retry_microdescs(DownloadSchedule::new(30, 10 * sec, 9));
581
        bld.override_net_params()
582
            .insert("wombats-per-quokka".to_owned(), 7);
583
        bld.path_rules()
584
            .ipv4_subnet_family_prefix(20)
585
            .ipv6_subnet_family_prefix(48);
586
        bld.circuit_timing()
587
            .max_dirtiness(90 * sec)
588
            .request_timeout(10 * sec)
589
            .request_max_retries(22)
590
            .request_loyalty(3600 * sec);
591
        bld.address_filter().allow_local_addrs(true);
592

            
593
        let val = bld.build().unwrap();
594

            
595
        assert_ne!(val, TorClientConfig::default());
596
    }
597
}