From 50915b66b8455b05beb5291934d67761fe69bbda Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Mon, 29 Jan 2024 13:47:34 +0100 Subject: [PATCH 1/4] Fix issues on set.rs I found two issues while attempting to create a set: 1. A straight forward bug on the ntf_set macro: expect call were called in non option or result types. 2. A not as straight forward issue, where all sets created had both the anonymous and constant flag. The anonymous one definitely should not be there, because we are creating a named set. The constant flag should be optional somehow. It doesn't really break my use case, but I didn't want it to be there, so I removed it. --- nftnl/src/set.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/nftnl/src/set.rs b/nftnl/src/set.rs index eb33866..4074c0a 100644 --- a/nftnl/src/set.rs +++ b/nftnl/src/set.rs @@ -17,9 +17,9 @@ macro_rules! nft_set { nft_set!($name, $id, $table, $family) }; ($name:expr, $id:expr, $table:expr, $family:expr; [ $($value:expr,)* ]) => {{ - let mut set = nft_set!($name, $id, $table, $family).expect("Set allocation failed"); + let mut set = nft_set!($name, $id, $table, $family); $( - set.add($value).expect(stringify!(Unable to add $value to set $name)); + set.add($value); )* set }}; @@ -45,11 +45,6 @@ impl<'a, K> Set<'a, K> { sys::nftnl_set_set_str(set, sys::NFTNL_SET_NAME as u16, name.as_ptr()); sys::nftnl_set_set_u32(set, sys::NFTNL_SET_ID as u16, id); - sys::nftnl_set_set_u32( - set, - sys::NFTNL_SET_FLAGS as u16, - (libc::NFT_SET_ANONYMOUS | libc::NFT_SET_CONSTANT) as u32, - ); sys::nftnl_set_set_u32(set, sys::NFTNL_SET_KEY_TYPE as u16, K::TYPE); sys::nftnl_set_set_u32(set, sys::NFTNL_SET_KEY_LEN as u16, K::LEN); From f14e104e803f95988ee8e57aec8b30c391b89259 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Mon, 29 Jan 2024 13:51:36 +0100 Subject: [PATCH 2/4] Add support for conntrack zone --- nftnl/src/expr/ct.rs | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/nftnl/src/expr/ct.rs b/nftnl/src/expr/ct.rs index ea9a5db..3221fca 100644 --- a/nftnl/src/expr/ct.rs +++ b/nftnl/src/expr/ct.rs @@ -37,6 +37,7 @@ pub enum Conntrack { State, Status, Mark { set: bool }, + Zone { set: bool }, } impl Conntrack { @@ -45,6 +46,9 @@ impl Conntrack { Conntrack::State => libc::NFT_CT_STATE as u32, Conntrack::Status => libc::NFT_CT_STATUS as u32, Conntrack::Mark { .. } => libc::NFT_CT_MARK as u32, + // TODO: Update this once libc has definitions for NFT_CT_ZONE + // (https://github.com/rust-lang/libc/issues/3566) + Conntrack::Zone { .. } => 17 as u32, } } } @@ -54,19 +58,23 @@ impl Expression for Conntrack { unsafe { let expr = try_alloc!(sys::nftnl_expr_alloc(b"ct\0" as *const _ as *const c_char)); - if let Conntrack::Mark { set: true } = self { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_CT_SREG as u16, - libc::NFT_REG_1 as u32, - ); - } else { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_CT_DREG as u16, - libc::NFT_REG_1 as u32, - ); + match &self { + Conntrack::Mark { set: true } | Conntrack::Zone { set: true } => { + sys::nftnl_expr_set_u32( + expr, + sys::NFTNL_EXPR_CT_SREG as u16, + libc::NFT_REG_1 as u32, + ); + } + _ => { + sys::nftnl_expr_set_u32( + expr, + sys::NFTNL_EXPR_CT_DREG as u16, + libc::NFT_REG_1 as u32, + ); + } } + sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_CT_KEY as u16, self.raw_key()); expr @@ -88,4 +96,10 @@ macro_rules! nft_expr_ct { (mark) => { $crate::expr::Conntrack::Mark { set: false } }; + (zone set) => { + $crate::expr::Conntrack::Zone { set: true } + }; + (zone) => { + $crate::expr::Conntrack::Zone { set: false } + }; } From 3b60247ddee8b2363bec5b194a778bfd91f9c003 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Mon, 29 Jan 2024 14:38:13 +0100 Subject: [PATCH 3/4] Add support for fib rules --- nftnl/src/expr/fib.rs | 121 ++++++++++++++++++++++++++++++++++++++++++ nftnl/src/expr/mod.rs | 6 +++ 2 files changed, 127 insertions(+) create mode 100644 nftnl/src/expr/fib.rs diff --git a/nftnl/src/expr/fib.rs b/nftnl/src/expr/fib.rs new file mode 100644 index 0000000..e071b3c --- /dev/null +++ b/nftnl/src/expr/fib.rs @@ -0,0 +1,121 @@ +use super::{Expression, Rule}; +use nftnl_sys::{self as sys, libc}; +use std::os::raw::c_char; +use std::str::FromStr; + +#[non_exhaustive] +pub enum FibResult { + Oif, + OifName, + AddrType, +} + +impl FromStr for FibResult { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s.trim().to_lowercase().as_str() { + "oif" => Ok(FibResult::Oif), + "oifname" => Ok(FibResult::OifName), + "type" => Ok(FibResult::AddrType), + _ => Err("Invalid FibResult variant"), + } + } +} + +impl FibResult { + pub fn raw_result_type(&self) -> u32 { + use FibResult::*; + + // From: linux/netfilter/nf_tables.h + match *self { + Oif => 1, + OifName => 2, + AddrType => 3, + } + } +} + +#[non_exhaustive] +pub enum Fib { + SAddr { result: &'static str }, + DAddr { result: &'static str }, + Mark { result: &'static str }, + Iif { result: &'static str }, + Oif { result: &'static str }, + Present { result: &'static str }, +} + +impl Fib { + pub fn flags(&self) -> u32 { + use Fib::*; + + // From: linux/netfilter/nf_tables.h + match *self { + SAddr { .. } => 1 << 0, + DAddr { .. } => 1 << 1, + Mark { .. } => 1 << 2, + Iif { .. } => 1 << 3, + Oif { .. } => 1 << 4, + Present { .. } => 1 << 5, + } + } + + pub fn result(&self) -> u32 { + use Fib::*; + + let result: FibResult = match self { + SAddr { result } + | DAddr { result } + | Mark { result } + | Iif { result } + | Oif { result } + | Present { result } => result + .parse() + .expect("Unexpected fib result. Must be type, oif or oifname."), + }; + + result.raw_result_type() + } +} + +impl Expression for Fib { + fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { + unsafe { + let expr = try_alloc!(sys::nftnl_expr_alloc(b"fib\0" as *const _ as *const c_char)); + + sys::nftnl_expr_set_u32( + expr, + sys::NFTNL_EXPR_FIB_DREG as u16, + libc::NFT_REG_1 as u32, + ); + + sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_FIB_RESULT as u16, self.result()); + sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_FIB_FLAGS as u16, self.flags()); + + expr + } + } +} + +#[macro_export] +macro_rules! nft_expr_fib { + (saddr $result:expr) => { + $crate::expr::Fib::SAddr { result: $result } + }; + (daddr $result:expr) => { + $crate::expr::Fib::DAddr { result: $result } + }; + (mark $result:expr) => { + $crate::expr::Fib::Mark { result: $result } + }; + (iif $result:expr) => { + $crate::expr::Fib::Iif { result: $result } + }; + (oif $result:expr) => { + $crate::expr::Fib::Oif { result: $result } + }; + (present $result:expr) => { + $crate::expr::Fib::Present { result: $result } + }; +} diff --git a/nftnl/src/expr/mod.rs b/nftnl/src/expr/mod.rs index b4695fb..fee89a2 100644 --- a/nftnl/src/expr/mod.rs +++ b/nftnl/src/expr/mod.rs @@ -63,6 +63,9 @@ pub use self::payload::*; mod verdict; pub use self::verdict::*; +mod fib; +pub use self::fib::*; + #[macro_export(local_inner_macros)] macro_rules! nft_expr { (bitwise mask $mask:expr,xor $xor:expr) => { @@ -104,4 +107,7 @@ macro_rules! nft_expr { (immediate $expr:ident $value:expr) => { nft_expr_immediate!($expr $value) }; + (fib $expr:ident $result:expr) => { + nft_expr_fib!($expr $result) + }; } From 5e2982d56838e1644cd4bce16b84da8aec68e599 Mon Sep 17 00:00:00 2001 From: Beatriz Rizental Date: Wed, 31 Jan 2024 18:28:00 +0100 Subject: [PATCH 4/4] Implement Send and Sync traits for Set Not really sure about this one, but just followed what was done for the other primitives. --- nftnl/src/set.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nftnl/src/set.rs b/nftnl/src/set.rs index 4074c0a..2d79252 100644 --- a/nftnl/src/set.rs +++ b/nftnl/src/set.rs @@ -32,6 +32,11 @@ pub struct Set<'a, K> { _marker: ::std::marker::PhantomData, } +// Safety: It should be safe to pass this around and +// *read* from it from multiple threads +unsafe impl<'a, K> Send for Set<'a, K> where K: Send + Sync {} +unsafe impl<'a, K> Sync for Set<'a, K> where K: Send + Sync {} + impl<'a, K> Set<'a, K> { pub fn new(name: &CStr, id: u32, table: &'a Table, family: ProtoFamily) -> Self where