diff --git a/Cargo.lock b/Cargo.lock index b294e08..8cf7a74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,27 @@ dependencies = [ "winnow", ] +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + [[package]] name = "either" version = "1.16.0" @@ -184,6 +205,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + [[package]] name = "js-sys" version = "0.3.103" @@ -402,6 +429,12 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + [[package]] name = "scopeguard" version = "1.2.0" @@ -484,6 +517,7 @@ version = "0.4.1" dependencies = [ "anyhow", "config", + "csv", "fastrand", "flume", "icmp-socket2", diff --git a/Cargo.toml b/Cargo.toml index 5f0b9c0..ec3eea2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ thiserror = "2.0" libc = "0.2" flume = { version = "0.12.0", default-features = false, features = ["eventual-fairness", "select"] } config = { version = "0.15.25", default-features = false } +csv = "1.4.0" serde = { version = "1", features = ["derive"] } [dependencies.log] diff --git a/src/settings/mod.rs b/src/settings/mod.rs index 001c90e..a57ba34 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -7,6 +7,7 @@ use config::{Config, ConfigError, Environment}; use log::Level; use serde::{Deserialize, Deserializer, de}; use std::fmt::{self, Display}; +use std::net::IpAddr; use std::str::FromStr; #[cfg(all(feature = "uci", unix))] @@ -61,6 +62,14 @@ impl FromStr for ObservabilityProtocol { } } +#[derive(Debug, Deserialize)] +struct ReflectorRecord { + reflector_ip: IpAddr, + ip_version: u8, + #[allow(dead_code)] + description: String, +} + #[derive(Clone, Debug, Deserialize)] pub(crate) struct Settings { pub(crate) network: NetworkSettings, @@ -92,6 +101,41 @@ impl Settings { built_config.try_deserialize() } + + pub fn load_reflectors(&self) -> anyhow::Result> { + let mut reader = csv::ReaderBuilder::new() + .has_headers(true) + .trim(csv::Trim::All) + .from_path(&self.advanced_settings.reflector_list_file) + .with_context(|| { + format!( + "failed to open reflector list: {}", + self.advanced_settings.reflector_list_file + ) + })?; + + let mut reflectors = Vec::with_capacity(50); + + for record in reader.deserialize::() { + let record = record.with_context(|| { + format!( + "failed to parse reflector list: {}", + self.advanced_settings.reflector_list_file + ) + })?; + + match (record.ip_version, record.reflector_ip) { + (4, IpAddr::V4(_)) | (6, IpAddr::V6(_)) => {} + (version, address) => { + bail!("reflector {address} has inconsistent IP version {version}"); + } + } + + reflectors.push(record.reflector_ip); + } + + Ok(reflectors) + } } #[derive(Clone, Debug, Deserialize)]