Introduce ClientConfig for is_localhost config parameter

This commit is contained in:
Neel Chauhan 2021-10-05 15:30:00 -07:00
parent f4caae3569
commit e76988738a
7 changed files with 59 additions and 7 deletions

2
Cargo.lock generated
View File

@ -116,7 +116,9 @@ name = "arti-tor-client"
version = "0.0.0"
dependencies = [
"anyhow",
"derive_builder",
"futures",
"serde",
"thiserror",
"tor-chanmgr",
"tor-circmgr",

View File

@ -104,3 +104,9 @@ request_max_retries = 32
# request is still waiting for its own circuits to complete, the request
# will wait this long before using the unexpectedly available circuit.
request_loyalty = "50 msec"
# Rules for client configuration
[client_config]
# Are we running as localhost (e.g. on chutney)?
is_localhost = false

View File

@ -91,6 +91,7 @@ mod proxy;
use std::sync::Arc;
use tor_circmgr::CircMgrConfig;
use tor_client::ClientConfig;
use tor_client::TorClient;
use tor_config::CfgPath;
use tor_dirmgr::{DirMgrConfig, DownloadScheduleConfig, NetworkConfig};
@ -175,6 +176,9 @@ pub struct ArtiConfig {
/// Information about how to expire circuits.
circuit_timing: tor_circmgr::CircuitTiming,
/// Information about client configuration parameters.
client_config: tor_client::ClientConfig,
}
/// Configuration for where information should be stored on disk.
@ -222,13 +226,14 @@ async fn run<R: Runtime>(
statecfg: PathBuf,
dircfg: DirMgrConfig,
circcfg: CircMgrConfig,
clientcfg: ClientConfig,
) -> Result<()> {
use futures::FutureExt;
futures::select!(
r = exit::wait_for_ctrl_c().fuse() => r,
r = async {
let client =
Arc::new(TorClient::bootstrap(runtime.clone(), statecfg, dircfg, circcfg).await?);
Arc::new(TorClient::bootstrap(runtime.clone(), statecfg, dircfg, circcfg, clientcfg).await?);
proxy::run_socks_proxy(runtime, client, socks_port).await
}.fuse() => r,
)
@ -272,6 +277,7 @@ fn main() -> Result<()> {
let statecfg = config.storage.state_dir.path()?;
let dircfg = config.get_dir_config()?;
let circcfg = config.get_circ_config()?;
let clientcfg = config.client_config;
let socks_port = match config.socks_port {
Some(s) => s,
@ -287,7 +293,7 @@ fn main() -> Result<()> {
let runtime = tor_rtcompat::async_std::create_runtime()?;
let rt_copy = runtime.clone();
rt_copy.block_on(run(runtime, socks_port, statecfg, dircfg, circcfg))?;
rt_copy.block_on(run(runtime, socks_port, statecfg, dircfg, circcfg, clientcfg))?;
Ok(())
}

View File

@ -25,8 +25,10 @@ tor-proto = { path="../tor-proto", version="0.0.0" }
tor-rtcompat = { path="../tor-rtcompat", version="0.0.0" }
anyhow = "1.0.38"
derive_builder = "0.10.2"
futures = "0.3.13"
tracing = "0.1.26"
serde = { version = "1.0.124", features = ["derive"] }
thiserror = "1.0.24"
[dev-dependencies]

View File

@ -4,6 +4,7 @@
//! Once the client is bootstrapped, you can make anonymous
//! connections ("streams") over the Tor network using
//! `TorClient::connect()`.
use crate::config::ClientConfig;
use tor_circmgr::{CircMgrConfig, IsolationToken, TargetPort};
use tor_dirmgr::{DirEvent, DirMgrConfig};
use tor_proto::circuit::{ClientCirc, IpVersionPreference};
@ -38,6 +39,8 @@ pub struct TorClient<R: Runtime> {
circmgr: Arc<tor_circmgr::CircMgr<R>>,
/// Directory manager for keeping our directory material up to date.
dirmgr: Arc<tor_dirmgr::DirMgr<R>>,
/// Client configuration
clientcfg: ClientConfig
}
/// Preferences for how to route a stream over the Tor network.
@ -136,13 +139,14 @@ impl<R: Runtime> TorClient<R> {
///
/// Return a client once there is enough directory material to
/// connect safely over the Tor network.
// TODO: Make a ClientConfig to combine DirMgrConfig and circ_cfg
// TODO: Expand ClientConfig to combine DirMgrConfig and circ_cfg
// and state_cfg.
pub async fn bootstrap(
runtime: R,
state_cfg: PathBuf,
dir_cfg: DirMgrConfig,
circ_cfg: CircMgrConfig,
client_cfg: ClientConfig,
) -> Result<TorClient<R>> {
let statemgr = tor_persist::FsStateMgr::from_path(state_cfg)?;
let chanmgr = Arc::new(tor_chanmgr::ChanMgr::new(runtime.clone()));
@ -154,6 +158,7 @@ impl<R: Runtime> TorClient<R> {
Arc::clone(&circmgr),
)
.await?;
let clientcfg = client_cfg;
circmgr.update_network_parameters(dirmgr.netdir().params());
@ -180,11 +185,12 @@ impl<R: Runtime> TorClient<R> {
runtime,
circmgr,
dirmgr,
clientcfg,
})
}
/// Validate if we are an valid hostname or not
fn is_valid_hostname(hostname: &str) -> bool {
fn is_valid_hostname(&self, hostname: &str) -> bool {
/// Check if we have the valid characters for a hostname
fn is_valid_char(byte: u8) -> bool {
((b'a'..=b'z').contains(&byte))
@ -208,7 +214,7 @@ impl<R: Runtime> TorClient<R> {
|| hostname.ends_with('.')
|| hostname.starts_with('.')
|| hostname.is_empty()
|| hostname.to_lowercase().eq("localhost"))
|| (hostname.to_lowercase().eq("localhost") && !self.clientcfg.is_localhost))
|| is_ipv6_str(hostname)
}
@ -235,7 +241,7 @@ impl<R: Runtime> TorClient<R> {
if addr.to_lowercase().ends_with(".onion") {
return Err(anyhow!("Rejecting .onion address as unsupported."));
}
if !Self::is_valid_hostname(addr) {
if !Self::is_valid_hostname(self, addr) {
return Err(anyhow!("Rejecting hostname as invalid."));
}
if let Ok(ip) = IpAddr::from_str(addr) {
@ -272,7 +278,7 @@ impl<R: Runtime> TorClient<R> {
if hostname.to_lowercase().ends_with(".onion") {
return Err(anyhow!("Rejecting .onion address as unsupported."));
}
if !Self::is_valid_hostname(hostname) {
if !Self::is_valid_hostname(self, hostname) {
return Err(anyhow!("Rejecting hostname as invalid."));
}

View File

@ -0,0 +1,26 @@
//! Configuration logic for launching a circuit manager.
use derive_builder::Builder;
use serde::Deserialize;
/// Configuration for clients
///
/// This type is immutable once constructed. To create an object of this type,
/// use [`ClientConfigBuilder`].
#[derive(Debug, Clone, Builder, Deserialize)]
#[builder]
pub struct ClientConfig {
/// Are we running as localhost?
#[builder(default)]
pub(crate) is_localhost: bool,
}
// NOTE: it seems that `unwrap` may be safe because of builder defaults
// check `derive_builder` documentation for details
// https://docs.rs/derive_builder/0.10.2/derive_builder/#default-values
#[allow(clippy::unwrap_used)]
impl Default for ClientConfig {
fn default() -> Self {
ClientConfigBuilder::default().build().unwrap()
}
}

View File

@ -94,10 +94,14 @@
#![warn(clippy::unseparated_literal_suffix)]
#![deny(clippy::unwrap_used)]
mod config;
mod client;
pub use client::{ConnectPrefs, TorClient};
pub use config::{ClientConfig, ClientConfigBuilder};
pub use tor_circmgr::IsolationToken;
/// An anonymized stream over the Tor network.
///