use tor_basic_utils::define_accessor_trait;
use tor_config::impl_standard_builder;
use tor_config::{define_list_builder_accessors, define_list_builder_helper, ConfigBuildError};
use tor_guardmgr::{GuardFilter, GuardMgrConfig};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use tor_netdoc::types::policy::AddrPortPattern;
use std::time::Duration;
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct PathConfig {
#[builder(default = "ipv4_prefix_default()")]
ipv4_subnet_family_prefix: u8,
#[builder(default = "ipv6_prefix_default()")]
ipv6_subnet_family_prefix: u8,
#[builder(sub_builder, setter(custom))]
pub(crate) reachable_addrs: ReachableAddrs,
}
impl_standard_builder! { PathConfig }
type ReachableAddrs = Vec<AddrPortPattern>;
fn default_reachable_addrs() -> ReachableAddrs {
vec![AddrPortPattern::new_all()]
}
define_list_builder_helper! {
struct ReachableAddrsBuilder {
pub(crate) patterns: [AddrPortPattern],
}
built: ReachableAddrs = patterns;
default = default_reachable_addrs();
item_build: |pat| Ok(pat.clone());
}
define_list_builder_accessors! {
struct PathConfigBuilder {
pub reachable_addrs: [AddrPortPattern],
}
}
fn ipv4_prefix_default() -> u8 {
16
}
fn ipv6_prefix_default() -> u8 {
32
}
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
}
}
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct PreemptiveCircuitConfig {
#[builder(default = "default_preemptive_threshold()")]
pub(crate) disable_at_threshold: usize,
#[builder(sub_builder, setter(custom))]
pub(crate) initial_predicted_ports: PredictedPortsList,
#[builder(default = "default_preemptive_duration()")]
#[builder_field_attr(serde(default, with = "humantime_serde::option"))]
pub(crate) prediction_lifetime: Duration,
#[builder(default = "default_preemptive_min_exit_circs_for_port()")]
pub(crate) min_exit_circs_for_port: usize,
}
impl_standard_builder! { PreemptiveCircuitConfig }
#[derive(Debug, Clone, Builder, Eq, PartialEq)]
#[builder(build_fn(error = "ConfigBuildError"))]
#[builder(derive(Debug, Serialize, Deserialize))]
pub struct CircuitTiming {
#[builder(default = "default_max_dirtiness()")]
#[builder_field_attr(serde(default, with = "humantime_serde::option"))]
pub(crate) max_dirtiness: Duration,
#[builder(default = "default_request_timeout()")]
#[builder_field_attr(serde(default, with = "humantime_serde::option"))]
pub(crate) request_timeout: Duration,
#[builder(default = "default_request_max_retries()")]
pub(crate) request_max_retries: u32,
#[builder(default = "default_request_loyalty()")]
#[builder_field_attr(serde(default, with = "humantime_serde::option"))]
pub(crate) request_loyalty: Duration,
}
impl_standard_builder! { CircuitTiming }
fn default_preemptive_threshold() -> usize {
12
}
type PredictedPortsList = Vec<u16>;
define_list_builder_helper! {
struct PredictedPortsListBuilder {
pub(crate) ports: [u16],
}
built: PredictedPortsList = ports;
default = default_preemptive_ports();
item_build: |&port| Ok(port);
}
define_list_builder_accessors! {
struct PreemptiveCircuitConfigBuilder {
pub initial_predicted_ports: [u16],
}
}
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_request_timeout() -> Duration {
Duration::from_secs(60)
}
fn default_request_max_retries() -> u32 {
16
}
fn default_request_loyalty() -> Duration {
Duration::from_millis(50)
}
define_accessor_trait! {
pub trait CircMgrConfig: GuardMgrConfig {
path_rules: PathConfig,
circuit_timing: CircuitTiming,
preemptive_circuits: PreemptiveCircuitConfig,
}
}
#[cfg(test)]
mod test {
#![allow(clippy::unwrap_used)]
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));
}
}