fix(probe): reject unsupported and undersized reflector sets
This commit is contained in:
3 files changed
+38
-12
No files matched your search
+23
@@ -191,6 +191,7 @@ fn restore_shaper<T: TrafficControlBackend>(
|
||||
fn setup_reflectors(settings: &Settings) -> anyhow::Result<ReflectorSetup> {
|
||||
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<ReflectorSetup> {
|
||||
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);
|
||||
|
||||
+11
-11
@@ -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 {
|
||||
|
||||
+4
-1
@@ -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}");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user