use rustables_macros::nfnetlink_struct;
use super::{Expression, Register};
use crate::{
error::DecodeError,
sys::{self, NFT_PAYLOAD_LL_HEADER, NFT_PAYLOAD_NETWORK_HEADER, NFT_PAYLOAD_TRANSPORT_HEADER},
};
#[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"
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum HighLevelPayload {
LinkLayer(LLHeaderField),
Network(NetworkHeaderField),
Transport(TransportHeaderField),
}
impl HighLevelPayload {
pub fn build(&self) -> Payload {
match *self {
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)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PayloadType {
LinkLayer(LLHeaderField),
Network,
Transport,
}
impl PayloadType {
pub fn parse_from_payload(raw: &Payload) -> Result<Self, DecodeError> {
if raw.base.is_none() {
return Err(DecodeError::PayloadMissingBase);
}
if raw.len.is_none() {
return Err(DecodeError::PayloadMissingLen);
}
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),
})
}
}
pub trait HeaderField {
fn offset(&self) -> u32;
fn len(&self) -> u32;
}
#[derive(Debug, 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,
}
}
}
impl LLHeaderField {
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),
}
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(Debug, 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,
}
}
}
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 {
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,
}
}
}
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),
}
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(Debug, 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,
}
}
}
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 {
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,
}
}
}
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 {
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,
}
}
}
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)),
})
}
}