diff --git a/Cargo.lock b/Cargo.lock index 4e5cc54..ef0c8d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -296,7 +296,7 @@ dependencies = [ "ipnet", "once_cell", "rand", - "thiserror", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -319,7 +319,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -683,15 +683,14 @@ version = "0.0.0" [[package]] name = "nftables" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c7288de9ee11086e792d89ee45adf490a5a778ff0fddc7e086ce1521989e657" +source = "git+https://github.com/mbuesch/nftables-rs.git?branch=helpers-asref-osstr#1c2a2bd967a97c94c652c288d803e93025881eab" dependencies = [ "serde", "serde_json", "serde_path_to_error", "strum", "strum_macros", - "thiserror", + "thiserror 2.0.9", ] [[package]] @@ -1016,7 +1015,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" +dependencies = [ + "thiserror-impl 2.0.9", ] [[package]] @@ -1030,6 +1038,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tinystr" version = "0.7.6" diff --git a/Cargo.toml b/Cargo.toml index 0abfb2e..a9764e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,4 +56,7 @@ debug-assertions = false overflow-checks = true codegen-units = 1 +[patch.crates-io] +nftables = { git = "https://github.com/mbuesch/nftables-rs.git", branch = "helpers-asref-osstr" } + # vim: ts=4 sw=4 expandtab diff --git a/letmeinfwd/src/firewall/nftables.rs b/letmeinfwd/src/firewall/nftables.rs index 5b7a725..5b95fec 100644 --- a/letmeinfwd/src/firewall/nftables.rs +++ b/letmeinfwd/src/firewall/nftables.rs @@ -15,12 +15,12 @@ use letmein_conf::Config; use nftables::{ batch::Batch, expr::{Expression, NamedExpression, Payload, PayloadField}, - helper::{apply_ruleset, get_current_ruleset}, + helper::{apply_ruleset_with_args, get_current_ruleset_with_args, DEFAULT_ARGS}, schema::{Chain, FlushObject, NfCmd, NfListObject, NfObject, Rule}, stmt::{Match, Operator, Statement}, types::NfFamily, }; -use std::{fmt::Write as _, net::IpAddr}; +use std::{borrow::Cow, fmt::Write as _, net::IpAddr}; struct NftNames<'a> { family: NfFamily, @@ -59,7 +59,7 @@ impl<'a> NftNames<'a> { } /// Create an nftables IP source address match statement. -fn statement_match_saddr(family: NfFamily, addr: IpAddr) -> ah::Result { +fn statement_match_saddr<'a>(family: NfFamily, addr: IpAddr) -> ah::Result> { let (protocol, addr) = match addr { IpAddr::V4(addr) => match family { NfFamily::INet | NfFamily::IP => ("ip", addr.to_string()), @@ -88,26 +88,26 @@ fn statement_match_saddr(family: NfFamily, addr: IpAddr) -> ah::Result Statement { +fn statement_match_dport<'a>(port: SingleLeasePort) -> Statement<'a> { let (protocol, port) = match port { - SingleLeasePort::Tcp(port) => ("tcp".to_string(), port), - SingleLeasePort::Udp(port) => ("udp".to_string(), port), + SingleLeasePort::Tcp(port) => ("tcp", port), + SingleLeasePort::Udp(port) => ("udp", port), }; Statement::Match(Match { left: Expression::Named(NamedExpression::Payload(Payload::PayloadField( PayloadField { - protocol, - field: "dport".to_string(), + protocol: Cow::Borrowed(protocol), + field: Cow::Borrowed("dport"), }, ))), right: Expression::Number(port.into()), @@ -116,7 +116,7 @@ fn statement_match_dport(port: SingleLeasePort) -> Statement { } /// Create an nftables `accept` statement. -fn statement_accept() -> Statement { +fn statement_accept<'a>() -> Statement<'a> { Statement::Accept(None) } @@ -149,18 +149,18 @@ fn gen_add_lease_cmd( expr.push(statement_accept()); let mut rule = Rule { family: names.family, - table: names.table.to_string(), - chain: names.chain_input.to_string(), - expr, + table: Cow::Borrowed(names.table), + chain: Cow::Borrowed(names.chain_input), + expr: Cow::Owned(expr), ..Default::default() }; - rule.comment = Some(gen_rule_comment(addr, port)?); + rule.comment = Some(Cow::Owned(gen_rule_comment(addr, port)?)); Ok(NfCmd::Add(NfListObject::Rule(rule))) } /// Generate the nftables add-rule commands for this lease. /// These commands will open the port(s) for the IP address. -fn gen_add_lease_cmds(conf: &Config, lease: &Lease) -> ah::Result> { +fn gen_add_lease_cmds<'a>(conf: &'a Config, lease: &Lease) -> ah::Result>> { let mut cmds = Vec::with_capacity(2); let addr = Some(lease.addr()); match lease.port() { @@ -181,20 +181,16 @@ fn gen_add_lease_cmds(conf: &Config, lease: &Lease) -> ah::Result> { Ok(cmds) } -struct ListedRuleset { - objs: Vec, +struct ListedRuleset<'a> { + objs: Cow<'a, [NfObject<'static>]>, } -impl ListedRuleset { +impl ListedRuleset<'_> { /// Get the active ruleset from the kernel. pub fn from_kernel(conf: &Config) -> ah::Result { - let exe = conf - .nft_exe() - .to_str() - .context("letmeind.conf nftables exe")?; - let ruleset = get_current_ruleset( - Some(exe), // program - None, // args + let ruleset = get_current_ruleset_with_args( + Some(conf.nft_exe()), // program + DEFAULT_ARGS, // args )?; Ok(Self { objs: ruleset.objects, @@ -212,9 +208,9 @@ impl ListedRuleset { port: SingleLeasePort, ) -> ah::Result { let comment = gen_rule_comment(Some(addr), port)?; - for obj in &self.objs { + for obj in &*self.objs { if let NfObject::ListObject(obj) = obj { - match &**obj { + match obj { NfListObject::Rule(Rule { family: rule_family, table: rule_table, @@ -240,7 +236,11 @@ impl ListedRuleset { /// Generate nftables delete-rules for this lease. /// These rules will close the ports for the IP address. - pub fn gen_delete_lease_cmds(&self, conf: &Config, lease: &Lease) -> ah::Result> { + pub fn gen_delete_lease_cmds<'a>( + &self, + conf: &'a Config, + lease: &Lease, + ) -> ah::Result>> { let mut cmds = Vec::with_capacity(2); let names = NftNames::get(conf).context("Read configuration")?; let addr = lease.addr(); @@ -248,9 +248,9 @@ impl ListedRuleset { let new_rule = |port: SingleLeasePort| -> ah::Result { let mut rule = Rule { family: names.family, - table: names.table.to_string(), - chain: names.chain_input.to_string(), - expr: vec![], + table: Cow::Borrowed(names.table), + chain: Cow::Borrowed(names.chain_input), + expr: Cow::Owned(vec![]), ..Default::default() }; rule.handle = @@ -326,15 +326,11 @@ impl NftFirewall { /// Apply a rules batch to the kernel. fn nftables_apply_batch(&self, conf: &Config, batch: Batch) -> ah::Result<()> { - let exe = conf - .nft_exe() - .to_str() - .context("letmeind.conf nftables exe")?; let ruleset = batch.to_nftables(); - apply_ruleset( - &ruleset, // rules - Some(exe), // program - None, // args + apply_ruleset_with_args( + &ruleset, // rules + Some(conf.nft_exe()), // program + DEFAULT_ARGS, // args ) .context("Apply nftables")?; Ok(()) @@ -349,8 +345,8 @@ impl NftFirewall { // Remove all rules from our chain. batch.add_cmd(NfCmd::Flush(FlushObject::Chain(Chain { family: names.family, - table: names.table.to_string(), - name: names.chain_input.to_string(), + table: Cow::Borrowed(names.table), + name: Cow::Borrowed(names.chain_input), ..Default::default() }))); if conf.debug() {