Introduce ClientConfig for is_localhost config parameter
This commit is contained in:
parent
f4caae3569
commit
e76988738a
|
@ -116,7 +116,9 @@ name = "arti-tor-client"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"derive_builder",
|
||||||
"futures",
|
"futures",
|
||||||
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tor-chanmgr",
|
"tor-chanmgr",
|
||||||
"tor-circmgr",
|
"tor-circmgr",
|
||||||
|
|
|
@ -104,3 +104,9 @@ request_max_retries = 32
|
||||||
# request is still waiting for its own circuits to complete, the request
|
# request is still waiting for its own circuits to complete, the request
|
||||||
# will wait this long before using the unexpectedly available circuit.
|
# will wait this long before using the unexpectedly available circuit.
|
||||||
request_loyalty = "50 msec"
|
request_loyalty = "50 msec"
|
||||||
|
|
||||||
|
# Rules for client configuration
|
||||||
|
[client_config]
|
||||||
|
|
||||||
|
# Are we running as localhost (e.g. on chutney)?
|
||||||
|
is_localhost = false
|
||||||
|
|
|
@ -91,6 +91,7 @@ mod proxy;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tor_circmgr::CircMgrConfig;
|
use tor_circmgr::CircMgrConfig;
|
||||||
|
use tor_client::ClientConfig;
|
||||||
use tor_client::TorClient;
|
use tor_client::TorClient;
|
||||||
use tor_config::CfgPath;
|
use tor_config::CfgPath;
|
||||||
use tor_dirmgr::{DirMgrConfig, DownloadScheduleConfig, NetworkConfig};
|
use tor_dirmgr::{DirMgrConfig, DownloadScheduleConfig, NetworkConfig};
|
||||||
|
@ -175,6 +176,9 @@ pub struct ArtiConfig {
|
||||||
|
|
||||||
/// Information about how to expire circuits.
|
/// Information about how to expire circuits.
|
||||||
circuit_timing: tor_circmgr::CircuitTiming,
|
circuit_timing: tor_circmgr::CircuitTiming,
|
||||||
|
|
||||||
|
/// Information about client configuration parameters.
|
||||||
|
client_config: tor_client::ClientConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configuration for where information should be stored on disk.
|
/// Configuration for where information should be stored on disk.
|
||||||
|
@ -222,13 +226,14 @@ async fn run<R: Runtime>(
|
||||||
statecfg: PathBuf,
|
statecfg: PathBuf,
|
||||||
dircfg: DirMgrConfig,
|
dircfg: DirMgrConfig,
|
||||||
circcfg: CircMgrConfig,
|
circcfg: CircMgrConfig,
|
||||||
|
clientcfg: ClientConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
futures::select!(
|
futures::select!(
|
||||||
r = exit::wait_for_ctrl_c().fuse() => r,
|
r = exit::wait_for_ctrl_c().fuse() => r,
|
||||||
r = async {
|
r = async {
|
||||||
let client =
|
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
|
proxy::run_socks_proxy(runtime, client, socks_port).await
|
||||||
}.fuse() => r,
|
}.fuse() => r,
|
||||||
)
|
)
|
||||||
|
@ -272,6 +277,7 @@ fn main() -> Result<()> {
|
||||||
let statecfg = config.storage.state_dir.path()?;
|
let statecfg = config.storage.state_dir.path()?;
|
||||||
let dircfg = config.get_dir_config()?;
|
let dircfg = config.get_dir_config()?;
|
||||||
let circcfg = config.get_circ_config()?;
|
let circcfg = config.get_circ_config()?;
|
||||||
|
let clientcfg = config.client_config;
|
||||||
|
|
||||||
let socks_port = match config.socks_port {
|
let socks_port = match config.socks_port {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
|
@ -287,7 +293,7 @@ fn main() -> Result<()> {
|
||||||
let runtime = tor_rtcompat::async_std::create_runtime()?;
|
let runtime = tor_rtcompat::async_std::create_runtime()?;
|
||||||
|
|
||||||
let rt_copy = runtime.clone();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,10 @@ tor-proto = { path="../tor-proto", version="0.0.0" }
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version="0.0.0" }
|
tor-rtcompat = { path="../tor-rtcompat", version="0.0.0" }
|
||||||
|
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
|
derive_builder = "0.10.2"
|
||||||
futures = "0.3.13"
|
futures = "0.3.13"
|
||||||
tracing = "0.1.26"
|
tracing = "0.1.26"
|
||||||
|
serde = { version = "1.0.124", features = ["derive"] }
|
||||||
thiserror = "1.0.24"
|
thiserror = "1.0.24"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//! Once the client is bootstrapped, you can make anonymous
|
//! Once the client is bootstrapped, you can make anonymous
|
||||||
//! connections ("streams") over the Tor network using
|
//! connections ("streams") over the Tor network using
|
||||||
//! `TorClient::connect()`.
|
//! `TorClient::connect()`.
|
||||||
|
use crate::config::ClientConfig;
|
||||||
use tor_circmgr::{CircMgrConfig, IsolationToken, TargetPort};
|
use tor_circmgr::{CircMgrConfig, IsolationToken, TargetPort};
|
||||||
use tor_dirmgr::{DirEvent, DirMgrConfig};
|
use tor_dirmgr::{DirEvent, DirMgrConfig};
|
||||||
use tor_proto::circuit::{ClientCirc, IpVersionPreference};
|
use tor_proto::circuit::{ClientCirc, IpVersionPreference};
|
||||||
|
@ -38,6 +39,8 @@ pub struct TorClient<R: Runtime> {
|
||||||
circmgr: Arc<tor_circmgr::CircMgr<R>>,
|
circmgr: Arc<tor_circmgr::CircMgr<R>>,
|
||||||
/// Directory manager for keeping our directory material up to date.
|
/// Directory manager for keeping our directory material up to date.
|
||||||
dirmgr: Arc<tor_dirmgr::DirMgr<R>>,
|
dirmgr: Arc<tor_dirmgr::DirMgr<R>>,
|
||||||
|
/// Client configuration
|
||||||
|
clientcfg: ClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Preferences for how to route a stream over the Tor network.
|
/// 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
|
/// Return a client once there is enough directory material to
|
||||||
/// connect safely over the Tor network.
|
/// 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.
|
// and state_cfg.
|
||||||
pub async fn bootstrap(
|
pub async fn bootstrap(
|
||||||
runtime: R,
|
runtime: R,
|
||||||
state_cfg: PathBuf,
|
state_cfg: PathBuf,
|
||||||
dir_cfg: DirMgrConfig,
|
dir_cfg: DirMgrConfig,
|
||||||
circ_cfg: CircMgrConfig,
|
circ_cfg: CircMgrConfig,
|
||||||
|
client_cfg: ClientConfig,
|
||||||
) -> Result<TorClient<R>> {
|
) -> Result<TorClient<R>> {
|
||||||
let statemgr = tor_persist::FsStateMgr::from_path(state_cfg)?;
|
let statemgr = tor_persist::FsStateMgr::from_path(state_cfg)?;
|
||||||
let chanmgr = Arc::new(tor_chanmgr::ChanMgr::new(runtime.clone()));
|
let chanmgr = Arc::new(tor_chanmgr::ChanMgr::new(runtime.clone()));
|
||||||
|
@ -154,6 +158,7 @@ impl<R: Runtime> TorClient<R> {
|
||||||
Arc::clone(&circmgr),
|
Arc::clone(&circmgr),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
let clientcfg = client_cfg;
|
||||||
|
|
||||||
circmgr.update_network_parameters(dirmgr.netdir().params());
|
circmgr.update_network_parameters(dirmgr.netdir().params());
|
||||||
|
|
||||||
|
@ -180,11 +185,12 @@ impl<R: Runtime> TorClient<R> {
|
||||||
runtime,
|
runtime,
|
||||||
circmgr,
|
circmgr,
|
||||||
dirmgr,
|
dirmgr,
|
||||||
|
clientcfg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate if we are an valid hostname or not
|
/// 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
|
/// Check if we have the valid characters for a hostname
|
||||||
fn is_valid_char(byte: u8) -> bool {
|
fn is_valid_char(byte: u8) -> bool {
|
||||||
((b'a'..=b'z').contains(&byte))
|
((b'a'..=b'z').contains(&byte))
|
||||||
|
@ -208,7 +214,7 @@ impl<R: Runtime> TorClient<R> {
|
||||||
|| hostname.ends_with('.')
|
|| hostname.ends_with('.')
|
||||||
|| hostname.starts_with('.')
|
|| hostname.starts_with('.')
|
||||||
|| hostname.is_empty()
|
|| hostname.is_empty()
|
||||||
|| hostname.to_lowercase().eq("localhost"))
|
|| (hostname.to_lowercase().eq("localhost") && !self.clientcfg.is_localhost))
|
||||||
|| is_ipv6_str(hostname)
|
|| is_ipv6_str(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +241,7 @@ impl<R: Runtime> TorClient<R> {
|
||||||
if addr.to_lowercase().ends_with(".onion") {
|
if addr.to_lowercase().ends_with(".onion") {
|
||||||
return Err(anyhow!("Rejecting .onion address as unsupported."));
|
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."));
|
return Err(anyhow!("Rejecting hostname as invalid."));
|
||||||
}
|
}
|
||||||
if let Ok(ip) = IpAddr::from_str(addr) {
|
if let Ok(ip) = IpAddr::from_str(addr) {
|
||||||
|
@ -272,7 +278,7 @@ impl<R: Runtime> TorClient<R> {
|
||||||
if hostname.to_lowercase().ends_with(".onion") {
|
if hostname.to_lowercase().ends_with(".onion") {
|
||||||
return Err(anyhow!("Rejecting .onion address as unsupported."));
|
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."));
|
return Err(anyhow!("Rejecting hostname as invalid."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,10 +94,14 @@
|
||||||
#![warn(clippy::unseparated_literal_suffix)]
|
#![warn(clippy::unseparated_literal_suffix)]
|
||||||
#![deny(clippy::unwrap_used)]
|
#![deny(clippy::unwrap_used)]
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
|
|
||||||
pub use client::{ConnectPrefs, TorClient};
|
pub use client::{ConnectPrefs, TorClient};
|
||||||
|
|
||||||
|
pub use config::{ClientConfig, ClientConfigBuilder};
|
||||||
|
|
||||||
pub use tor_circmgr::IsolationToken;
|
pub use tor_circmgr::IsolationToken;
|
||||||
/// An anonymized stream over the Tor network.
|
/// An anonymized stream over the Tor network.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue