diff options
author | Simon THOBY <git@nightmared.fr> | 2021-10-23 12:24:28 +0200 |
---|---|---|
committer | Simon THOBY <git@nightmared.fr> | 2021-11-02 22:18:11 +0100 |
commit | 88d35077681438d479c0914c325d7054a589fe21 (patch) | |
tree | 918eaf7e1d337f4331edfb367b0734f68d411b70 /rustables/src | |
parent | 867e2df78a0e92cab93f647c3eeccabca5b869a2 (diff) |
add support for deserializing Payload expressions
Diffstat (limited to 'rustables/src')
-rw-r--r-- | rustables/src/expr/payload.rs | 213 |
1 files changed, 188 insertions, 25 deletions
diff --git a/rustables/src/expr/payload.rs b/rustables/src/expr/payload.rs index de77e0c..a6b5ddf 100644 --- a/rustables/src/expr/payload.rs +++ b/rustables/src/expr/payload.rs @@ -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,40 +16,99 @@ 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::LinkLayer(RawPayloadData { + offset: f.offset(), + len: f.len(), + }), + Payload::Transport(ref f) => RawPayload::LinkLayer(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) -> Option<Self> { + 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 => { + Some(Self::LinkLayer(RawPayloadData { offset, len })) + } + libc::NFT_PAYLOAD_NETWORK_HEADER => { + Some(Self::Network(RawPayloadData { offset, len })) + } + libc::NFT_PAYLOAD_TRANSPORT_HEADER => { + Some(Self::Transport(RawPayloadData { offset, len })) + } + + _ => return None, + } + } + } + fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr { unsafe { let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name())); @@ -68,7 +127,7 @@ impl Expression for Payload { } } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum LLHeaderField { Daddr, @@ -96,7 +155,24 @@ impl HeaderField for LLHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +impl LLHeaderField { + pub fn from_raw_data(data: &RawPayloadData) -> Option<Self> { + let off = data.offset; + let len = data.len; + + if off == 0 && len == 6 { + Some(Self::Daddr) + } else if off == 6 && len == 6 { + Some(Self::Saddr) + } else if off == 12 && len == 2 { + Some(Self::EtherType) + } else { + None + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum NetworkHeaderField { Ipv4(Ipv4HeaderField), Ipv6(Ipv6HeaderField), @@ -120,7 +196,7 @@ impl HeaderField for NetworkHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum Ipv4HeaderField { Ttl, @@ -151,7 +227,26 @@ impl HeaderField for Ipv4HeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +impl Ipv4HeaderField { + pub fn from_raw_data(data: &RawPayloadData) -> Option<Self> { + let off = data.offset; + let len = data.len; + + if off == 8 && len == 1 { + Some(Self::Ttl) + } else if off == 9 && len == 1 { + Some(Self::Protocol) + } else if off == 12 && len == 4 { + Some(Self::Saddr) + } else if off == 16 && len == 4 { + Some(Self::Daddr) + } else { + None + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum Ipv6HeaderField { NextHeader, @@ -182,7 +277,26 @@ impl HeaderField for Ipv6HeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +impl Ipv6HeaderField { + pub fn from_raw_data(data: &RawPayloadData) -> Option<Self> { + let off = data.offset; + let len = data.len; + + if off == 6 && len == 1 { + Some(Self::NextHeader) + } else if off == 7 && len == 1 { + Some(Self::HopLimit) + } else if off == 8 && len == 16 { + Some(Self::Saddr) + } else if off == 24 && len == 16 { + Some(Self::Daddr) + } else { + None + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum TransportHeaderField { Tcp(TcpHeaderField), @@ -210,7 +324,7 @@ impl HeaderField for TransportHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum TcpHeaderField { Sport, @@ -235,7 +349,22 @@ impl HeaderField for TcpHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +impl TcpHeaderField { + pub fn from_raw_data(data: &RawPayloadData) -> Option<Self> { + let off = data.offset; + let len = data.len; + + if off == 0 && len == 2 { + Some(Self::Sport) + } else if off == 2 && len == 2 { + Some(Self::Dport) + } else { + None + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum UdpHeaderField { Sport, @@ -263,7 +392,24 @@ impl HeaderField for UdpHeaderField { } } -#[derive(Copy, Clone, Eq, PartialEq)] +impl UdpHeaderField { + pub fn from_raw_data(data: &RawPayloadData) -> Option<Self> { + let off = data.offset; + let len = data.len; + + if off == 0 && len == 2 { + Some(Self::Sport) + } else if off == 2 && len == 2 { + Some(Self::Dport) + } else if off == 4 && len == 2 { + Some(Self::Len) + } else { + None + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[non_exhaustive] pub enum Icmpv6HeaderField { Type, @@ -291,6 +437,23 @@ impl HeaderField for Icmpv6HeaderField { } } +impl Icmpv6HeaderField { + pub fn from_raw_data(data: &RawPayloadData) -> Option<Self> { + let off = data.offset; + let len = data.len; + + if off == 0 && len == 1 { + Some(Self::Type) + } else if off == 1 && len == 1 { + Some(Self::Code) + } else if off == 2 && len == 2 { + Some(Self::Checksum) + } else { + None + } + } +} + #[macro_export(local_inner_macros)] macro_rules! nft_expr_payload { (@ipv4_field ttl) => { |