From 92ac9346cc08d000f0fdf4108470b8410f3312cd Mon Sep 17 00:00:00 2001 From: Patrick Date: Wed, 1 Jan 2025 19:14:45 +0100 Subject: [PATCH] feat: config --- Cargo.lock | 180 +++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 4 ++ example.json | 11 ++++ src/main.rs | 50 +++++++++----- 4 files changed, 222 insertions(+), 23 deletions(-) create mode 100644 example.json diff --git a/Cargo.lock b/Cargo.lock index d73b349..9d5ff0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,55 @@ dependencies = [ "memchr", ] +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + [[package]] name = "autocfg" version = "1.4.0" @@ -74,6 +123,46 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + [[package]] name = "color-eyre" version = "0.6.3" @@ -101,6 +190,12 @@ dependencies = [ "tracing-error", ] +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "eyre" version = "0.6.12" @@ -123,6 +218,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "indenter" version = "0.3.3" @@ -138,6 +239,18 @@ dependencies = [ "serde", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + [[package]] name = "lazy_static" version = "1.5.0" @@ -183,7 +296,7 @@ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -393,9 +506,13 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" name = "rust" version = "0.1.0" dependencies = [ + "clap", "color-eyre", "pnet", "regex", + "serde", + "serde_json", + "serde_regex", "simple-dns", "socket2", "tokio", @@ -407,6 +524,12 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + [[package]] name = "scopeguard" version = "1.2.0" @@ -415,24 +538,46 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "serde_json" +version = "1.0.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_regex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8136f1a4ea815d7eac4101cfd0b16dc0cb5e1fe1b8609dfd728058656b7badf" +dependencies = [ + "regex", + "serde", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -479,9 +624,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.91" @@ -518,7 +669,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -579,6 +730,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "valuable" version = "0.1.0" @@ -622,6 +779,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" version = "0.52.6" diff --git a/Cargo.toml b/Cargo.toml index 53029bb..e15bdc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,13 @@ version = "0.1.0" edition = "2021" [dependencies] +clap = { version = "4.5.23", features = ["derive"] } color-eyre = "0.6.3" pnet = "0.35.0" regex = "1.11.1" +serde = { version = "1.0.217", features = ["derive"] } +serde_json = "1.0.134" +serde_regex = "1.1.0" simple-dns = "0.9.1" socket2 = { version = "0.5.8", features = ["all"] } tokio = { version = "1.42.0", features = ["full"] } diff --git a/example.json b/example.json new file mode 100644 index 0000000..ac0f789 --- /dev/null +++ b/example.json @@ -0,0 +1,11 @@ +{ + "interfaces": "lan*", + "rules": [ + { + "from": "wan", + "to": "lan", + "allow_questions": "printer", + "allow_answers": ".*" + } + ] +} diff --git a/src/main.rs b/src/main.rs index febc13d..034a698 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,16 @@ const ADDR: Ipv4Addr = Ipv4Addr::new(224, 0, 0, 251); +use clap::{command, Parser}; use color_eyre::{eyre::bail, Result}; use pnet::datalink::{interfaces, NetworkInterface}; use pnet::ipnetwork::IpNetwork::{V4, V6}; use regex::Regex; +use serde::{Deserialize, Deserializer}; +use serde_json::from_reader; use simple_dns::Packet; use socket2::{Domain, Protocol, Socket, Type}; +use std::borrow::Cow; +use std::fs::File; +use std::io::BufReader; use std::{ collections::HashSet, net::{Ipv4Addr, SocketAddr, SocketAddrV4}, @@ -33,10 +39,14 @@ fn get_answers(packet: &Packet) -> HashSet { packet.answers.iter().map(|x| x.name.to_string()).collect() } +#[derive(Deserialize)] struct Rule { + #[serde(with = "serde_regex")] from: Regex, to: String, + #[serde(with = "serde_regex")] allow_questions: Regex, + #[serde(with = "serde_regex")] allow_answers: Regex, } @@ -45,22 +55,27 @@ struct Iface { socket: socket2::Socket, } +#[derive(Parser)] +#[command(version, about)] +struct Cli { + /// Path to the config file. + #[arg(short, long)] + config: String, +} + +#[derive(Deserialize)] +struct Config { + #[serde(with = "serde_regex")] + interfaces: Regex, + rules: Vec, +} + #[tokio::main] async fn main() -> Result<()> { - let mut rules = Vec::new(); - rules.push(Rule { - from: Regex::new("lan-home")?, - to: "lan-services".to_string(), - allow_answers: Regex::new(".*")?, - allow_questions: Regex::new(".*")?, - }); - rules.push(Rule { - from: Regex::new("lan-services")?, - to: "lan-home".to_string(), - allow_answers: Regex::new(".*")?, - allow_questions: Regex::new(".*")?, - }); - let iface_reg = Regex::new(r"^lan.*$")?; + let cli = Cli::parse(); + let file = File::open(cli.config)?; + let reader = BufReader::new(file); + let config: Config = from_reader(reader)?; let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?; socket.set_reuse_address(true)?; @@ -74,7 +89,10 @@ async fn main() -> Result<()> { let interfaces = interfaces .iter() .filter(|x| { - x.is_up() && !x.is_loopback() && !x.ips.is_empty() && iface_reg.is_match(&x.name) + x.is_up() + && !x.is_loopback() + && !x.ips.is_empty() + && config.interfaces.is_match(&x.name) }) .map(|x| -> Result { let socket = Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?; @@ -120,7 +138,7 @@ async fn main() -> Result<()> { iface, from, questions, answers ); let mut out = HashSet::new(); - for r in &rules { + for r in &config.rules { if r.from.is_match(&iface) && (questions.iter().any(|x| r.allow_questions.is_match(x)) || answers.iter().any(|x| r.allow_answers.is_match(x)))