diff options
author | Simon THOBY <git@nightmared.fr> | 2022-12-07 23:22:01 +0100 |
---|---|---|
committer | Simon THOBY <git@nightmared.fr> | 2022-12-07 23:22:01 +0100 |
commit | d43356f31a3d4062ea076376a5ee1b457be1b226 (patch) | |
tree | 8b14934c73bbd1388633ba677e19c4f7297c91c4 | |
parent | edb440a952320ea4f021c1d7063ff6d5f2f13818 (diff) |
add the payload and nat expressions
-rw-r--r-- | src/expr/mod.rs | 6 | ||||
-rw-r--r-- | src/expr/nat.rs | 45 | ||||
-rw-r--r-- | src/expr/payload.rs | 444 | ||||
-rw-r--r-- | src/parser.rs | 33 | ||||
-rw-r--r-- | tests/expr.rs | 210 |
5 files changed, 316 insertions, 422 deletions
diff --git a/src/expr/mod.rs b/src/expr/mod.rs index d2cd917..8b3f5c2 100644 --- a/src/expr/mod.rs +++ b/src/expr/mod.rs @@ -52,13 +52,11 @@ pub use self::masquerade::*; mod meta; pub use self::meta::*; -/* mod nat; pub use self::nat::*; mod payload; pub use self::payload::*; -*/ mod reject; pub use self::reject::{IcmpCode, Reject, RejectType}; @@ -225,7 +223,9 @@ create_expr_variant!( [ExpressionRaw, ExpressionRaw], [Meta, Meta], [Reject, Reject], - [Counter, Counter] + [Counter, Counter], + [Nat, Nat], + [Payload, Payload] ); #[derive(Debug, Clone, PartialEq, Eq, Default)] diff --git a/src/expr/nat.rs b/src/expr/nat.rs index ce6b881..8fb73fa 100644 --- a/src/expr/nat.rs +++ b/src/expr/nat.rs @@ -1,41 +1,41 @@ -use super::{DeserializationError, Expression, Register, Rule}; -use crate::ProtoFamily; -use crate::sys::{self, libc}; -use std::{convert::TryFrom, os::raw::c_char}; +use rustables_macros::{nfnetlink_enum, nfnetlink_struct}; + +use super::{Expression, Register}; +use crate::{ + sys::{self, NFT_NAT_DNAT, NFT_NAT_SNAT}, + ProtocolFamily, +}; #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[repr(i32)] +#[nfnetlink_enum(i32)] pub enum NatType { /// Source NAT. Changes the source address of a packet. - SNat = libc::NFT_NAT_SNAT, + SNat = NFT_NAT_SNAT, /// Destination NAT. Changes the destination address of a packet. - DNat = libc::NFT_NAT_DNAT, -} - -impl NatType { - fn from_raw(val: u32) -> Result<Self, DeserializationError> { - match val as i32 { - libc::NFT_NAT_SNAT => Ok(NatType::SNat), - libc::NFT_NAT_DNAT => Ok(NatType::DNat), - _ => Err(DeserializationError::InvalidValue), - } - } + DNat = NFT_NAT_DNAT, } /// A source or destination NAT statement. Modifies the source or destination address (and possibly /// port) of packets. -#[derive(Debug, PartialEq)] +#[derive(Default, Debug, Clone, PartialEq, Eq)] +#[nfnetlink_struct(nested = true)] pub struct Nat { + #[field(sys::NFTA_NAT_TYPE)] pub nat_type: NatType, - pub family: ProtoFamily, + #[field(sys::NFTA_NAT_FAMILY)] + pub family: ProtocolFamily, + #[field(sys::NFTA_NAT_REG_ADDR_MIN)] pub ip_register: Register, - pub port_register: Option<Register>, + #[field(sys::NFTA_NAT_REG_PROTO_MIN)] + pub port_register: Register, } impl Expression for Nat { - fn get_raw_name() -> *const libc::c_char { - b"nat\0" as *const _ as *const c_char + fn get_name() -> &'static str { + "nat" } +} +/* fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> where @@ -97,3 +97,4 @@ impl Expression for Nat { expr } } +*/ diff --git a/src/expr/payload.rs b/src/expr/payload.rs index a108fe8..f1cd468 100644 --- a/src/expr/payload.rs +++ b/src/expr/payload.rs @@ -1,128 +1,97 @@ -use super::{DeserializationError, Expression, Rule}; -use crate::sys::{self, libc}; -use std::os::raw::c_char; +use rustables_macros::nfnetlink_struct; -pub trait HeaderField { - fn offset(&self) -> u32; - fn len(&self) -> u32; +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}, +}; + +/// Payload expressions refer to data from the packet's payload. +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] +#[nfnetlink_struct(nested = true)] +pub struct Payload { + #[field(sys::NFTA_PAYLOAD_DREG)] + dreg: Register, + #[field(sys::NFTA_PAYLOAD_BASE)] + base: u32, + #[field(sys::NFTA_PAYLOAD_OFFSET)] + offset: u32, + #[field(sys::NFTA_PAYLOAD_LEN)] + len: u32, + #[field(sys::NFTA_PAYLOAD_SREG)] + sreg: Register, +} + +impl Expression for Payload { + fn get_name() -> &'static str { + "payload" + } } /// Payload expressions refer to data from the packet's payload. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum Payload { +pub enum HighLevelPayload { LinkLayer(LLHeaderField), Network(NetworkHeaderField), Transport(TransportHeaderField), } -impl Payload { - pub fn build(&self) -> RawPayload { +impl HighLevelPayload { + pub fn build(&self) -> Payload { match *self { - Payload::LinkLayer(ref f) => RawPayload::LinkLayer(RawPayloadData { - offset: f.offset(), - len: f.len(), - }), - Payload::Network(ref f) => RawPayload::Network(RawPayloadData { - offset: f.offset(), - len: f.len(), - }), - Payload::Transport(ref f) => RawPayload::Transport(RawPayloadData { - offset: f.offset(), - len: f.len(), - }), + HighLevelPayload::LinkLayer(ref f) => Payload::default() + .with_base(NFT_PAYLOAD_LL_HEADER) + .with_offset(f.offset()) + .with_len(f.len()), + HighLevelPayload::Network(ref f) => Payload::default() + .with_base(NFT_PAYLOAD_NETWORK_HEADER) + .with_offset(f.offset()) + .with_len(f.len()), + HighLevelPayload::Transport(ref f) => Payload::default() + .with_base(NFT_PAYLOAD_TRANSPORT_HEADER) + .with_offset(f.offset()) + .with_len(f.len()), } + .with_dreg(Register::Reg1) } } -impl Expression for Payload { - fn get_raw_name() -> *const libc::c_char { - RawPayload::get_raw_name() - } - - fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr { - self.build().to_expr(rule) - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct RawPayloadData { - offset: u32, - len: u32, -} - -/// Because deserializing a `Payload` expression is not possible (there is not enough information -/// in the expression itself), this enum should be used to deserialize payloads. +/// Payload expressions refer to data from the packet's payload. #[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum RawPayload { - LinkLayer(RawPayloadData), - Network(RawPayloadData), - Transport(RawPayloadData), +pub enum PayloadType { + LinkLayer(LLHeaderField), + Network, + Transport, } -impl RawPayload { - fn base(&self) -> u32 { - match self { - Self::LinkLayer(_) => libc::NFT_PAYLOAD_LL_HEADER as u32, - Self::Network(_) => libc::NFT_PAYLOAD_NETWORK_HEADER as u32, - Self::Transport(_) => libc::NFT_PAYLOAD_TRANSPORT_HEADER as u32, +impl PayloadType { + fn parse_from_payload(raw: &Payload) -> Result<Self, DecodeError> { + if raw.base.is_none() { + return Err(DecodeError::PayloadMissingBase); } - } -} - -impl HeaderField for RawPayload { - fn offset(&self) -> u32 { - match self { - Self::LinkLayer(ref f) | Self::Network(ref f) | Self::Transport(ref f) => f.offset, + if raw.len.is_none() { + return Err(DecodeError::PayloadMissingLen); } - } - - fn len(&self) -> u32 { - match self { - Self::LinkLayer(ref f) | Self::Network(ref f) | Self::Transport(ref f) => f.len, + if raw.offset.is_none() { + return Err(DecodeError::PayloadMissingOffset); } + Ok(match raw.base { + Some(NFT_PAYLOAD_LL_HEADER) => PayloadType::LinkLayer(LLHeaderField::from_raw_data( + raw.offset.unwrap(), + raw.len.unwrap(), + )?), + Some(NFT_PAYLOAD_NETWORK_HEADER) => PayloadType::Network, + Some(NFT_PAYLOAD_TRANSPORT_HEADER) => PayloadType::Transport, + Some(v) => return Err(DecodeError::UnknownPayloadType(v)), + None => return Err(DecodeError::PayloadMissingBase), + }) } } -impl Expression for RawPayload { - fn get_raw_name() -> *const libc::c_char { - b"payload\0" as *const _ as *const c_char - } - - fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> { - unsafe { - let base = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_PAYLOAD_BASE as u16); - let offset = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_PAYLOAD_OFFSET as u16); - let len = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_PAYLOAD_LEN as u16); - match base as i32 { - libc::NFT_PAYLOAD_LL_HEADER => Ok(Self::LinkLayer(RawPayloadData { offset, len })), - libc::NFT_PAYLOAD_NETWORK_HEADER => { - Ok(Self::Network(RawPayloadData { offset, len })) - } - libc::NFT_PAYLOAD_TRANSPORT_HEADER => { - Ok(Self::Transport(RawPayloadData { offset, len })) - } - - _ => return Err(DeserializationError::InvalidValue), - } - } - } - - fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { - unsafe { - let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name())); - - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_PAYLOAD_BASE as u16, self.base()); - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_PAYLOAD_OFFSET as u16, self.offset()); - sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_PAYLOAD_LEN as u16, self.len()); - sys::nftnl_expr_set_u32( - expr, - sys::NFTNL_EXPR_PAYLOAD_DREG as u16, - libc::NFT_REG_1 as u32, - ); - - expr - } - } +pub trait HeaderField { + fn offset(&self) -> u32; + fn len(&self) -> u32; } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -154,58 +123,52 @@ impl HeaderField for LLHeaderField { } impl LLHeaderField { - pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> { - let off = data.offset; - let len = data.len; - - if off == 0 && len == 6 { - Ok(Self::Daddr) - } else if off == 6 && len == 6 { - Ok(Self::Saddr) - } else if off == 12 && len == 2 { - Ok(Self::EtherType) - } else { - Err(DeserializationError::InvalidValue) - } + pub fn from_raw_data(offset: u32, len: u32) -> Result<Self, DecodeError> { + Ok(match (offset, len) { + (0, 6) => Self::Daddr, + (6, 6) => Self::Saddr, + (12, 2) => Self::EtherType, + _ => return Err(DecodeError::UnknownLinkLayerHeaderField(offset, len)), + }) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum NetworkHeaderField { - Ipv4(Ipv4HeaderField), - Ipv6(Ipv6HeaderField), + IPv4(IPv4HeaderField), + IPv6(IPv6HeaderField), } impl HeaderField for NetworkHeaderField { fn offset(&self) -> u32 { use self::NetworkHeaderField::*; match *self { - Ipv4(ref f) => f.offset(), - Ipv6(ref f) => f.offset(), + IPv4(ref f) => f.offset(), + IPv6(ref f) => f.offset(), } } fn len(&self) -> u32 { use self::NetworkHeaderField::*; match *self { - Ipv4(ref f) => f.len(), - Ipv6(ref f) => f.len(), + IPv4(ref f) => f.len(), + IPv6(ref f) => f.len(), } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] -pub enum Ipv4HeaderField { +pub enum IPv4HeaderField { Ttl, Protocol, Saddr, Daddr, } -impl HeaderField for Ipv4HeaderField { +impl HeaderField for IPv4HeaderField { fn offset(&self) -> u32 { - use self::Ipv4HeaderField::*; + use self::IPv4HeaderField::*; match *self { Ttl => 8, Protocol => 9, @@ -215,7 +178,7 @@ impl HeaderField for Ipv4HeaderField { } fn len(&self) -> u32 { - use self::Ipv4HeaderField::*; + use self::IPv4HeaderField::*; match *self { Ttl => 1, Protocol => 1, @@ -225,37 +188,30 @@ impl HeaderField for Ipv4HeaderField { } } -impl Ipv4HeaderField { - pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> { - let off = data.offset; - let len = data.len; - - if off == 8 && len == 1 { - Ok(Self::Ttl) - } else if off == 9 && len == 1 { - Ok(Self::Protocol) - } else if off == 12 && len == 4 { - Ok(Self::Saddr) - } else if off == 16 && len == 4 { - Ok(Self::Daddr) - } else { - Err(DeserializationError::InvalidValue) - } +impl IPv4HeaderField { + pub fn from_raw_data(offset: u32, len: u32) -> Result<Self, DecodeError> { + Ok(match (offset, len) { + (8, 1) => Self::Ttl, + (9, 1) => Self::Protocol, + (12, 4) => Self::Saddr, + (16, 4) => Self::Daddr, + _ => return Err(DecodeError::UnknownIPv4HeaderField(offset, len)), + }) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] -pub enum Ipv6HeaderField { +pub enum IPv6HeaderField { NextHeader, HopLimit, Saddr, Daddr, } -impl HeaderField for Ipv6HeaderField { +impl HeaderField for IPv6HeaderField { fn offset(&self) -> u32 { - use self::Ipv6HeaderField::*; + use self::IPv6HeaderField::*; match *self { NextHeader => 6, HopLimit => 7, @@ -265,7 +221,7 @@ impl HeaderField for Ipv6HeaderField { } fn len(&self) -> u32 { - use self::Ipv6HeaderField::*; + use self::IPv6HeaderField::*; match *self { NextHeader => 1, HopLimit => 1, @@ -275,31 +231,24 @@ impl HeaderField for Ipv6HeaderField { } } -impl Ipv6HeaderField { - pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> { - let off = data.offset; - let len = data.len; - - if off == 6 && len == 1 { - Ok(Self::NextHeader) - } else if off == 7 && len == 1 { - Ok(Self::HopLimit) - } else if off == 8 && len == 16 { - Ok(Self::Saddr) - } else if off == 24 && len == 16 { - Ok(Self::Daddr) - } else { - Err(DeserializationError::InvalidValue) - } +impl IPv6HeaderField { + pub fn from_raw_data(offset: u32, len: u32) -> Result<Self, DecodeError> { + Ok(match (offset, len) { + (6, 1) => Self::NextHeader, + (7, 1) => Self::HopLimit, + (8, 16) => Self::Saddr, + (24, 16) => Self::Daddr, + _ => return Err(DecodeError::UnknownIPv6HeaderField(offset, len)), + }) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum TransportHeaderField { - Tcp(TcpHeaderField), - Udp(UdpHeaderField), - Icmpv6(Icmpv6HeaderField), + Tcp(TCPHeaderField), + Udp(UDPHeaderField), + ICMPv6(ICMPv6HeaderField), } impl HeaderField for TransportHeaderField { @@ -308,7 +257,7 @@ impl HeaderField for TransportHeaderField { match *self { Tcp(ref f) => f.offset(), Udp(ref f) => f.offset(), - Icmpv6(ref f) => f.offset(), + ICMPv6(ref f) => f.offset(), } } @@ -317,21 +266,21 @@ impl HeaderField for TransportHeaderField { match *self { Tcp(ref f) => f.len(), Udp(ref f) => f.len(), - Icmpv6(ref f) => f.len(), + ICMPv6(ref f) => f.len(), } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] -pub enum TcpHeaderField { +pub enum TCPHeaderField { Sport, Dport, } -impl HeaderField for TcpHeaderField { +impl HeaderField for TCPHeaderField { fn offset(&self) -> u32 { - use self::TcpHeaderField::*; + use self::TCPHeaderField::*; match *self { Sport => 0, Dport => 2, @@ -339,7 +288,7 @@ impl HeaderField for TcpHeaderField { } fn len(&self) -> u32 { - use self::TcpHeaderField::*; + use self::TCPHeaderField::*; match *self { Sport => 2, Dport => 2, @@ -347,32 +296,27 @@ impl HeaderField for TcpHeaderField { } } -impl TcpHeaderField { - pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> { - let off = data.offset; - let len = data.len; - - if off == 0 && len == 2 { - Ok(Self::Sport) - } else if off == 2 && len == 2 { - Ok(Self::Dport) - } else { - Err(DeserializationError::InvalidValue) - } +impl TCPHeaderField { + pub fn from_raw_data(offset: u32, len: u32) -> Result<Self, DecodeError> { + Ok(match (offset, len) { + (0, 2) => Self::Sport, + (2, 2) => Self::Dport, + _ => return Err(DecodeError::UnknownTCPHeaderField(offset, len)), + }) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] -pub enum UdpHeaderField { +pub enum UDPHeaderField { Sport, Dport, Len, } -impl HeaderField for UdpHeaderField { +impl HeaderField for UDPHeaderField { fn offset(&self) -> u32 { - use self::UdpHeaderField::*; + use self::UDPHeaderField::*; match *self { Sport => 0, Dport => 2, @@ -381,7 +325,7 @@ impl HeaderField for UdpHeaderField { } fn len(&self) -> u32 { - use self::UdpHeaderField::*; + use self::UDPHeaderField::*; match *self { Sport => 2, Dport => 2, @@ -390,34 +334,28 @@ impl HeaderField for UdpHeaderField { } } -impl UdpHeaderField { - pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> { - let off = data.offset; - let len = data.len; - - if off == 0 && len == 2 { - Ok(Self::Sport) - } else if off == 2 && len == 2 { - Ok(Self::Dport) - } else if off == 4 && len == 2 { - Ok(Self::Len) - } else { - Err(DeserializationError::InvalidValue) - } +impl UDPHeaderField { + pub fn from_raw_data(offset: u32, len: u32) -> Result<Self, DecodeError> { + Ok(match (offset, len) { + (0, 2) => Self::Sport, + (2, 2) => Self::Dport, + (4, 2) => Self::Len, + _ => return Err(DecodeError::UnknownUDPHeaderField(offset, len)), + }) } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] -pub enum Icmpv6HeaderField { +pub enum ICMPv6HeaderField { Type, Code, Checksum, } -impl HeaderField for Icmpv6HeaderField { +impl HeaderField for ICMPv6HeaderField { fn offset(&self) -> u32 { - use self::Icmpv6HeaderField::*; + use self::ICMPv6HeaderField::*; match *self { Type => 0, Code => 1, @@ -426,7 +364,7 @@ impl HeaderField for Icmpv6HeaderField { } fn len(&self) -> u32 { - use self::Icmpv6HeaderField::*; + use self::ICMPv6HeaderField::*; match *self { Type => 1, Code => 1, @@ -435,97 +373,13 @@ impl HeaderField for Icmpv6HeaderField { } } -impl Icmpv6HeaderField { - pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> { - let off = data.offset; - let len = data.len; - - if off == 0 && len == 1 { - Ok(Self::Type) - } else if off == 1 && len == 1 { - Ok(Self::Code) - } else if off == 2 && len == 2 { - Ok(Self::Checksum) - } else { - Err(DeserializationError::InvalidValue) - } +impl ICMPv6HeaderField { + pub fn from_raw_data(offset: u32, len: u32) -> Result<Self, DecodeError> { + Ok(match (offset, len) { + (0, 1) => Self::Type, + (1, 1) => Self::Code, + (2, 2) => Self::Checksum, + _ => return Err(DecodeError::UnknownICMPv6HeaderField(offset, len)), + }) } } - -#[macro_export(local_inner_macros)] -macro_rules! nft_expr_payload { - (@ipv4_field ttl) => { - $crate::expr::Ipv4HeaderField::Ttl - }; - (@ipv4_field protocol) => { - $crate::expr::Ipv4HeaderField::Protocol - }; - (@ipv4_field saddr) => { - $crate::expr::Ipv4HeaderField::Saddr - }; - (@ipv4_field daddr) => { - $crate::expr::Ipv4HeaderField::Daddr - }; - - (@ipv6_field nextheader) => { - $crate::expr::Ipv6HeaderField::NextHeader - }; - (@ipv6_field hoplimit) => { - $crate::expr::Ipv6HeaderField::HopLimit - }; - (@ipv6_field saddr) => { - $crate::expr::Ipv6HeaderField::Saddr - }; - (@ipv6_field daddr) => { - $crate::expr::Ipv6HeaderField::Daddr - }; - - (@tcp_field sport) => { - $crate::expr::TcpHeaderField::Sport - }; - (@tcp_field dport) => { - $crate::expr::TcpHeaderField::Dport - }; - - (@udp_field sport) => { - $crate::expr::UdpHeaderField::Sport - }; - (@udp_field dport) => { - $crate::expr::UdpHeaderField::Dport - }; - (@udp_field len) => { - $crate::expr::UdpHeaderField::Len - }; - - (ethernet daddr) => { - $crate::expr::Payload::LinkLayer($crate::expr::LLHeaderField::Daddr) - }; - (ethernet saddr) => { - $crate::expr::Payload::LinkLayer($crate::expr::LLHeaderField::Saddr) - }; - (ethernet ethertype) => { - $crate::expr::Payload::LinkLayer($crate::expr::LLHeaderField::EtherType) - }; - - (ipv4 $field:ident) => { - $crate::expr::Payload::Network($crate::expr::NetworkHeaderField::Ipv4( - nft_expr_payload!(@ipv4_field $field), - )) - }; - (ipv6 $field:ident) => { - $crate::expr::Payload::Network($crate::expr::NetworkHeaderField::Ipv6( - nft_expr_payload!(@ipv6_field $field), - )) - }; - - (tcp $field:ident) => { - $crate::expr::Payload::Transport($crate::expr::TransportHeaderField::Tcp( - nft_expr_payload!(@tcp_field $field), - )) - }; - (udp $field:ident) => { - $crate::expr::Payload::Transport($crate::expr::TransportHeaderField::Udp( - nft_expr_payload!(@udp_field $field), - )) - }; -} diff --git a/src/parser.rs b/src/parser.rs index 55f1e1c..17905c4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -76,6 +76,39 @@ pub enum DecodeError { #[error("Invalid type for a verdict expression")] UnknownVerdictType(i32), + #[error("Invalid type for a nat expression")] + UnknownNatType(i32), + + #[error("Invalid type for a payload expression")] + UnknownPayloadType(u32), + + #[error("Unsupported value for a link layer header field")] + UnknownLinkLayerHeaderField(u32, u32), + + #[error("Unsupported value for an IPv4 header field")] + UnknownIPv4HeaderField(u32, u32), + + #[error("Unsupported value for an IPv6 header field")] + UnknownIPv6HeaderField(u32, u32), + + #[error("Unsupported value for a TCP header field")] + UnknownTCPHeaderField(u32, u32), + + #[error("Unsupported value for an UDP header field")] + UnknownUDPHeaderField(u32, u32), + + #[error("Unsupported value for an ICMPv6 header field")] + UnknownICMPv6HeaderField(u32, u32), + + #[error("Missing the 'base' attribute to deserialize the payload object")] + PayloadMissingBase, + + #[error("Missing the 'offset' attribute to deserialize the payload object")] + PayloadMissingOffset, + + #[error("Missing the 'len' attribute to deserialize the payload object")] + PayloadMissingLen, + #[error("The object does not contain a name for the expression being parsed")] MissingExpressionName, diff --git a/tests/expr.rs b/tests/expr.rs index 5baec2a..2d0e12a 100644 --- a/tests/expr.rs +++ b/tests/expr.rs @@ -1,16 +1,20 @@ use rustables::{ expr::{ - Bitwise, ExpressionList, IcmpCode, Immediate, Log, Meta, MetaType, Register, Reject, - RejectType, VerdictKind, + Bitwise, 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_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_REJECT_ICMP_CODE, NFTA_REJECT_TYPE, NFTA_RULE_CHAIN, - NFTA_RULE_EXPRESSIONS, NFTA_RULE_TABLE, NFTA_VERDICT_CODE, NFT_META_PROTOCOL, NFT_REG_1, - NFT_REG_VERDICT, NFT_REJECT_ICMPX_UNREACH, + 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_META_PROTOCOL, NFT_NAT_SNAT, + NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, NFT_REG_VERDICT, NFT_REJECT_ICMPX_UNREACH, }, + ProtocolFamily, }; //use rustables::expr::{ // Bitwise, Cmp, CmpOp, Conntrack, Counter, Expression, HeaderField, IcmpCode, Immediate, Log, @@ -393,103 +397,105 @@ fn meta_expr_is_valid() { .to_raw() ); } -// -//#[test] -//fn nat_expr_is_valid() { -// let nat = Nat { -// nat_type: NatType::SNat, -// family: ProtoFamily::Ipv4, -// ip_register: Register::Reg1, -// port_register: None, -// }; -// let mut rule = get_test_rule(); -// let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &nat); -// assert_eq!(nlmsghdr.nlmsg_len, 96); -// -// 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"nat\0".to_vec()), -// NetlinkExpr::Nested( -// NFTA_EXPR_DATA, -// vec![ -// NetlinkExpr::Final( -// NFTA_NAT_TYPE, -// NFT_NAT_SNAT.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final( -// NFTA_NAT_FAMILY, -// (ProtoFamily::Ipv4 as u32).to_be_bytes().to_vec(), -// ), -// NetlinkExpr::Final( -// NFTA_NAT_REG_ADDR_MIN, -// NFT_REG_1.to_be_bytes().to_vec() -// ) -// ] -// ) -// ] -// )] -// ) -// ]) -// .to_raw() -// ); -//} -// -//#[test] -//fn payload_expr_is_valid() { -// let tcp_header_field = TcpHeaderField::Sport; -// let transport_header_field = TransportHeaderField::Tcp(tcp_header_field); -// let payload = Payload::Transport(transport_header_field); -// let mut rule = get_test_rule(); -// let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &payload); -// assert_eq!(nlmsghdr.nlmsg_len, 108); -// -// 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"payload\0".to_vec()), -// NetlinkExpr::Nested( -// NFTA_EXPR_DATA, -// vec![ -// NetlinkExpr::Final( -// NFTA_PAYLOAD_DREG, -// NFT_REG_1.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final( -// NFTA_PAYLOAD_BASE, -// NFT_PAYLOAD_TRANSPORT_HEADER.to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final( -// NFTA_PAYLOAD_OFFSET, -// tcp_header_field.offset().to_be_bytes().to_vec() -// ), -// NetlinkExpr::Final( -// NFTA_PAYLOAD_LEN, -// tcp_header_field.len().to_be_bytes().to_vec() -// ), -// ] -// ) -// ] -// )] -// ) -// ]) -// .to_raw() -// ); -//} + +#[test] +fn nat_expr_is_valid() { + let nat = Nat::default() + .with_nat_type(NatType::SNat) + .with_family(ProtocolFamily::Ipv4) + .with_ip_register(Register::Reg1); + let mut rule = get_test_rule().with_expressions(vec![nat]); + + let mut buf = Vec::new(); + let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule); + assert_eq!(nlmsghdr.nlmsg_len, 96); + + 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"nat".to_vec()), + NetlinkExpr::Nested( + NFTA_EXPR_DATA, + vec![ + NetlinkExpr::Final( + NFTA_NAT_TYPE, + NFT_NAT_SNAT.to_be_bytes().to_vec() + ), + NetlinkExpr::Final( + NFTA_NAT_FAMILY, + (ProtocolFamily::Ipv4 as u32).to_be_bytes().to_vec(), + ), + NetlinkExpr::Final( + NFTA_NAT_REG_ADDR_MIN, + NFT_REG_1.to_be_bytes().to_vec() + ) + ] + ) + ] + )] + ) + ]) + .to_raw() + ); +} + +#[test] +fn payload_expr_is_valid() { + let tcp_header_field = TCPHeaderField::Sport; + let transport_header_field = TransportHeaderField::Tcp(tcp_header_field); + let payload = HighLevelPayload::Transport(transport_header_field); + let mut rule = get_test_rule().with_expressions(vec![payload.build()]); + + let mut buf = Vec::new(); + let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule); + assert_eq!(nlmsghdr.nlmsg_len, 108); + + 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"payload".to_vec()), + NetlinkExpr::Nested( + NFTA_EXPR_DATA, + vec![ + NetlinkExpr::Final( + NFTA_PAYLOAD_DREG, + NFT_REG_1.to_be_bytes().to_vec() + ), + NetlinkExpr::Final( + NFTA_PAYLOAD_BASE, + NFT_PAYLOAD_TRANSPORT_HEADER.to_be_bytes().to_vec() + ), + NetlinkExpr::Final( + NFTA_PAYLOAD_OFFSET, + tcp_header_field.offset().to_be_bytes().to_vec() + ), + NetlinkExpr::Final( + NFTA_PAYLOAD_LEN, + tcp_header_field.len().to_be_bytes().to_vec() + ), + ] + ) + ] + )] + ) + ]) + .to_raw() + ); +} #[test] fn reject_expr_is_valid() { |