aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-05-27 13:46:27 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-05-27 13:46:27 +0200
commit343727fdede3d7c2e6f5338d2267be41295859f1 (patch)
tree5279811faba137994c5175ac3b78ab7448721f3a
parent39982629ee8c4bc129f3a80b844d9d3d9486d5d7 (diff)
parentaccce17a2becb7310a91c8632551c48c49b67554 (diff)
Merge branch 'add-reject-expr'
-rw-r--r--CHANGELOG.md2
-rw-r--r--nftnl/src/expr/bitwise.rs4
-rw-r--r--nftnl/src/expr/cmp.rs4
-rw-r--r--nftnl/src/expr/counter.rs4
-rw-r--r--nftnl/src/expr/ct.rs4
-rw-r--r--nftnl/src/expr/immediate.rs104
-rw-r--r--nftnl/src/expr/lookup.rs4
-rw-r--r--nftnl/src/expr/masquerade.rs4
-rw-r--r--nftnl/src/expr/meta.rs4
-rw-r--r--nftnl/src/expr/mod.rs6
-rw-r--r--nftnl/src/expr/payload.rs4
-rw-r--r--nftnl/src/expr/verdict.rs175
-rw-r--r--nftnl/src/lib.rs2
-rw-r--r--nftnl/src/rule.rs2
14 files changed, 203 insertions, 120 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8df81e0..d4e44d4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
+### Added
+- Add `Reject` verdict for responding with ICMP packets or TCP RST to the origin.
## [0.3.0] - 2020-04-20
diff --git a/nftnl/src/expr/bitwise.rs b/nftnl/src/expr/bitwise.rs
index f017899..be2a0cf 100644
--- a/nftnl/src/expr/bitwise.rs
+++ b/nftnl/src/expr/bitwise.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use crate::expr::cmp::ToSlice;
use libc;
use nftnl_sys::{
@@ -21,7 +21,7 @@ impl<M: ToSlice, X: ToSlice> Bitwise<M, X> {
}
impl<M: ToSlice, X: ToSlice> Expression for Bitwise<M, X> {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
unsafe {
let expr = try_alloc!(sys::nftnl_expr_alloc(
b"bitwise\0" as *const _ as *const c_char
diff --git a/nftnl/src/expr/cmp.rs b/nftnl/src/expr/cmp.rs
index 838c079..36bcc25 100644
--- a/nftnl/src/expr/cmp.rs
+++ b/nftnl/src/expr/cmp.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use libc;
use nftnl_sys::{
self as sys,
@@ -59,7 +59,7 @@ impl<T: ToSlice> Cmp<T> {
}
impl<T: ToSlice> Expression for Cmp<T> {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
unsafe {
let expr = try_alloc!(sys::nftnl_expr_alloc(b"cmp\0" as *const _ as *const c_char));
diff --git a/nftnl/src/expr/counter.rs b/nftnl/src/expr/counter.rs
index 822a714..3f1415c 100644
--- a/nftnl/src/expr/counter.rs
+++ b/nftnl/src/expr/counter.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use nftnl_sys::{self as sys, libc::c_char};
/// A counter expression adds a counter to the rule that is incremented to count number of packets
@@ -6,7 +6,7 @@ use nftnl_sys::{self as sys, libc::c_char};
pub struct Counter;
impl Expression for Counter {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
try_alloc!(unsafe { sys::nftnl_expr_alloc(b"counter\0" as *const _ as *const c_char) })
}
}
diff --git a/nftnl/src/expr/ct.rs b/nftnl/src/expr/ct.rs
index 65b47bc..97e61a3 100644
--- a/nftnl/src/expr/ct.rs
+++ b/nftnl/src/expr/ct.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use libc;
use nftnl_sys::{self as sys, libc::c_char};
@@ -27,7 +27,7 @@ impl Conntrack {
}
impl Expression for Conntrack {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
unsafe {
let expr = try_alloc!(sys::nftnl_expr_alloc(b"ct\0" as *const _ as *const c_char));
diff --git a/nftnl/src/expr/immediate.rs b/nftnl/src/expr/immediate.rs
index 0e89abc..f0e0c2c 100644
--- a/nftnl/src/expr/immediate.rs
+++ b/nftnl/src/expr/immediate.rs
@@ -1,7 +1,7 @@
-use super::Expression;
+use super::{Expression, Rule};
use libc;
use nftnl_sys::{self as sys, libc::{c_char, c_void}};
-use std::{ffi::{CStr, CString}, mem::size_of_val};
+use std::mem::size_of_val;
/// An immediate expression. Used to set immediate data.
/// Verdicts are handled separately by [Verdict].
@@ -11,7 +11,7 @@ pub struct Immediate<T> {
}
impl<T> Expression for Immediate<T> {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
unsafe {
let expr = try_alloc!(sys::nftnl_expr_alloc(
b"immediate\0" as *const _ as *const c_char
@@ -41,101 +41,3 @@ macro_rules! nft_expr_immediate {
$crate::expr::Immediate { data: $value }
};
}
-
-/// A verdict expression. In the background actually an "Immediate" expression in nftnl terms,
-/// but here it's 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,
- Queue,
- Continue,
- Break,
- Jump {
- chain: CString,
- },
- Goto {
- chain: CString,
- },
- Return,
-}
-
-impl Verdict {
- fn verdict_const(&self) -> i32 {
- match *self {
- Verdict::Drop => libc::NF_DROP,
- Verdict::Accept => libc::NF_ACCEPT,
- Verdict::Queue => libc::NF_QUEUE,
- Verdict::Continue => libc::NFT_CONTINUE,
- Verdict::Break => libc::NFT_BREAK,
- Verdict::Jump { .. } => libc::NFT_JUMP,
- Verdict::Goto { .. } => libc::NFT_GOTO,
- Verdict::Return => libc::NFT_RETURN,
- }
- }
-
- 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 {
- unsafe {
- 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,
- self.verdict_const() as u32,
- );
-
- expr
- }
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_verdict {
- (drop) => {
- $crate::expr::Verdict::Drop
- };
- (accept) => {
- $crate::expr::Verdict::Accept
- };
- (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
- };
-}
diff --git a/nftnl/src/expr/lookup.rs b/nftnl/src/expr/lookup.rs
index 08fccf5..449d52a 100644
--- a/nftnl/src/expr/lookup.rs
+++ b/nftnl/src/expr/lookup.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use crate::set::Set;
use libc;
use nftnl_sys::{self as sys, libc::c_char};
@@ -19,7 +19,7 @@ impl Lookup {
}
impl Expression for Lookup {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
unsafe {
let expr = try_alloc!(sys::nftnl_expr_alloc(
b"lookup\0" as *const _ as *const c_char
diff --git a/nftnl/src/expr/masquerade.rs b/nftnl/src/expr/masquerade.rs
index e6684c2..d136a65 100644
--- a/nftnl/src/expr/masquerade.rs
+++ b/nftnl/src/expr/masquerade.rs
@@ -1,11 +1,11 @@
-use super::Expression;
+use super::{Expression, Rule};
use nftnl_sys::{self as sys, libc::c_char};
/// Sets the source IP to that of the output interface.
pub struct Masquerade;
impl Expression for Masquerade {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
try_alloc!(unsafe { sys::nftnl_expr_alloc(b"masq\0" as *const _ as *const c_char) })
}
}
diff --git a/nftnl/src/expr/meta.rs b/nftnl/src/expr/meta.rs
index 8b3218d..49a3c3f 100644
--- a/nftnl/src/expr/meta.rs
+++ b/nftnl/src/expr/meta.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use libc;
use nftnl_sys::{self as sys, libc::c_char};
@@ -52,7 +52,7 @@ impl Meta {
}
impl Expression for Meta {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
unsafe {
let expr = try_alloc!(sys::nftnl_expr_alloc(
b"meta\0" as *const _ as *const c_char
diff --git a/nftnl/src/expr/mod.rs b/nftnl/src/expr/mod.rs
index 84d7035..e4c4adb 100644
--- a/nftnl/src/expr/mod.rs
+++ b/nftnl/src/expr/mod.rs
@@ -3,13 +3,14 @@
//!
//! [`Rule`]: struct.Rule.html
+use super::rule::Rule;
use nftnl_sys as sys;
/// 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) -> *mut sys::nftnl_expr;
+ fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr;
}
mod bitwise;
@@ -39,6 +40,9 @@ pub use self::meta::*;
mod payload;
pub use self::payload::*;
+mod verdict;
+pub use self::verdict::*;
+
#[macro_export(local_inner_macros)]
macro_rules! nft_expr {
(bitwise mask $mask:expr,xor $xor:expr) => {
diff --git a/nftnl/src/expr/payload.rs b/nftnl/src/expr/payload.rs
index 83ce7a7..45e5955 100644
--- a/nftnl/src/expr/payload.rs
+++ b/nftnl/src/expr/payload.rs
@@ -1,4 +1,4 @@
-use super::Expression;
+use super::{Expression, Rule};
use libc;
use nftnl_sys::{self as sys, libc::c_char};
@@ -47,7 +47,7 @@ impl HeaderField for Payload {
}
impl Expression for Payload {
- fn to_expr(&self) -> *mut sys::nftnl_expr {
+ 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
diff --git a/nftnl/src/expr/verdict.rs b/nftnl/src/expr/verdict.rs
new file mode 100644
index 0000000..1395a94
--- /dev/null
+++ b/nftnl/src/expr/verdict.rs
@@ -0,0 +1,175 @@
+use super::{Expression, Rule};
+use crate::ProtoFamily;
+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(RejectionType),
+ Queue,
+ Continue,
+ Break,
+ Jump {
+ chain: CString,
+ },
+ Goto {
+ chain: CString,
+ },
+ Return,
+}
+
+/// The type of rejection message sent by the Reject verdict.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+pub enum RejectionType {
+ /// Return an ICMP unreachable packet
+ Icmp(IcmpCode),
+ /// Reject by sending a TCP RST packet
+ TcpRst,
+}
+
+impl RejectionType {
+ fn to_raw(&self, family: ProtoFamily) -> u32 {
+ use libc::*;
+ let value = match *self {
+ RejectionType::Icmp(..) => match family {
+ ProtoFamily::Bridge | ProtoFamily::Inet => NFT_REJECT_ICMPX_UNREACH,
+ _ => NFT_REJECT_ICMP_UNREACH,
+ },
+ RejectionType::TcpRst => NFT_REJECT_TCP_RST,
+ };
+ value as u32
+ }
+}
+
+/// An ICMP reject code.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+#[repr(u8)]
+pub enum IcmpCode {
+ NoRoute = libc::NFT_REJECT_ICMPX_NO_ROUTE as u8,
+ PortUnreach = libc::NFT_REJECT_ICMPX_PORT_UNREACH as u8,
+ HostUnreach = libc::NFT_REJECT_ICMPX_HOST_UNREACH as u8,
+ AdminProhibited = libc::NFT_REJECT_ICMPX_ADMIN_PROHIBITED as u8,
+}
+
+impl Verdict {
+ unsafe fn to_immediate_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
+ }
+
+ unsafe fn to_reject_expr(
+ &self,
+ reject_type: RejectionType,
+ family: ProtoFamily,
+ ) -> *mut sys::nftnl_expr {
+ 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,
+ reject_type.to_raw(family),
+ );
+
+ let reject_code = match reject_type {
+ RejectionType::Icmp(code) => code as u8,
+ RejectionType::TcpRst => 0,
+ };
+
+ sys::nftnl_expr_set_u8(expr, sys::NFTNL_EXPR_REJECT_CODE as u16, reject_code);
+
+ 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, rule: &Rule) -> *mut sys::nftnl_expr {
+ let immediate_const = match *self {
+ Verdict::Drop => libc::NF_DROP,
+ Verdict::Accept => libc::NF_ACCEPT,
+ Verdict::Queue => libc::NF_QUEUE,
+ Verdict::Continue => libc::NFT_CONTINUE,
+ Verdict::Break => libc::NFT_BREAK,
+ Verdict::Jump { .. } => libc::NFT_JUMP,
+ Verdict::Goto { .. } => libc::NFT_GOTO,
+ Verdict::Return => libc::NFT_RETURN,
+ Verdict::Reject(reject_type) => {
+ return unsafe {
+ self.to_reject_expr(reject_type, rule.get_chain().get_table().get_family())
+ }
+ }
+ };
+ unsafe { self.to_immediate_expr(immediate_const) }
+ }
+}
+
+#[macro_export]
+macro_rules! nft_expr_verdict {
+ (drop) => {
+ $crate::expr::Verdict::Drop
+ };
+ (accept) => {
+ $crate::expr::Verdict::Accept
+ };
+ (reject icmp $code:expr) => {
+ $crate::expr::Verdict::Reject(RejectionType::Icmp($code))
+ };
+ (reject tcp-rst) => {
+ $crate::expr::Verdict::Reject(RejectionType::TcpRst)
+ };
+ (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
+ };
+}
diff --git a/nftnl/src/lib.rs b/nftnl/src/lib.rs
index e47a600..31375bf 100644
--- a/nftnl/src/lib.rs
+++ b/nftnl/src/lib.rs
@@ -87,7 +87,7 @@ pub enum MsgType {
}
/// Denotes a protocol. Used to specify which protocol a table or set belongs to.
-#[derive(Debug, Copy, Clone)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(u16)]
pub enum ProtoFamily {
Unspec = libc::NFPROTO_UNSPEC as u16,
diff --git a/nftnl/src/rule.rs b/nftnl/src/rule.rs
index 77a0e1c..18f1084 100644
--- a/nftnl/src/rule.rs
+++ b/nftnl/src/rule.rs
@@ -53,7 +53,7 @@ impl<'a> Rule<'a> {
/// As soon as an expression does not match the packet it's being evaluated for, evaluation
/// stops and the packet is evaluated against the next rule in the chain.
pub fn add_expr(&mut self, expr: &impl Expression) {
- unsafe { sys::nftnl_rule_add_expr(self.rule, expr.to_expr()) }
+ unsafe { sys::nftnl_rule_add_expr(self.rule, expr.to_expr(self)) }
}
/// Returns a reference to the [`Chain`] this rule lives in.