aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/expr/lookup.rs2
-rw-r--r--src/expr/payload.rs2
-rw-r--r--src/lib.rs3
-rw-r--r--src/set.rs28
-rw-r--r--tests/chain.rs70
-rw-r--r--tests/expr.rs166
-rw-r--r--tests/lib.rs169
-rw-r--r--tests/rule.rs119
-rw-r--r--tests/set.rs66
-rw-r--r--tests/table.rs70
10 files changed, 529 insertions, 166 deletions
diff --git a/src/expr/lookup.rs b/src/expr/lookup.rs
index 8e288a0..fa12197 100644
--- a/src/expr/lookup.rs
+++ b/src/expr/lookup.rs
@@ -13,7 +13,7 @@ pub struct Lookup {
impl Lookup {
/// Creates a new lookup entry.
/// May return None if the set have no name.
- pub fn new<K>(set: &Set<'_, K>) -> Option<Self> {
+ pub fn new<K>(set: &Set<K>) -> Option<Self> {
set.get_name().map(|set_name| Lookup {
set_name: set_name.to_owned(),
set_id: set.get_id(),
diff --git a/src/expr/payload.rs b/src/expr/payload.rs
index 7612fd9..4ba47df 100644
--- a/src/expr/payload.rs
+++ b/src/expr/payload.rs
@@ -28,7 +28,7 @@ impl Payload {
}),
Payload::Transport(ref f) => RawPayload::Transport(RawPayloadData {
offset: f.offset(),
- len: f.offset(),
+ len: f.len(),
}),
}
}
diff --git a/src/lib.rs b/src/lib.rs
index 5cf9ca6..665f752 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -77,8 +77,8 @@ use thiserror::Error;
extern crate log;
pub mod sys;
-use sys::libc;
use std::{convert::TryFrom, ffi::c_void, ops::Deref};
+use sys::libc;
macro_rules! try_alloc {
($e:expr) => {{
@@ -123,6 +123,7 @@ mod rule_methods;
pub use rule_methods::{iface_index, Protocol, RuleMethods, Error as MatchError};
pub mod set;
+pub use set::Set;
/// The type of the message as it's sent to netfilter. A message consists of an object, such as a
/// [`Table`], [`Chain`] or [`Rule`] for example, and a [`MsgType`] to describe what to do with
diff --git a/src/set.rs b/src/set.rs
index d6b9514..1e20475 100644
--- a/src/set.rs
+++ b/src/set.rs
@@ -1,5 +1,5 @@
-use crate::{table::Table, MsgType, ProtoFamily};
use crate::sys::{self, libc};
+use crate::{table::Table, MsgType, ProtoFamily};
use std::{
cell::Cell,
ffi::{c_void, CStr, CString},
@@ -26,15 +26,15 @@ macro_rules! nft_set {
}};
}
-pub struct Set<'a, K> {
+pub struct Set<K> {
pub(crate) set: *mut sys::nftnl_set,
- pub(crate) table: &'a Table,
+ pub(crate) table: Rc<Table>,
pub(crate) family: ProtoFamily,
_marker: ::std::marker::PhantomData<K>,
}
-impl<'a, K> Set<'a, K> {
- pub fn new(name: &CStr, id: u32, table: &'a Table, family: ProtoFamily) -> Self
+impl<K> Set<K> {
+ pub fn new(name: &CStr, id: u32, table: Rc<Table>, family: ProtoFamily) -> Self
where
K: SetKey,
{
@@ -63,7 +63,7 @@ impl<'a, K> Set<'a, K> {
}
}
- pub unsafe fn from_raw(set: *mut sys::nftnl_set, table: &'a Table, family: ProtoFamily) -> Self
+ pub unsafe fn from_raw(set: *mut sys::nftnl_set, table: Rc<Table>, family: ProtoFamily) -> Self
where
K: SetKey,
{
@@ -95,7 +95,7 @@ impl<'a, K> Set<'a, K> {
}
}
- pub fn elems_iter(&'a self) -> SetElemsIter<'a, K> {
+ pub fn elems_iter(&self) -> SetElemsIter<K> {
SetElemsIter::new(self)
}
@@ -146,13 +146,13 @@ impl<'a, K> Set<'a, K> {
}
}
-impl<'a, K> Debug for Set<'a, K> {
+impl<K> Debug for Set<K> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.get_str())
}
}
-unsafe impl<'a, K> crate::NlMsg for Set<'a, K> {
+unsafe impl<K> crate::NlMsg for Set<K> {
unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
let type_ = match msg_type {
MsgType::Add => libc::NFT_MSG_NEWSET,
@@ -169,20 +169,20 @@ unsafe impl<'a, K> crate::NlMsg for Set<'a, K> {
}
}
-impl<'a, K> Drop for Set<'a, K> {
+impl<K> Drop for Set<K> {
fn drop(&mut self) {
unsafe { sys::nftnl_set_free(self.set) };
}
}
pub struct SetElemsIter<'a, K> {
- set: &'a Set<'a, K>,
+ set: &'a Set<K>,
iter: *mut sys::nftnl_set_elems_iter,
ret: Rc<Cell<i32>>,
}
impl<'a, K> SetElemsIter<'a, K> {
- fn new(set: &'a Set<'a, K>) -> Self {
+ fn new(set: &'a Set<K>) -> Self {
let iter = try_alloc!(unsafe {
sys::nftnl_set_elems_iter_create(set.set as *const sys::nftnl_set)
});
@@ -194,7 +194,7 @@ impl<'a, K> SetElemsIter<'a, K> {
}
}
-impl<'a, K: 'a> Iterator for SetElemsIter<'a, K> {
+impl<'a, K> Iterator for SetElemsIter<'a, K> {
type Item = SetElemsMsg<'a, K>;
fn next(&mut self) -> Option<Self::Item> {
@@ -219,7 +219,7 @@ impl<'a, K> Drop for SetElemsIter<'a, K> {
}
pub struct SetElemsMsg<'a, K> {
- set: &'a Set<'a, K>,
+ set: &'a Set<K>,
iter: *mut sys::nftnl_set_elems_iter,
ret: Rc<Cell<i32>>,
}
diff --git a/tests/chain.rs b/tests/chain.rs
new file mode 100644
index 0000000..4b6da91
--- /dev/null
+++ b/tests/chain.rs
@@ -0,0 +1,70 @@
+use std::ffi::CStr;
+
+mod sys;
+use rustables::MsgType;
+use sys::*;
+
+mod lib;
+use lib::*;
+
+#[test]
+fn new_empty_chain() {
+ let mut chain = get_test_chain();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut chain);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWCHAIN as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 52);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_CHAIN_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_CHAIN_NAME, CHAIN_NAME.to_vec()),
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn new_empty_chain_with_userdata() {
+ let mut chain = get_test_chain();
+ chain.set_userdata(CStr::from_bytes_with_nul(CHAIN_USERDATA).unwrap());
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut chain);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWCHAIN as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 72);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_CHAIN_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_CHAIN_NAME, CHAIN_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_CHAIN_USERDATA, CHAIN_USERDATA.to_vec())
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn delete_empty_chain() {
+ let mut chain = get_test_chain();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_with_msg_type(&mut chain, MsgType::Del);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_DELCHAIN as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 52);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_CHAIN_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_CHAIN_NAME, CHAIN_NAME.to_vec()),
+ ])
+ .to_raw()
+ );
+}
diff --git a/tests/expr.rs b/tests/expr.rs
index 5c27119..4af18f2 100644
--- a/tests/expr.rs
+++ b/tests/expr.rs
@@ -1,114 +1,19 @@
-use rustables::{nft_nlmsg_maxsize, Chain, MsgType, NlMsg, ProtoFamily, Rule, Table};
-use rustables::set::Set;
-use rustables::sys::libc::{nlmsghdr, AF_UNIX, NFNETLINK_V0, NFNL_SUBSYS_NFTABLES, NF_DROP};
use rustables::expr::{
Bitwise, Cmp, CmpOp, Conntrack, Counter, Expression, HeaderField, IcmpCode, Immediate, Log,
LogGroup, LogPrefix, Lookup, Meta, Nat, NatType, Payload, Register, Reject, TcpHeaderField,
- TransportHeaderField, Verdict
+ TransportHeaderField, Verdict,
};
-use std::ffi::{c_void, CStr};
-use std::mem::size_of;
+use rustables::set::Set;
+use rustables::sys::libc::{nlmsghdr, NF_DROP};
+use rustables::{ProtoFamily, Rule};
+use std::ffi::CStr;
use std::net::Ipv4Addr;
-use std::rc::Rc;
-use thiserror::Error;
mod sys;
use sys::*;
-fn get_subsystem_from_nlmsghdr_type(x: u16) -> u8 {
- ((x & 0xff00) >> 8) as u8
-}
-fn get_operation_from_nlmsghdr_type(x: u16) -> u8 {
- (x & 0x00ff) as u8
-}
-
-const TABLE_NAME: &[u8; 10] = b"mocktable\0";
-const CHAIN_NAME: &[u8; 10] = b"mockchain\0";
-
-type NetLinkType = u16;
-
-#[derive(Debug, PartialEq)]
-enum NetlinkExpr {
- Nested(NetLinkType, Vec<NetlinkExpr>),
- Final(NetLinkType, Vec<u8>),
- List(Vec<NetlinkExpr>),
-}
-
-#[derive(Debug, Error)]
-#[error("empty data")]
-struct EmptyDataError;
-
-impl NetlinkExpr {
- fn to_raw(self) -> Vec<u8> {
- match self {
- NetlinkExpr::Final(ty, val) => {
- let len = val.len() + 4;
- let mut res = Vec::with_capacity(len);
-
- res.extend(&(len as u16).to_le_bytes());
- res.extend(&ty.to_le_bytes());
- res.extend(val);
- // alignment
- while res.len() % 4 != 0 {
- res.push(0);
- }
-
- res
- }
- NetlinkExpr::Nested(ty, exprs) => {
- // some heuristic to decrease allocations (even though this is
- // only useful for testing so performance is not an objective)
- let mut sub = Vec::with_capacity(exprs.len() * 50);
-
- for expr in exprs {
- sub.append(&mut expr.to_raw());
- }
-
- let len = sub.len() + 4;
- let mut res = Vec::with_capacity(len);
-
- // set the "NESTED" flag
- res.extend(&(len as u16).to_le_bytes());
- res.extend(&(ty | 0x8000).to_le_bytes());
- res.extend(sub);
-
- res
- }
- NetlinkExpr::List(exprs) => {
- // some heuristic to decrease allocations (even though this is
- // only useful for testing so performance is not an objective)
- let mut list = Vec::with_capacity(exprs.len() * 50);
-
- for expr in exprs {
- list.append(&mut expr.to_raw());
- }
-
- list
- }
- }
- }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy)]
-struct Nfgenmsg {
- family: u8, /* AF_xxx */
- version: u8, /* nfnetlink version */
- res_id: u16, /* resource id */
-}
-
-fn get_test_rule() -> Rule {
- let table = Rc::new(Table::new(
- &CStr::from_bytes_with_nul(TABLE_NAME).unwrap(),
- ProtoFamily::Inet,
- ));
- let chain = Rc::new(Chain::new(
- &CStr::from_bytes_with_nul(CHAIN_NAME).unwrap(),
- Rc::clone(&table),
- ));
- let rule = Rule::new(Rc::clone(&chain));
- rule
-}
+mod lib;
+use lib::*;
fn get_test_nlmsg_from_expr(
rule: &mut Rule,
@@ -116,44 +21,12 @@ fn get_test_nlmsg_from_expr(
) -> (nlmsghdr, Nfgenmsg, Vec<u8>) {
rule.add_expr(expr);
- let mut buf = vec![0u8; nft_nlmsg_maxsize() as usize];
- unsafe {
- rule.write(buf.as_mut_ptr() as *mut c_void, 0, MsgType::Add);
-
- // right now the message is composed of the following parts:
- // - nlmsghdr (contains the message size and type)
- // - nfgenmsg (nftables header that describes the message family)
- // - the raw expression that we want to validate
-
- let size_of_hdr = size_of::<nlmsghdr>();
- let size_of_nfgenmsg = size_of::<Nfgenmsg>();
- let nlmsghdr = *(buf[0..size_of_hdr].as_ptr() as *const nlmsghdr);
- let nfgenmsg =
- *(buf[size_of_hdr..size_of_hdr + size_of_nfgenmsg].as_ptr() as *const Nfgenmsg);
- let raw_expr = buf[size_of_hdr + size_of_nfgenmsg..nlmsghdr.nlmsg_len as usize]
- .iter()
- .map(|x| *x)
- .collect();
-
- // sanity checks on the global message (this should be very similar/factorisable for the
- // most part in other tests)
- // TODO: check the messages flags
- assert_eq!(
- get_subsystem_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
- NFNL_SUBSYS_NFTABLES as u8
- );
- assert_eq!(
- get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
- NFT_MSG_NEWRULE as u8
- );
- assert_eq!(nlmsghdr.nlmsg_seq, 0);
- assert_eq!(nlmsghdr.nlmsg_pid, 0);
- assert_eq!(nfgenmsg.family, AF_UNIX as u8);
- assert_eq!(nfgenmsg.version, NFNETLINK_V0 as u8);
- assert_eq!(nfgenmsg.res_id.to_be(), 0);
-
- (nlmsghdr, nfgenmsg, raw_expr)
- }
+ let (nlmsghdr, nfgenmsg, raw_expr) = get_test_nlmsg(rule);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWRULE as u8
+ );
+ (nlmsghdr, nfgenmsg, raw_expr)
}
#[test]
@@ -408,7 +281,7 @@ fn lookup_expr_is_valid() {
let set_name = &CStr::from_bytes_with_nul(b"mockset\0").unwrap();
let mut rule = get_test_rule();
let table = rule.get_chain().get_table();
- let mut set = Set::new(set_name, 0, &table, ProtoFamily::Inet);
+ let mut set = Set::new(set_name, 0, table, ProtoFamily::Inet);
let address: Ipv4Addr = [8, 8, 8, 8].into();
set.add(&address);
let lookup = Lookup::new(&set).unwrap();
@@ -544,9 +417,7 @@ fn nat_expr_is_valid() {
),
NetlinkExpr::Final(
NFTA_NAT_FAMILY,
- // TODO find the right value to substitute here.
- //(ProtoFamily::Ipv4 as u16).to_le_bytes().to_vec()
- 2u32.to_be_bytes().to_vec()
+ (ProtoFamily::Ipv4 as u32).to_be_bytes().to_vec(),
),
NetlinkExpr::Final(
NFTA_NAT_REG_ADDR_MIN,
@@ -564,7 +435,6 @@ fn nat_expr_is_valid() {
#[test]
fn payload_expr_is_valid() {
- // TODO test loaded payload ?
let tcp_header_field = TcpHeaderField::Sport;
let transport_header_field = TransportHeaderField::Tcp(tcp_header_field);
let payload = Payload::Transport(transport_header_field);
@@ -600,8 +470,7 @@ fn payload_expr_is_valid() {
),
NetlinkExpr::Final(
NFTA_PAYLOAD_LEN,
- //tcp_header_field.len().to_be_bytes().to_vec()
- 0u32.to_be_bytes().to_vec()
+ tcp_header_field.len().to_be_bytes().to_vec()
),
]
)
@@ -671,7 +540,6 @@ fn verdict_expr_is_valid() {
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"immediate\0".to_vec()),
- // TODO find the right arrangement for Verdict's data.
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
@@ -685,7 +553,7 @@ fn verdict_expr_is_valid() {
NFTA_DATA_VERDICT,
vec![NetlinkExpr::Final(
NFTA_VERDICT_CODE,
- NF_DROP.to_be_bytes().to_vec() //0u32.to_be_bytes().to_vec()
+ NF_DROP.to_be_bytes().to_vec()
),]
)],
),
diff --git a/tests/lib.rs b/tests/lib.rs
new file mode 100644
index 0000000..0d7132c
--- /dev/null
+++ b/tests/lib.rs
@@ -0,0 +1,169 @@
+#![allow(dead_code)]
+use libc::{nlmsghdr, AF_UNIX, NFNETLINK_V0, NFNL_SUBSYS_NFTABLES};
+use rustables::set::SetKey;
+use rustables::{nft_nlmsg_maxsize, Chain, MsgType, NlMsg, ProtoFamily, Rule, Set, Table};
+use std::ffi::{c_void, CStr};
+use std::mem::size_of;
+use std::rc::Rc;
+
+pub fn get_subsystem_from_nlmsghdr_type(x: u16) -> u8 {
+ ((x & 0xff00) >> 8) as u8
+}
+
+pub fn get_operation_from_nlmsghdr_type(x: u16) -> u8 {
+ (x & 0x00ff) as u8
+}
+
+pub const TABLE_NAME: &[u8; 10] = b"mocktable\0";
+pub const CHAIN_NAME: &[u8; 10] = b"mockchain\0";
+pub const SET_NAME: &[u8; 8] = b"mockset\0";
+
+pub const TABLE_USERDATA: &[u8; 14] = b"mocktabledata\0";
+pub const CHAIN_USERDATA: &[u8; 14] = b"mockchaindata\0";
+pub const RULE_USERDATA: &[u8; 13] = b"mockruledata\0";
+pub const SET_USERDATA: &[u8; 12] = b"mocksetdata\0";
+
+pub const SET_ID: u32 = 123456;
+
+type NetLinkType = u16;
+
+#[derive(Debug, thiserror::Error)]
+#[error("empty data")]
+pub struct EmptyDataError;
+
+#[derive(Debug, PartialEq)]
+pub enum NetlinkExpr {
+ Nested(NetLinkType, Vec<NetlinkExpr>),
+ Final(NetLinkType, Vec<u8>),
+ List(Vec<NetlinkExpr>),
+}
+
+impl NetlinkExpr {
+ pub fn to_raw(self) -> Vec<u8> {
+ match self {
+ NetlinkExpr::Final(ty, val) => {
+ let len = val.len() + 4;
+ let mut res = Vec::with_capacity(len);
+
+ res.extend(&(len as u16).to_le_bytes());
+ res.extend(&ty.to_le_bytes());
+ res.extend(val);
+ // alignment
+ while res.len() % 4 != 0 {
+ res.push(0);
+ }
+
+ res
+ }
+ NetlinkExpr::Nested(ty, exprs) => {
+ // some heuristic to decrease allocations (even though this is
+ // only useful for testing so performance is not an objective)
+ let mut sub = Vec::with_capacity(exprs.len() * 50);
+
+ for expr in exprs {
+ sub.append(&mut expr.to_raw());
+ }
+
+ let len = sub.len() + 4;
+ let mut res = Vec::with_capacity(len);
+
+ // set the "NESTED" flag
+ res.extend(&(len as u16).to_le_bytes());
+ res.extend(&(ty | 0x8000).to_le_bytes());
+ res.extend(sub);
+
+ res
+ }
+ NetlinkExpr::List(exprs) => {
+ // some heuristic to decrease allocations (even though this is
+ // only useful for testing so performance is not an objective)
+ let mut list = Vec::with_capacity(exprs.len() * 50);
+
+ for expr in exprs {
+ list.append(&mut expr.to_raw());
+ }
+
+ list
+ }
+ }
+ }
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct Nfgenmsg {
+ family: u8, /* AF_xxx */
+ version: u8, /* nfnetlink version */
+ res_id: u16, /* resource id */
+}
+
+pub fn get_test_table() -> Table {
+ Table::new(
+ &CStr::from_bytes_with_nul(TABLE_NAME).unwrap(),
+ ProtoFamily::Inet,
+ )
+}
+
+pub fn get_test_chain() -> Chain {
+ Chain::new(
+ &CStr::from_bytes_with_nul(CHAIN_NAME).unwrap(),
+ Rc::new(get_test_table()),
+ )
+}
+
+pub fn get_test_rule() -> Rule {
+ Rule::new(Rc::new(get_test_chain()))
+}
+
+pub fn get_test_set<T: SetKey>() -> Set<T> {
+ Set::new(
+ CStr::from_bytes_with_nul(SET_NAME).unwrap(),
+ SET_ID,
+ Rc::new(get_test_table()),
+ ProtoFamily::Ipv4,
+ )
+}
+
+pub fn get_test_nlmsg_with_msg_type(
+ obj: &mut dyn NlMsg,
+ msg_type: MsgType,
+) -> (nlmsghdr, Nfgenmsg, Vec<u8>) {
+ let mut buf = vec![0u8; nft_nlmsg_maxsize() as usize];
+ unsafe {
+ obj.write(buf.as_mut_ptr() as *mut c_void, 0, msg_type);
+
+ // right now the message is composed of the following parts:
+ // - nlmsghdr (contains the message size and type)
+ // - nfgenmsg (nftables header that describes the message family)
+ // - the raw value that we want to validate
+
+ let size_of_hdr = size_of::<nlmsghdr>();
+ let size_of_nfgenmsg = size_of::<Nfgenmsg>();
+ let nlmsghdr = *(buf[0..size_of_hdr].as_ptr() as *const nlmsghdr);
+ let nfgenmsg =
+ *(buf[size_of_hdr..size_of_hdr + size_of_nfgenmsg].as_ptr() as *const Nfgenmsg);
+ let raw_value = buf[size_of_hdr + size_of_nfgenmsg..nlmsghdr.nlmsg_len as usize]
+ .iter()
+ .map(|x| *x)
+ .collect();
+
+ // sanity checks on the global message (this should be very similar/factorisable for the
+ // most part in other tests)
+ // TODO: check the messages flags
+ assert_eq!(
+ get_subsystem_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFNL_SUBSYS_NFTABLES as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_seq, 0);
+ assert_eq!(nlmsghdr.nlmsg_pid, 0);
+ assert_eq!(nfgenmsg.family, AF_UNIX as u8);
+ assert_eq!(nfgenmsg.version, NFNETLINK_V0 as u8);
+ assert_eq!(nfgenmsg.res_id.to_be(), 0);
+
+ (nlmsghdr, nfgenmsg, raw_value)
+ }
+}
+
+pub fn get_test_nlmsg(obj: &mut dyn NlMsg) -> (nlmsghdr, Nfgenmsg, Vec<u8>) {
+ get_test_nlmsg_with_msg_type(obj, MsgType::Add)
+}
diff --git a/tests/rule.rs b/tests/rule.rs
new file mode 100644
index 0000000..b601a61
--- /dev/null
+++ b/tests/rule.rs
@@ -0,0 +1,119 @@
+use std::ffi::CStr;
+
+mod sys;
+use rustables::MsgType;
+use sys::*;
+
+mod lib;
+use lib::*;
+
+#[test]
+fn new_empty_rule() {
+ let mut rule = get_test_rule();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut rule);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWRULE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 52);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn new_empty_rule_with_userdata() {
+ let mut rule = get_test_rule();
+ rule.set_userdata(CStr::from_bytes_with_nul(RULE_USERDATA).unwrap());
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut rule);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWRULE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 72);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_USERDATA, RULE_USERDATA.to_vec())
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn new_empty_rule_with_position_and_handle() {
+ let handle = 1337;
+ let position = 42;
+ let mut rule = get_test_rule();
+ rule.set_handle(handle);
+ rule.set_position(position);
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut rule);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWRULE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 76);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_HANDLE, handle.to_be_bytes().to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_POSITION, position.to_be_bytes().to_vec()),
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn delete_empty_rule() {
+ let mut rule = get_test_rule();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_with_msg_type(&mut rule, MsgType::Del);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_DELRULE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 52);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn delete_empty_rule_with_handle() {
+ let handle = 42;
+ let mut rule = get_test_rule();
+ rule.set_handle(handle);
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_with_msg_type(&mut rule, MsgType::Del);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_DELRULE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 64);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_RULE_HANDLE, handle.to_be_bytes().to_vec()),
+ ])
+ .to_raw()
+ );
+}
diff --git a/tests/set.rs b/tests/set.rs
new file mode 100644
index 0000000..d5b2ad7
--- /dev/null
+++ b/tests/set.rs
@@ -0,0 +1,66 @@
+mod sys;
+use std::net::{Ipv4Addr, Ipv6Addr};
+
+use rustables::{set::SetKey, MsgType};
+use sys::*;
+
+mod lib;
+use lib::*;
+
+#[test]
+fn new_empty_set() {
+ let mut set = get_test_set::<Ipv4Addr>();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut set);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWSET as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 80);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_SET_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_SET_NAME, SET_NAME.to_vec()),
+ NetlinkExpr::Final(
+ NFTA_SET_FLAGS,
+ ((libc::NFT_SET_ANONYMOUS | libc::NFT_SET_CONSTANT) as u32)
+ .to_be_bytes()
+ .to_vec()
+ ),
+ NetlinkExpr::Final(NFTA_SET_KEY_TYPE, Ipv4Addr::TYPE.to_be_bytes().to_vec()),
+ NetlinkExpr::Final(NFTA_SET_KEY_LEN, Ipv4Addr::LEN.to_be_bytes().to_vec()),
+ NetlinkExpr::Final(NFTA_SET_ID, SET_ID.to_be_bytes().to_vec()),
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn delete_empty_set() {
+ let mut set = get_test_set::<Ipv6Addr>();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_with_msg_type(&mut set, MsgType::Del);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_DELSET as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 80);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_SET_TABLE, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_SET_NAME, SET_NAME.to_vec()),
+ NetlinkExpr::Final(
+ NFTA_SET_FLAGS,
+ ((libc::NFT_SET_ANONYMOUS | libc::NFT_SET_CONSTANT) as u32)
+ .to_be_bytes()
+ .to_vec()
+ ),
+ NetlinkExpr::Final(NFTA_SET_KEY_TYPE, Ipv6Addr::TYPE.to_be_bytes().to_vec()),
+ NetlinkExpr::Final(NFTA_SET_KEY_LEN, Ipv6Addr::LEN.to_be_bytes().to_vec()),
+ NetlinkExpr::Final(NFTA_SET_ID, SET_ID.to_be_bytes().to_vec()),
+ ])
+ .to_raw()
+ );
+}
diff --git a/tests/table.rs b/tests/table.rs
new file mode 100644
index 0000000..3d8957c
--- /dev/null
+++ b/tests/table.rs
@@ -0,0 +1,70 @@
+use std::ffi::CStr;
+
+mod sys;
+use rustables::MsgType;
+use sys::*;
+
+mod lib;
+use lib::*;
+
+#[test]
+fn new_empty_table() {
+ let mut table = get_test_table();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut table);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWTABLE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 44);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_TABLE_NAME, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_TABLE_FLAGS, 0u32.to_be_bytes().to_vec()),
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn new_empty_table_with_userdata() {
+ let mut table = get_test_table();
+ table.set_userdata(CStr::from_bytes_with_nul(TABLE_USERDATA).unwrap());
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut table);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_NEWTABLE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 64);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_TABLE_NAME, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_TABLE_FLAGS, 0u32.to_be_bytes().to_vec()),
+ NetlinkExpr::Final(NFTA_TABLE_USERDATA, TABLE_USERDATA.to_vec())
+ ])
+ .to_raw()
+ );
+}
+
+#[test]
+fn delete_empty_table() {
+ let mut table = get_test_table();
+ let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_with_msg_type(&mut table, MsgType::Del);
+ assert_eq!(
+ get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
+ NFT_MSG_DELTABLE as u8
+ );
+ assert_eq!(nlmsghdr.nlmsg_len, 44);
+
+ assert_eq!(
+ raw_expr,
+ NetlinkExpr::List(vec![
+ NetlinkExpr::Final(NFTA_TABLE_NAME, TABLE_NAME.to_vec()),
+ NetlinkExpr::Final(NFTA_TABLE_FLAGS, 0u32.to_be_bytes().to_vec()),
+ ])
+ .to_raw()
+ );
+}