aboutsummaryrefslogtreecommitdiff
path: root/src/expr/payload.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/expr/payload.rs')
-rw-r--r--src/expr/payload.rs443
1 files changed, 148 insertions, 295 deletions
diff --git a/src/expr/payload.rs b/src/expr/payload.rs
index a108fe8..d0b2cea 100644
--- a/src/expr/payload.rs
+++ b/src/expr/payload.rs
@@ -1,128 +1,96 @@
-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::{
+ error::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 {
+ pub 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 +122,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 +177,7 @@ impl HeaderField for Ipv4HeaderField {
}
fn len(&self) -> u32 {
- use self::Ipv4HeaderField::*;
+ use self::IPv4HeaderField::*;
match *self {
Ttl => 1,
Protocol => 1,
@@ -225,37 +187,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 +220,7 @@ impl HeaderField for Ipv6HeaderField {
}
fn len(&self) -> u32 {
- use self::Ipv6HeaderField::*;
+ use self::IPv6HeaderField::*;
match *self {
NextHeader => 1,
HopLimit => 1,
@@ -275,31 +230,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 +256,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 +265,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 +287,7 @@ impl HeaderField for TcpHeaderField {
}
fn len(&self) -> u32 {
- use self::TcpHeaderField::*;
+ use self::TCPHeaderField::*;
match *self {
Sport => 2,
Dport => 2,
@@ -347,32 +295,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 +324,7 @@ impl HeaderField for UdpHeaderField {
}
fn len(&self) -> u32 {
- use self::UdpHeaderField::*;
+ use self::UDPHeaderField::*;
match *self {
Sport => 2,
Dport => 2,
@@ -390,34 +333,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 +363,7 @@ impl HeaderField for Icmpv6HeaderField {
}
fn len(&self) -> u32 {
- use self::Icmpv6HeaderField::*;
+ use self::ICMPv6HeaderField::*;
match *self {
Type => 1,
Code => 1,
@@ -435,97 +372,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),
- ))
- };
-}