use derive_deftly::Deftly;
use tor_basic_utils::define_accessor_trait;
use tor_guardmgr::{GuardFilter, GuardMgrConfig, VanguardConfig};
use tor_netdoc::types::policy::AddrPortPattern;
use tor_relay_selection::RelaySelectionConfig;
use tor_config::derive::prelude::*;
use std::collections::HashSet;
use std::time::Duration;
#[derive(Debug, Clone, Eq, PartialEq, Deftly)]
#[derive_deftly(TorConfig)]
pub struct PathConfig {
#[deftly(tor_config(default = "ipv4_prefix_default()"))]
ipv4_subnet_family_prefix: u8,
#[deftly(tor_config(default = "ipv6_prefix_default()"))]
ipv6_subnet_family_prefix: u8,
#[deftly(tor_config(list(element(clone)), default = "long_lived_ports_default()"))]
pub(crate) long_lived_ports: HashSet<u16>,
#[deftly(tor_config(list(element(clone)), default = "default_reachable_addrs()"))]
pub(crate) reachable_addrs: Vec<AddrPortPattern>,
}
fn default_reachable_addrs() -> Vec<AddrPortPattern> {
vec![AddrPortPattern::new_all()]
}
fn ipv4_prefix_default() -> u8 {
16
}
fn ipv6_prefix_default() -> u8 {
32
}
fn long_lived_ports_default() -> Vec<u16> {
vec![
21, 22, 706, 1863, 5050, 5190, 5222, 5223, 6523, 6667, 6697, 8300,
]
}
impl PathConfig {
pub fn subnet_config(&self) -> tor_netdir::SubnetConfig {
tor_netdir::SubnetConfig::new(
self.ipv4_subnet_family_prefix,
self.ipv6_subnet_family_prefix,
)
}
pub(crate) fn at_least_as_permissive_as(&self, other: &Self) -> bool {
self.ipv4_subnet_family_prefix >= other.ipv4_subnet_family_prefix
&& self.ipv6_subnet_family_prefix >= other.ipv6_subnet_family_prefix
&& self.reachable_addrs == other.reachable_addrs
}
pub(crate) fn build_guard_filter(&self) -> GuardFilter {
let mut filt = GuardFilter::default();
filt.push_reachable_addresses(self.reachable_addrs.clone());
filt
}
pub(crate) fn relay_selection_config(&self) -> RelaySelectionConfig<'_> {
RelaySelectionConfig {
long_lived_ports: &self.long_lived_ports,
subnet_config: self.subnet_config(),
}
}
}
#[derive(Debug, Clone, Deftly, Eq, PartialEq)]
#[derive_deftly(TorConfig)]
pub struct PreemptiveCircuitConfig {
#[deftly(tor_config(default = "default_preemptive_threshold()"))]
pub(crate) disable_at_threshold: usize,
#[deftly(tor_config(list(element(clone)), default = "default_preemptive_ports()"))]
pub(crate) initial_predicted_ports: Vec<u16>,
#[deftly(tor_config(default = "default_preemptive_duration()"))]
pub(crate) prediction_lifetime: Duration,
#[deftly(tor_config(default = "default_preemptive_min_exit_circs_for_port()"))]
pub(crate) min_exit_circs_for_port: usize,
}
#[derive(Debug, Clone, Eq, PartialEq, Deftly)]
#[derive(amplify::Getters)]
#[derive_deftly(TorConfig)]
pub struct CircuitTiming {
#[deftly(tor_config(default = "default_max_dirtiness()"))]
#[getter(skip)]
pub(crate) max_dirtiness: Duration,
#[deftly(tor_config(default = "default_disused_timeout()"))]
#[getter(skip)]
pub(crate) disused_circuit_timeout: Duration,
#[deftly(tor_config(default = "default_request_timeout()"))]
#[getter(skip)]
pub(crate) request_timeout: Duration,
#[deftly(tor_config(default = "default_request_max_retries()"))]
#[getter(skip)]
pub(crate) request_max_retries: u32,
#[deftly(tor_config(default = "default_request_loyalty()"))]
#[getter(skip)]
pub(crate) request_loyalty: Duration,
#[cfg(feature = "hs-client")]
#[deftly(tor_config(default = "default_hs_max_attempts()"))]
#[getter(as_copy)]
pub(crate) hs_desc_fetch_attempts: u32,
#[cfg(feature = "hs-client")]
#[deftly(tor_config(default = "default_hs_max_attempts()"))]
#[getter(as_copy)]
pub(crate) hs_intro_rend_attempts: u32,
}
fn default_preemptive_threshold() -> usize {
12
}
fn default_preemptive_ports() -> Vec<u16> {
vec![80, 443]
}
fn default_preemptive_duration() -> Duration {
Duration::from_secs(60 * 60)
}
fn default_preemptive_min_exit_circs_for_port() -> usize {
2
}
fn default_max_dirtiness() -> Duration {
Duration::from_secs(60 * 10)
}
fn default_disused_timeout() -> Duration {
Duration::from_secs(60 * 60)
}
fn default_request_timeout() -> Duration {
Duration::from_secs(60)
}
fn default_request_max_retries() -> u32 {
16
}
#[cfg(feature = "hs-client")]
fn default_hs_max_attempts() -> u32 {
6
}
fn default_request_loyalty() -> Duration {
Duration::from_millis(50)
}
define_accessor_trait! {
pub trait CircMgrConfig: GuardMgrConfig {
path_rules: PathConfig,
vanguard_config: VanguardConfig,
circuit_timing: CircuitTiming,
preemptive_circuits: PreemptiveCircuitConfig,
}
}
#[cfg(any(test, feature = "testing"))]
pub(crate) mod test_config {
use super::*;
use crate::*;
use tor_guardmgr::VanguardConfig;
use tor_guardmgr::bridge::BridgeConfig;
#[derive(Default, derive_more::AsRef)]
#[allow(clippy::exhaustive_structs)]
#[allow(missing_docs)]
#[cfg_attr(docsrs, doc(cfg(feature = "testing")))]
pub struct TestConfig {
pub path_rules: PathConfig,
pub circuit_timing: CircuitTiming,
pub preemptive_circuits: PreemptiveCircuitConfig,
pub guardmgr: tor_guardmgr::TestConfig,
pub vanguard_config: VanguardConfig,
}
impl AsRef<[BridgeConfig]> for TestConfig {
fn as_ref(&self) -> &[BridgeConfig] {
&self.guardmgr.bridges
}
}
impl AsRef<FallbackList> for TestConfig {
fn as_ref(&self) -> &FallbackList {
&self.guardmgr.fallbacks
}
}
impl GuardMgrConfig for TestConfig {
fn bridges_enabled(&self) -> bool {
self.guardmgr.bridges_enabled()
}
}
impl CircMgrConfig for TestConfig {
fn path_rules(&self) -> &PathConfig {
&self.path_rules
}
fn circuit_timing(&self) -> &CircuitTiming {
&self.circuit_timing
}
fn preemptive_circuits(&self) -> &PreemptiveCircuitConfig {
&self.preemptive_circuits
}
fn vanguard_config(&self) -> &tor_guardmgr::VanguardConfig {
&self.vanguard_config
}
}
}
#[cfg(test)]
mod test {
#![allow(clippy::bool_assert_comparison)]
#![allow(clippy::clone_on_copy)]
#![allow(clippy::dbg_macro)]
#![allow(clippy::mixed_attributes_style)]
#![allow(clippy::print_stderr)]
#![allow(clippy::print_stdout)]
#![allow(clippy::single_char_pattern)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::unchecked_time_subtraction)]
#![allow(clippy::useless_vec)]
#![allow(clippy::needless_pass_by_value)]
use super::*;
#[test]
fn path_config() {
let pc1 = PathConfig::default();
let pc2 = PathConfig::builder()
.ipv4_subnet_family_prefix(32)
.build()
.unwrap();
let pc3 = PathConfig::builder()
.ipv6_subnet_family_prefix(128)
.build()
.unwrap();
assert!(pc2.at_least_as_permissive_as(&pc1));
assert!(pc3.at_least_as_permissive_as(&pc1));
assert!(pc1.at_least_as_permissive_as(&pc1));
assert!(!pc1.at_least_as_permissive_as(&pc2));
assert!(!pc1.at_least_as_permissive_as(&pc3));
assert!(!pc3.at_least_as_permissive_as(&pc2));
}
}