Make DNS fields in arti-client/src/client.rs configurable

This commit is contained in:
Neel Chauhan 2021-12-03 10:28:42 -08:00
parent 68d4070038
commit f32a10865e
6 changed files with 116 additions and 15 deletions

1
Cargo.lock generated
View File

@ -91,6 +91,7 @@ dependencies = [
"derive_builder", "derive_builder",
"directories", "directories",
"futures", "futures",
"humantime-serde",
"hyper", "hyper",
"pin-project", "pin-project",
"serde", "serde",

View File

@ -31,6 +31,7 @@ tor-persist = { path="../tor-persist", version = "0.0.2"}
tor-proto = { path="../tor-proto", version = "0.0.2"} tor-proto = { path="../tor-proto", version = "0.0.2"}
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.2"} tor-rtcompat = { path="../tor-rtcompat", version = "0.0.2"}
humantime-serde = "1.0.1"
derive_builder = "0.10.2" derive_builder = "0.10.2"
directories = "4.0.1" directories = "4.0.1"
futures = "0.3.13" futures = "0.3.13"

View File

@ -6,7 +6,7 @@
//! `TorClient::connect()`. //! `TorClient::connect()`.
use crate::address::IntoTorAddr; use crate::address::IntoTorAddr;
use crate::config::{ClientAddrConfig, TorClientConfig}; use crate::config::{ClientAddrConfig, ClientDNSConfig, TorClientConfig};
use tor_circmgr::{DirInfo, IsolationToken, StreamIsolationBuilder, TargetPort}; use tor_circmgr::{DirInfo, IsolationToken, StreamIsolationBuilder, TargetPort};
use tor_dirmgr::DirEvent; use tor_dirmgr::DirEvent;
use tor_persist::{FsStateMgr, StateMgr}; use tor_persist::{FsStateMgr, StateMgr};
@ -45,6 +45,8 @@ pub struct TorClient<R: Runtime> {
dirmgr: Arc<tor_dirmgr::DirMgr<R>>, dirmgr: Arc<tor_dirmgr::DirMgr<R>>,
/// Client address configuration /// Client address configuration
addrcfg: ClientAddrConfig, addrcfg: ClientAddrConfig,
/// Client DNS configuration
dnscfg: ClientDNSConfig,
} }
/// Preferences for how to route a stream over the Tor network. /// Preferences for how to route a stream over the Tor network.
@ -171,6 +173,7 @@ impl<R: Runtime> TorClient<R> {
); );
} }
let addr_cfg = config.address_filter.clone(); let addr_cfg = config.address_filter.clone();
let dns_cfg = config.dns_rules.clone();
let chanmgr = Arc::new(tor_chanmgr::ChanMgr::new(runtime.clone())); let chanmgr = Arc::new(tor_chanmgr::ChanMgr::new(runtime.clone()));
let circmgr = let circmgr =
tor_circmgr::CircMgr::new(circ_cfg, statemgr.clone(), &runtime, Arc::clone(&chanmgr))?; tor_circmgr::CircMgr::new(circ_cfg, statemgr.clone(), &runtime, Arc::clone(&chanmgr))?;
@ -217,6 +220,7 @@ impl<R: Runtime> TorClient<R> {
circmgr, circmgr,
dirmgr, dirmgr,
addrcfg: addr_cfg, addrcfg: addr_cfg,
dnscfg: dns_cfg,
}) })
} }
@ -257,14 +261,11 @@ impl<R: Runtime> TorClient<R> {
let circ = self.get_or_launch_exit_circ(&exit_ports, &flags).await?; let circ = self.get_or_launch_exit_circ(&exit_ports, &flags).await?;
info!("Got a circuit for {}:{}", addr, port); info!("Got a circuit for {}:{}", addr, port);
// TODO: make this configurable.
let stream_timeout = Duration::new(10, 0);
let stream_future = circ.begin_stream(&addr, port, Some(flags.stream_parameters())); let stream_future = circ.begin_stream(&addr, port, Some(flags.stream_parameters()));
// This timeout is needless but harmless for optimistic streams. // This timeout is needless but harmless for optimistic streams.
let stream = self let stream = self
.runtime .runtime
.timeout(stream_timeout, stream_future) .timeout(self.dnscfg.stream_timeout, stream_future)
.await??; .await??;
Ok(stream) Ok(stream)
@ -282,13 +283,10 @@ impl<R: Runtime> TorClient<R> {
let flags = flags.unwrap_or_default(); let flags = flags.unwrap_or_default();
let circ = self.get_or_launch_exit_circ(&[], &flags).await?; let circ = self.get_or_launch_exit_circ(&[], &flags).await?;
// TODO: make this configurable.
let resolve_timeout = Duration::new(10, 0);
let resolve_future = circ.resolve(hostname); let resolve_future = circ.resolve(hostname);
let addrs = self let addrs = self
.runtime .runtime
.timeout(resolve_timeout, resolve_future) .timeout(self.dnscfg.resolve_timeout, resolve_future)
.await??; .await??;
Ok(addrs) Ok(addrs)
@ -305,13 +303,10 @@ impl<R: Runtime> TorClient<R> {
let flags = flags.unwrap_or_default(); let flags = flags.unwrap_or_default();
let circ = self.get_or_launch_exit_circ(&[], &flags).await?; let circ = self.get_or_launch_exit_circ(&[], &flags).await?;
// TODO: make this configurable.
let resolve_ptr_timeout = Duration::new(10, 0);
let resolve_ptr_future = circ.resolve_ptr(addr); let resolve_ptr_future = circ.resolve_ptr(addr);
let hostnames = self let hostnames = self
.runtime .runtime
.timeout(resolve_ptr_timeout, resolve_ptr_future) .timeout(self.dnscfg.resolve_ptr_timeout, resolve_ptr_future)
.await??; .await??;
Ok(hostnames) Ok(hostnames)

View File

@ -7,6 +7,7 @@ use serde::Deserialize;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration;
use tor_config::CfgPath; use tor_config::CfgPath;
pub use tor_config::ConfigBuildError; pub use tor_config::ConfigBuildError;
@ -45,6 +46,31 @@ pub struct ClientAddrConfig {
pub(crate) allow_local_addrs: bool, pub(crate) allow_local_addrs: bool,
} }
/// Configuration for client behavior relating to DNS
///
/// This type is immutable once constructed. To create an object of this type,
/// use [`ClientDNSConfigBuilder`].
#[derive(Debug, Clone, Builder, Deserialize, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[serde(deny_unknown_fields)]
#[non_exhaustive]
pub struct ClientDNSConfig {
/// The client DNS stream timeout
#[builder(default = "default_dns_stream_timeout()")]
#[serde(with = "humantime_serde", default = "default_dns_stream_timeout")]
pub stream_timeout: Duration,
/// The client DNS resolve timeout
#[builder(default = "default_dns_resolve_timeout()")]
#[serde(with = "humantime_serde", default = "default_dns_resolve_timeout")]
pub resolve_timeout: Duration,
/// The client DNS resolve timeout
#[builder(default = "default_dns_resolve_ptr_timeout()")]
#[serde(with = "humantime_serde", default = "default_dns_resolve_ptr_timeout")]
pub resolve_ptr_timeout: Duration,
}
// NOTE: it seems that `unwrap` may be safe because of builder defaults // NOTE: it seems that `unwrap` may be safe because of builder defaults
// check `derive_builder` documentation for details // check `derive_builder` documentation for details
// https://docs.rs/derive_builder/0.10.2/derive_builder/#default-values // https://docs.rs/derive_builder/0.10.2/derive_builder/#default-values
@ -70,6 +96,47 @@ impl ClientAddrConfig {
} }
} }
#[allow(clippy::unwrap_used)]
impl Default for ClientDNSConfig {
fn default() -> Self {
ClientDNSConfigBuilder::default().build().unwrap()
}
}
impl From<ClientDNSConfig> for ClientDNSConfigBuilder {
fn from(cfg: ClientDNSConfig) -> ClientDNSConfigBuilder {
let mut builder = ClientDNSConfigBuilder::default();
builder
.stream_timeout(cfg.stream_timeout)
.resolve_timeout(cfg.resolve_timeout)
.resolve_ptr_timeout(cfg.resolve_ptr_timeout);
builder
}
}
impl ClientDNSConfig {
/// Return a new [`ClientDNSConfigBuilder`].
pub fn builder() -> ClientDNSConfigBuilder {
ClientDNSConfigBuilder::default()
}
}
/// Return the default stream timeout
fn default_dns_stream_timeout() -> Duration {
Duration::new(10, 0)
}
/// Return the default resolve timeout
fn default_dns_resolve_timeout() -> Duration {
Duration::new(10, 0)
}
/// Return the default PTR resolve timeout
fn default_dns_resolve_ptr_timeout() -> Duration {
Duration::new(10, 0)
}
/// Configuration for where information should be stored on disk. /// Configuration for where information should be stored on disk.
/// ///
/// By default, cache information will be stored in `${ARTI_CACHE}`, and /// By default, cache information will be stored in `${ARTI_CACHE}`, and
@ -190,6 +257,9 @@ pub struct TorClientConfig {
/// Rules about which addresses the client is willing to connect to. /// Rules about which addresses the client is willing to connect to.
pub(crate) address_filter: ClientAddrConfig, pub(crate) address_filter: ClientAddrConfig,
/// Rules about client DNS configuration
pub(crate) dns_rules: ClientDNSConfig,
} }
impl Default for TorClientConfig { impl Default for TorClientConfig {
@ -249,6 +319,8 @@ pub struct TorClientConfigBuilder {
circuit_timing: circ::CircuitTimingBuilder, circuit_timing: circ::CircuitTimingBuilder,
/// Inner builder for the `address_filter` section. /// Inner builder for the `address_filter` section.
address_filter: ClientAddrConfigBuilder, address_filter: ClientAddrConfigBuilder,
/// Inner builder for the `dns_rules` section.
dns_rules: ClientDNSConfigBuilder,
} }
impl TorClientConfigBuilder { impl TorClientConfigBuilder {
@ -276,6 +348,7 @@ impl TorClientConfigBuilder {
.address_filter .address_filter
.build() .build()
.map_err(|e| e.within("address_filter"))?; .map_err(|e| e.within("address_filter"))?;
let dns_rules = self.dns_rules.build().map_err(|e| e.within("dns_rules"))?;
Ok(TorClientConfig { Ok(TorClientConfig {
tor_network, tor_network,
@ -285,6 +358,7 @@ impl TorClientConfigBuilder {
path_rules, path_rules,
circuit_timing, circuit_timing,
address_filter, address_filter,
dns_rules,
}) })
} }
@ -384,6 +458,7 @@ impl From<TorClientConfig> for TorClientConfigBuilder {
path_rules, path_rules,
circuit_timing, circuit_timing,
address_filter, address_filter,
dns_rules,
} = cfg; } = cfg;
TorClientConfigBuilder { TorClientConfigBuilder {
@ -394,6 +469,7 @@ impl From<TorClientConfig> for TorClientConfigBuilder {
path_rules: path_rules.into(), path_rules: path_rules.into(),
circuit_timing: circuit_timing.into(), circuit_timing: circuit_timing.into(),
address_filter: address_filter.into(), address_filter: address_filter.into(),
dns_rules: dns_rules.into(),
} }
} }
} }

