aboutsummaryrefslogtreecommitdiff
path: root/rustables/src/expr/mod.rs
diff options
context:
space:
mode:
authorSimon THOBY <git@nightmared.fr>2021-10-23 23:02:22 +0200
committerSimon THOBY <git@nightmared.fr>2021-11-02 22:18:12 +0100
commit7f7b2c3af6e6f7a596a85ada823408bdd0b02118 (patch)
tree48908226b5252d0e86758fe36d05c1491f080ac1 /rustables/src/expr/mod.rs
parent82ebb702c1358ac4af40c7ee43efa6f364fa6d50 (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.rs122
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) => {