diff options
author | Simon THOBY <git@nightmared.fr> | 2021-10-23 23:02:22 +0200 |
---|---|---|
committer | Simon THOBY <git@nightmared.fr> | 2021-11-02 22:18:12 +0100 |
commit | 7f7b2c3af6e6f7a596a85ada823408bdd0b02118 (patch) | |
tree | 48908226b5252d0e86758fe36d05c1491f080ac1 /rustables/src/expr/mod.rs | |
parent | 82ebb702c1358ac4af40c7ee43efa6f364fa6d50 (diff) |
replace Optionnals by Results for a better error propagation when deserializing expressions
Diffstat (limited to 'rustables/src/expr/mod.rs')
-rw-r--r-- | rustables/src/expr/mod.rs | 122 |
1 files changed, 119 insertions, 3 deletions
diff --git a/rustables/src/expr/mod.rs b/rustables/src/expr/mod.rs index 431a0b9..b20a752 100644 --- a/rustables/src/expr/mod.rs +++ b/rustables/src/expr/mod.rs @@ -3,8 +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}; +use thiserror::Error; mod bitwise; pub use self::bitwise::*; @@ -51,18 +57,47 @@ 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 None if the attempted parsing failed. - fn from_expr(_expr: *const sys::nftnl_expr) -> Option<Self> + /// returning a [DeserializationError] if the attempted parsing failed. + fn from_expr(_expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> where Self: Sized, { - None + Err(DeserializationError::NotImplemented) } /// Allocates and returns the low level `nftnl_expr` representation of this expression. @@ -70,6 +105,87 @@ pub trait 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) => { |