diff options
Diffstat (limited to 'rustables/src/expr/payload.rs')
-rw-r--r-- | rustables/src/expr/payload.rs | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/rustables/src/expr/payload.rs b/rustables/src/expr/payload.rs new file mode 100644 index 0000000..2da4e1f --- /dev/null +++ b/rustables/src/expr/payload.rs @@ -0,0 +1,368 @@ +use super::{Expression, Rule}; +use rustables_sys::{self as sys, libc}; +use std::os::raw::c_char; + +trait HeaderField { + fn offset(&self) -> u32; + fn len(&self) -> u32; +} + +/// Payload expressions refer to data from the packet's payload. +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum Payload { + LinkLayer(LLHeaderField), + Network(NetworkHeaderField), + Transport(TransportHeaderField), +} + +impl Payload { + 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, + } + } +} + +impl HeaderField for Payload { + fn offset(&self) -> u32 { + use self::Payload::*; + match *self { + LinkLayer(ref f) => f.offset(), + Network(ref f) => f.offset(), + 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(), + } + } +} + +impl Expression for Payload { + 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 + )); + + 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 + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum LLHeaderField { + Daddr, + Saddr, + EtherType, +} + +impl HeaderField for LLHeaderField { + fn offset(&self) -> u32 { + use self::LLHeaderField::*; + match *self { + Daddr => 0, + Saddr => 6, + EtherType => 12, + } + } + + fn len(&self) -> u32 { + use self::LLHeaderField::*; + match *self { + Daddr => 6, + Saddr => 6, + EtherType => 2, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum NetworkHeaderField { + 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(), + } + } + + fn len(&self) -> u32 { + use self::NetworkHeaderField::*; + match *self { + Ipv4(ref f) => f.len(), + Ipv6(ref f) => f.len(), + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum Ipv4HeaderField { + Ttl, + Protocol, + Saddr, + Daddr, +} + +impl HeaderField for Ipv4HeaderField { + fn offset(&self) -> u32 { + use self::Ipv4HeaderField::*; + match *self { + Ttl => 8, + Protocol => 9, + Saddr => 12, + Daddr => 16, + } + } + + fn len(&self) -> u32 { + use self::Ipv4HeaderField::*; + match *self { + Ttl => 1, + Protocol => 1, + Saddr => 4, + Daddr => 4, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum Ipv6HeaderField { + NextHeader, + HopLimit, + Saddr, + Daddr, +} + +impl HeaderField for Ipv6HeaderField { + fn offset(&self) -> u32 { + use self::Ipv6HeaderField::*; + match *self { + NextHeader => 6, + HopLimit => 7, + Saddr => 8, + Daddr => 24, + } + } + + fn len(&self) -> u32 { + use self::Ipv6HeaderField::*; + match *self { + NextHeader => 1, + HopLimit => 1, + Saddr => 16, + Daddr => 16, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum TransportHeaderField { + Tcp(TcpHeaderField), + Udp(UdpHeaderField), + Icmpv6(Icmpv6HeaderField), +} + +impl HeaderField for TransportHeaderField { + fn offset(&self) -> u32 { + use self::TransportHeaderField::*; + match *self { + Tcp(ref f) => f.offset(), + Udp(ref f) => f.offset(), + Icmpv6(ref f) => f.offset(), + } + } + + fn len(&self) -> u32 { + use self::TransportHeaderField::*; + match *self { + Tcp(ref f) => f.len(), + Udp(ref f) => f.len(), + Icmpv6(ref f) => f.len(), + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum TcpHeaderField { + Sport, + Dport, +} + +impl HeaderField for TcpHeaderField { + fn offset(&self) -> u32 { + use self::TcpHeaderField::*; + match *self { + Sport => 0, + Dport => 2, + } + } + + fn len(&self) -> u32 { + use self::TcpHeaderField::*; + match *self { + Sport => 2, + Dport => 2, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum UdpHeaderField { + Sport, + Dport, + Len, +} + +impl HeaderField for UdpHeaderField { + fn offset(&self) -> u32 { + use self::UdpHeaderField::*; + match *self { + Sport => 0, + Dport => 2, + Len => 4, + } + } + + fn len(&self) -> u32 { + use self::UdpHeaderField::*; + match *self { + Sport => 2, + Dport => 2, + Len => 2, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +#[non_exhaustive] +pub enum Icmpv6HeaderField { + Type, + Code, + Checksum, +} + +impl HeaderField for Icmpv6HeaderField { + fn offset(&self) -> u32 { + use self::Icmpv6HeaderField::*; + match *self { + Type => 0, + Code => 1, + Checksum => 2, + } + } + + fn len(&self) -> u32 { + use self::Icmpv6HeaderField::*; + match *self { + Type => 1, + Code => 1, + Checksum => 2, + } + } +} + +#[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), + )) + }; +} |