diff --git a/Cargo.lock b/Cargo.lock index 663457c..a23b0af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,35 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bindgen" +version = "0.68.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash 1.1.0", + "shlex", + "syn", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.6.0" @@ -159,6 +188,15 @@ dependencies = [ "shlex", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -186,6 +224,17 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.21" @@ -281,6 +330,22 @@ dependencies = [ "syn", ] +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "fnv" version = "1.0.7" @@ -378,12 +443,27 @@ dependencies = [ "syn", ] +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "1.1.0" @@ -651,11 +731,11 @@ dependencies = [ "git-version", "ipnet", "lazy_static", - "mnl", - "nftnl", - "nix", + "nix 0.29.0", "regex", "reqwest", + "rustables", + "rustables-macros", "sd-notify", "serde", "serde_json", @@ -669,6 +749,12 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -696,12 +782,34 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "litemap" version = "0.7.4" @@ -730,12 +838,27 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -758,46 +881,16 @@ dependencies = [ ] [[package]] -name = "mnl" -version = "0.2.2" +name = "nix" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a5469630da93e1813bb257964c0ccee3b26b6879dd858039ddec35cc8681ed" -dependencies = [ - "libc", - "log", - "mnl-sys", -] - -[[package]] -name = "mnl-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9750685b201e1ecfaaf7aa5d0387829170fa565989cc481b49080aa155f70457" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "nftnl" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a7491dd91b71643f65546389f25506da70723d1f1ec8c8d6d20444d1c23f27" -dependencies = [ - "bitflags", - "log", - "nftnl-sys", -] - -[[package]] -name = "nftnl-sys" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193f2c2a70e6421534c3f3b75eaaed4e4b9df45281b3d94f5bc8c32fb346cbb" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" dependencies = [ + "bitflags 1.3.2", + "cc", "cfg-if", "libc", - "pkg-config", + "memoffset", ] [[package]] @@ -806,12 +899,22 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -865,6 +968,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -883,12 +992,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - [[package]] name = "ppv-lite86" version = "0.2.20" @@ -898,6 +1001,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.92" @@ -907,6 +1020,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + [[package]] name = "quinn" version = "0.11.6" @@ -917,7 +1043,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "socket2", "thiserror 2.0.3", @@ -935,7 +1061,7 @@ dependencies = [ "getrandom", "rand", "ring", - "rustc-hash", + "rustc-hash 2.0.0", "rustls", "rustls-pki-types", "slab", @@ -1004,7 +1130,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags", + "bitflags 2.6.0", ] [[package]] @@ -1093,18 +1219,67 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustables" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177fda7beae62153f2ee2d0d3f2c7cf37da4b31a7240483fa1e06f7ccc25fb1c" +dependencies = [ + "bindgen", + "bitflags 1.3.2", + "ipnetwork", + "libc", + "log", + "nix 0.23.2", + "regex", + "rustables-macros", + "thiserror 1.0.69", +] + +[[package]] +name = "rustables-macros" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "698b79177cbf57522a1dcc118ac31393dc2a7ccc9bdb3625a6601ff5c27a3085" +dependencies = [ + "once_cell", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-hash" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +[[package]] +name = "rustix" +version = "0.38.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "rustls" version = "0.23.18" @@ -1194,7 +1369,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -1688,6 +1863,18 @@ dependencies = [ "rustls-pki-types", ] +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -1821,6 +2008,12 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "yoke" version = "0.7.5" diff --git a/Cargo.toml b/Cargo.toml index 6a8e7e3..59c4b98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,11 @@ clap = { version = "4.5", features = ["string"] } git-version = "0.3" ipnet = "2.10" lazy_static = "1.5" -mnl = "0.2" -nftnl = "0.7" nix = { version = "0.29", features = ["hostname", "inotify"] } regex = "1.11" reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } +rustables = "0.8.5" +rustables-macros = "0.1.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" sd-notify = { version = "0.4" } diff --git a/src/fw.rs b/src/fw.rs index 81d5302..d5aa021 100644 --- a/src/fw.rs +++ b/src/fw.rs @@ -1,13 +1,12 @@ -use crate::ip::IpData; -use crate::ipblc::PKG_NAME; +use crate::{ip::IpData, ipblc::PKG_NAME}; -use nftnl::{nft_expr, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table}; use std::{ - ffi::CString, io::Error, net::{Ipv4Addr, Ipv6Addr}, }; +use rustables::*; + pub enum FwTableType { IPv4, IPv6, @@ -21,37 +20,22 @@ pub fn fwglobalinit<'a>() -> ((Batch, Table), (Batch, Table)) { macro_rules! initrules { ($batch:expr, $table:expr, $chain:ident) => { - $chain.set_hook(nftnl::Hook::In, 1); - $chain.set_policy(nftnl::Policy::Accept); + $chain.set_hook(Hook::new(HookClass::In, 1)); - $batch.add(&$chain, nftnl::MsgType::Add); - $batch.add(&Rule::new(&$chain), nftnl::MsgType::Del); - - let mut rule = Rule::new(&$chain); - rule.add_expr(&nft_expr!(ct state)); - rule.add_expr(&nft_expr!(bitwise mask 4u32, xor 0u32)); - rule.add_expr(&nft_expr!(cmp != 0u32)); - rule.add_expr(&nft_expr!(counter)); - rule.add_expr(&nft_expr!(verdict accept)); - $batch.add(&rule, nftnl::MsgType::Add); + $batch.add(&$chain, MsgType::Add); + $batch.add(&Rule::new(&$chain).unwrap(), MsgType::Del); }; } macro_rules! createrules { ($ipdata:ident, $chain:ident, $batch:ident, $t:ty, $ip_t:ident) => { - let mut rule = Rule::new(&$chain); let ip = $ipdata.ip.parse::<$t>().unwrap(); - - rule.add_expr(&nft_expr!(payload $ip_t saddr)); - rule.add_expr(&nft_expr!(cmp == ip)); - rule.add_expr(&nft_expr!(ct state)); - rule.add_expr(&nft_expr!(bitwise mask 10u32, xor 0u32)); - rule.add_expr(&nft_expr!(cmp != 0u32)); - rule.add_expr(&nft_expr!(counter)); - rule.add_expr(&nft_expr!(verdict drop)); - - $batch.add(&rule, nftnl::MsgType::Add); - } + Rule::new(&$chain) + .unwrap() + .saddr(ip.into()) + .drop() + .add_to_batch(&mut $batch); + }; } fn fwinit(t: FwTableType) -> (Batch, Table) { @@ -60,38 +44,32 @@ fn fwinit(t: FwTableType) -> (Batch, Table) { match t { FwTableType::IPv4 => { table_name = format!("{PKG_NAME}4"); - table = Table::new( - &CString::new(format!("{table_name}")).unwrap(), - ProtoFamily::Ipv4, - ); + table = Table::new(ProtocolFamily::Ipv4).with_name(table_name) } FwTableType::IPv6 => { table_name = format!("{PKG_NAME}6"); - table = Table::new( - &CString::new(format!("{table_name}")).unwrap(), - ProtoFamily::Ipv6, - ); + table = Table::new(ProtocolFamily::Ipv6).with_name(table_name); } } let mut batch = Batch::new(); - batch.add(&table, nftnl::MsgType::Add); - batch.add(&table, nftnl::MsgType::Del); - - batch.add(&table, nftnl::MsgType::Add); + batch.add(&table, MsgType::Add); (batch, table) } -pub fn fwblock( +pub fn fwblock<'a>( ips_add_all: &Vec, ret: &mut Vec, fwlen: &mut usize, ) -> std::result::Result<(), Error> { let ((mut batch4, table4), (mut batch6, table6)) = fwglobalinit(); - let mut chain4 = Chain::new(&CString::new(PKG_NAME).unwrap(), &table4); - let mut chain6 = Chain::new(&CString::new(PKG_NAME).unwrap(), &table6); - + let mut chain4 = Chain::new(&table4) + .with_policy(ChainPolicy::Accept) + .with_name(PKG_NAME); + let mut chain6 = Chain::new(&table6) + .with_policy(ChainPolicy::Accept) + .with_name(PKG_NAME); initrules!(batch4, table4, chain4); initrules!(batch6, table6, chain6); @@ -124,14 +102,14 @@ pub fn fwblock( // validate and send batch for b in [batch4, batch6] { - let bf = b.finalize(); - match send_and_process(&bf) { + match b.send() { Ok(_) => {} Err(e) => { println!("error sending batch: {e}"); } }; } + if fwlen != &mut ips_add_all.len() { ret.push(format!( "{length} ip in firewall", @@ -141,31 +119,3 @@ pub fn fwblock( *fwlen = ips_add_all.len(); Ok(()) } - -fn send_and_process(batch: &FinalizedBatch) -> std::result::Result<(), Error> { - let seq: u32 = 2; - let socket = mnl::Socket::new(mnl::Bus::Netfilter)?; - socket.send_all(batch)?; - let mut buffer = vec![0; nftnl::nft_nlmsg_maxsize() as usize]; - while let Some(message) = socket_recv(&socket, &mut buffer[..])? { - match mnl::cb_run(message, seq, socket.portid())? { - mnl::CbResult::Stop => { - break; - } - mnl::CbResult::Ok => (), - } - } - Ok(()) -} - -fn socket_recv<'a>( - socket: &mnl::Socket, - buf: &'a mut [u8], -) -> std::result::Result, Error> { - let ret = socket.recv(buf)?; - if ret > 0 { - Ok(Some(&buf[..ret])) - } else { - Ok(None) - } -} diff --git a/src/ipblc.rs b/src/ipblc.rs index ceef99b..e11b880 100644 --- a/src/ipblc.rs +++ b/src/ipblc.rs @@ -1,5 +1,5 @@ use crate::config::{Context, GIT_VERSION}; -use crate::fw::{fwblock, fwglobalinit}; +use crate::fw::fwblock; use crate::ip::{filter, IpData, IpEvent}; use crate::ipevent; use crate::monitoring::apiserver; @@ -40,7 +40,6 @@ pub async fn run() { let mut last_cfg_reload: DateTime = Local::now().trunc_subsecs(0); log_with_systemd!(format!("Launching {}, version {}", PKG_NAME, pkgversion)); - fwglobalinit(); let ctxapi = Arc::clone(&ctxarc); apiserver(&ctxapi).await.unwrap(); @@ -125,7 +124,21 @@ pub async fn run() { }; let ctxclone = Arc::clone(&ctxarc); - handle_fwblock(ctxclone, &mut ret, &mut fwlen).await; + let tounblock = { + let mut ctx = ctxclone.write().await; + ctx.gc_blocklist().await + }; + let toblock = { + let ctx = ctxclone.read().await; + ctx.get_blocklist_toblock().await + }; + // apply firewall blocking + match fwblock(&toblock, &mut ret, &mut fwlen) { + Ok(_) => {} + Err(e) => { + println!("err: {e}, unable to push firewall rules, use super user") + } + }; // log lines if ret.len() > 0 { @@ -176,25 +189,6 @@ async fn handle_cfg_reload( }; } -async fn handle_fwblock(ctxclone: Arc>, ret: &mut Vec, fwlen: &mut usize) { - { - let mut ctx = ctxclone.write().await; - ctx.gc_blocklist().await; - } - let toblock = { - let ctx = ctxclone.read().await; - ctx.get_blocklist_toblock().await - }; - - // apply firewall blocking - match fwblock(&toblock, ret, fwlen) { - Ok(_) => {} - Err(e) => { - println!("err: {e}, unable to push firewall rules, use super user") - } - }; -} - async fn watchfiles(inoarc: Arc>) -> Receiver { let (bltx, blrx): (Sender, Receiver) = channel(BL_CHAN_SIZE); tokio::spawn(async move {