diff options
Diffstat (limited to 'rustables/src/expr/payload.rs')
-rw-r--r-- | rustables/src/expr/payload.rs | 221 |
1 files changed, 192 insertions, 29 deletions
diff --git a/rustables/src/expr/payload.rs b/rustables/src/expr/payload.rs index 2da4e1f..25a71ad 100644 --- a/rustables/src/expr/payload.rs +++ b/rustables/src/expr/payload.rs @@ -1,4 +1,4 @@ -use super::{Expression, Rule}; +use super::{DeserializationError, Expression, Rule}; use rustables_sys::{self as sys, libc}; use std::os::raw::c_char; @@ -8,7 +8,7 @@ trait HeaderField { } /// Payload expressions refer to data from the packet's payload. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Payload { LinkLayer(LLHeaderField), Network(NetworkHeaderField), @@ -16,41 +16,100 @@ pub enum Payload { } impl Payload { - fn base(self) -> u32 { + pub fn build(&self) -> RawPayload { + 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.offset(), + }), + } + } +} + +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. +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum RawPayload { + LinkLayer(RawPayloadData), + Network(RawPayloadData), + Transport(RawPayloadData), +} + +impl RawPayload { + fn base(&self) -> u32 { match self { - Payload::LinkLayer(_) => libc::NFT_PAYLOAD_LL_HEADER as u32, - Payload::Network(_) => libc::NFT_PAYLOAD_NETWORK_HEADER as u32, - Payload::Transport(_) => libc::NFT_PAYLOAD_TRANSPORT_HEADER as u32, + 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 HeaderField for Payload { +impl HeaderField for RawPayload { fn offset(&self) -> u32 { - use self::Payload::*; - match *self { - LinkLayer(ref f) => f.offset(), - Network(ref f) => f.offset(), - Transport(ref f) => f.offset(), + match self { + Self::LinkLayer(ref f) | Self::Network(ref f) | Self::Transport(ref f) => f.offset, } } fn len(&self) -> u32 { - use self::Payload::*; - match *self { - LinkLayer(ref f) => f.len(), - Network(ref f) => f.len(), - Transport(ref f) => f.len(), + match self { + Self::LinkLayer(ref f) | Self::Network(ref f) | Self::Transport(ref f) => f.len, } } } -impl Expression for Payload { +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( - b"payload\0" as *const _ as *const c_char - )); + 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()); @@ -66,7 +125,7 @@ impl Expression for Payload { } } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum LLHeaderField { Daddr, @@ -94,7 +153,24 @@ impl HeaderField for LLHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +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) + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum NetworkHeaderField { Ipv4(Ipv4HeaderField), Ipv6(Ipv6HeaderField), @@ -118,7 +194,7 @@ impl HeaderField for NetworkHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum Ipv4HeaderField { Ttl, @@ -149,7 +225,26 @@ impl HeaderField for Ipv4HeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +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) + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum Ipv6HeaderField { NextHeader, @@ -180,7 +275,26 @@ impl HeaderField for Ipv6HeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +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) + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum TransportHeaderField { Tcp(TcpHeaderField), @@ -208,7 +322,7 @@ impl HeaderField for TransportHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum TcpHeaderField { Sport, @@ -233,7 +347,22 @@ impl HeaderField for TcpHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +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) + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum UdpHeaderField { Sport, @@ -261,7 +390,24 @@ impl HeaderField for UdpHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +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) + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum Icmpv6HeaderField { Type, @@ -289,6 +435,23 @@ 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) + } + } +} + #[macro_export(local_inner_macros)] macro_rules! nft_expr_payload { (@ipv4_field ttl) => { |