View File

@ -110,3 +110,15 @@ request_loyalty = "50 msec"
# Should we allow attempts to make Tor connections to local addresses? # Should we allow attempts to make Tor connections to local addresses?
allow_local_addrs = false allow_local_addrs = false
# Rules for a client's DNS resolution
[dns_rules]
# How long should we wait before timing out a stream when connecting to a host?
stream_timeout = "10 sec"
# How long should we wait before timing out when resolving a DNS record?
resolve_timeout = "10 sec"
# How long should we wait before timing out when resolving a DNS PTR record?
resolve_ptr_timeout = "10 sec"

View File

@ -3,8 +3,8 @@
use arti_client::config::{ use arti_client::config::{
circ, circ,
dir::{self, DownloadScheduleConfig, NetworkConfig}, dir::{self, DownloadScheduleConfig, NetworkConfig},
ClientAddrConfig, ClientAddrConfigBuilder, StorageConfig, StorageConfigBuilder, ClientAddrConfig, ClientAddrConfigBuilder, ClientDNSConfig, ClientDNSConfigBuilder,
TorClientConfig, TorClientConfigBuilder, StorageConfig, StorageConfigBuilder, TorClientConfig, TorClientConfigBuilder,
}; };
use derive_builder::Builder; use derive_builder::Builder;
use serde::Deserialize; use serde::Deserialize;
@ -157,6 +157,9 @@ pub struct ArtiConfig {
/// Rules about which addresses the client is willing to connect to. /// Rules about which addresses the client is willing to connect to.
address_filter: ClientAddrConfig, address_filter: ClientAddrConfig,
/// Rules about a client's DNS resolution.
dns_rules: ClientDNSConfig,
} }
impl From<ArtiConfig> for TorClientConfigBuilder { impl From<ArtiConfig> for TorClientConfigBuilder {
@ -232,6 +235,8 @@ pub struct ArtiConfigBuilder {
circuit_timing: circ::CircuitTimingBuilder, circuit_timing: circ::CircuitTimingBuilder,
/// Builder for the address_filter section. /// Builder for the address_filter section.
address_filter: ClientAddrConfigBuilder, address_filter: ClientAddrConfigBuilder,
/// Builder for the DNS resolution rules.
dns_rules: ClientDNSConfigBuilder,
} }
impl ArtiConfigBuilder { impl ArtiConfigBuilder {
@ -261,6 +266,7 @@ impl ArtiConfigBuilder {
.address_filter .address_filter
.build() .build()
.map_err(|e| e.within("address_filter"))?; .map_err(|e| e.within("address_filter"))?;
let dns_rules = self.dns_rules.build().map_err(|e| e.within("dns_rules"))?;
Ok(ArtiConfig { Ok(ArtiConfig {
proxy, proxy,
logging, logging,
@ -271,6 +277,7 @@ impl ArtiConfigBuilder {
path_rules, path_rules,
circuit_timing, circuit_timing,
address_filter, address_filter,
dns_rules,
}) })
} }
@ -355,6 +362,14 @@ impl ArtiConfigBuilder {
pub fn address_filter(&mut self) -> &mut ClientAddrConfigBuilder { pub fn address_filter(&mut self) -> &mut ClientAddrConfigBuilder {
&mut self.address_filter &mut self.address_filter
} }
/// Return a mutable reference to a [`ClientDNSConfigBuilder`].
///
/// This section controls how Arti should handle an exit relay's DNS
/// resolution.
pub fn dns_rules(&mut self) -> &mut ClientDNSConfigBuilder {
&mut self.dns_rules
}
} }
impl From<ArtiConfig> for ArtiConfigBuilder { impl From<ArtiConfig> for ArtiConfigBuilder {
@ -369,6 +384,7 @@ impl From<ArtiConfig> for ArtiConfigBuilder {
path_rules: cfg.path_rules.into(), path_rules: cfg.path_rules.into(),
circuit_timing: cfg.circuit_timing.into(), circuit_timing: cfg.circuit_timing.into(),
address_filter: cfg.address_filter.into(), address_filter: cfg.address_filter.into(),
dns_rules: cfg.dns_rules.into(),
} }
} }
} }