aboutsummaryrefslogtreecommitdiff
path: root/rustables/src/expr/payload.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rustables/src/expr/payload.rs')
-rw-r--r--rustables/src/expr/payload.rs221
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) => {