-
Notifications
You must be signed in to change notification settings - Fork 29
/
Copy pathchain.rs
195 lines (179 loc) · 6.51 KB
/
chain.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
use crate::{MsgType, Table};
use nftnl_sys::{self as sys, libc};
use std::{
ffi::{c_void, CStr},
fmt,
os::raw::c_char,
};
pub type Priority = i32;
/// The netfilter event hooks a chain can register for.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(u16)]
pub enum Hook {
/// Hook into the pre-routing stage of netfilter. Corresponds to `NF_INET_PRE_ROUTING`.
PreRouting = libc::NF_INET_PRE_ROUTING as u16,
/// Hook into the input stage of netfilter. Corresponds to `NF_INET_LOCAL_IN`.
In = libc::NF_INET_LOCAL_IN as u16,
/// Hook into the forward stage of netfilter. Corresponds to `NF_INET_FORWARD`.
Forward = libc::NF_INET_FORWARD as u16,
/// Hook into the output stage of netfilter. Corresponds to `NF_INET_LOCAL_OUT`.
Out = libc::NF_INET_LOCAL_OUT as u16,
/// Hook into the post-routing stage of netfilter. Corresponds to `NF_INET_POST_ROUTING`.
PostRouting = libc::NF_INET_POST_ROUTING as u16,
}
/// A chain policy. Decides what to do with a packet that was processed by the chain but did not
/// match any rules.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(u32)]
pub enum Policy {
/// Accept the packet.
Accept = libc::NF_ACCEPT as u32,
/// Drop the packet.
Drop = libc::NF_DROP as u32,
}
/// Base chain type.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum ChainType {
/// Used to filter packets.
/// Supported protocols: ip, ip6, inet, arp, and bridge tables.
Filter,
/// Used to reroute packets if IP headers or packet marks are modified.
/// Supported protocols: ip, and ip6 tables.
Route,
/// Used to perform NAT.
/// Supported protocols: ip, and ip6 tables.
Nat,
}
impl ChainType {
fn as_c_str(&self) -> &'static [u8] {
match *self {
ChainType::Filter => b"filter\0",
ChainType::Route => b"route\0",
ChainType::Nat => b"nat\0",
}
}
}
/// Abstraction of a `nftnl_chain`. Chains reside inside [`Table`]s and they hold [`Rule`]s.
///
/// There are two types of chains, "base chain" and "regular chain". See [`set_hook`] for more
/// details.
///
/// [`Table`]: struct.Table.html
/// [`Rule`]: struct.Rule.html
/// [`set_hook`]: #method.set_hook
pub struct Chain<'a> {
chain: *mut sys::nftnl_chain,
table: &'a Table,
}
// Safety: It should be safe to pass this around and *read* from it
// from multiple threads
unsafe impl Send for Chain<'_> {}
unsafe impl Sync for Chain<'_> {}
impl<'a> Chain<'a> {
/// Creates a new chain instance inside the given [`Table`] and with the given name.
///
/// [`Table`]: struct.Table.html
pub fn new<T: AsRef<CStr>>(name: &T, table: &'a Table) -> Chain<'a> {
unsafe {
let chain = try_alloc!(sys::nftnl_chain_alloc());
sys::nftnl_chain_set_u32(
chain,
sys::NFTNL_CHAIN_FAMILY as u16,
table.get_family() as u32,
);
sys::nftnl_chain_set_str(
chain,
sys::NFTNL_CHAIN_TABLE as u16,
table.get_name().as_ptr(),
);
sys::nftnl_chain_set_str(chain, sys::NFTNL_CHAIN_NAME as u16, name.as_ref().as_ptr());
Chain { chain, table }
}
}
/// Sets the hook and priority for this chain. Without calling this method the chain well
/// become a "regular chain" without any hook and will thus not receive any traffic unless
/// some rule forward packets to it via goto or jump verdicts.
///
/// By calling `set_hook` with a hook the chain that is created will be registered with that
/// hook and is thus a "base chain". A "base chain" is an entry point for packets from the
/// networking stack.
pub fn set_hook(&mut self, hook: Hook, priority: Priority) {
unsafe {
sys::nftnl_chain_set_u32(self.chain, sys::NFTNL_CHAIN_HOOKNUM as u16, hook as u32);
sys::nftnl_chain_set_s32(self.chain, sys::NFTNL_CHAIN_PRIO as u16, priority);
}
}
/// Set the type of a base chain. This only applies if the chain has been registered
/// with a hook by calling `set_hook`.
pub fn set_type(&mut self, chain_type: ChainType) {
unsafe {
sys::nftnl_chain_set_str(
self.chain,
sys::NFTNL_CHAIN_TYPE as u16,
chain_type.as_c_str().as_ptr() as *const c_char,
);
}
}
/// Sets the default policy for this chain. That means what action netfilter will apply to
/// packets processed by this chain, but that did not match any rules in it.
pub fn set_policy(&mut self, policy: Policy) {
unsafe {
sys::nftnl_chain_set_u32(self.chain, sys::NFTNL_CHAIN_POLICY as u16, policy as u32);
}
}
/// Returns the name of this chain.
pub fn get_name(&self) -> &CStr {
unsafe {
let ptr = sys::nftnl_chain_get_str(self.chain, sys::NFTNL_CHAIN_NAME as u16);
CStr::from_ptr(ptr)
}
}
/// Returns a reference to the [`Table`] this chain belongs to
///
/// [`Table`]: struct.Table.html
pub fn get_table(&self) -> &Table {
self.table
}
}
impl fmt::Debug for Chain<'_> {
/// Return a string representation of the chain.
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut buffer: [u8; 4096] = [0; 4096];
unsafe {
sys::nftnl_chain_snprintf(
buffer.as_mut_ptr() as *mut c_char,
buffer.len(),
self.chain,
sys::NFTNL_OUTPUT_DEFAULT,
0,
);
}
let s = unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) };
write!(fmt, "{:?}", s)
}
}
unsafe impl crate::NlMsg for Chain<'_> {
unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
let raw_msg_type = match msg_type {
MsgType::Add => libc::NFT_MSG_NEWCHAIN,
MsgType::Del => libc::NFT_MSG_DELCHAIN,
};
let flags: u16 = match msg_type {
MsgType::Add => (libc::NLM_F_ACK | libc::NLM_F_CREATE) as u16,
MsgType::Del => libc::NLM_F_ACK as u16,
};
let header = sys::nftnl_nlmsg_build_hdr(
buf as *mut c_char,
raw_msg_type as u16,
self.table.get_family() as u16,
flags,
seq,
);
sys::nftnl_chain_nlmsg_build_payload(header, self.chain);
}
}
impl Drop for Chain<'_> {
fn drop(&mut self) {
unsafe { sys::nftnl_chain_free(self.chain) };
}
}