diff options
Diffstat (limited to 'rustables/src/expr/mod.rs')
-rw-r--r-- | rustables/src/expr/mod.rs | 170 |
1 files changed, 145 insertions, 25 deletions
diff --git a/rustables/src/expr/mod.rs b/rustables/src/expr/mod.rs index 99ea44b..b20a752 100644 --- a/rustables/src/expr/mod.rs +++ b/rustables/src/expr/mod.rs @@ -3,32 +3,14 @@ //! //! [`Rule`]: struct.Rule.html +use std::borrow::Cow; +use std::net::IpAddr; +use std::net::Ipv4Addr; +use std::net::Ipv6Addr; + use super::rule::Rule; use rustables_sys::{self as sys, libc}; - -/// Trait for every safe wrapper of an nftables expression. -pub trait Expression { - /// Allocates and returns the low level `nftnl_expr` representation of this expression. - /// The caller to this method is responsible for freeing the expression. - fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr; -} - -/// A netfilter data register. The expressions store and read data to and from these -/// when evaluating rule statements. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -#[repr(i32)] -pub enum Register { - Reg1 = libc::NFT_REG_1, - Reg2 = libc::NFT_REG_2, - Reg3 = libc::NFT_REG_3, - Reg4 = libc::NFT_REG_4, -} - -impl Register { - pub fn to_raw(self) -> u32 { - self as u32 - } -} +use thiserror::Error; mod bitwise; pub use self::bitwise::*; @@ -63,9 +45,147 @@ pub use self::nat::*; mod payload; pub use self::payload::*; +mod reject; +pub use self::reject::{IcmpCode, Reject}; + +mod register; +pub use self::register::Register; + mod verdict; pub use self::verdict::*; +mod wrapper; +pub use self::wrapper::ExpressionWrapper; + +#[derive(Debug, Error)] +pub enum DeserializationError { + #[error("The expected expression type doesn't match the name of the raw expression")] + /// The expected expression type doesn't match the name of the raw expression + InvalidExpressionKind, + + #[error("Deserializing the requested type isn't implemented yet")] + /// Deserializing the requested type isn't implemented yet + NotImplemented, + + #[error("The expression value cannot be deserialized to the requested type")] + /// The expression value cannot be deserialized to the requested type + InvalidValue, + + #[error("A pointer was null while a non-null pointer was expected")] + /// A pointer was null while a non-null pointer was expected + NullPointer, + + #[error( + "The size of a raw value was incoherent with the expected type of the deserialized value" + )] + /// The size of a raw value was incoherent with the expected type of the deserialized value + InvalidDataSize, + + #[error(transparent)] + /// Couldn't find a matching protocol + InvalidProtolFamily(#[from] super::InvalidProtocolFamily), +} + +/// Trait for every safe wrapper of an nftables expression. +pub trait Expression { + /// Returns the raw name used by nftables to identify the rule. + fn get_raw_name() -> *const libc::c_char; + + /// Try to parse the expression from a raw nftables expression, + /// returning a [DeserializationError] if the attempted parsing failed. + fn from_expr(_expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> + where + Self: Sized, + { + Err(DeserializationError::NotImplemented) + } + + /// Allocates and returns the low level `nftnl_expr` representation of this expression. + /// The caller to this method is responsible for freeing the expression. + fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr; +} + +/// A type that can be converted into a byte buffer. +pub trait ToSlice { + /// Returns the data this type represents. + fn to_slice(&self) -> Cow<'_, [u8]>; +} + +impl<'a> ToSlice for &'a [u8] { + fn to_slice(&self) -> Cow<'_, [u8]> { + Cow::Borrowed(self) + } +} + +impl<'a> ToSlice for &'a [u16] { + fn to_slice(&self) -> Cow<'_, [u8]> { + let ptr = self.as_ptr() as *const u8; + let len = self.len() * 2; + Cow::Borrowed(unsafe { std::slice::from_raw_parts(ptr, len) }) + } +} + +impl ToSlice for IpAddr { + fn to_slice(&self) -> Cow<'_, [u8]> { + match *self { + IpAddr::V4(ref addr) => addr.to_slice(), + IpAddr::V6(ref addr) => addr.to_slice(), + } + } +} + +impl ToSlice for Ipv4Addr { + fn to_slice(&self) -> Cow<'_, [u8]> { + Cow::Owned(self.octets().to_vec()) + } +} + +impl ToSlice for Ipv6Addr { + fn to_slice(&self) -> Cow<'_, [u8]> { + Cow::Owned(self.octets().to_vec()) + } +} + +impl ToSlice for u8 { + fn to_slice(&self) -> Cow<'_, [u8]> { + Cow::Owned(vec![*self]) + } +} + +impl ToSlice for u16 { + fn to_slice(&self) -> Cow<'_, [u8]> { + let b0 = (*self & 0x00ff) as u8; + let b1 = (*self >> 8) as u8; + Cow::Owned(vec![b0, b1]) + } +} + +impl ToSlice for u32 { + fn to_slice(&self) -> Cow<'_, [u8]> { + let b0 = *self as u8; + let b1 = (*self >> 8) as u8; + let b2 = (*self >> 16) as u8; + let b3 = (*self >> 24) as u8; + Cow::Owned(vec![b0, b1, b2, b3]) + } +} + +impl ToSlice for i32 { + fn to_slice(&self) -> Cow<'_, [u8]> { + let b0 = *self as u8; + let b1 = (*self >> 8) as u8; + let b2 = (*self >> 16) as u8; + let b3 = (*self >> 24) as u8; + Cow::Owned(vec![b0, b1, b2, b3]) + } +} + +impl<'a> ToSlice for &'a str { + fn to_slice(&self) -> Cow<'_, [u8]> { + Cow::from(self.as_bytes()) + } +} + #[macro_export(local_inner_macros)] macro_rules! nft_expr { (bitwise mask $mask:expr,xor $xor:expr) => { @@ -75,7 +195,7 @@ macro_rules! nft_expr { nft_expr_cmp!($op $data) }; (counter) => { - $crate::expr::Counter + $crate::expr::Counter { nb_bytes: 0, nb_packets: 0} }; (ct $key:ident set) => { nft_expr_ct!($key set) |