From 5fbf51008eb7e2d55e074cd12c877b59f4a41f79 Mon Sep 17 00:00:00 2001 From: Simon THOBY Date: Fri, 9 Dec 2022 23:30:10 +0100 Subject: re-impl the ct expression --- src/expr/ct.rs | 106 ++++++++++++----------------- src/expr/mod.rs | 5 +- src/expr/nat.rs | 63 ------------------ src/expr/payload.rs | 3 +- src/parser.rs | 3 + tests/expr.rs | 187 +++++++++++++++++++++++++++------------------------- 6 files changed, 144 insertions(+), 223 deletions(-) diff --git a/src/expr/ct.rs b/src/expr/ct.rs index 7d6614c..ccf61e1 100644 --- a/src/expr/ct.rs +++ b/src/expr/ct.rs @@ -1,9 +1,13 @@ -use super::{DeserializationError, Expression, Rule}; -use crate::sys::{self, libc}; -use std::os::raw::c_char; +use rustables_macros::{nfnetlink_enum, nfnetlink_struct}; + +use crate::sys::{ + NFTA_CT_DIRECTION, NFTA_CT_DREG, NFTA_CT_KEY, NFTA_CT_SREG, NFT_CT_MARK, NFT_CT_STATE, +}; + +use super::{Expression, Register}; bitflags::bitflags! { - pub struct States: u32 { + pub struct ConnTrackState: u32 { const INVALID = 1; const ESTABLISHED = 2; const RELATED = 4; @@ -12,76 +16,50 @@ bitflags::bitflags! { } } -pub enum Conntrack { - State, - Mark { set: bool }, +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[nfnetlink_enum(u32, nested = true)] +pub enum ConntrackKey { + State = NFT_CT_STATE, + Mark = NFT_CT_MARK, } -impl Conntrack { - fn raw_key(&self) -> u32 { - match *self { - Conntrack::State => libc::NFT_CT_STATE as u32, - Conntrack::Mark { .. } => libc::NFT_CT_MARK as u32, - } - } +#[derive(Default, Clone, Debug, PartialEq, Eq)] +#[nfnetlink_struct(nested = true)] +pub struct Conntrack { + #[field(NFTA_CT_DREG)] + pub dreg: Register, + #[field(NFTA_CT_KEY)] + pub key: ConntrackKey, + #[field(NFTA_CT_DIRECTION)] + pub direction: u8, + #[field(NFTA_CT_SREG)] + pub sreg: Register, } impl Expression for Conntrack { - fn get_raw_name() -> *const c_char { - b"ct\0" as *const _ as *const c_char + fn get_name() -> &'static str { + "ct" } +} - fn from_expr(expr: *const sys::nftnl_expr) -> Result - where - Self: Sized, - { - unsafe { - let ct_key = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_CT_KEY as u16); - let ct_sreg_is_set = sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_CT_SREG as u16); - - match ct_key as i32 { - libc::NFT_CT_STATE => Ok(Conntrack::State), - libc::NFT_CT_MARK => Ok(Conntrack::Mark { - set: ct_sreg_is_set, - }), - _ => Err(DeserializationError::InvalidValue), - } - } +impl Conntrack { + pub fn set_mark_value(&mut self, reg: Register) { + self.set_sreg(reg); + self.set_key(ConntrackKey::Mark); } - fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { - unsafe { - let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name())); - - if let Conntrack::Mark { set: true } = self { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_CT_SREG as u16, - libc::NFT_REG_1 as u32, - ); - } else { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_CT_DREG as u16, - libc::NFT_REG_1 as u32, - ); - } - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_CT_KEY as u16, self.raw_key()); + pub fn with_mark_value(mut self, reg: Register) -> Self { + self.set_mark_value(reg); + self + } - expr - } + pub fn retrieve_value(&mut self, key: ConntrackKey) { + self.set_key(key); + self.set_dreg(Register::Reg1); } -} -#[macro_export] -macro_rules! nft_expr_ct { - (state) => { - $crate::expr::Conntrack::State - }; - (mark set) => { - $crate::expr::Conntrack::Mark { set: true } - }; - (mark) => { - $crate::expr::Conntrack::Mark { set: false } - }; + pub fn with_retrieve_value(mut self, key: ConntrackKey) -> Self { + self.retrieve_value(key); + self + } } diff --git a/src/expr/mod.rs b/src/expr/mod.rs index 0a7f54c..a6da2cd 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -27,11 +27,9 @@ pub use self::cmp::*; mod counter; pub use self::counter::*; -/* pub mod ct; pub use self::ct::*; -*/ mod immediate; pub use self::immediate::*; @@ -224,7 +222,8 @@ create_expr_variant!( [Counter, Counter], [Nat, Nat], [Payload, Payload], - [Cmp, Cmp] + [Cmp, Cmp], + [Conntrack, Conntrack] ); #[derive(Debug, Clone, PartialEq, Eq, Default)] diff --git a/src/expr/nat.rs b/src/expr/nat.rs index 8fb73fa..406b2e6 100644 --- a/src/expr/nat.rs +++ b/src/expr/nat.rs @@ -35,66 +35,3 @@ impl Expression for Nat { "nat" } } -/* - - fn from_expr(expr: *const sys::nftnl_expr) -> Result - where - Self: Sized, - { - unsafe { - let nat_type = NatType::from_raw(sys::nftnl_expr_get_u32( - expr, - sys::NFTNL_EXPR_NAT_TYPE as u16, - ))?; - - let family = ProtoFamily::try_from(sys::nftnl_expr_get_u32( - expr, - sys::NFTNL_EXPR_NAT_FAMILY as u16, - ) as i32)?; - - let ip_register = Register::from_raw(sys::nftnl_expr_get_u32( - expr, - sys::NFTNL_EXPR_NAT_REG_ADDR_MIN as u16, - ))?; - - let mut port_register = None; - if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_NAT_REG_PROTO_MIN as u16) { - port_register = Some(Register::from_raw(sys::nftnl_expr_get_u32( - expr, - sys::NFTNL_EXPR_NAT_REG_PROTO_MIN as u16, - ))?); - } - - Ok(Nat { - ip_register, - nat_type, - family, - port_register, - }) - } - } - - fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { - let expr = try_alloc!(unsafe { sys::nftnl_expr_alloc(Self::get_raw_name()) }); - - unsafe { - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_NAT_TYPE as u16, self.nat_type as u32); - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_NAT_FAMILY as u16, self.family as u32); - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_NAT_REG_ADDR_MIN as u16, - self.ip_register.to_raw(), - ); - if let Some(port_register) = self.port_register { - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_NAT_REG_PROTO_MIN as u16, - port_register.to_raw(), - ); - } - } - - expr - } -} -*/ diff --git a/src/expr/payload.rs b/src/expr/payload.rs index f1cd468..490a4ec 100644 --- a/src/expr/payload.rs +++ b/src/expr/payload.rs @@ -2,7 +2,6 @@ use rustables_macros::nfnetlink_struct; use super::{Expression, Register}; use crate::{ - nlmsg::{NfNetlinkAttribute, NfNetlinkDeserializable}, parser::DecodeError, sys::{self, NFT_PAYLOAD_LL_HEADER, NFT_PAYLOAD_NETWORK_HEADER, NFT_PAYLOAD_TRANSPORT_HEADER}, }; @@ -66,7 +65,7 @@ pub enum PayloadType { } impl PayloadType { - fn parse_from_payload(raw: &Payload) -> Result { + pub fn parse_from_payload(raw: &Payload) -> Result { if raw.base.is_none() { return Err(DecodeError::PayloadMissingBase); } diff --git a/src/parser.rs b/src/parser.rs index b5e9f18..c402dae 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -85,6 +85,9 @@ pub enum DecodeError { #[error("Invalid type for a compare expression")] UnknownCmpOp(u32), + #[error("Invalid type for a conntrack key")] + UnknownConntrackKey(u32), + #[error("Unsupported value for a link layer header field")] UnknownLinkLayerHeaderField(u32, u32), diff --git a/tests/expr.rs b/tests/expr.rs index 3b71c12..4367116 100644 --- a/tests/expr.rs +++ b/tests/expr.rs @@ -1,19 +1,20 @@ use rustables::{ expr::{ - Bitwise, Cmp, CmpOp, ExpressionList, HeaderField, HighLevelPayload, IcmpCode, Immediate, - Log, Meta, MetaType, Nat, NatType, Register, Reject, RejectType, TCPHeaderField, - TransportHeaderField, VerdictKind, + Bitwise, Cmp, CmpOp, Conntrack, ConntrackKey, Counter, ExpressionList, HeaderField, + HighLevelPayload, IcmpCode, Immediate, Log, Meta, MetaType, Nat, NatType, Register, Reject, + RejectType, TCPHeaderField, TransportHeaderField, VerdictKind, }, sys::{ NFTA_BITWISE_DREG, NFTA_BITWISE_LEN, NFTA_BITWISE_MASK, NFTA_BITWISE_SREG, - NFTA_BITWISE_XOR, NFTA_CMP_DATA, NFTA_CMP_OP, NFTA_CMP_SREG, NFTA_DATA_VALUE, - NFTA_DATA_VERDICT, NFTA_EXPR_DATA, NFTA_EXPR_NAME, NFTA_IMMEDIATE_DATA, - NFTA_IMMEDIATE_DREG, NFTA_LIST_ELEM, NFTA_LOG_GROUP, NFTA_LOG_PREFIX, NFTA_META_DREG, - NFTA_META_KEY, NFTA_NAT_FAMILY, NFTA_NAT_REG_ADDR_MIN, NFTA_NAT_TYPE, NFTA_PAYLOAD_BASE, - NFTA_PAYLOAD_DREG, NFTA_PAYLOAD_LEN, NFTA_PAYLOAD_OFFSET, NFTA_REJECT_ICMP_CODE, - NFTA_REJECT_TYPE, NFTA_RULE_CHAIN, NFTA_RULE_EXPRESSIONS, NFTA_RULE_TABLE, - NFTA_VERDICT_CODE, NFT_CMP_EQ, NFT_META_PROTOCOL, NFT_NAT_SNAT, - NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, NFT_REG_VERDICT, NFT_REJECT_ICMPX_UNREACH, + NFTA_BITWISE_XOR, NFTA_CMP_DATA, NFTA_CMP_OP, NFTA_CMP_SREG, NFTA_COUNTER_BYTES, + NFTA_COUNTER_PACKETS, NFTA_CT_DREG, NFTA_CT_KEY, NFTA_DATA_VALUE, NFTA_DATA_VERDICT, + NFTA_EXPR_DATA, NFTA_EXPR_NAME, NFTA_IMMEDIATE_DATA, NFTA_IMMEDIATE_DREG, NFTA_LIST_ELEM, + NFTA_LOG_GROUP, NFTA_LOG_PREFIX, NFTA_META_DREG, NFTA_META_KEY, NFTA_NAT_FAMILY, + NFTA_NAT_REG_ADDR_MIN, NFTA_NAT_TYPE, NFTA_PAYLOAD_BASE, NFTA_PAYLOAD_DREG, + NFTA_PAYLOAD_LEN, NFTA_PAYLOAD_OFFSET, NFTA_REJECT_ICMP_CODE, NFTA_REJECT_TYPE, + NFTA_RULE_CHAIN, NFTA_RULE_EXPRESSIONS, NFTA_RULE_TABLE, NFTA_VERDICT_CODE, NFT_CMP_EQ, + NFT_CT_STATE, NFT_META_PROTOCOL, NFT_NAT_SNAT, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, + NFT_REG_VERDICT, NFT_REJECT_ICMPX_UNREACH, }, ProtocolFamily, }; @@ -132,86 +133,90 @@ fn cmp_expr_is_valid() { ); } -//#[test] -//fn counter_expr_is_valid() { -// let nb_bytes = 123456u64; -// let nb_packets = 987u64; -// let mut counter = Counter::new(); -// counter.nb_bytes = nb_bytes; -// counter.nb_packets = nb_packets; -// -// let mut rule = get_test_rule(); -// let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &counter); -// assert_eq!(nlmsghdr.nlmsg_len, 100); -// -// 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"counter\0".to_vec()), -// NetlinkExpr::Nested( -// NFTA_EXPR_DATA, -// vec![ -// NetlinkExpr::Final( -// NFTA_COUNTER_BYTES, -// nb_bytes.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final( -// NFTA_COUNTER_PACKETS, -// nb_packets.to_be_bytes().to_vec() -// ) -// ] -// ) -// ] -// )] -// ) -// ]) -// .to_raw() -// ); -//} -// -//#[test] -//fn ct_expr_is_valid() { -// let ct = Conntrack::State; -// let mut rule = get_test_rule(); -// let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &ct); -// assert_eq!(nlmsghdr.nlmsg_len, 88); -// -// 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"ct\0".to_vec()), -// NetlinkExpr::Nested( -// NFTA_EXPR_DATA, -// vec![ -// NetlinkExpr::Final( -// NFTA_CT_KEY, -// NFT_CT_STATE.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final(NFTA_CT_DREG, NFT_REG_1.to_be_bytes().to_vec()) -// ] -// ) -// ] -// )] -// ) -// ]) -// .to_raw() -// ) -//} -// +#[test] +fn counter_expr_is_valid() { + let nb_bytes = 123456u64; + let nb_packets = 987u64; + let counter = Counter::default() + .with_nb_bytes(nb_bytes) + .with_nb_packets(nb_packets); + + let mut rule = get_test_rule().with_expressions(vec![counter]); + + let mut buf = Vec::new(); + let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule); + assert_eq!(nlmsghdr.nlmsg_len, 100); + + 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"counter".to_vec()), + NetlinkExpr::Nested( + NFTA_EXPR_DATA, + vec![ + NetlinkExpr::Final( + NFTA_COUNTER_BYTES, + nb_bytes.to_be_bytes().to_vec() + ), + NetlinkExpr::Final( + NFTA_COUNTER_PACKETS, + nb_packets.to_be_bytes().to_vec() + ) + ] + ) + ] + )] + ) + ]) + .to_raw() + ); +} + +#[test] +fn ct_expr_is_valid() { + let ct = Conntrack::default().with_retrieve_value(ConntrackKey::State); + let mut rule = get_test_rule().with_expressions(vec![ct]); + + let mut buf = Vec::new(); + let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule); + assert_eq!(nlmsghdr.nlmsg_len, 88); + + 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"ct".to_vec()), + NetlinkExpr::Nested( + NFTA_EXPR_DATA, + vec![ + NetlinkExpr::Final( + NFTA_CT_KEY, + NFT_CT_STATE.to_be_bytes().to_vec() + ), + NetlinkExpr::Final(NFTA_CT_DREG, NFT_REG_1.to_be_bytes().to_vec()) + ] + ) + ] + )] + ) + ]) + .to_raw() + ) +} + #[test] fn immediate_expr_is_valid() { let immediate = Immediate::new_data(vec![42u8], Register::Reg1); -- cgit v1.2.3