diff --git a/proxychains/src/hook/hooks.rs b/proxychains/src/hook/hooks.rs index 21c4f3d..43e12bb 100644 --- a/proxychains/src/hook/hooks.rs +++ b/proxychains/src/hook/hooks.rs @@ -10,7 +10,7 @@ use std::net::IpAddr; use std::os::raw::c_char; use std::os::unix::io::IntoRawFd; use std::sync::OnceLock; -use std::time::{Duration, Instant}; +use std::time::Instant; use libc::{c_int, socklen_t}; use parking_lot::Mutex; @@ -27,6 +27,7 @@ use super::interpose::{ init_original_functions, original_connect, original_freeaddrinfo, original_getaddrinfo, original_gethostbyname, original_getnameinfo, }; +use super::reload::config_reload_interval; /// Global state for the hook library pub struct HookState { @@ -40,7 +41,7 @@ impl HookState { Self { config, initialized: true, - next_reload_check: Instant::now() + Duration::from_secs(2), + next_reload_check: Instant::now() + config_reload_interval(), } } } @@ -72,8 +73,6 @@ fn custom_alloc_map() -> &'static Mutex CUSTOM_ADDRINFO_ALLOCATIONS.get_or_init(|| Mutex::new(HashMap::new())) } -const CONFIG_RELOAD_INTERVAL: Duration = Duration::from_secs(2); - struct HookSnapshot { config: Config, dns_resolver: crate::dns::DnsResolver, @@ -85,7 +84,7 @@ fn maybe_reload_config(state: &mut HookState) { if now < state.next_reload_check { return; } - state.next_reload_check = now + CONFIG_RELOAD_INTERVAL; + state.next_reload_check = now + config_reload_interval(); match ConfigParser::new().parse() { Ok(config) => { diff --git a/proxychains/src/hook/hooks_windows.rs b/proxychains/src/hook/hooks_windows.rs index ff61c13..1fa283e 100644 --- a/proxychains/src/hook/hooks_windows.rs +++ b/proxychains/src/hook/hooks_windows.rs @@ -10,7 +10,7 @@ use std::net::{IpAddr, Ipv4Addr}; use std::os::windows::io::FromRawSocket; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::OnceLock; -use std::time::{Duration, Instant}; +use std::time::Instant; use parking_lot::Mutex; use rand::seq::SliceRandom; @@ -32,6 +32,7 @@ use super::interpose_windows::{ init_original_functions, original_connect, original_freeaddrinfo, original_getaddrinfo, original_gethostbyname, original_getnameinfo, }; +use super::reload::config_reload_interval; /// Global state for the hook library (Windows). pub struct HookState { @@ -49,7 +50,7 @@ impl HookState { config: Mutex::new(config), proxy_states, load_balance_counter: AtomicUsize::new(0), - next_reload_check: Mutex::new(Instant::now() + Duration::from_secs(2)), + next_reload_check: Mutex::new(Instant::now() + config_reload_interval()), initialized: true, } } @@ -71,8 +72,6 @@ fn custom_alloc_map() -> &'static Mutex CUSTOM_ADDRINFO_ALLOCATIONS.get_or_init(|| Mutex::new(HashMap::new())) } -const CONFIG_RELOAD_INTERVAL: Duration = Duration::from_secs(2); - fn maybe_reload_config(state: &HookState) { let now = Instant::now(); { @@ -80,7 +79,7 @@ fn maybe_reload_config(state: &HookState) { if now < *next { return; } - *next = now + CONFIG_RELOAD_INTERVAL; + *next = now + config_reload_interval(); } match ConfigParser::new().parse() { diff --git a/proxychains/src/hook/mod.rs b/proxychains/src/hook/mod.rs index 14c395c..3d51a56 100644 --- a/proxychains/src/hook/mod.rs +++ b/proxychains/src/hook/mod.rs @@ -18,6 +18,7 @@ mod interpose; mod hooks_windows; #[cfg(windows)] mod interpose_windows; +mod reload; // Re-export based on platform #[cfg(unix)] diff --git a/proxychains/src/hook/reload.rs b/proxychains/src/hook/reload.rs new file mode 100644 index 0000000..bba328a --- /dev/null +++ b/proxychains/src/hook/reload.rs @@ -0,0 +1,32 @@ +//! Shared helpers for hook runtime reload behavior. + +use std::time::Duration; + +/// Environment variable to tune hook config reload interval. +pub const ENV_RELOAD_INTERVAL_MS: &str = "PROXYCHAINS_CONFIG_RELOAD_INTERVAL_MS"; + +/// Default reload interval used when env var is absent/invalid. +const DEFAULT_RELOAD_INTERVAL_MS: u64 = 2000; + +/// Returns config reload interval for hook runtime. +/// +/// Values <= 0 are ignored and default is used. +pub fn config_reload_interval() -> Duration { + let value = std::env::var(ENV_RELOAD_INTERVAL_MS) + .ok() + .and_then(|v| v.parse::().ok()) + .filter(|v| *v > 0) + .unwrap_or(DEFAULT_RELOAD_INTERVAL_MS); + Duration::from_millis(value) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_default_reload_interval() { + std::env::remove_var(ENV_RELOAD_INTERVAL_MS); + assert_eq!(config_reload_interval(), Duration::from_millis(2000)); + } +}