diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/chain.rs | 133 | ||||
-rw-r--r-- | src/chain_methods.rs | 40 | ||||
-rw-r--r-- | src/expr/bitwise.rs | 39 | ||||
-rw-r--r-- | src/expr/immediate.rs | 14 | ||||
-rw-r--r-- | src/expr/log.rs | 73 | ||||
-rw-r--r-- | src/expr/meta.rs | 230 | ||||
-rw-r--r-- | src/expr/mod.rs | 175 | ||||
-rw-r--r-- | src/expr/verdict.rs | 18 | ||||
-rw-r--r-- | src/lib.rs | 24 | ||||
-rw-r--r-- | src/nlmsg.rs | 17 | ||||
-rw-r--r-- | src/parser.rs | 366 | ||||
-rw-r--r-- | src/query.rs | 15 | ||||
-rw-r--r-- | src/rule.rs | 191 | ||||
-rw-r--r-- | src/table.rs | 88 |
14 files changed, 539 insertions, 884 deletions
diff --git a/src/chain.rs b/src/chain.rs index cce0fa9..eeedcd1 100644 --- a/src/chain.rs +++ b/src/chain.rs @@ -1,12 +1,12 @@ use libc::{NF_ACCEPT, NF_DROP}; -use crate::nlmsg::{ - NfNetlinkAttribute, NfNetlinkAttributes, NfNetlinkDeserializable, NfNetlinkObject, - NfNetlinkWriter, -}; -use crate::parser::{parse_object, DecodeError, InnerFormat, NfNetlinkAttributeReader}; +use crate::nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable, NfNetlinkObject, NfNetlinkWriter}; +use crate::parser::{DecodeError, InnerFormat, Parsable}; use crate::sys::{self, NFT_MSG_DELCHAIN, NFT_MSG_NEWCHAIN, NLM_F_ACK, NLM_F_CREATE}; -use crate::{impl_attr_getters_and_setters, MsgType, ProtocolFamily, Table}; +use crate::{ + create_wrapper_type, impl_attr_getters_and_setters, impl_nfnetlinkattribute, MsgType, + ProtocolFamily, Table, +}; use std::convert::TryFrom; use std::fmt::Debug; @@ -28,29 +28,8 @@ pub enum HookClass { PostRouting = libc::NF_INET_POST_ROUTING, } -#[derive(Clone, PartialEq, Eq)] -pub struct Hook { - inner: NfNetlinkAttributes, -} - -impl Hook { - pub fn new(class: HookClass, priority: ChainPriority) -> Self { - Hook { - inner: NfNetlinkAttributes::new(), - } - .with_class(class as u32) - .with_priority(priority as u32) - } -} - -impl Debug for Hook { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.inner_format_struct(f.debug_struct("Hook"))?.finish() - } -} - -impl_attr_getters_and_setters!( - Hook, +create_wrapper_type!( + nested: Hook, [ // Define the action netfilter will apply to packets processed by this chain, but that did not match any rules in it. ( @@ -58,7 +37,7 @@ impl_attr_getters_and_setters!( set_class, with_class, sys::NFTA_HOOK_HOOKNUM, - U32, + class, u32 ), ( @@ -66,31 +45,17 @@ impl_attr_getters_and_setters!( set_priority, with_priority, sys::NFTA_HOOK_PRIORITY, - U32, + priority, u32 ) ] ); -impl NfNetlinkAttribute for Hook { - fn is_nested(&self) -> bool { - true - } - - fn get_size(&self) -> usize { - self.inner.get_size() - } - - unsafe fn write_payload(&self, addr: *mut u8) { - self.inner.write_payload(addr) - } -} - -impl NfNetlinkDeserializable for Hook { - fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { - let reader = NfNetlinkAttributeReader::new(buf, buf.len())?; - let inner = reader.decode::<Self>()?; - Ok((Hook { inner }, &[])) +impl Hook { + pub fn new(class: HookClass, priority: ChainPriority) -> Self { + Hook::default() + .with_class(class as u32) + .with_priority(priority as u32) } } @@ -186,10 +151,16 @@ impl NfNetlinkDeserializable for ChainType { /// [`Table`]: struct.Table.html /// [`Rule`]: struct.Rule.html /// [`set_hook`]: #method.set_hook -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Default)] pub struct Chain { family: ProtocolFamily, - inner: NfNetlinkAttributes, + flags: Option<u32>, + name: Option<String>, + hook: Option<Hook>, + policy: Option<ChainPolicy>, + table: Option<String>, + chain_type: Option<ChainType>, + userdata: Option<Vec<u8>>, } impl Chain { @@ -197,10 +168,8 @@ impl Chain { /// /// [`Table`]: struct.Table.html pub fn new(table: &Table) -> Chain { - let mut chain = Chain { - family: table.get_family(), - inner: NfNetlinkAttributes::new(), - }; + let mut chain = Chain::default(); + chain.family = table.family; if let Some(table_name) = table.get_name() { chain.set_table(table_name); @@ -213,10 +182,6 @@ impl Chain { self.family } - fn raw_attributes(&self) -> &NfNetlinkAttributes { - &self.inner - } - /* /// Returns a textual description of the chain. pub fn get_str(&self) -> CString { @@ -268,31 +233,29 @@ impl NfNetlinkObject for Chain { seq, None, ); - self.inner.serialize(writer); + let buf = writer.add_data_zeroed(self.get_size()); + unsafe { + self.write_payload(buf.as_mut_ptr()); + } writer.finalize_writing_object(); } } impl NfNetlinkDeserializable for Chain { fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { - let (inner, nfgenmsg, remaining_data) = - parse_object::<Self>(buf, NFT_MSG_NEWCHAIN, NFT_MSG_DELCHAIN)?; + let (mut obj, nfgenmsg, remaining_data) = + Self::parse_object(buf, NFT_MSG_NEWCHAIN, NFT_MSG_DELCHAIN)?; + obj.family = ProtocolFamily::try_from(nfgenmsg.nfgen_family as i32)?; - Ok(( - Self { - inner, - family: ProtocolFamily::try_from(nfgenmsg.nfgen_family as i32)?, - }, - remaining_data, - )) + Ok((obj, remaining_data)) } } impl_attr_getters_and_setters!( Chain, [ - (get_flags, set_flags, with_flags, sys::NFTA_CHAIN_FLAGS, U32, u32), - (get_name, set_name, with_name, sys::NFTA_CHAIN_NAME, String, String), + (get_table, set_table, with_table, sys::NFTA_CHAIN_TABLE, table, String), + (get_name, set_name, with_name, sys::NFTA_CHAIN_NAME, name, String), // Sets the hook and priority for this chain. Without calling this method the chain will // become a "regular chain" without any hook and will thus not receive any traffic unless // some rule forward packets to it via goto or jump verdicts. @@ -300,22 +263,38 @@ impl_attr_getters_and_setters!( // By calling `set_hook` with a hook the chain that is created will be registered with that // hook and is thus a "base chain". A "base chain" is an entry point for packets from the // networking stack. - (get_hook, set_hook, with_hook, sys::NFTA_CHAIN_HOOK, ChainHook, Hook), - (get_policy, set_policy, with_policy, sys::NFTA_CHAIN_POLICY, ChainPolicy, ChainPolicy), - (get_table, set_table, with_table, sys::NFTA_CHAIN_TABLE, String, String), + (get_hook, set_hook, with_hook, sys::NFTA_CHAIN_HOOK, hook, Hook), + (get_policy, set_policy, with_policy, sys::NFTA_CHAIN_POLICY, policy, ChainPolicy), // This only applies if the chain has been registered with a hook by calling `set_hook`. - (get_type, set_type, with_type, sys::NFTA_CHAIN_TYPE, ChainType, ChainType), + (get_type, set_type, with_type, sys::NFTA_CHAIN_TYPE, chain_type, ChainType), + (get_flags, set_flags, with_flags, sys::NFTA_CHAIN_FLAGS, flags, u32), ( get_userdata, set_userdata, with_userdata, sys::NFTA_CHAIN_USERDATA, - VecU8, + userdata, Vec<u8> ) ] ); +impl_nfnetlinkattribute!( + inline : Chain, + [ + (sys::NFTA_CHAIN_TABLE, table), + (sys::NFTA_CHAIN_NAME, name), + (sys::NFTA_CHAIN_HOOK, hook), + (sys::NFTA_CHAIN_POLICY, policy), + (sys::NFTA_CHAIN_TYPE, chain_type), + (sys::NFTA_CHAIN_FLAGS, flags), + ( + sys::NFTA_CHAIN_USERDATA, + userdata + ) + ] +); + pub fn list_chains_for_table(table: &Table) -> Result<Vec<Chain>, crate::query::Error> { let mut result = Vec::new(); crate::query::list_objects_with_data( diff --git a/src/chain_methods.rs b/src/chain_methods.rs deleted file mode 100644 index d384c35..0000000 --- a/src/chain_methods.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::{Batch, Chain, Hook, MsgType, Policy, Table}; -use std::ffi::CString; -use std::rc::Rc; - - -/// A helper trait over [`crate::Chain`]. -pub trait ChainMethods { - /// Creates a new Chain instance from a [`crate::Hook`] over a [`crate::Table`]. - fn from_hook(hook: Hook, table: Rc<Table>) -> Self - where Self: std::marker::Sized; - /// Adds a [`crate::Policy`] to the current Chain. - fn verdict(self, policy: Policy) -> Self; - fn add_to_batch(self, batch: &mut Batch) -> Self; -} - - -impl ChainMethods for Chain { - fn from_hook(hook: Hook, table: Rc<Table>) -> Self { - let chain_name = match hook { - Hook::PreRouting => "prerouting", - Hook::Out => "out", - Hook::PostRouting => "postrouting", - Hook::Forward => "forward", - Hook::In => "in", - }; - let chain_name = CString::new(chain_name).unwrap(); - let mut chain = Chain::new(&chain_name, table); - chain.set_hook(hook, 0); - chain - } - fn verdict(mut self, policy: Policy) -> Self { - self.set_policy(policy); - self - } - fn add_to_batch(self, batch: &mut Batch) -> Self { - batch.add(&self, MsgType::Add); - self - } -} - diff --git a/src/expr/bitwise.rs b/src/expr/bitwise.rs index 38c0383..73c2467 100644 --- a/src/expr/bitwise.rs +++ b/src/expr/bitwise.rs @@ -1,41 +1,34 @@ use super::{Expression, ExpressionData, Register}; -use crate::create_expr_type; +use crate::create_wrapper_type; use crate::parser::DecodeError; use crate::sys; -create_expr_type!( - inline with_builder : Bitwise, +create_wrapper_type!( + inline: Bitwise, [ ( - get_dreg, - set_dreg, - with_dreg, - sys::NFTA_BITWISE_DREG, - Register, - Register - ), - ( get_sreg, set_sreg, with_sreg, sys::NFTA_BITWISE_SREG, - Register, + sreg, Register ), ( - get_len, - set_len, - with_len, - sys::NFTA_BITWISE_LEN, - U32, - u32 + get_dreg, + set_dreg, + with_dreg, + sys::NFTA_BITWISE_DREG, + dreg, + Register ), + (get_len, set_len, with_len, sys::NFTA_BITWISE_LEN, len, u32), ( get_mask, set_mask, with_mask, sys::NFTA_BITWISE_MASK, - ExprData, + mask, ExpressionData ), ( @@ -43,7 +36,7 @@ create_expr_type!( set_xor, with_xor, sys::NFTA_BITWISE_XOR, - ExprData, + xor, ExpressionData ) ] @@ -64,11 +57,11 @@ impl Bitwise { if mask.len() != xor.len() { return Err(DecodeError::IncompatibleLength); } - Ok(Self::builder() + Ok(Bitwise::default() .with_sreg(Register::Reg1) .with_dreg(Register::Reg1) .with_len(mask.len() as u32) - .with_xor(ExpressionData::builder().with_value(xor)) - .with_mask(ExpressionData::builder().with_value(mask))) + .with_xor(ExpressionData::default().with_value(xor)) + .with_mask(ExpressionData::default().with_value(mask))) } } diff --git a/src/expr/immediate.rs b/src/expr/immediate.rs index 6f26bc3..925ca06 100644 --- a/src/expr/immediate.rs +++ b/src/expr/immediate.rs @@ -1,15 +1,15 @@ use super::{Expression, ExpressionData, Register}; -use crate::{create_expr_type, sys}; +use crate::{create_wrapper_type, sys}; -create_expr_type!( - inline with_builder : Immediate, +create_wrapper_type!( + inline: Immediate, [ ( get_dreg, set_dreg, with_dreg, sys::NFTA_IMMEDIATE_DREG, - Register, + dreg, Register ), ( @@ -17,7 +17,7 @@ create_expr_type!( set_data, with_data, sys::NFTA_IMMEDIATE_DATA, - ExprData, + data, ExpressionData ) ] @@ -25,9 +25,9 @@ create_expr_type!( impl Immediate { pub fn new_data(data: Vec<u8>, register: Register) -> Self { - Immediate::builder() + Immediate::default() .with_dreg(register) - .with_data(ExpressionData::builder().with_value(data)) + .with_data(ExpressionData::default().with_value(data)) } } diff --git a/src/expr/log.rs b/src/expr/log.rs index cf50cb2..82c201d 100644 --- a/src/expr/log.rs +++ b/src/expr/log.rs @@ -1,18 +1,17 @@ use super::{Expression, ExpressionError}; -use crate::create_expr_type; -use crate::nlmsg::NfNetlinkAttributes; +use crate::create_wrapper_type; use crate::sys; // A Log expression will log all packets that match the rule. -create_expr_type!( - inline with_builder : Log, +create_wrapper_type!( + inline: Log, [ ( get_group, set_group, with_group, sys::NFTA_LOG_GROUP, - U32, + group, u32 ), ( @@ -20,7 +19,7 @@ create_expr_type!( set_prefix, with_prefix, sys::NFTA_LOG_PREFIX, - String, + prefix, String ) ] @@ -31,11 +30,7 @@ impl Log { group: Option<u16>, prefix: Option<impl Into<String>>, ) -> Result<Log, ExpressionError> { - let mut res = Log { - inner: NfNetlinkAttributes::new(), - //pub group: Option<LogGroup>, - //pub prefix: Option<LogPrefix>, - }; + let mut res = Log::default(); if let Some(group) = group { res.set_group(group); } @@ -55,60 +50,4 @@ impl Expression for Log { fn get_name() -> &'static str { "log" } - /* - fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> - where - Self: Sized, - { - unsafe { - let mut group = None; - if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_LOG_GROUP as u16) { - group = Some(LogGroup(sys::nftnl_expr_get_u32( - expr, - sys::NFTNL_EXPR_LOG_GROUP as u16, - ) as u16)); - } - let mut prefix = None; - if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_LOG_PREFIX as u16) { - let raw_prefix = sys::nftnl_expr_get_str(expr, sys::NFTNL_EXPR_LOG_PREFIX as u16); - if raw_prefix.is_null() { - return Err(DeserializationError::NullPointer); - } else { - prefix = Some(LogPrefix(CStr::from_ptr(raw_prefix).to_owned())); - } - } - Ok(Log { group, prefix }) - } - } - - fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { - unsafe { - let expr = try_alloc!(sys::nftnl_expr_alloc(b"log\0" as *const _ as *const c_char)); - if let Some(log_group) = self.group { - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_LOG_GROUP as u16, log_group.0 as u32); - }; - if let Some(LogPrefix(prefix)) = &self.prefix { - sys::nftnl_expr_set_str(expr, sys::NFTNL_EXPR_LOG_PREFIX as u16, prefix.as_ptr()); - }; - - expr - } - } - */ -} - -#[macro_export] -macro_rules! nft_expr_log { - (group $group:ident prefix $prefix:expr) => { - $crate::expr::Log::new(Some($group), Some($prefix)) - }; - (prefix $prefix:expr) => { - $crate::expr::Log::new(None, Some($prefix)) - }; - (group $group:ident) => { - $crate::expr::Log::new(Some($group), None) - }; - () => { - $crate::expr::Log::new(None, None) - }; } diff --git a/src/expr/meta.rs b/src/expr/meta.rs index a015f65..bb8023d 100644 --- a/src/expr/meta.rs +++ b/src/expr/meta.rs @@ -1,175 +1,115 @@ -use super::{DeserializationError, Expression, Rule}; -use crate::sys::{self, libc}; -use std::os::raw::c_char; +use super::{Expression, Register, Rule}; +use crate::{ + create_wrapper_type, + nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable}, + parser::DecodeError, + sys, +}; +use std::convert::TryFrom; /// A meta expression refers to meta data associated with a packet. #[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[repr(u32)] #[non_exhaustive] -pub enum Meta { +pub enum MetaType { /// Packet ethertype protocol (skb->protocol), invalid in OUTPUT. - Protocol, + Protocol = sys::NFT_META_PROTOCOL, /// Packet mark. - Mark { set: bool }, + Mark = sys::NFT_META_MARK, /// Packet input interface index (dev->ifindex). - Iif, + Iif = sys::NFT_META_IIF, /// Packet output interface index (dev->ifindex). - Oif, + Oif = sys::NFT_META_OIF, /// Packet input interface name (dev->name). - IifName, + IifName = sys::NFT_META_IIFNAME, /// Packet output interface name (dev->name). - OifName, + OifName = sys::NFT_META_OIFNAME, /// Packet input interface type (dev->type). - IifType, + IifType = sys::NFT_META_IFTYPE, /// Packet output interface type (dev->type). - OifType, + OifType = sys::NFT_META_OIFTYPE, /// Originating socket UID (fsuid). - SkUid, + SkUid = sys::NFT_META_SKUID, /// Originating socket GID (fsgid). - SkGid, + SkGid = sys::NFT_META_SKGID, /// Netfilter protocol (Transport layer protocol). - NfProto, + NfProto = sys::NFT_META_NFPROTO, /// Layer 4 protocol number. - L4Proto, + L4Proto = sys::NFT_META_L4PROTO, /// Socket control group (skb->sk->sk_classid). - Cgroup, + Cgroup = sys::NFT_META_CGROUP, /// A 32bit pseudo-random number. - PRandom, + PRandom = sys::NFT_META_PRANDOM, } -impl Meta { - /// Returns the corresponding `NFT_*` constant for this meta expression. - pub fn to_raw_key(&self) -> u32 { - use Meta::*; - match *self { - Protocol => libc::NFT_META_PROTOCOL as u32, - Mark { .. } => libc::NFT_META_MARK as u32, - Iif => libc::NFT_META_IIF as u32, - Oif => libc::NFT_META_OIF as u32, - IifName => libc::NFT_META_IIFNAME as u32, - OifName => libc::NFT_META_OIFNAME as u32, - IifType => libc::NFT_META_IIFTYPE as u32, - OifType => libc::NFT_META_OIFTYPE as u32, - SkUid => libc::NFT_META_SKUID as u32, - SkGid => libc::NFT_META_SKGID as u32, - NfProto => libc::NFT_META_NFPROTO as u32, - L4Proto => libc::NFT_META_L4PROTO as u32, - Cgroup => libc::NFT_META_CGROUP as u32, - PRandom => libc::NFT_META_PRANDOM as u32, - } +impl NfNetlinkAttribute for MetaType { + fn get_size(&self) -> usize { + (*self as u32).get_size() } - fn from_raw(val: u32) -> Result<Self, DeserializationError> { - match val as i32 { - libc::NFT_META_PROTOCOL => Ok(Self::Protocol), - libc::NFT_META_MARK => Ok(Self::Mark { set: false }), - libc::NFT_META_IIF => Ok(Self::Iif), - libc::NFT_META_OIF => Ok(Self::Oif), - libc::NFT_META_IIFNAME => Ok(Self::IifName), - libc::NFT_META_OIFNAME => Ok(Self::OifName), - libc::NFT_META_IIFTYPE => Ok(Self::IifType), - libc::NFT_META_OIFTYPE => Ok(Self::OifType), - libc::NFT_META_SKUID => Ok(Self::SkUid), - libc::NFT_META_SKGID => Ok(Self::SkGid), - libc::NFT_META_NFPROTO => Ok(Self::NfProto), - libc::NFT_META_L4PROTO => Ok(Self::L4Proto), - libc::NFT_META_CGROUP => Ok(Self::Cgroup), - libc::NFT_META_PRANDOM => Ok(Self::PRandom), - _ => Err(DeserializationError::InvalidValue), - } + unsafe fn write_payload(&self, addr: *mut u8) { + (*self as u32).write_payload(addr); } } -impl Expression for Meta { - fn get_raw_name() -> *const libc::c_char { - b"meta\0" as *const _ as *const c_char - } - - fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> - where - Self: Sized, - { - unsafe { - let mut ret = Self::from_raw(sys::nftnl_expr_get_u32( - expr, - sys::NFTNL_EXPR_META_KEY as u16, - ))?; - - if let Self::Mark { ref mut set } = ret { - *set = sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_META_SREG as u16); - } - - Ok(ret) - } +impl NfNetlinkDeserializable for MetaType { + fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { + let (v, remaining_data) = u32::deserialize(buf)?; + Ok(( + match v { + sys::NFT_META_PROTOCOL => Self::Protocol, + sys::NFT_META_MARK => Self::Mark, + sys::NFT_META_IIF => Self::Iif, + sys::NFT_META_OIF => Self::Oif, + sys::NFT_META_IIFNAME => Self::IifName, + sys::NFT_META_OIFNAME => Self::OifName, + sys::NFT_META_IFTYPE => Self::IifType, + sys::NFT_META_OIFTYPE => Self::OifType, + sys::NFT_META_SKUID => Self::SkUid, + sys::NFT_META_SKGID => Self::SkGid, + sys::NFT_META_NFPROTO => Self::NfProto, + sys::NFT_META_L4PROTO => Self::L4Proto, + sys::NFT_META_CGROUP => Self::Cgroup, + sys::NFT_META_PRANDOM => Self::PRandom, + value => return Err(DecodeError::UnknownMetaType(value)), + }, + remaining_data, + )) } +} - fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { - unsafe { - let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name())); +create_wrapper_type!( + inline: Meta, + [ + ( + get_dreg, + set_dreg, + with_dreg, + sys::NFTA_META_DREG, + dreg, + Register + ), + ( + get_key, + set_key, + with_key, + sys::NFTA_META_KEY, + key, + MetaType + ), + ( + get_sreg, + set_sreg, + with_sreg, + sys::NFTA_META_SREG, + sreg, + Register + ) + ] +); - if let Meta::Mark { set: true } = self { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_META_SREG as u16, - libc::NFT_REG_1 as u32, - ); - } else { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_META_DREG as u16, - libc::NFT_REG_1 as u32, - ); - } - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_META_KEY as u16, self.to_raw_key()); - expr - } +impl Expression for Meta { + fn get_name() -> &'static str { + "meta" } } - -#[macro_export] -macro_rules! nft_expr_meta { - (proto) => { - $crate::expr::Meta::Protocol - }; - (mark set) => { - $crate::expr::Meta::Mark { set: true } - }; - (mark) => { - $crate::expr::Meta::Mark { set: false } - }; - (iif) => { - $crate::expr::Meta::Iif - }; - (oif) => { - $crate::expr::Meta::Oif - }; - (iifname) => { - $crate::expr::Meta::IifName - }; - (oifname) => { - $crate::expr::Meta::OifName - }; - (iiftype) => { - $crate::expr::Meta::IifType - }; - (oiftype) => { - $crate::expr::Meta::OifType - }; - (skuid) => { - $crate::expr::Meta::SkUid - }; - (skgid) => { - $crate::expr::Meta::SkGid - }; - (nfproto) => { - $crate::expr::Meta::NfProto - }; - (l4proto) => { - $crate::expr::Meta::L4Proto - }; - (cgroup) => { - $crate::expr::Meta::Cgroup - }; - (random) => { - $crate::expr::Meta::PRandom - }; -} diff --git a/src/expr/mod.rs b/src/expr/mod.rs index 78b1717..6dfa6c7 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -12,14 +12,13 @@ use std::net::Ipv6Addr; use std::slice::Iter; use super::rule::Rule; +use crate::create_wrapper_type; use crate::nlmsg::AttributeDecoder; use crate::nlmsg::NfNetlinkAttribute; -use crate::nlmsg::NfNetlinkAttributes; use crate::nlmsg::NfNetlinkDeserializable; use crate::parser::pad_netlink_object; use crate::parser::pad_netlink_object_with_variable_size; use crate::parser::write_attribute; -use crate::parser::AttributeType; use crate::parser::DecodeError; use crate::parser::InnerFormat; use crate::sys::{self, nlattr}; @@ -52,10 +51,12 @@ pub use self::lookup::*; mod masquerade; pub use self::masquerade::*; +*/ mod meta; pub use self::meta::*; +/* mod nat; pub use self::nat::*; @@ -111,91 +112,15 @@ pub trait Expression { fn get_name() -> &'static str; } -// wrapper for the general case, as we need to create many holder types given the depth of some -// netlink expressions -#[macro_export] -macro_rules! create_expr_type { - (without_decoder : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { - #[derive(Clone, PartialEq, Eq)] - pub struct $struct { - inner: $crate::nlmsg::NfNetlinkAttributes, - } - - - $crate::impl_attr_getters_and_setters!(without_decoder $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - - impl std::fmt::Debug for $struct { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use $crate::parser::InnerFormat; - self.inner_format_struct(f.debug_struct(stringify!($struct)))? - .finish() - } - } - - - impl $crate::nlmsg::NfNetlinkDeserializable for $struct { - fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), $crate::parser::DecodeError> { - let reader = $crate::parser::NfNetlinkAttributeReader::new(buf, buf.len())?; - let inner = reader.decode::<Self>()?; - Ok(($struct { inner }, &[])) - } - } - - }; - ($struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { - create_expr_type!(without_decoder : $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - $crate::impl_attr_getters_and_setters!(decoder $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - }; - (with_builder : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { - create_expr_type!($struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - - impl $struct { - pub fn builder() -> Self { - Self { inner: $crate::nlmsg::NfNetlinkAttributes::new() } - } - } - }; - (inline $($($attrs:ident) +)? : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { - create_expr_type!($($($attrs) + :)? $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - - impl $crate::nlmsg::NfNetlinkAttribute for $struct { - fn get_size(&self) -> usize { - self.inner.get_size() - } - - unsafe fn write_payload(&self, addr: *mut u8) { - self.inner.write_payload(addr) - } - } - }; - (nested $($($attrs:ident) +)? : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { - create_expr_type!($($($attrs) + :)? $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - - impl $crate::nlmsg::NfNetlinkAttribute for $struct { - fn is_nested(&self) -> bool { - true - } - - fn get_size(&self) -> usize { - self.inner.get_size() - } - - unsafe fn write_payload(&self, addr: *mut u8) { - self.inner.write_payload(addr) - } - } - }; -} - -create_expr_type!( - nested without_decoder : ExpressionHolder, [ +create_wrapper_type!( + nested without_deser : RawExpression, [ // Define the action netfilter will apply to packets processed by this chain, but that did not match any rules in it. ( get_name, set_name, with_name, sys::NFTA_EXPR_NAME, - String, + name, String ), ( @@ -203,22 +128,20 @@ create_expr_type!( set_data, with_data, sys::NFTA_EXPR_DATA, - ExpressionVariant, + data, ExpressionVariant ) ]); -impl ExpressionHolder { +impl RawExpression { pub fn new<T>(expr: T) -> Self where T: Expression, ExpressionVariant: From<T>, { - ExpressionHolder { - inner: NfNetlinkAttributes::new(), - } - .with_name(T::get_name()) - .with_data(ExpressionVariant::from(expr)) + RawExpression::default() + .with_name(T::get_name()) + .with_data(ExpressionVariant::from(expr)) } } @@ -262,44 +185,45 @@ macro_rules! create_expr_variant { } )+ - impl AttributeDecoder for ExpressionHolder { + impl $crate::nlmsg::AttributeDecoder for RawExpression { fn decode_attribute( - attrs: &NfNetlinkAttributes, + &mut self, attr_type: u16, buf: &[u8], - ) -> Result<AttributeType, DecodeError> { + ) -> Result<(), $crate::parser::DecodeError> { debug!("Decoding attribute {} in an expression", attr_type); match attr_type { x if x == sys::NFTA_EXPR_NAME => { debug!("Calling {}::deserialize()", std::any::type_name::<String>()); let (val, remaining) = String::deserialize(buf)?; if remaining.len() != 0 { - return Err(DecodeError::InvalidDataSize); + return Err($crate::parser::DecodeError::InvalidDataSize); } - Ok(AttributeType::String(val)) + self.name = Some(val); + Ok(()) }, x if x == sys::NFTA_EXPR_DATA => { // we can assume we have already the name parsed, as that's how we identify the // type of expression - let name = attrs - .get_attr(sys::NFTA_EXPR_NAME) - .ok_or(DecodeError::MissingExpressionName)?; + let name = self.name.as_ref() + .ok_or($crate::parser::DecodeError::MissingExpressionName)?; match name { $( - AttributeType::String(x) if x == <$type>::get_name() => { + x if x == <$type>::get_name() => { debug!("Calling {}::deserialize()", std::any::type_name::<$type>()); let (res, remaining) = <$type>::deserialize(buf)?; if remaining.len() != 0 { return Err($crate::parser::DecodeError::InvalidDataSize); } - Ok(AttributeType::ExpressionVariant(ExpressionVariant::from(res))) + self.data = Some(ExpressionVariant::from(res)); + Ok(()) }, )+ - AttributeType::String(name) => { + name => { info!("Unrecognized expression '{}', generating an ExpressionRaw", name); - ExpressionRaw::deserialize(buf).map(|(res, _)| AttributeType::ExpressionVariant(ExpressionVariant::ExpressionRaw(res))) - }, - _ => unreachable!() + self.data = Some(ExpressionVariant::ExpressionRaw(ExpressionRaw::deserialize(buf)?.0)); + Ok(()) + } } }, _ => Err(DecodeError::UnsupportedAttributeType(attr_type)), @@ -314,12 +238,13 @@ create_expr_variant!( [Log, Log], [Immediate, Immediate], [Bitwise, Bitwise], - [ExpressionRaw, ExpressionRaw] + [ExpressionRaw, ExpressionRaw], + [Meta, Meta] ); -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct ExpressionList { - exprs: Vec<AttributeType>, + exprs: Vec<RawExpression>, } impl ExpressionList { @@ -327,9 +252,9 @@ impl ExpressionList { Self { exprs: Vec::new() } } - /// Useful to add raw expressions because ExpressionHolder cannot infer alone its type - pub fn add_raw_expression(&mut self, e: ExpressionHolder) { - self.exprs.push(AttributeType::Expression(e)); + /// Useful to add raw expressions because RawExpression cannot infer alone its type + pub fn add_raw_expression(&mut self, e: RawExpression) { + self.exprs.push(e); } pub fn add_expression<T>(&mut self, e: T) @@ -337,8 +262,7 @@ impl ExpressionList { T: Expression, ExpressionVariant: From<T>, { - self.exprs - .push(AttributeType::Expression(ExpressionHolder::new(e))); + self.exprs.push(RawExpression::new(e)); } pub fn with_expression<T>(mut self, e: T) -> Self @@ -351,10 +275,7 @@ impl ExpressionList { } pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a ExpressionVariant> { - self.exprs.iter().map(|t| match t { - AttributeType::Expression(e) => e.get_data().unwrap(), - _ => unreachable!(), - }) + self.exprs.iter().map(|e| e.get_data().unwrap()) } } @@ -392,13 +313,13 @@ impl NfNetlinkDeserializable for ExpressionList { return Err(DecodeError::UnsupportedAttributeType(nla_type)); } - let (expr, remaining) = ExpressionHolder::deserialize( + let (expr, remaining) = RawExpression::deserialize( &buf[pos + pad_netlink_object::<nlattr>()..pos + nlattr.nla_len as usize], )?; if remaining.len() != 0 { return Err(DecodeError::InvalidDataSize); } - exprs.push(AttributeType::Expression(expr)); + exprs.push(expr); pos += pad_netlink_object_with_variable_size(nlattr.nla_len as usize); } @@ -411,15 +332,27 @@ impl NfNetlinkDeserializable for ExpressionList { } } -create_expr_type!( - nested with_builder : ExpressionData, +impl<T> From<Vec<T>> for ExpressionList +where + ExpressionVariant: From<T>, + T: Expression, +{ + fn from(v: Vec<T>) -> Self { + ExpressionList { + exprs: v.into_iter().map(RawExpression::new).collect(), + } + } +} + +create_wrapper_type!( + nested : ExpressionData, [ ( get_value, set_value, with_value, sys::NFTA_DATA_VALUE, - VecU8, + value, Vec<u8> ), ( @@ -427,7 +360,7 @@ create_expr_type!( set_verdict, with_verdict, sys::NFTA_DATA_VERDICT, - ExprVerdictAttribute, + verdict, VerdictAttribute ) ] @@ -454,7 +387,7 @@ impl NfNetlinkDeserializable for ExpressionRaw { } // Because we loose the name of the expression when parsing, this is the only expression -// where deserializing a message and the reserializing it alter its content +// where deserializing a message and then reserializing it is invalid impl Expression for ExpressionRaw { fn get_name() -> &'static str { "unknown_expression" diff --git a/src/expr/verdict.rs b/src/expr/verdict.rs index 7c27af6..547ba91 100644 --- a/src/expr/verdict.rs +++ b/src/expr/verdict.rs @@ -4,7 +4,7 @@ use libc::{NF_ACCEPT, NF_DROP, NF_QUEUE}; use super::{ExpressionData, Immediate, Register}; use crate::{ - create_expr_type, + create_wrapper_type, nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable}, parser::DecodeError, sys::{self, NFT_BREAK, NFT_CONTINUE, NFT_GOTO, NFT_JUMP, NFT_RETURN}, @@ -53,15 +53,15 @@ impl NfNetlinkDeserializable for VerdictType { } } -create_expr_type!( - nested with_builder : VerdictAttribute, +create_wrapper_type!( + nested: VerdictAttribute, [ ( get_code, set_code, with_code, sys::NFTA_VERDICT_CODE, - ExprVerdictType, + code, VerdictType ), ( @@ -69,7 +69,7 @@ create_expr_type!( set_chain, with_chain, sys::NFTA_VERDICT_CHAIN, - String, + chain, String ), ( @@ -77,7 +77,7 @@ create_expr_type!( set_chain_id, with_chain_id, sys::NFTA_VERDICT_CHAIN_ID, - U32, + chain_id, u32 ) ] @@ -113,12 +113,12 @@ impl Immediate { VerdictKind::Goto { .. } => VerdictType::Goto, VerdictKind::Return => VerdictType::Return, }; - let mut data = VerdictAttribute::builder().with_code(code); + let mut data = VerdictAttribute::default().with_code(code); if let VerdictKind::Jump { chain } | VerdictKind::Goto { chain } = kind { data.set_chain(chain); } - Immediate::builder() + Immediate::default() .with_dreg(Register::Verdict) - .with_data(ExpressionData::builder().with_verdict(data)) + .with_data(ExpressionData::default().with_verdict(data)) } } @@ -78,25 +78,11 @@ extern crate log; pub mod sys; use libc; -use std::{convert::TryFrom, ffi::c_void, ops::Deref}; - -macro_rules! try_alloc { - ($e:expr) => {{ - let ptr = $e; - if ptr.is_null() { - // OOM, and the tried allocation was likely very small, - // so we are in a very tight situation. We do what libstd does, aborts. - std::process::abort(); - } - ptr - }}; -} +use std::convert::TryFrom; mod batch; pub use batch::{default_batch_page_size, Batch}; -pub mod expr; - mod table; pub use table::list_tables; pub use table::Table; @@ -117,6 +103,8 @@ mod rule; pub use rule::list_rules_for_chain; pub use rule::Rule; +pub mod expr; + //mod rule_methods; //pub use rule_methods::{iface_index, Error as MatchError, Protocol, RuleMethods}; @@ -155,6 +143,12 @@ pub enum ProtocolFamily { DecNet = libc::NFPROTO_DECNET, } +impl Default for ProtocolFamily { + fn default() -> Self { + Self::Unspec + } +} + impl TryFrom<i32> for ProtocolFamily { type Error = DecodeError; fn try_from(value: i32) -> Result<Self, Self::Error> { diff --git a/src/nlmsg.rs b/src/nlmsg.rs index 8960146..8563a37 100644 --- a/src/nlmsg.rs +++ b/src/nlmsg.rs @@ -1,12 +1,9 @@ -use std::{collections::BTreeMap, fmt::Debug, mem::size_of}; +use std::{fmt::Debug, mem::size_of}; use crate::{ - parser::{ - pad_netlink_object, pad_netlink_object_with_variable_size, write_attribute, AttributeType, - DecodeError, - }, + parser::{pad_netlink_object, pad_netlink_object_with_variable_size, DecodeError}, sys::{ - nfgenmsg, nlattr, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN, NFNL_MSG_BATCH_END, + nfgenmsg, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN, NFNL_MSG_BATCH_END, NFNL_SUBSYS_NFTABLES, }, MsgType, ProtocolFamily, @@ -88,11 +85,7 @@ impl<'a> NfNetlinkWriter<'a> { } pub trait AttributeDecoder { - fn decode_attribute( - attrs: &NfNetlinkAttributes, - attr_type: u16, - buf: &[u8], - ) -> Result<AttributeType, DecodeError>; + fn decode_attribute(&mut self, attr_type: u16, buf: &[u8]) -> Result<(), DecodeError>; } pub trait NfNetlinkDeserializable: Sized { @@ -119,6 +112,7 @@ pub trait NfNetlinkAttribute: Debug + Sized { unsafe fn write_payload(&self, addr: *mut u8); } +/* #[derive(Debug, Clone, PartialEq, Eq)] pub struct NfNetlinkAttributes { pub attributes: BTreeMap<NetlinkType, AttributeType>, @@ -170,3 +164,4 @@ impl NfNetlinkAttribute for NfNetlinkAttributes { } } } +*/ diff --git a/src/parser.rs b/src/parser.rs index 8b14d74..b7d0ac3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -9,10 +9,9 @@ use std::{ use thiserror::Error; use crate::{ - expr::ExpressionHolder, + //expr::ExpressionHolder, nlmsg::{ - AttributeDecoder, NetlinkType, NfNetlinkAttribute, NfNetlinkAttributes, - NfNetlinkDeserializable, NfNetlinkWriter, + AttributeDecoder, NetlinkType, NfNetlinkAttribute, NfNetlinkDeserializable, NfNetlinkWriter, }, sys::{ nfgenmsg, nlattr, nlmsgerr, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN, @@ -66,6 +65,9 @@ pub enum DecodeError { #[error("Invalid policy for a chain")] UnknownChainPolicy, + #[error("Unknown type for a Meta expression")] + UnknownMetaType(u32), + #[error("Invalid value for a register")] UnknownRegisterValue, @@ -208,7 +210,11 @@ pub fn parse_nlmsg<'a>(buf: &'a [u8]) -> Result<(nlmsghdr, NlMsg<'a>), DecodeErr /// Write the attribute, preceded by a `libc::nlattr` // rewrite of `mnl_attr_put` -pub unsafe fn write_attribute<'a>(ty: NetlinkType, obj: &AttributeType, mut buf: *mut u8) { +pub unsafe fn write_attribute<'a>( + ty: NetlinkType, + obj: &impl NfNetlinkAttribute, + mut buf: *mut u8, +) { let header_len = pad_netlink_object::<libc::nlattr>(); // copy the header *(buf as *mut nlattr) = nlattr { @@ -296,7 +302,6 @@ impl NfNetlinkDeserializable for u64 { } } -// TODO: safe handling for null-delimited strings impl NfNetlinkAttribute for String { fn get_size(&self) -> usize { self.len() @@ -346,122 +351,42 @@ impl NfNetlinkDeserializable for ProtocolFamily { } } -pub struct NfNetlinkAttributeReader<'a> { - buf: &'a [u8], - pos: usize, - remaining_size: usize, - attrs: NfNetlinkAttributes, -} - -impl<'a> NfNetlinkAttributeReader<'a> { - pub fn new(buf: &'a [u8], remaining_size: usize) -> Result<Self, DecodeError> { - if buf.len() < remaining_size { - return Err(DecodeError::BufTooSmall); +pub(crate) fn read_attributes<T: AttributeDecoder + Default>(buf: &[u8]) -> Result<T, DecodeError> { + debug!( + "Calling <{} as NfNetlinkDeserialize>::deserialize()", + std::any::type_name::<T>() + ); + let mut remaining_size = buf.len(); + let mut pos = 0; + let mut res = T::default(); + while remaining_size > pad_netlink_object::<nlattr>() { + let nlattr = unsafe { *transmute::<*const u8, *const nlattr>(buf[pos..].as_ptr()) }; + // ignore the byteorder and nested attributes + let nla_type = nlattr.nla_type & NLA_TYPE_MASK as u16; + + pos += pad_netlink_object::<nlattr>(); + let attr_remaining_size = nlattr.nla_len as usize - pad_netlink_object::<nlattr>(); + match T::decode_attribute(&mut res, nla_type, &buf[pos..pos + attr_remaining_size]) { + Ok(()) => {} + Err(DecodeError::UnsupportedAttributeType(t)) => info!( + "Ignoring unsupported attribute type {} for type {}", + t, + std::any::type_name::<T>() + ), + Err(e) => return Err(e), } + pos += pad_netlink_object_with_variable_size(attr_remaining_size); - Ok(Self { - buf, - pos: 0, - remaining_size, - attrs: NfNetlinkAttributes::new(), - }) + remaining_size -= pad_netlink_object_with_variable_size(nlattr.nla_len as usize); } - pub fn get_raw_data(&self) -> &'a [u8] { - &self.buf[self.pos..] - } - - pub fn decode<T: AttributeDecoder + 'static>( - mut self, - ) -> Result<NfNetlinkAttributes, DecodeError> { - debug!( - "Calling NfNetlinkAttributeReader::decode() on {}", - std::any::type_name::<T>() - ); - while self.remaining_size > pad_netlink_object::<nlattr>() { - let nlattr = - unsafe { *transmute::<*const u8, *const nlattr>(self.buf[self.pos..].as_ptr()) }; - // ignore the byteorder and nested attributes - let nla_type = nlattr.nla_type & NLA_TYPE_MASK as u16; - - self.pos += pad_netlink_object::<nlattr>(); - let attr_remaining_size = nlattr.nla_len as usize - pad_netlink_object::<nlattr>(); - match T::decode_attribute( - &self.attrs, - nla_type, - &self.buf[self.pos..self.pos + attr_remaining_size], - ) { - Ok(x) => self.attrs.set_attr(nla_type, x), - Err(DecodeError::UnsupportedAttributeType(t)) => info!( - "Ignoring unsupported attribute type {} for type {}", - t, - std::any::type_name::<T>() - ), - Err(e) => return Err(e), - } - self.pos += pad_netlink_object_with_variable_size(attr_remaining_size); - - self.remaining_size -= pad_netlink_object_with_variable_size(nlattr.nla_len as usize); - } - - if self.remaining_size != 0 { - Err(DecodeError::InvalidDataSize) - } else { - Ok(self.attrs) - } + if remaining_size != 0 { + Err(DecodeError::InvalidDataSize) + } else { + Ok(res) } } -#[macro_export] -macro_rules! impl_attribute_holder { - ($enum_name:ident, $([$internal_name:ident, $type:ty]),+) => { - #[derive(Debug, Clone, PartialEq, Eq)] - pub enum $enum_name { - $( - $internal_name($type), - )+ - } - - impl NfNetlinkAttribute for $enum_name { - fn is_nested(&self) -> bool { - match self { - $( - $enum_name::$internal_name(val) => val.is_nested() - ),+ - } - } - - fn get_size(&self) -> usize { - match self { - $( - $enum_name::$internal_name(val) => val.get_size() - ),+ - } - } - - unsafe fn write_payload(&self, addr: *mut u8) { - match self { - $( - $enum_name::$internal_name(val) => val.write_payload(addr) - ),+ - } - } - } - - impl $enum_name { - $( - #[allow(non_snake_case)] - pub fn $internal_name(&self) -> Option<&$type> { - match self { - $enum_name::$internal_name(val) => Some(val), - _ => None - } - } - )+ - } - }; -} - pub trait InnerFormat { fn inner_format_struct<'a, 'b: 'a>( &'a self, @@ -469,49 +394,24 @@ pub trait InnerFormat { ) -> Result<DebugStruct<'a, 'b>, std::fmt::Error>; } -impl_attribute_holder!( - AttributeType, - [String, String], - [U8, u8], - [U16, u16], - [I32, i32], - [U32, u32], - [U64, u64], - [VecU8, Vec<u8>], - [ChainHook, crate::chain::Hook], - [ChainPolicy, crate::chain::ChainPolicy], - [ChainType, crate::chain::ChainType], - [ProtocolFamily, crate::ProtocolFamily], - [Expression, crate::expr::ExpressionHolder], - [ExpressionVariant, crate::expr::ExpressionVariant], - [ExpressionList, crate::expr::ExpressionList], - [ExprLog, crate::expr::Log], - [ExprImmediate, crate::expr::Immediate], - [ExprData, crate::expr::ExpressionData], - [ExprVerdictAttribute, crate::expr::VerdictAttribute], - [ExprVerdictType, crate::expr::VerdictType], - [Register, crate::expr::Register], - [ExprRaw, crate::expr::ExpressionRaw] -); - #[macro_export] macro_rules! impl_attr_getters_and_setters { - (without_decoder $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { + (without_deser $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { impl $struct { $( #[allow(dead_code)] pub fn $getter_name(&self) -> Option<&$type> { - self.inner.get_attr($attr_name as $crate::nlmsg::NetlinkType).map(|x| x.$internal_name()).flatten() + self.$internal_name.as_ref() } #[allow(dead_code)] pub fn $setter_name(&mut self, val: impl Into<$type>) { - self.inner.set_attr($attr_name as $crate::nlmsg::NetlinkType, $crate::parser::AttributeType::$internal_name(val.into())); + self.$internal_name = Some(val.into()); } #[allow(dead_code)] pub fn $in_place_edit_name(mut self, val: impl Into<$type>) -> Self { - self.inner.set_attr($attr_name as $crate::nlmsg::NetlinkType, $crate::parser::AttributeType::$internal_name(val.into())); + self.$internal_name = Some(val.into()); self } @@ -540,10 +440,10 @@ macro_rules! impl_attr_getters_and_setters { } }; - (decoder $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { + (deser $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { impl $crate::nlmsg::AttributeDecoder for $struct { #[allow(dead_code)] - fn decode_attribute(_attrs: &$crate::nlmsg::NfNetlinkAttributes, attr_type: u16, buf: &[u8]) -> Result<$crate::parser::AttributeType, $crate::parser::DecodeError> { + fn decode_attribute(&mut self, attr_type: u16, buf: &[u8]) -> Result<(), $crate::parser::DecodeError> { use $crate::nlmsg::NfNetlinkDeserializable; debug!("Decoding attribute {} in type {}", attr_type, std::any::type_name::<$struct>()); match attr_type { @@ -554,7 +454,8 @@ macro_rules! impl_attr_getters_and_setters { if remaining.len() != 0 { return Err($crate::parser::DecodeError::InvalidDataSize); } - Ok($crate::parser::AttributeType::$internal_name(val)) + self.$setter_name(val); + Ok(()) }, )+ _ => Err($crate::parser::DecodeError::UnsupportedAttributeType(attr_type)), @@ -563,39 +464,168 @@ macro_rules! impl_attr_getters_and_setters { } }; ($struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { - $crate::impl_attr_getters_and_setters!(without_decoder $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); - $crate::impl_attr_getters_and_setters!(decoder $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + $crate::impl_attr_getters_and_setters!(without_deser $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + $crate::impl_attr_getters_and_setters!(deser $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); }; } -pub fn parse_object<T: AttributeDecoder + 'static>( - buf: &[u8], - add_obj: u32, - del_obj: u32, -) -> Result<(NfNetlinkAttributes, nfgenmsg, &[u8]), DecodeError> { - debug!("parse_object() running"); - let (hdr, msg) = parse_nlmsg(buf)?; +pub trait Parsable +where + Self: Sized, +{ + fn parse_object( + buf: &[u8], + add_obj: u32, + del_obj: u32, + ) -> Result<(Self, nfgenmsg, &[u8]), DecodeError>; +} + +impl<T> Parsable for T +where + T: AttributeDecoder + Default + Sized, +{ + fn parse_object( + buf: &[u8], + add_obj: u32, + del_obj: u32, + ) -> Result<(Self, nfgenmsg, &[u8]), DecodeError> { + debug!("parse_object() started"); + let (hdr, msg) = parse_nlmsg(buf)?; + + let op = get_operation_from_nlmsghdr_type(hdr.nlmsg_type) as u32; + + if op != add_obj && op != del_obj { + return Err(DecodeError::UnexpectedType(hdr.nlmsg_type)); + } + + let obj_size = hdr.nlmsg_len as usize + - pad_netlink_object_with_variable_size(size_of::<nlmsghdr>() + size_of::<nfgenmsg>()); - let op = get_operation_from_nlmsghdr_type(hdr.nlmsg_type) as u32; + let remaining_data_offset = pad_netlink_object_with_variable_size(hdr.nlmsg_len as usize); + let remaining_data = &buf[remaining_data_offset..]; - if op != add_obj && op != del_obj { - return Err(DecodeError::UnexpectedType(hdr.nlmsg_type)); + let (nfgenmsg, res) = match msg { + NlMsg::NfGenMsg(nfgenmsg, content) => { + (nfgenmsg, read_attributes(&content[..obj_size])?) + } + _ => return Err(DecodeError::UnexpectedType(hdr.nlmsg_type)), + }; + + Ok((res, nfgenmsg, remaining_data)) } +} + +#[macro_export] +macro_rules! impl_nfnetlinkattribute { + (__inner : $struct:ident, [$(($attr_name:expr, $internal_name:ident)),+]) => { + impl $struct { + fn inner_get_size(&self) -> usize { + use $crate::nlmsg::NfNetlinkAttribute; + use $crate::parser::{pad_netlink_object, pad_netlink_object_with_variable_size}; + use $crate::sys::nlattr; + let mut size = 0; + + $( + if let Some(val) = &self.$internal_name { + // Attribute header + attribute value + size += pad_netlink_object::<nlattr>() + + pad_netlink_object_with_variable_size(val.get_size()); + } + )+ + + size + } + + unsafe fn inner_write_payload(&self, mut addr: *mut u8) { + use $crate::nlmsg::NfNetlinkAttribute; + use $crate::parser::{pad_netlink_object, pad_netlink_object_with_variable_size}; + use $crate::sys::nlattr; + $( + if let Some(val) = &self.$internal_name { + debug!("writing attribute {} - {:?}", $attr_name, val); + + unsafe { + $crate::parser::write_attribute($attr_name, val, addr); + } + let size = pad_netlink_object::<nlattr>() + + pad_netlink_object_with_variable_size(val.get_size()); + #[allow(unused)] + { + addr = addr.offset(size as isize); + } + } + )+ + } + } + }; + (inline : $struct:ident, [$(($attr_name:expr, $internal_name:ident)),+]) => { + $crate::impl_nfnetlinkattribute!(__inner : $struct, [$(($attr_name, $internal_name)),+]); + + impl $crate::nlmsg::NfNetlinkAttribute for $struct { + fn get_size(&self) -> usize { + self.inner_get_size() + } + + unsafe fn write_payload(&self, addr: *mut u8) { + self.inner_write_payload(addr); + } + } + }; + (nested : $struct:ident, [$(($attr_name:expr, $internal_name:ident)),+]) => { + $crate::impl_nfnetlinkattribute!(__inner : $struct, [$(($attr_name, $internal_name)),+]); - let obj_size = hdr.nlmsg_len as usize - - pad_netlink_object_with_variable_size(size_of::<nlmsghdr>() + size_of::<nfgenmsg>()); + impl $crate::nlmsg::NfNetlinkAttribute for $struct { + fn is_nested(&self) -> bool { + true + } - let remaining_data_offset = pad_netlink_object_with_variable_size(hdr.nlmsg_len as usize); - let remaining_data = &buf[remaining_data_offset..]; + fn get_size(&self) -> usize { + self.inner_get_size() + } - let (nfgenmsg, attrs) = match msg { - NlMsg::NfGenMsg(nfgenmsg, content) => { - (nfgenmsg, NfNetlinkAttributeReader::new(content, obj_size)?) + unsafe fn write_payload(&self, addr: *mut u8) { + self.inner_write_payload(addr); + } } - _ => return Err(DecodeError::UnexpectedType(hdr.nlmsg_type)), }; +} - let inner = attrs.decode::<T>()?; +#[macro_export] +macro_rules! create_wrapper_type { + (without_deser : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { + #[derive(Clone, PartialEq, Eq, Default)] + pub struct $struct { + $( + $internal_name: Option<$type> + ),+ + } - Ok((inner, nfgenmsg, remaining_data)) + $crate::impl_attr_getters_and_setters!(without_deser $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + + impl std::fmt::Debug for $struct { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use $crate::parser::InnerFormat; + self.inner_format_struct(f.debug_struct(stringify!($struct)))? + .finish() + } + } + + impl $crate::nlmsg::NfNetlinkDeserializable for $struct { + fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), $crate::parser::DecodeError> { + Ok(($crate::parser::read_attributes(buf)?, &[])) + } + } + }; + ($struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { + create_wrapper_type!(without_deser : $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + $crate::impl_attr_getters_and_setters!(deser $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + }; + (inline $($($attrs:ident) +)? : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { + create_wrapper_type!($($($attrs) + :)? $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + $crate::impl_nfnetlinkattribute!(inline : $struct, [$(($attr_name, $internal_name)),+]); + }; + (nested $($($attrs:ident) +)? : $struct:ident, [$(($getter_name:ident, $setter_name:ident, $in_place_edit_name:ident, $attr_name:expr, $internal_name:ident, $type:ty)),+]) => { + create_wrapper_type!($($($attrs) + :)? $struct, [$(($getter_name, $setter_name, $in_place_edit_name, $attr_name, $internal_name, $type)),+]); + $crate::impl_nfnetlinkattribute!(nested : $struct, [$(($attr_name, $internal_name)),+]); + }; } diff --git a/src/query.rs b/src/query.rs index 8ea7b89..294cbfe 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,7 +1,7 @@ use std::os::unix::prelude::RawFd; use crate::{ - nlmsg::{NfNetlinkAttributes, NfNetlinkObject, NfNetlinkWriter}, + nlmsg::{NfNetlinkAttribute, NfNetlinkObject, NfNetlinkWriter}, parser::{nft_nlmsg_maxsize, pad_netlink_object_with_variable_size}, sys::{nlmsgerr, NLM_F_DUMP, NLM_F_MULTI}, ProtocolFamily, @@ -152,10 +152,10 @@ where /// Returns a buffer containing a netlink message which requests a list of all the netfilter /// matching objects (e.g. tables, chains, rules, ...). /// Supply the type of objects to retrieve (e.g. libc::NFT_MSG_GETTABLE), and a search filter. -pub fn get_list_of_objects( +pub fn get_list_of_objects<T: NfNetlinkAttribute>( msg_type: u16, seq: u32, - filter: Option<&NfNetlinkAttributes>, + filter: Option<&T>, ) -> Result<Vec<u8>, Error> { let mut buffer = Vec::new(); let mut writer = NfNetlinkWriter::new(&mut buffer); @@ -167,7 +167,10 @@ pub fn get_list_of_objects( None, ); if let Some(filter) = filter { - filter.serialize(&mut writer); + let buf = writer.add_data_zeroed(filter.get_size()); + unsafe { + filter.write_payload(buf.as_mut_ptr()); + } } writer.finalize_writing_object(); Ok(buffer) @@ -180,11 +183,11 @@ pub fn get_list_of_objects( pub fn list_objects_with_data<'a, Object, Accumulator>( data_type: u16, cb: &dyn Fn(Object, &mut Accumulator) -> Result<(), Error>, - filter: Option<&NfNetlinkAttributes>, + filter: Option<&Object>, working_data: &'a mut Accumulator, ) -> Result<(), Error> where - Object: NfNetlinkObject, + Object: NfNetlinkObject + NfNetlinkAttribute, { debug!("Listing objects of kind {}", data_type); let sock = socket::socket( diff --git a/src/rule.rs b/src/rule.rs index a596fce..5f2889e 100644 --- a/src/rule.rs +++ b/src/rule.rs @@ -1,20 +1,23 @@ use crate::expr::ExpressionList; -use crate::nlmsg::{ - NfNetlinkAttributes, NfNetlinkDeserializable, NfNetlinkObject, NfNetlinkWriter, -}; -use crate::parser::InnerFormat; -use crate::parser::{parse_object, DecodeError}; +use crate::nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable, NfNetlinkObject, NfNetlinkWriter}; +use crate::parser::{DecodeError, InnerFormat, Parsable}; use crate::query::list_objects_with_data; use crate::sys::{self, NFT_MSG_DELRULE, NFT_MSG_NEWRULE, NLM_F_ACK, NLM_F_CREATE}; use crate::{chain::Chain, MsgType}; -use crate::{impl_attr_getters_and_setters, ProtocolFamily}; +use crate::{impl_attr_getters_and_setters, impl_nfnetlinkattribute, ProtocolFamily}; use std::convert::TryFrom; use std::fmt::Debug; /// A nftables firewall rule. -#[derive(PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Default)] pub struct Rule { - inner: NfNetlinkAttributes, + id: Option<u32>, + handle: Option<u64>, + position: Option<u64>, + table: Option<String>, + chain: Option<String>, + userdata: Option<Vec<u8>>, + expressions: Option<ExpressionList>, family: ProtocolFamily, } @@ -23,21 +26,18 @@ impl Rule { /// /// [`Chain`]: struct.Chain.html pub fn new(chain: &Chain) -> Result<Rule, DecodeError> { - let inner = NfNetlinkAttributes::new(); - Ok(Rule { - inner, - family: chain.get_family(), - } - .with_table( - chain - .get_table() - .ok_or(DecodeError::MissingChainInformationError)?, - ) - .with_chain( - chain - .get_name() - .ok_or(DecodeError::MissingChainInformationError)?, - )) + Ok(Rule::default() + .with_family(chain.get_family()) + .with_table( + chain + .get_table() + .ok_or(DecodeError::MissingChainInformationError)?, + ) + .with_chain( + chain + .get_name() + .ok_or(DecodeError::MissingChainInformationError)?, + )) } pub fn get_family(&self) -> ProtocolFamily { @@ -53,10 +53,6 @@ impl Rule { self } - fn raw_attributes(&self) -> &NfNetlinkAttributes { - &self.inner - } - /* /// Adds an expression to this rule. Expressions are evaluated from first to last added. /// As soon as an expression does not match the packet it's being evaluated for, evaluation @@ -191,143 +187,58 @@ impl NfNetlinkObject for Rule { seq, None, ); - self.inner.serialize(writer); + let buf = writer.add_data_zeroed(self.get_size()); + unsafe { + self.write_payload(buf.as_mut_ptr()); + } writer.finalize_writing_object(); } } impl NfNetlinkDeserializable for Rule { fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { - let (inner, nfgenmsg, remaining_data) = - parse_object::<Self>(buf, NFT_MSG_NEWRULE, NFT_MSG_DELRULE)?; + let (mut obj, nfgenmsg, remaining_data) = + Self::parse_object(buf, NFT_MSG_NEWRULE, NFT_MSG_DELRULE)?; + obj.family = ProtocolFamily::try_from(nfgenmsg.nfgen_family as i32)?; - Ok(( - Self { - inner, - family: ProtocolFamily::try_from(nfgenmsg.nfgen_family as i32)?, - }, - remaining_data, - )) + Ok((obj, remaining_data)) } } impl_attr_getters_and_setters!( Rule, [ - (get_id, set_id, with_id, sys::NFTA_RULE_ID, U32, u32), - (get_handle, set_handle, with_handle, sys::NFTA_RULE_HANDLE, U64, u64), + (get_table, set_table, with_table, sys::NFTA_RULE_TABLE, table, String), + (get_chain, set_chain, with_chain, sys::NFTA_RULE_CHAIN, chain, String), + (get_handle, set_handle, with_handle, sys::NFTA_RULE_HANDLE, handle, u64), + (get_expressions, set_expressions, with_expressions, sys::NFTA_RULE_EXPRESSIONS, expressions, ExpressionList), // Sets the position of this rule within the chain it lives in. By default a new rule is added // to the end of the chain. - (get_position, set_position, with_position, sys::NFTA_RULE_POSITION, U64, u64), - (get_table, set_table, with_table, sys::NFTA_RULE_TABLE, String, String), - (get_chain, set_chain, with_chain, sys::NFTA_RULE_CHAIN, String, String), + (get_position, set_position, with_position, sys::NFTA_RULE_POSITION, position, u64), ( get_userdata, set_userdata, with_userdata, sys::NFTA_RULE_USERDATA, - VecU8, + userdata, Vec<u8> ), - (get_expressions, set_expressions, with_expressions, sys::NFTA_RULE_EXPRESSIONS, ExpressionList, ExpressionList) + (get_id, set_id, with_id, sys::NFTA_RULE_ID, id, u32) ] ); -/* - -impl PartialEq for Rule { - fn eq(&self, other: &Self) -> bool { - 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; - } -} - -unsafe impl NlMsg for Rule { - unsafe fn write(&self, buf: &mut Vec<u8>, seq: u32, msg_type: MsgType) { - let type_ = match msg_type { - MsgType::Add => libc::NFT_MSG_NEWRULE, - MsgType::Del => libc::NFT_MSG_DELRULE, - }; - let flags: u16 = match msg_type { - MsgType::Add => (libc::NLM_F_CREATE | libc::NLM_F_APPEND | libc::NLM_F_EXCL) as u16, - MsgType::Del => 0u16, - } | libc::NLM_F_ACK as u16; - /* - let header = sys::nftnl_nlmsg_build_hdr( - buf as *mut c_char, - type_ as u16, - self.chain.get_table().get_family() as u16, - flags, - seq, - ); - sys::nftnl_rule_nlmsg_build_payload(header, self.rule); - */ - } -} - -impl Drop for Rule { - fn drop(&mut self) { - unsafe { sys::nftnl_rule_free(self.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) }; - } -} -*/ +impl_nfnetlinkattribute!(inline : Rule, [ + (sys::NFTA_RULE_TABLE, table), + (sys::NFTA_RULE_CHAIN, chain), + (sys::NFTA_RULE_HANDLE, handle), + (sys::NFTA_RULE_EXPRESSIONS, expressions), + (sys::NFTA_RULE_POSITION, position), + ( + sys::NFTA_RULE_USERDATA, + userdata + ), + (sys::NFTA_RULE_ID, id) +]); pub fn list_rules_for_chain(chain: &Chain) -> Result<Vec<Rule>, crate::query::Error> { let mut result = Vec::new(); @@ -338,7 +249,7 @@ pub fn list_rules_for_chain(chain: &Chain) -> Result<Vec<Rule>, crate::query::Er Ok(()) }, // only retrieve rules from the currently targetted chain - Some(&Rule::new(chain)?.raw_attributes()), + Some(&Rule::new(chain)?), &mut result, )?; Ok(result) diff --git a/src/table.rs b/src/table.rs index 5074ac9..96a4964 100644 --- a/src/table.rs +++ b/src/table.rs @@ -1,62 +1,33 @@ use std::convert::TryFrom; use std::fmt::Debug; -use crate::nlmsg::{ - NfNetlinkAttributes, NfNetlinkDeserializable, NfNetlinkObject, NfNetlinkWriter, -}; -use crate::parser::{parse_object, DecodeError, InnerFormat}; +use crate::nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable, NfNetlinkObject, NfNetlinkWriter}; +use crate::parser::Parsable; +use crate::parser::{DecodeError, InnerFormat}; use crate::sys::{ - self, NFNL_SUBSYS_NFTABLES, NFTA_OBJ_TABLE, NFTA_TABLE_FLAGS, NFTA_TABLE_NAME, - NFT_MSG_DELTABLE, NFT_MSG_GETTABLE, NFT_MSG_NEWTABLE, NLM_F_ACK, NLM_F_CREATE, + self, NFT_MSG_DELTABLE, NFT_MSG_GETTABLE, NFT_MSG_NEWTABLE, NLM_F_ACK, NLM_F_CREATE, }; -use crate::{impl_attr_getters_and_setters, MsgType, ProtocolFamily}; +use crate::{impl_attr_getters_and_setters, impl_nfnetlinkattribute, MsgType, ProtocolFamily}; /// Abstraction of a `nftnl_table`, the top level container in netfilter. A table has a protocol /// family and contains [`Chain`]s that in turn hold the rules. /// /// [`Chain`]: struct.Chain.html -#[derive(PartialEq, Eq)] +#[derive(Default, PartialEq, Eq)] pub struct Table { - inner: NfNetlinkAttributes, - family: ProtocolFamily, + flags: Option<u32>, + name: Option<String>, + userdata: Option<Vec<u8>>, + pub family: ProtocolFamily, } impl Table { pub fn new(family: ProtocolFamily) -> Table { - Table { - inner: NfNetlinkAttributes::new(), - family, - } - } - - pub fn get_family(&self) -> ProtocolFamily { - self.family - } - - /* - /// Returns a textual description of the table. - pub fn get_str(&self) -> CString { - let mut descr_buf = vec![0i8; 4096]; - unsafe { - sys::nftnl_table_snprintf( - descr_buf.as_mut_ptr() as *mut c_char, - (descr_buf.len() - 1) as u64, - self.table, - sys::NFTNL_OUTPUT_DEFAULT, - 0, - ); - CStr::from_ptr(descr_buf.as_ptr() as *mut c_char).to_owned() - } + let mut res = Self::default(); + res.family = family; + res } - */ } -/* -impl PartialEq for Table { - fn eq(&self, other: &Self) -> bool { - self.get_name() == other.get_name() && self.family == other.family - } -} -*/ impl Debug for Table { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -83,42 +54,49 @@ impl NfNetlinkObject for Table { seq, None, ); - self.inner.serialize(writer); + let buf = writer.add_data_zeroed(self.get_size()); + unsafe { + self.write_payload(buf.as_mut_ptr()); + } writer.finalize_writing_object(); } } impl NfNetlinkDeserializable for Table { fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { - let (inner, nfgenmsg, remaining_data) = - parse_object::<Self>(buf, NFT_MSG_NEWTABLE, NFT_MSG_DELTABLE)?; + let (mut obj, nfgenmsg, remaining_data) = + Self::parse_object(buf, NFT_MSG_NEWTABLE, NFT_MSG_DELTABLE)?; + obj.family = ProtocolFamily::try_from(nfgenmsg.nfgen_family as i32)?; - Ok(( - Self { - inner, - family: ProtocolFamily::try_from(nfgenmsg.nfgen_family as i32)?, - }, - remaining_data, - )) + Ok((obj, remaining_data)) } } impl_attr_getters_and_setters!( Table, [ - (get_flags, set_flags, with_flags, sys::NFTA_TABLE_FLAGS, U32, u32), - (get_name, set_name, with_name, sys::NFTA_TABLE_NAME, String, String), + (get_name, set_name, with_name, sys::NFTA_TABLE_NAME, name, String), + (get_flags, set_flags, with_flags, sys::NFTA_TABLE_FLAGS, flags, u32), ( get_userdata, set_userdata, with_userdata, sys::NFTA_TABLE_USERDATA, - VecU8, + userdata, Vec<u8> ) ] ); +impl_nfnetlinkattribute!( + inline : Table, + [ + (sys::NFTA_TABLE_NAME, name), + (sys::NFTA_TABLE_FLAGS, flags), + (sys::NFTA_TABLE_USERDATA, userdata) + ] +); + pub fn list_tables() -> Result<Vec<Table>, crate::query::Error> { let mut result = Vec::new(); crate::query::list_objects_with_data( |