aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon THOBY <git@nightmared.fr>2022-11-11 23:50:29 +0100
committerSimon THOBY <git@nightmared.fr>2022-11-12 12:13:01 +0100
commit6cd97d19b54eeedffa18fddebb1b09045b0e79cf (patch)
tree5444a37a1b19618313ca515c6e46c880155f66d5 /src
parent84fc84c32e62e3d2c5fe7ab6c35b5d05f890e8a6 (diff)
re-add support for querying chains
Diffstat (limited to 'src')
-rw-r--r--src/batch.rs3
-rw-r--r--src/chain.rs239
-rw-r--r--src/lib.rs10
-rw-r--r--src/nlmsg.rs83
-rw-r--r--src/parser.rs115
-rw-r--r--src/table.rs49
6 files changed, 198 insertions, 301 deletions
diff --git a/src/batch.rs b/src/batch.rs
index 01f0c31..a1c7e0f 100644
--- a/src/batch.rs
+++ b/src/batch.rs
@@ -3,6 +3,7 @@ use libc;
use thiserror::Error;
use crate::nlmsg::{NfNetlinkObject, NfNetlinkWriter};
+use crate::sys::NFNL_SUBSYS_NFTABLES;
use crate::{MsgType, ProtoFamily};
use crate::query::Error;
@@ -81,7 +82,7 @@ impl Batch {
ProtoFamily::Unspec,
0,
self.seq,
- Some(libc::NFNL_SUBSYS_NFTABLES as u16),
+ Some(NFNL_SUBSYS_NFTABLES as u16),
);
self.writer.finalize_writing_object();
*self.buf
diff --git a/src/chain.rs b/src/chain.rs
index e29b239..000a196 100644
--- a/src/chain.rs
+++ b/src/chain.rs
@@ -1,17 +1,14 @@
+use crate::nlmsg::NfNetlinkSerializable;
use crate::nlmsg::{
- AttributeDecoder, NfNetlinkAttribute, NfNetlinkAttributes, NfNetlinkDeserializable,
- NfNetlinkObject, NfNetlinkWriter,
+ NfNetlinkAttribute, NfNetlinkAttributes, NfNetlinkDeserializable, NfNetlinkObject,
+ NfNetlinkWriter,
+};
+use crate::parser::{
+ parse_object, DecodeError, InnerFormat, NestedAttribute, NfNetlinkAttributeReader,
};
-use crate::parser::{DecodeError, NestedAttribute, NfNetlinkAttributeReader};
use crate::sys::{self, NFT_MSG_DELCHAIN, NFT_MSG_NEWCHAIN, NLM_F_ACK};
use crate::{impl_attr_getters_and_setters, MsgType, ProtoFamily, Table};
-use std::convert::TryFrom;
-use std::{
- ffi::{c_void, CStr, CString},
- fmt,
- os::raw::c_char,
- rc::Rc,
-};
+use std::fmt::Debug;
pub type Priority = i32;
@@ -31,13 +28,13 @@ pub enum HookClass {
PostRouting = libc::NF_INET_POST_ROUTING as u32,
}
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Clone, PartialEq, Eq)]
pub struct Hook {
inner: NestedAttribute,
}
impl Hook {
- fn new(class: HookClass, priority: Priority) -> Self {
+ pub fn new(class: HookClass, priority: Priority) -> Self {
Hook {
inner: NestedAttribute::new(),
}
@@ -46,6 +43,12 @@ impl Hook {
}
}
+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,
[
@@ -113,15 +116,40 @@ pub enum ChainType {
}
impl ChainType {
- fn as_c_str(&self) -> &'static [u8] {
+ fn as_str(&self) -> &'static str {
match *self {
- ChainType::Filter => b"filter\0",
- ChainType::Route => b"route\0",
- ChainType::Nat => b"nat\0",
+ ChainType::Filter => "filter",
+ ChainType::Route => "route",
+ ChainType::Nat => "nat",
}
}
}
+impl NfNetlinkAttribute for ChainType {
+ fn get_size(&self) -> usize {
+ self.as_str().len()
+ }
+
+ unsafe fn write_payload(&self, addr: *mut u8) {
+ self.as_str().to_string().write_payload(addr);
+ }
+}
+
+impl NfNetlinkDeserializable for ChainType {
+ fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+ let (s, remaining_data) = String::deserialize(buf)?;
+ Ok((
+ match s.as_str() {
+ "filter" => ChainType::Filter,
+ "route" => ChainType::Route,
+ "nat" => ChainType::Nat,
+ _ => return Err(DecodeError::UnknownChainType),
+ },
+ remaining_data,
+ ))
+ }
+}
+
/// Abstraction of a `nftnl_chain`. Chains reside inside [`Table`]s and they hold [`Rule`]s.
///
/// There are two types of chains, "base chain" and "regular chain". See [`set_hook`] for more
@@ -130,7 +158,7 @@ impl ChainType {
/// [`Table`]: struct.Table.html
/// [`Rule`]: struct.Rule.html
/// [`set_hook`]: #method.set_hook
-#[derive(Debug, PartialEq, Eq)]
+#[derive(PartialEq, Eq)]
pub struct Chain {
inner: NfNetlinkAttributes,
}
@@ -139,7 +167,7 @@ impl Chain {
/// Creates a new chain instance inside the given [`Table`].
///
/// [`Table`]: struct.Table.html
- pub fn new<T: AsRef<CStr>>(table: &Table) -> Chain {
+ pub fn new(table: &Table) -> Chain {
let mut chain = Chain {
inner: NfNetlinkAttributes::new(),
};
@@ -152,20 +180,6 @@ impl Chain {
}
/*
- /// 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.
- ///
- /// 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.
- pub fn set_hook(&mut self, hook: Hook, priority: Priority) {
- self.set_hook_type(hook);
- self.set_hook_priority(priority);
- }
- */
-
- /*
/// Returns a textual description of the chain.
pub fn get_str(&self) -> CString {
let mut descr_buf = vec![0i8; 4096];
@@ -184,13 +198,6 @@ impl Chain {
}
/*
-impl fmt::Debug for Chain {
- /// Returns a string representation of the chain.
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(fmt, "{:?}", self.get_str())
- }
-}
-
impl PartialEq for Chain {
fn eq(&self, other: &Self) -> bool {
self.get_table() == other.get_table() && self.get_name() == other.get_name()
@@ -198,7 +205,12 @@ impl PartialEq for Chain {
}
*/
-/*
+impl Debug for Chain {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ self.inner_format_struct(f.debug_struct("Chain"))?.finish()
+ }
+}
+
impl NfNetlinkObject for Chain {
fn add_or_remove<'a>(&self, writer: &mut NfNetlinkWriter<'a>, msg_type: MsgType, seq: u32) {
let raw_msg_type = match msg_type {
@@ -215,137 +227,29 @@ impl NfNetlinkObject for Chain {
self.inner.serialize(writer);
writer.finalize_writing_object();
}
-
- fn decode_attribute(attr_type: u16, buf: &[u8]) -> Result<AttributeType, DecodeError> {
- match attr_type {
- NFTA_TABLE_NAME => Ok(AttributeType::String(String::from_utf8(buf.to_vec())?)),
- NFTA_TABLE_FLAGS => {
- let val = [buf[0], buf[1], buf[2], buf[3]];
-
- Ok(AttributeType::U32(u32::from_ne_bytes(val)))
- }
- NFTA_TABLE_USERDATA => Ok(AttributeType::VecU8(buf.to_vec())),
- _ => Err(DecodeError::UnsupportedAttributeType(attr_type)),
- }
- }
-
- fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
- let (hdr, msg) = parse_nlmsg(buf)?;
-
- let op = get_operation_from_nlmsghdr_type(hdr.nlmsg_type) as u32;
-
- if op != NFT_MSG_NEWTABLE && op != NFT_MSG_DELTABLE {
- return Err(DecodeError::UnexpectedType(hdr.nlmsg_type));
- }
-
- let (nfgenmsg, attrs, remaining_data) = parse_object(hdr, msg, buf)?;
-
- let inner = attrs.decode::<Table>()?;
-
- Ok((
- Table {
- inner,
- family: ProtoFamily::try_from(nfgenmsg.family as i32)?,
- },
- remaining_data,
- ))
- }
-}
-*/
-
-/*
-unsafe impl NlMsg for Chain {
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- let raw_msg_type = match msg_type {
- MsgType::Add => libc::NFT_MSG_NEWCHAIN,
- MsgType::Del => libc::NFT_MSG_DELCHAIN,
- };
- let flags: u16 = match msg_type {
- MsgType::Add => (libc::NLM_F_ACK | libc::NLM_F_CREATE) as u16,
- MsgType::Del => libc::NLM_F_ACK as u16,
- } | libc::NLM_F_ACK as u16;
- let header = sys::nftnl_nlmsg_build_hdr(
- buf as *mut c_char,
- raw_msg_type as u16,
- self.table.get_family() as u16,
- flags,
- seq,
- );
- sys::nftnl_chain_nlmsg_build_payload(header, self.chain);
- }
}
-impl Drop for Chain {
- fn drop(&mut self) {
- unsafe { sys::nftnl_chain_free(self.chain) };
- }
-}
-
-pub fn get_chains_cb<'a>(
- header: &libc::nlmsghdr,
- _genmsg: &Nfgenmsg,
- _data: &[u8],
- (table, chains): &mut (&Rc<Table>, &mut Vec<Chain>),
-) -> Result<(), crate::query::Error> {
- unsafe {
- let chain = sys::nftnl_chain_alloc();
- if chain == std::ptr::null_mut() {
- return Err(ParseError::Custom(Box::new(std::io::Error::new(
- std::io::ErrorKind::Other,
- "Chain allocation failed",
- )))
- .into());
- }
- let err = sys::nftnl_chain_nlmsg_parse(header, chain);
- if err < 0 {
- sys::nftnl_chain_free(chain);
- return Err(ParseError::Custom(Box::new(std::io::Error::new(
- std::io::ErrorKind::Other,
- "The netlink chain couldn't be parsed !?",
- )))
- .into());
- }
-
- let table_name = CStr::from_ptr(sys::nftnl_chain_get_str(
- chain,
- sys::NFTNL_CHAIN_TABLE as u16,
- ));
- let family = sys::nftnl_chain_get_u32(chain, sys::NFTNL_CHAIN_FAMILY as u16);
- let family = match crate::ProtoFamily::try_from(family as i32) {
- Ok(family) => family,
- Err(crate::InvalidProtocolFamily) => {
- error!("The netlink table didn't have a valid protocol family !?");
- sys::nftnl_chain_free(chain);
- return Err(ParseError::Custom(Box::new(std::io::Error::new(
- std::io::ErrorKind::Other,
- "The netlink table didn't have a valid protocol family !?",
- )))
- .into());
- }
- };
-
- if table_name != table.get_name() {
- sys::nftnl_chain_free(chain);
- return Ok(());
- }
-
- if family != crate::ProtoFamily::Unspec && family != table.get_family() {
- sys::nftnl_chain_free(chain);
- return Ok(());
- }
+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)?;
- chains.push(Chain::from_raw(chain, table.clone()));
+ Ok((Self { inner }, remaining_data))
}
-
- Ok(())
}
-*/
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),
+ // 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.
+ //
+ // 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.
(set_hook, get_hook, with_hook, sys::NFTA_CHAIN_HOOK, ChainHook, Hook),
(get_policy, set_policy, with_policy, sys::NFTA_CHAIN_POLICY, U32, u32),
(get_table, set_table, with_table, sys::NFTA_CHAIN_TABLE, String, String),
@@ -362,15 +266,24 @@ impl_attr_getters_and_setters!(
]
);
-/*
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(
libc::NFT_MSG_GETCHAIN as u16,
- &get_chains_cb,
+ &|chain: Chain, (table, chains): &mut (&Table, &mut Vec<Chain>)| {
+ if chain.get_table() == table.get_name() {
+ chains.push(chain);
+ } else {
+ info!(
+ "Ignoring chain {:?} because it doesn't map the table {:?}",
+ chain.get_name(),
+ table.get_name()
+ );
+ }
+ Ok(())
+ },
None,
&mut (&table, &mut result),
)?;
Ok(result)
}
-*/
diff --git a/src/lib.rs b/src/lib.rs
index 7c330bb..61ee5fc 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -97,12 +97,12 @@ pub use batch::{default_batch_page_size, Batch};
//pub mod expr;
pub mod table;
+pub use table::list_tables;
pub use table::Table;
-//pub use table::{get_tables_cb, list_tables};
-//
-mod chain;
-//pub use chain::{get_chains_cb, list_chains_for_table};
-//pub use chain::{Chain, ChainType, Hook, Policy, Priority};
+
+pub mod chain;
+pub use chain::list_chains_for_table;
+pub use chain::{Chain, ChainType, Hook, Policy, Priority};
//mod chain_methods;
//pub use chain_methods::ChainMethods;
diff --git a/src/nlmsg.rs b/src/nlmsg.rs
index 435fed3..a1bb200 100644
--- a/src/nlmsg.rs
+++ b/src/nlmsg.rs
@@ -8,26 +8,22 @@ use std::{
use crate::{
parser::{
pad_netlink_object, pad_netlink_object_with_variable_size, AttributeType, DecodeError,
- Nfgenmsg,
},
sys::{
- nlattr, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN, NFNL_MSG_BATCH_END,
- NFNL_SUBSYS_NFTABLES, NLA_TYPE_MASK,
+ nfgenmsg, nlattr, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN, NFNL_MSG_BATCH_END,
+ NFNL_SUBSYS_NFTABLES,
},
MsgType, ProtoFamily,
};
pub struct NfNetlinkWriter<'a> {
buf: &'a mut Vec<u8>,
- headers: HeaderStack<'a>,
+ headers: Option<(usize, usize)>,
}
impl<'a> NfNetlinkWriter<'a> {
pub fn new(buf: &'a mut Vec<u8>) -> NfNetlinkWriter<'a> {
- NfNetlinkWriter {
- buf,
- headers: HeaderStack::new(),
- }
+ NfNetlinkWriter { buf, headers: None }
}
pub fn add_data_zeroed<'b>(&'b mut self, size: usize) -> &'b mut [u8] {
@@ -35,7 +31,12 @@ impl<'a> NfNetlinkWriter<'a> {
let start = self.buf.len();
self.buf.resize(start + padded_size, 0);
- self.headers.add_size(padded_size as u32);
+ if let Some((msghdr_idx, _nfgenmsg_idx)) = self.headers {
+ let mut hdr: &mut nlmsghdr = unsafe {
+ std::mem::transmute(self.buf[msghdr_idx..].as_mut_ptr() as *mut nlmsghdr)
+ };
+ hdr.nlmsg_len += padded_size as u32;
+ }
&mut self.buf[start..start + size]
}
@@ -53,14 +54,16 @@ impl<'a> NfNetlinkWriter<'a> {
seq: u32,
ressource_id: Option<u16>,
) {
+ if self.headers.is_some() {
+ error!("Calling write_header while still holding headers open!?");
+ }
+
let nlmsghdr_len = pad_netlink_object::<nlmsghdr>();
- let nfgenmsg_len = pad_netlink_object::<Nfgenmsg>();
- let nlmsghdr_buf = self.add_data_zeroed(nlmsghdr_len);
+ let nfgenmsg_len = pad_netlink_object::<nfgenmsg>();
+ let nlmsghdr_buf = self.add_data_zeroed(nlmsghdr_len);
let mut hdr: &mut nlmsghdr =
unsafe { std::mem::transmute(nlmsghdr_buf.as_mut_ptr() as *mut nlmsghdr) };
- //let mut hdr = &mut unsafe { *(nlmsghdr_buf.as_mut_ptr() as *mut nlmsghdr) };
-
hdr.nlmsg_len = (nlmsghdr_len + nfgenmsg_len) as u32;
hdr.nlmsg_type = msg_type;
// batch messages are not specific to the nftables subsystem
@@ -71,58 +74,20 @@ impl<'a> NfNetlinkWriter<'a> {
hdr.nlmsg_seq = seq;
let nfgenmsg_buf = self.add_data_zeroed(nfgenmsg_len);
-
- let mut nfgenmsg: &mut Nfgenmsg =
- unsafe { std::mem::transmute(nfgenmsg_buf.as_mut_ptr() as *mut Nfgenmsg) };
- nfgenmsg.family = family as u8;
+ let mut nfgenmsg: &mut nfgenmsg =
+ unsafe { std::mem::transmute(nfgenmsg_buf.as_mut_ptr() as *mut nfgenmsg) };
+ nfgenmsg.nfgen_family = family as u8;
nfgenmsg.version = NFNETLINK_V0 as u8;
nfgenmsg.res_id = ressource_id.unwrap_or(0);
- self.headers.add_level(hdr, Some(nfgenmsg));
- }
-
- pub fn get_current_header(&mut self) -> Option<&mut nlmsghdr> {
- let stack_size = self.headers.stack.len();
- if stack_size > 0 {
- Some(unsafe { std::mem::transmute(self.headers.stack[stack_size - 1].0) })
- } else {
- None
- }
+ self.headers = Some((
+ self.buf.len() - (nlmsghdr_len + nfgenmsg_len),
+ self.buf.len() - nfgenmsg_len,
+ ));
}
pub fn finalize_writing_object(&mut self) {
- self.headers.pop_level();
- }
-}
-
-struct HeaderStack<'a> {
- stack: Vec<(*mut nlmsghdr, Option<*mut Nfgenmsg>)>,
- lifetime: PhantomData<&'a ()>,
-}
-
-impl<'a> HeaderStack<'a> {
- fn new() -> HeaderStack<'a> {
- HeaderStack {
- stack: Vec::new(),
- lifetime: PhantomData,
- }
- }
-
- /// resize all the stacked netlink containers to hold additional_size new bytes
- fn add_size(&mut self, additional_size: u32) {
- for (hdr, _) in &mut self.stack {
- unsafe {
- (**hdr).nlmsg_len = (**hdr).nlmsg_len + additional_size;
- }
- }
- }
-
- fn add_level(&mut self, hdr: *mut nlmsghdr, nfgenmsg: Option<*mut Nfgenmsg>) {
- self.stack.push((hdr, nfgenmsg));
- }
-
- fn pop_level(&mut self) {
- self.stack.pop();
+ self.headers = None;
}
}
diff --git a/src/parser.rs b/src/parser.rs
index 8e12c5e..2d05f4f 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,7 +1,7 @@
use std::{
any::TypeId,
collections::HashMap,
- fmt::Debug,
+ fmt::{Debug, DebugStruct},
mem::{size_of, transmute},
string::FromUtf8Error,
};
@@ -14,9 +14,9 @@ use crate::{
NfNetlinkDeserializable, NfNetlinkObject, NfNetlinkSerializable, NfNetlinkWriter,
},
sys::{
- nlattr, nlmsgerr, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN, NFNL_MSG_BATCH_END,
- NFNL_SUBSYS_NFTABLES, NLA_TYPE_MASK, NLMSG_ALIGNTO, NLMSG_DONE, NLMSG_ERROR,
- NLMSG_MIN_TYPE, NLMSG_NOOP, NLM_F_DUMP_INTR,
+ nfgenmsg, nlattr, nlmsgerr, nlmsghdr, NFNETLINK_V0, NFNL_MSG_BATCH_BEGIN,
+ NFNL_MSG_BATCH_END, NFNL_SUBSYS_NFTABLES, NLA_TYPE_MASK, NLMSG_ALIGNTO, NLMSG_DONE,
+ NLMSG_ERROR, NLMSG_MIN_TYPE, NLMSG_NOOP, NLM_F_DUMP_INTR,
},
InvalidProtocolFamily, ProtoFamily,
};
@@ -53,6 +53,9 @@ pub enum DecodeError {
#[error("Invalid attribute type")]
InvalidAttributeType,
+ #[error("Invalid type for a chain")]
+ UnknownChainType,
+
#[error("Unsupported attribute type")]
UnsupportedAttributeType(u16),
@@ -89,14 +92,6 @@ pub const fn pad_netlink_object<T>() -> usize {
pad_netlink_object_with_variable_size(size)
}
-#[repr(C)]
-#[derive(Debug, Clone, Copy)]
-pub struct Nfgenmsg {
- pub family: u8, /* AF_xxx */
- pub version: u8, /* nfnetlink version */
- pub res_id: u16, /* resource id */
-}
-
pub fn get_subsystem_from_nlmsghdr_type(x: u16) -> u8 {
((x & 0xff00) >> 8) as u8
}
@@ -126,12 +121,12 @@ pub fn get_nlmsghdr(buf: &[u8]) -> Result<nlmsghdr, DecodeError> {
Ok(nlmsghdr)
}
-#[derive(Debug)]
+#[derive(Debug, Clone, PartialEq)]
pub enum NlMsg<'a> {
Done,
Noop,
Error(nlmsgerr),
- NfGenMsg(Nfgenmsg, &'a [u8]),
+ NfGenMsg(nfgenmsg, &'a [u8]),
}
pub fn parse_nlmsg<'a>(buf: &'a [u8]) -> Result<(nlmsghdr, NlMsg<'a>), DecodeError> {
@@ -173,14 +168,14 @@ pub fn parse_nlmsg<'a>(buf: &'a [u8]) -> Result<(nlmsghdr, NlMsg<'a>), DecodeErr
}
}
- let size_of_nfgenmsg = pad_netlink_object::<Nfgenmsg>();
+ let size_of_nfgenmsg = pad_netlink_object::<nfgenmsg>();
if hdr.nlmsg_len as usize > buf.len()
|| (hdr.nlmsg_len as usize) < size_of_hdr + size_of_nfgenmsg
{
return Err(DecodeError::NlMsgTooSmall);
}
- let nfgenmsg_ptr = buf[size_of_hdr..size_of_hdr + size_of_nfgenmsg].as_ptr() as *const Nfgenmsg;
+ let nfgenmsg_ptr = buf[size_of_hdr..size_of_hdr + size_of_nfgenmsg].as_ptr() as *const nfgenmsg;
let nfgenmsg = unsafe { *nfgenmsg_ptr };
if nfgenmsg.version != NFNETLINK_V0 as u8 {
@@ -302,7 +297,11 @@ impl NfNetlinkAttribute for String {
}
impl NfNetlinkDeserializable for String {
- fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+ fn deserialize(mut buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
+ // ignore the NULL byte terminator, if any
+ if buf.len() > 0 && buf[buf.len() - 1] == 0 {
+ buf = &buf[..buf.len() - 1];
+ }
Ok((String::from_utf8(buf.to_vec())?, &[]))
}
}
@@ -394,7 +393,7 @@ impl<'a> NfNetlinkAttributeReader<'a> {
) {
Ok(x) => self.attrs.set_attr(nla_type, x),
Err(DecodeError::UnsupportedAttributeType(t)) => info!(
- "Ignore attribute type {} for type id {:?}",
+ "Ignore attribute type {} for type identified by {:?}",
t,
TypeId::of::<T>()
),
@@ -413,26 +412,6 @@ impl<'a> NfNetlinkAttributeReader<'a> {
}
}
-pub fn parse_object<'a>(
- hdr: nlmsghdr,
- msg: NlMsg<'a>,
- buf: &'a [u8],
-) -> Result<(Nfgenmsg, NfNetlinkAttributeReader<'a>, &'a [u8]), DecodeError> {
- let remaining_size = hdr.nlmsg_len as usize
- - pad_netlink_object_with_variable_size(size_of::<nlmsghdr>() + size_of::<Nfgenmsg>());
-
- let remaining_data = &buf[pad_netlink_object_with_variable_size(hdr.nlmsg_len as usize)..];
-
- match msg {
- NlMsg::NfGenMsg(nfgenmsg, content) => Ok((
- nfgenmsg,
- NfNetlinkAttributeReader::new(content, remaining_size)?,
- remaining_data,
- )),
- _ => Err(DecodeError::UnexpectedType(hdr.nlmsg_type)),
- }
-}
-
impl NfNetlinkSerializable for NfNetlinkAttributes {
fn serialize<'a>(&self, writer: &mut NfNetlinkWriter<'a>) {
// TODO: improve performance by not sorting this
@@ -485,6 +464,13 @@ macro_rules! impl_attribute_holder {
};
}
+pub trait InnerFormat {
+ fn inner_format_struct<'a, 'b: 'a>(
+ &'a self,
+ s: DebugStruct<'a, 'b>,
+ ) -> Result<DebugStruct<'a, 'b>, std::fmt::Error>;
+}
+
impl_attribute_holder!(
AttributeType,
[String, String],
@@ -539,5 +525,58 @@ macro_rules! impl_attr_getters_and_setters {
}
}
}
+
+
+ impl $crate::parser::InnerFormat for $struct {
+ fn inner_format_struct<'a, 'b: 'a>(&'a self, mut s: std::fmt::DebugStruct<'a, 'b>) -> Result<std::fmt::DebugStruct<'a, 'b>, std::fmt::Error> {
+ $(
+ // Rewrite attributes names to be readable: 'sys::NFTA_CHAIN_NAME' -> 'name'
+ // Performance must be terrible, but this is the Debug impl anyway, so that
+ // must mean we can afford to be slow, right? ;)
+ if let Some(val) = self.$getter_name() {
+ let mut attr = stringify!($attr_name);
+ if let Some((nfta_idx, _match )) = attr.rmatch_indices("NFTA_").next() {
+ if let Some(underscore_idx) = &attr[nfta_idx+5..].find('_') {
+ attr = &attr[nfta_idx+underscore_idx+6..];
+ }
+ }
+ let attr = attr.to_lowercase();
+ s.field(&attr, val);
+ }
+ )+
+ Ok(s)
+ }
+ }
};
}
+
+pub fn parse_object<T: AttributeDecoder + 'static>(
+ buf: &[u8],
+ add_obj: u32,
+ del_obj: u32,
+) -> Result<(NfNetlinkAttributes, nfgenmsg, &[u8]), DecodeError> {
+ 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 remaining_data_offset = pad_netlink_object_with_variable_size(hdr.nlmsg_len as usize);
+ let remaining_data = &buf[remaining_data_offset..];
+
+ let (nfgenmsg, attrs) = match msg {
+ NlMsg::NfGenMsg(nfgenmsg, content) => {
+ (nfgenmsg, NfNetlinkAttributeReader::new(content, obj_size)?)
+ }
+ _ => return Err(DecodeError::UnexpectedType(hdr.nlmsg_type)),
+ };
+
+ let inner = attrs.decode::<T>()?;
+
+ Ok((inner, nfgenmsg, remaining_data))
+}
diff --git a/src/table.rs b/src/table.rs
index 66dc667..a21f3f2 100644
--- a/src/table.rs
+++ b/src/table.rs
@@ -5,10 +5,7 @@ use crate::nlmsg::{
AttributeDecoder, NfNetlinkAttributes, NfNetlinkDeserializable, NfNetlinkObject,
NfNetlinkSerializable, NfNetlinkWriter,
};
-use crate::parser::{
- get_operation_from_nlmsghdr_type, parse_nlmsg, parse_object, DecodeError,
- NfNetlinkAttributeReader,
-};
+use crate::parser::{parse_object, DecodeError, InnerFormat};
use crate::sys::{
self, NFTA_OBJ_TABLE, NFTA_TABLE_FLAGS, NFTA_TABLE_NAME, NFT_MSG_DELTABLE, NFT_MSG_GETTABLE,
NFT_MSG_NEWTABLE, NLM_F_ACK,
@@ -19,7 +16,7 @@ use crate::{impl_attr_getters_and_setters, MsgType, ProtoFamily};
/// family and contains [`Chain`]s that in turn hold the rules.
///
/// [`Chain`]: struct.Chain.html
-#[derive(Debug, PartialEq, Eq)]
+#[derive(PartialEq, Eq)]
pub struct Table {
inner: NfNetlinkAttributes,
family: ProtoFamily,
@@ -58,6 +55,14 @@ impl PartialEq for Table {
}
*/
+impl Debug for Table {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let mut res = f.debug_struct("Table");
+ res.field("family", &self.family);
+ self.inner_format_struct(res)?.finish()
+ }
+}
+
impl NfNetlinkObject for Table {
fn add_or_remove<'a>(&self, writer: &mut NfNetlinkWriter<'a>, msg_type: MsgType, seq: u32) {
let raw_msg_type = match msg_type {
@@ -72,45 +77,19 @@ impl NfNetlinkObject for Table {
impl NfNetlinkDeserializable for Table {
fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> {
- let (hdr, msg) = parse_nlmsg(buf)?;
-
- let op = get_operation_from_nlmsghdr_type(hdr.nlmsg_type) as u32;
-
- if op != NFT_MSG_NEWTABLE && op != NFT_MSG_DELTABLE {
- return Err(DecodeError::UnexpectedType(hdr.nlmsg_type));
- }
-
- let (nfgenmsg, attrs, remaining_data) = parse_object(hdr, msg, buf)?;
-
- let inner = attrs.decode::<Table>()?;
+ let (inner, nfgenmsg, remaining_data) =
+ parse_object::<Self>(buf, NFT_MSG_NEWTABLE, NFT_MSG_DELTABLE)?;
Ok((
- Table {
+ Self {
inner,
- family: ProtoFamily::try_from(nfgenmsg.family as i32)?,
+ family: ProtoFamily::try_from(nfgenmsg.nfgen_family as i32)?,
},
remaining_data,
))
}
}
-/*
-impl AttributeDecoder for Table {
- fn decode_attribute(attr_type: u16, buf: &[u8]) -> Result<AttributeType, DecodeError> {
- match attr_type {
- NFTA_TABLE_NAME => Ok(AttributeType::String(String::from_utf8(buf.to_vec())?)),
- NFTA_TABLE_FLAGS => {
- let val = [buf[0], buf[1], buf[2], buf[3]];
-
- Ok(AttributeType::U32(u32::from_ne_bytes(val)))
- }
- NFTA_TABLE_USERDATA => Ok(AttributeType::VecU8(buf.to_vec())),
- _ => Err(DecodeError::UnsupportedAttributeType(attr_type)),
- }
- }
-}
-*/
-
impl_attr_getters_and_setters!(
Table,
[