diff options
-rw-r--r-- | src/expr/bitwise.rs | 127 | ||||
-rw-r--r-- | src/expr/cmp.rs | 25 | ||||
-rw-r--r-- | src/expr/immediate.rs | 30 | ||||
-rw-r--r-- | src/expr/mod.rs | 121 | ||||
-rw-r--r-- | src/expr/reject.rs | 5 | ||||
-rw-r--r-- | src/expr/verdict.rs | 12 | ||||
-rw-r--r-- | src/parser.rs | 13 | ||||
-rw-r--r-- | tests/expr.rs | 117 |
8 files changed, 212 insertions, 238 deletions
diff --git a/src/expr/bitwise.rs b/src/expr/bitwise.rs index d34d22c..38c0383 100644 --- a/src/expr/bitwise.rs +++ b/src/expr/bitwise.rs @@ -1,69 +1,74 @@ -use super::{Expression, Rule, ToSlice}; -use crate::sys::{self, libc}; -use std::ffi::c_void; -use std::os::raw::c_char; +use super::{Expression, ExpressionData, Register}; +use crate::create_expr_type; +use crate::parser::DecodeError; +use crate::sys; -/// Expression for performing bitwise masking and XOR on the data in a register. -pub struct Bitwise<M: ToSlice, X: ToSlice> { - mask: M, - xor: X, -} +create_expr_type!( + inline with_builder : Bitwise, + [ + ( + get_dreg, + set_dreg, + with_dreg, + sys::NFTA_BITWISE_DREG, + Register, + Register + ), + ( + get_sreg, + set_sreg, + with_sreg, + sys::NFTA_BITWISE_SREG, + Register, + Register + ), + ( + get_len, + set_len, + with_len, + sys::NFTA_BITWISE_LEN, + U32, + u32 + ), + ( + get_mask, + set_mask, + with_mask, + sys::NFTA_BITWISE_MASK, + ExprData, + ExpressionData + ), + ( + get_xor, + set_xor, + with_xor, + sys::NFTA_BITWISE_XOR, + ExprData, + ExpressionData + ) + ] +); -impl<M: ToSlice, X: ToSlice> Bitwise<M, X> { - /// Returns a new `Bitwise` instance that first masks the value it's applied to with `mask` and - /// then performs xor with the value in `xor`. - pub fn new(mask: M, xor: X) -> Self { - Self { mask, xor } +impl Expression for Bitwise { + fn get_name() -> &'static str { + "bitwise" } } -impl<M: ToSlice, X: ToSlice> Expression for Bitwise<M, X> { - fn get_raw_name() -> *const c_char { - b"bitwise\0" as *const _ as *const c_char - } - - fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { - unsafe { - let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name())); - - let mask = self.mask.to_slice(); - let xor = self.xor.to_slice(); - assert!(mask.len() == xor.len()); - let len = mask.len() as u32; - - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_BITWISE_SREG as u16, - libc::NFT_REG_1 as u32, - ); - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_BITWISE_DREG as u16, - libc::NFT_REG_1 as u32, - ); - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_BITWISE_LEN as u16, len); - - sys::nftnl_expr_set( - expr, - sys::NFTNL_EXPR_BITWISE_MASK as u16, - mask.as_ref() as *const _ as *const c_void, - len, - ); - sys::nftnl_expr_set( - expr, - sys::NFTNL_EXPR_BITWISE_XOR as u16, - xor.as_ref() as *const _ as *const c_void, - len, - ); - - expr +impl Bitwise { + /// Returns a new `Bitwise` instance that first masks the value it's applied to with `mask` and + /// then performs xor with the value in `xor` + pub fn new(mask: impl Into<Vec<u8>>, xor: impl Into<Vec<u8>>) -> Result<Self, DecodeError> { + let mask = mask.into(); + let xor = xor.into(); + if mask.len() != xor.len() { + return Err(DecodeError::IncompatibleLength); } + Ok(Self::builder() + .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))) } } - -#[macro_export] -macro_rules! nft_expr_bitwise { - (mask $mask:expr,xor $xor:expr) => { - $crate::expr::Bitwise::new($mask, $xor) - }; -} diff --git a/src/expr/cmp.rs b/src/expr/cmp.rs index f6ea900..d8f825f 100644 --- a/src/expr/cmp.rs +++ b/src/expr/cmp.rs @@ -157,31 +157,6 @@ impl<const N: usize> Expression for Cmp<[u8; N]> { } } -#[macro_export(local_inner_macros)] -macro_rules! nft_expr_cmp { - (@cmp_op ==) => { - $crate::expr::CmpOp::Eq - }; - (@cmp_op !=) => { - $crate::expr::CmpOp::Neq - }; - (@cmp_op <) => { - $crate::expr::CmpOp::Lt - }; - (@cmp_op <=) => { - $crate::expr::CmpOp::Lte - }; - (@cmp_op >) => { - $crate::expr::CmpOp::Gt - }; - (@cmp_op >=) => { - $crate::expr::CmpOp::Gte - }; - ($op:tt $data:expr) => { - $crate::expr::Cmp::new(nft_expr_cmp!(@cmp_op $op), $data) - }; -} - /// Can be used to compare the value loaded by [`Meta::IifName`] and [`Meta::OifName`]. Please note /// that it is faster to check interface index than name. /// diff --git a/src/expr/immediate.rs b/src/expr/immediate.rs index e9f7b5b..6f26bc3 100644 --- a/src/expr/immediate.rs +++ b/src/expr/immediate.rs @@ -1,29 +1,7 @@ -use super::{Expression, Register, VerdictAttribute}; +use super::{Expression, ExpressionData, Register}; use crate::{create_expr_type, sys}; create_expr_type!( - nested with_builder : ImmediateData, - [ - ( - get_value, - set_value, - with_value, - sys::NFTA_DATA_VALUE, - VecU8, - Vec<u8> - ), - ( - get_verdict, - set_verdict, - with_verdict, - sys::NFTA_DATA_VERDICT, - ExprVerdictAttribute, - VerdictAttribute - ) - ] -); - -create_expr_type!( inline with_builder : Immediate, [ ( @@ -39,8 +17,8 @@ create_expr_type!( set_data, with_data, sys::NFTA_IMMEDIATE_DATA, - ExprImmediateData, - ImmediateData + ExprData, + ExpressionData ) ] ); @@ -49,7 +27,7 @@ impl Immediate { pub fn new_data(data: Vec<u8>, register: Register) -> Self { Immediate::builder() .with_dreg(register) - .with_data(ImmediateData::builder().with_value(data)) + .with_data(ExpressionData::builder().with_value(data)) } } diff --git a/src/expr/mod.rs b/src/expr/mod.rs index 4c702b2..78b1717 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -26,10 +26,10 @@ use crate::sys::{self, nlattr}; use libc::NLA_TYPE_MASK; use thiserror::Error; -/* mod bitwise; pub use self::bitwise::*; +/* mod cmp; pub use self::cmp::*; @@ -295,7 +295,10 @@ macro_rules! create_expr_variant { Ok(AttributeType::ExpressionVariant(ExpressionVariant::from(res))) }, )+ - AttributeType::String(name) => Err(DecodeError::UnknownExpressionName(name.to_string())), + AttributeType::String(name) => { + info!("Unrecognized expression '{}', generating an ExpressionRaw", name); + ExpressionRaw::deserialize(buf).map(|(res, _)| AttributeType::ExpressionVariant(ExpressionVariant::ExpressionRaw(res))) + }, _ => unreachable!() } }, @@ -306,7 +309,13 @@ macro_rules! create_expr_variant { }; } -create_expr_variant!(ExpressionVariant, [Log, Log], [Immediate, Immediate]); +create_expr_variant!( + ExpressionVariant, + [Log, Log], + [Immediate, Immediate], + [Bitwise, Bitwise], + [ExpressionRaw, ExpressionRaw] +); #[derive(Debug, Clone, PartialEq, Eq)] pub struct ExpressionList { @@ -318,6 +327,11 @@ 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)); + } + pub fn add_expression<T>(&mut self, e: T) where T: Expression, @@ -397,57 +411,52 @@ impl NfNetlinkDeserializable for ExpressionList { } } -#[macro_export(local_inner_macros)] -macro_rules! nft_expr { - (bitwise mask $mask:expr,xor $xor:expr) => { - nft_expr_bitwise!(mask $mask, xor $xor) - }; - (cmp $op:tt $data:expr) => { - nft_expr_cmp!($op $data) - }; - (counter) => { - $crate::expr::Counter { nb_bytes: 0, nb_packets: 0} - }; - (ct $key:ident set) => { - nft_expr_ct!($key set) - }; - (ct $key:ident) => { - nft_expr_ct!($key) - }; - (immediate $expr:ident $value:expr) => { - nft_expr_immediate!($expr $value) - }; - (log group $group:ident prefix $prefix:expr) => { - nft_expr_log!(group $group prefix $prefix) - }; - (log group $group:ident) => { - nft_expr_log!(group $group) - }; - (log prefix $prefix:expr) => { - nft_expr_log!(prefix $prefix) - }; - (log) => { - nft_expr_log!() - }; - (lookup $set:expr) => { - nft_expr_lookup!($set) - }; - (masquerade) => { - $crate::expr::Masquerade - }; - (meta $expr:ident set) => { - nft_expr_meta!($expr set) - }; - (meta $expr:ident) => { - nft_expr_meta!($expr) - }; - (payload $proto:ident $field:ident) => { - nft_expr_payload!($proto $field) - }; - (verdict $verdict:ident) => { - nft_expr_verdict!($verdict) - }; - (verdict $verdict:ident $chain:expr) => { - nft_expr_verdict!($verdict $chain) - }; +create_expr_type!( + nested with_builder : ExpressionData, + [ + ( + get_value, + set_value, + with_value, + sys::NFTA_DATA_VALUE, + VecU8, + Vec<u8> + ), + ( + get_verdict, + set_verdict, + with_verdict, + sys::NFTA_DATA_VERDICT, + ExprVerdictAttribute, + VerdictAttribute + ) + ] +); + +// default type for expressions that we do not handle yet +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ExpressionRaw(Vec<u8>); + +impl NfNetlinkAttribute for ExpressionRaw { + fn get_size(&self) -> usize { + self.0.get_size() + } + + unsafe fn write_payload(&self, addr: *mut u8) { + self.0.write_payload(addr); + } +} + +impl NfNetlinkDeserializable for ExpressionRaw { + fn deserialize(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError> { + Ok((ExpressionRaw(buf.to_vec()), &[])) + } +} + +// 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 +impl Expression for ExpressionRaw { + fn get_name() -> &'static str { + "unknown_expression" + } } diff --git a/src/expr/reject.rs b/src/expr/reject.rs index 19752ce..34fbee5 100644 --- a/src/expr/reject.rs +++ b/src/expr/reject.rs @@ -1,6 +1,9 @@ use super::{DeserializationError, Expression, Rule}; +use crate::sys::{ + self, + libc::{self, c_char}, +}; use crate::ProtoFamily; -use crate::sys::{self, libc::{self, c_char}}; /// A reject expression that defines the type of rejection message sent when discarding a packet. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] diff --git a/src/expr/verdict.rs b/src/expr/verdict.rs index 326ef3b..7c27af6 100644 --- a/src/expr/verdict.rs +++ b/src/expr/verdict.rs @@ -2,12 +2,12 @@ use std::fmt::Debug; use libc::{NF_ACCEPT, NF_DROP, NF_QUEUE}; -use super::{Expression, Immediate, ImmediateData, Register, Rule}; +use super::{ExpressionData, Immediate, Register}; use crate::{ - create_expr_type, impl_attr_getters_and_setters, - nlmsg::{NfNetlinkAttribute, NfNetlinkAttributes, NfNetlinkDeserializable}, - parser::{DecodeError, InnerFormat}, - sys::{self, NFT_BREAK, NFT_CONTINUE, NFT_GOTO, NFT_JUMP, NFT_REG_VERDICT, NFT_RETURN}, + create_expr_type, + nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable}, + parser::DecodeError, + sys::{self, NFT_BREAK, NFT_CONTINUE, NFT_GOTO, NFT_JUMP, NFT_RETURN}, }; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -119,6 +119,6 @@ impl Immediate { } Immediate::builder() .with_dreg(Register::Verdict) - .with_data(ImmediateData::builder().with_verdict(data)) + .with_data(ExpressionData::builder().with_verdict(data)) } } diff --git a/src/parser.rs b/src/parser.rs index 42bcb00..8b14d74 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -36,6 +36,9 @@ pub enum DecodeError { #[error("Missing information in the chain to create a rule")] MissingChainInformationError, + #[error("The length of the arguments are not compatible with each other")] + IncompatibleLength, + #[error("Invalid subsystem, expected NFTABLES")] InvalidSubsystem(u8), @@ -72,9 +75,6 @@ pub enum DecodeError { #[error("The object does not contain a name for the expression being parsed")] MissingExpressionName, - #[error("The expression name was not recognized")] - UnknownExpressionName(String), - #[error("Unsupported attribute type")] UnsupportedAttributeType(u16), @@ -486,11 +486,12 @@ impl_attribute_holder!( [ExpressionVariant, crate::expr::ExpressionVariant], [ExpressionList, crate::expr::ExpressionList], [ExprLog, crate::expr::Log], - [ExprImmediate, crate::expr::ImmediateData], - [ExprImmediateData, crate::expr::ImmediateData], + [ExprImmediate, crate::expr::Immediate], + [ExprData, crate::expr::ExpressionData], [ExprVerdictAttribute, crate::expr::VerdictAttribute], [ExprVerdictType, crate::expr::VerdictType], - [Register, crate::expr::Register] + [Register, crate::expr::Register], + [ExprRaw, crate::expr::ExpressionRaw] ); #[macro_export] diff --git a/tests/expr.rs b/tests/expr.rs index 1a7b6f7..46b50f0 100644 --- a/tests/expr.rs +++ b/tests/expr.rs @@ -1,4 +1,4 @@ -use rustables::expr::{ExpressionList, Immediate, Register, VerdictKind}; +use rustables::expr::{Bitwise, ExpressionList, Immediate, Register, VerdictKind}; //use rustables::expr::{ // Bitwise, Cmp, CmpOp, Conntrack, Counter, Expression, HeaderField, IcmpCode, Immediate, Log, // LogGroup, LogPrefix, Lookup, Meta, Nat, NatType, Payload, Register, Reject, TcpHeaderField, @@ -9,8 +9,8 @@ use rustables::expr::{ExpressionList, Immediate, Register, VerdictKind}; //use rustables::sys::libc::{nlmsghdr, NF_DROP}; //use rustables::{ProtoFamily, Rule}; //use std::ffi::CStr; -//use std::net::Ipv4Addr; -// +use std::net::Ipv4Addr; + mod sys; use libc::NF_DROP; use sys::*; @@ -18,60 +18,63 @@ use sys::*; mod lib; use lib::*; -//#[test] -//fn bitwise_expr_is_valid() { -// let netmask = Ipv4Addr::new(255, 255, 255, 0); -// let bitwise = Bitwise::new(netmask, 0); -// let mut rule = get_test_rule(); -// let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &bitwise); -// assert_eq!(nlmsghdr.nlmsg_len, 124); -// -// 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::Nested( -// NFTA_RULE_EXPRESSIONS, -// vec![NetlinkExpr::Nested( -// NFTA_LIST_ELEM, -// vec![ -// NetlinkExpr::Final(NFTA_EXPR_NAME, b"bitwise\0".to_vec()), -// NetlinkExpr::Nested( -// NFTA_EXPR_DATA, -// vec![ -// NetlinkExpr::Final( -// NFTA_BITWISE_SREG, -// NFT_REG_1.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final( -// NFTA_BITWISE_DREG, -// NFT_REG_1.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final(NFTA_BITWISE_LEN, 4u32.to_be_bytes().to_vec()), -// NetlinkExpr::Nested( -// NFTA_BITWISE_MASK, -// vec![NetlinkExpr::Final( -// NFTA_DATA_VALUE, -// vec![255, 255, 255, 0] -// )] -// ), -// NetlinkExpr::Nested( -// NFTA_BITWISE_XOR, -// vec![NetlinkExpr::Final( -// NFTA_DATA_VALUE, -// 0u32.to_be_bytes().to_vec() -// )] -// ) -// ] -// ) -// ] -// )] -// ) -// ]) -// .to_raw() -// ); -//} +#[test] +fn bitwise_expr_is_valid() { + let netmask = Ipv4Addr::new(255, 255, 255, 0); + let bitwise = Bitwise::new(netmask.octets(), [0, 0, 0, 0]).unwrap(); + let mut rule = + get_test_rule().with_expressions(ExpressionList::builder().with_expression(bitwise)); + + let mut buf = Vec::new(); + let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule); + assert_eq!(nlmsghdr.nlmsg_len, 124); + + assert_eq!( + raw_expr, + NetlinkExpr::List(vec![ + NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()), + NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()), + NetlinkExpr::Nested( + NFTA_RULE_EXPRESSIONS, + vec![NetlinkExpr::Nested( + NFTA_LIST_ELEM, + vec![ + NetlinkExpr::Final(NFTA_EXPR_NAME, b"bitwise".to_vec()), + NetlinkExpr::Nested( + NFTA_EXPR_DATA, + vec![ + NetlinkExpr::Final( + NFTA_BITWISE_SREG, + NFT_REG_1.to_be_bytes().to_vec() + ), + NetlinkExpr::Final( + NFTA_BITWISE_DREG, + NFT_REG_1.to_be_bytes().to_vec() + ), + NetlinkExpr::Final(NFTA_BITWISE_LEN, 4u32.to_be_bytes().to_vec()), + NetlinkExpr::Nested( + NFTA_BITWISE_MASK, + vec![NetlinkExpr::Final( + NFTA_DATA_VALUE, + vec![255, 255, 255, 0] + )] + ), + NetlinkExpr::Nested( + NFTA_BITWISE_XOR, + vec![NetlinkExpr::Final( + NFTA_DATA_VALUE, + 0u32.to_be_bytes().to_vec() + )] + ) + ] + ) + ] + )] + ) + ]) + .to_raw() + ); +} // //#[test] //fn cmp_expr_is_valid() { |