aboutsummaryrefslogtreecommitdiff
path: root/nftnl/src/expr/verdict.rs
diff options
context:
space:
mode:
Diffstat (limited to 'nftnl/src/expr/verdict.rs')
-rw-r--r--nftnl/src/expr/verdict.rs138
1 files changed, 138 insertions, 0 deletions
diff --git a/nftnl/src/expr/verdict.rs b/nftnl/src/expr/verdict.rs
new file mode 100644
index 0000000..35bc893
--- /dev/null
+++ b/nftnl/src/expr/verdict.rs
@@ -0,0 +1,138 @@
+use super::Expression;
+use nftnl_sys::{self as sys, libc::{self, c_char}};
+use std::{ffi::{CStr, CString}};
+
+/// A verdict expression. In the background, this is usually an "Immediate" expression in nftnl
+/// terms, but here it is simplified to only represent a verdict.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub enum Verdict {
+ /// Silently drop the packet.
+ Drop,
+ /// Accept the packet and let it pass.
+ Accept,
+ /// Reject the packet and return a message.
+ Reject,
+ Queue,
+ Continue,
+ Break,
+ Jump {
+ chain: CString,
+ },
+ Goto {
+ chain: CString,
+ },
+ Return,
+}
+
+impl Verdict {
+ fn immediate_const(&self) -> Option<i32> {
+ match *self {
+ Verdict::Drop => Some(libc::NF_DROP),
+ Verdict::Accept => Some(libc::NF_ACCEPT),
+ Verdict::Queue => Some(libc::NF_QUEUE),
+ Verdict::Continue => Some(libc::NFT_CONTINUE),
+ Verdict::Break => Some(libc::NFT_BREAK),
+ Verdict::Jump { .. } => Some(libc::NFT_JUMP),
+ Verdict::Goto { .. } => Some(libc::NFT_GOTO),
+ Verdict::Return => Some(libc::NFT_RETURN),
+ _ => None,
+ }
+ }
+
+ unsafe fn immediate_to_expr(&self, immediate_const: i32) -> *mut sys::nftnl_expr {
+ let expr = try_alloc!(sys::nftnl_expr_alloc(
+ b"immediate\0" as *const _ as *const c_char
+ ));
+
+ sys::nftnl_expr_set_u32(
+ expr,
+ sys::NFTNL_EXPR_IMM_DREG as u16,
+ libc::NFT_REG_VERDICT as u32,
+ );
+
+ if let Some(chain) = self.chain() {
+ sys::nftnl_expr_set_str(expr, sys::NFTNL_EXPR_IMM_CHAIN as u16, chain.as_ptr());
+ }
+ sys::nftnl_expr_set_u32(
+ expr,
+ sys::NFTNL_EXPR_IMM_VERDICT as u16,
+ immediate_const as u32,
+ );
+
+ expr
+ }
+
+ fn chain(&self) -> Option<&CStr> {
+ match *self {
+ Verdict::Jump { ref chain } => Some(chain.as_c_str()),
+ Verdict::Goto { ref chain } => Some(chain.as_c_str()),
+ _ => None,
+ }
+ }
+}
+
+impl Expression for Verdict {
+
+ fn to_expr(&self) -> *mut sys::nftnl_expr {
+ if let Some(immediate_const) = self.immediate_const() {
+ return unsafe { self.immediate_to_expr(immediate_const) };
+ }
+
+ match *self {
+ Verdict::Reject => {
+ unsafe {
+ let expr = try_alloc!(sys::nftnl_expr_alloc(
+ b"reject\0" as *const _ as *const c_char
+ ));
+
+ sys::nftnl_expr_set_u32(
+ expr,
+ sys::NFTNL_EXPR_REJECT_TYPE as u16,
+ libc::NFT_REJECT_ICMPX_UNREACH as u32,
+ );
+
+ // TODO: Allow setting the ICMP code
+ sys::nftnl_expr_set_u8(
+ expr,
+ sys::NFTNL_EXPR_REJECT_CODE as u16,
+ libc::NFT_REJECT_ICMPX_HOST_UNREACH as u8,
+ );
+
+ expr
+ }
+ }
+ _ => unreachable!("unsupported verdict"),
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! nft_expr_verdict {
+ (drop) => {
+ $crate::expr::Verdict::Drop
+ };
+ (accept) => {
+ $crate::expr::Verdict::Accept
+ };
+ (reject) => {
+ $crate::expr::Verdict::Reject
+ };
+ (queue) => {
+ $crate::expr::Verdict::Queue
+ };
+ (continue) => {
+ $crate::expr::Verdict::Continue
+ };
+ (break) => {
+ $crate::expr::Verdict::Break
+ };
+ (jump $chain:expr) => {
+ $crate::expr::Verdict::Jump { chain: $chain }
+ };
+ (goto $chain:expr) => {
+ $crate::expr::Verdict::Goto { chain: $chain }
+ };
+ (return) => {
+ $crate::expr::Verdict::Return
+ };
+}