diff options
Diffstat (limited to 'rustables/src/rule.rs')
-rw-r--r-- | rustables/src/rule.rs | 132 |
1 files changed, 125 insertions, 7 deletions
diff --git a/rustables/src/rule.rs b/rustables/src/rule.rs index 6e15db7..b315daf 100644 --- a/rustables/src/rule.rs +++ b/rustables/src/rule.rs @@ -1,3 +1,4 @@ +use crate::expr::ExpressionWrapper; use crate::{chain::Chain, expr::Expression, MsgType}; use rustables_sys::{self as sys, libc}; use std::ffi::{c_void, CStr, CString}; @@ -7,8 +8,8 @@ use std::rc::Rc; /// A nftables firewall rule. pub struct Rule { - rule: *mut sys::nftnl_rule, - chain: Rc<Chain>, + pub(crate) rule: *mut sys::nftnl_rule, + pub(crate) chain: Rc<Chain>, } impl Rule { @@ -82,14 +83,15 @@ impl Rule { pub fn get_userdata(&self) -> Option<&CStr> { unsafe { let ptr = sys::nftnl_rule_get_str(self.rule, sys::NFTNL_RULE_USERDATA as u16); - if ptr == std::ptr::null() { - return None; + if !ptr.is_null() { + Some(CStr::from_ptr(ptr)) + } else { + None } - Some(CStr::from_ptr(ptr)) } } - /// Update the userdata of this chain. + /// Updates the userdata of this chain. pub fn set_userdata(&self, data: &CStr) { unsafe { sys::nftnl_rule_set_str(self.rule, sys::NFTNL_RULE_USERDATA as u16, data.as_ptr()); @@ -111,6 +113,11 @@ impl Rule { } } + /// Retrieves an iterator to loop over the expressions of the rule + pub fn get_exprs(self: &Rc<Self>) -> RuleExprsIter { + RuleExprsIter::new(self.clone()) + } + #[cfg(feature = "unsafe-raw-handles")] /// Returns the raw handle. pub fn as_ptr(&self) -> *const sys::nftnl_rule { @@ -122,6 +129,59 @@ impl Rule { pub fn as_mut_ptr(&mut self) -> *mut sys::nftnl_rule { self.rule } + + /// Perform a deep comparizon of rules, by checking they have the same expressions inside. + /// This is not enabled by default in our PartialEq implementation because of the + /// difficulty to compare an expression generated by the library with the expressions returned + /// by the kernel when iterating over the currently in-use rules. The kernel-returned + /// expressions may have additional attributes despite being generated from the same rule. + /// This is particularly true for the 'nat' expression). + pub fn deep_eq(&self, other: &Self) -> bool { + if self != other { + return false; + } + + let self_exprs = + try_alloc!(unsafe { sys::nftnl_expr_iter_create(self.rule as *const sys::nftnl_rule) }); + let other_exprs = try_alloc!(unsafe { + sys::nftnl_expr_iter_create(other.rule as *const sys::nftnl_rule) + }); + + loop { + let self_next = unsafe { sys::nftnl_expr_iter_next(self_exprs) }; + let other_next = unsafe { sys::nftnl_expr_iter_next(other_exprs) }; + if self_next.is_null() && other_next.is_null() { + return true; + } else if self_next.is_null() || other_next.is_null() { + return false; + } + + // we are falling back on comparing the strings, because there is no easy mechanism to + // perform a memcmp() between the two expressions :/ + let mut self_str = [0; 256]; + let mut other_str = [0; 256]; + unsafe { + sys::nftnl_expr_snprintf( + self_str.as_mut_ptr(), + (self_str.len() - 1) as u64, + self_next, + sys::NFTNL_OUTPUT_DEFAULT, + 0, + ); + sys::nftnl_expr_snprintf( + other_str.as_mut_ptr(), + (other_str.len() - 1) as u64, + other_next, + sys::NFTNL_OUTPUT_DEFAULT, + 0, + ); + } + + if self_str != other_str { + return false; + } + } + } } impl Debug for Rule { @@ -132,7 +192,28 @@ impl Debug for Rule { impl PartialEq for Rule { fn eq(&self, other: &Self) -> bool { - self.get_chain() == other.get_chain() && self.get_handle() == other.get_handle() + if self.get_chain() != other.get_chain() { + return false; + } + + unsafe { + if sys::nftnl_rule_is_set(self.rule, sys::NFTNL_RULE_HANDLE as u16) + && sys::nftnl_rule_is_set(other.rule, sys::NFTNL_RULE_HANDLE as u16) + { + if self.get_handle() != other.get_handle() { + return false; + } + } + if sys::nftnl_rule_is_set(self.rule, sys::NFTNL_RULE_POSITION as u16) + && sys::nftnl_rule_is_set(other.rule, sys::NFTNL_RULE_POSITION as u16) + { + if self.get_position() != other.get_position() { + return false; + } + } + } + + return false; } } @@ -163,6 +244,43 @@ impl Drop for Rule { } } +pub struct RuleExprsIter { + rule: Rc<Rule>, + iter: *mut sys::nftnl_expr_iter, +} + +impl RuleExprsIter { + fn new(rule: Rc<Rule>) -> Self { + let iter = + try_alloc!(unsafe { sys::nftnl_expr_iter_create(rule.rule as *const sys::nftnl_rule) }); + RuleExprsIter { rule, iter } + } +} + +impl Iterator for RuleExprsIter { + type Item = ExpressionWrapper; + + fn next(&mut self) -> Option<Self::Item> { + let next = unsafe { sys::nftnl_expr_iter_next(self.iter) }; + if next.is_null() { + trace!("RulesExprsIter iterator ending"); + None + } else { + trace!("RulesExprsIter returning new expression"); + Some(ExpressionWrapper { + expr: next, + rule: self.rule.clone(), + }) + } + } +} + +impl Drop for RuleExprsIter { + fn drop(&mut self) { + unsafe { sys::nftnl_expr_iter_destroy(self.iter) }; + } +} + #[cfg(feature = "query")] pub fn get_rules_cb( header: &libc::nlmsghdr, |