diff options
-rw-r--r-- | src/expr/lookup.rs | 2 | ||||
-rw-r--r-- | src/expr/payload.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | src/set.rs | 28 | ||||
-rw-r--r-- | tests/chain.rs | 70 | ||||
-rw-r--r-- | tests/expr.rs | 166 | ||||
-rw-r--r-- | tests/lib.rs | 169 | ||||
-rw-r--r-- | tests/rule.rs | 119 | ||||
-rw-r--r-- | tests/set.rs | 66 | ||||
-rw-r--r-- | tests/table.rs | 70 |
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(), }), } } @@ -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 @@ -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() + ); +} |