From 33a0ab1503175a3391d90d1970ae304cd78d95c5 Mon Sep 17 00:00:00 2001 From: Nils Andreas Svee Date: Thu, 24 Sep 2026 23:11:09 +0700 Subject: [PATCH] fix(probe): reject unsupported and undersized reflector sets --- src/main.rs | 23 +++++++++++++++++++++++ src/pinger.rs | 22 +++++++++++----------- src/settings/mod.rs | 5 ++++- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/main.rs b/src/main.rs index 9cb7758..72b924a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -191,6 +191,7 @@ fn restore_shaper( fn setup_reflectors(settings: &Settings) -> anyhow::Result { let configured = settings.load_reflectors()?; let configured_count = configured.len(); + let requested_count = settings.advanced_settings.num_reflectors as usize; let default_reflectors = [ IpAddr::from_str("9.9.9.9")?, @@ -201,6 +202,17 @@ fn setup_reflectors(settings: &Settings) -> anyhow::Result { IpAddr::from_str("94.140.14.14")?, ]; + let available_count = if configured.is_empty() { + default_reflectors.len() + } else { + configured_count + }; + if available_count < requested_count { + anyhow::bail!( + "only {available_count} reflectors available, fewer than the configured {requested_count}" + ); + } + let reselection_enabled = configured_count > settings.advanced_settings.num_reflectors as usize; let (peers, pool) = if reselection_enabled { (default_reflectors.to_vec(), configured) @@ -512,6 +524,17 @@ mod tests { }; let setup = setup_reflectors(&settings).unwrap(); let configured = settings.load_reflectors().unwrap(); + std::fs::write( + &path, + "reflector_ip,ip_version,description\n192.0.2.1,4,test\n192.0.2.2,4,test\n192.0.2.3,4,test\n192.0.2.4,4,test\n", + ).unwrap(); + assert!(setup_reflectors(&settings).is_err()); + std::fs::write( + &path, + "reflector_ip,ip_version,description\n2001:db8::1,6,test\n", + ) + .unwrap(); + assert!(setup_reflectors(&settings).is_err()); std::fs::remove_file(path).unwrap(); assert!(!setup.reselection_enabled); assert_eq!(*setup.peers.read().unwrap(), configured); diff --git a/src/pinger.rs b/src/pinger.rs index 2436c18..1efb5e6 100644 --- a/src/pinger.rs +++ b/src/pinger.rs @@ -14,7 +14,7 @@ use icmp_socket2::socket::IcmpSocket; use icmp_socket2::{IcmpSocket4, Icmpv4Packet}; use log::{debug, info, warn}; use std::collections::HashMap; -use std::net::{IpAddr, Ipv4Addr}; +use std::net::IpAddr; use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex, RwLock}; use std::time::{Duration, Instant}; @@ -185,10 +185,15 @@ pub trait PingSender { info!("Ping sender shutting down"); return Ok(()); } - // Clone the reflectors vec and drop the read lock immediately — - // holding it for the entire tick would starve the reflector selector's write lock. + // Release the read lock before sending so reselection can update peers. let reflectors_unlocked = reflectors_lock.read_anyhow()?; - let reflectors = reflectors_unlocked.clone(); + let reflectors: Vec<_> = reflectors_unlocked + .iter() + .filter_map(|reflector| match reflector { + IpAddr::V4(addr) => Some(*addr), + IpAddr::V6(_) => None, + }) + .collect(); drop(reflectors_unlocked); if reflectors.is_empty() { @@ -202,15 +207,10 @@ pub trait PingSender { let sleep_duration = Duration::from_secs_f64(tick_interval / reflectors.len() as f64); - for reflector in reflectors.iter() { - let addr: Ipv4Addr = match reflector { - IpAddr::V4(ipv4) => *ipv4, - IpAddr::V6(_) => continue, - }; - + for &addr in &reflectors { let (packet, originate_timestamp) = self.craft_packet(id, seq); let sent_at = Instant::now(); - let key = (*reflector, type_, seq); + let key = (IpAddr::V4(addr), type_, seq); inflight.lock_anyhow()?.insert( key, InFlightProbe { diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 15152e9..577ee55 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -192,7 +192,10 @@ impl Settings { })?; match (record.ip_version, record.reflector_ip) { - (4, IpAddr::V4(_)) | (6, IpAddr::V6(_)) => {} + (4, IpAddr::V4(_)) => {} + (6, address @ IpAddr::V6(_)) => { + bail!("reflector {address} is IPv6; only IPv4 reflectors are supported"); + } (version, address) => { bail!("reflector {address} has inconsistent IP version {version}"); }