1use netlink_packet_core::{
4 DecodeError, DefaultNla, Emitable, ErrorContext, NetlinkDeserializable,
5 NetlinkHeader, NetlinkPayload, NetlinkSerializable, ParseableParametrized,
6};
7use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
8
9use crate::{
10 conntrack::ConntrackMessage, nflog::ULogMessage, nftables::NfTablesMessage,
11 none::ControlMessage,
12};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17#[non_exhaustive]
18pub enum NetfilterProtoFamily {
19 Unspec,
20 Inet,
21 IPv4,
22 ARP,
23 NetDev,
24 Bridge,
25 IPv6,
26 DECNet,
27 Other(u8),
28}
29
30const NFPROTO_UNSPEC: u8 = 0;
31const NFPROTO_INET: u8 = 1;
32const NFPROTO_IPV4: u8 = 2;
33const NFPROTO_ARP: u8 = 3;
34const NFPROTO_NETDEV: u8 = 5;
35const NFPROTO_BRIDGE: u8 = 7;
36const NFPROTO_IPV6: u8 = 10;
37const NFPROTO_DECNET: u8 = 12;
38
39impl From<NetfilterProtoFamily> for u8 {
40 fn from(proto_family: NetfilterProtoFamily) -> Self {
41 match proto_family {
42 NetfilterProtoFamily::Unspec => NFPROTO_UNSPEC,
43 NetfilterProtoFamily::Inet => NFPROTO_INET,
44 NetfilterProtoFamily::IPv4 => NFPROTO_IPV4,
45 NetfilterProtoFamily::ARP => NFPROTO_ARP,
46 NetfilterProtoFamily::NetDev => NFPROTO_NETDEV,
47 NetfilterProtoFamily::Bridge => NFPROTO_BRIDGE,
48 NetfilterProtoFamily::IPv6 => NFPROTO_IPV6,
49 NetfilterProtoFamily::DECNet => NFPROTO_DECNET,
50 NetfilterProtoFamily::Other(p) => p,
51 }
52 }
53}
54
55impl From<u8> for NetfilterProtoFamily {
56 fn from(proto_family_num: u8) -> Self {
57 match proto_family_num {
58 NFPROTO_UNSPEC => NetfilterProtoFamily::Unspec,
59 NFPROTO_INET => NetfilterProtoFamily::Inet,
60 NFPROTO_IPV4 => NetfilterProtoFamily::IPv4,
61 NFPROTO_ARP => NetfilterProtoFamily::ARP,
62 NFPROTO_NETDEV => NetfilterProtoFamily::NetDev,
63 NFPROTO_BRIDGE => NetfilterProtoFamily::Bridge,
64 NFPROTO_IPV6 => NetfilterProtoFamily::IPv6,
65 NFPROTO_DECNET => NetfilterProtoFamily::DECNet,
66 _ => NetfilterProtoFamily::Other(proto_family_num),
67 }
68 }
69}
70
71pub(crate) const NETFILTER_HEADER_LEN: usize = 4;
72
73#[derive(
74 Debug,
75 PartialEq,
76 Eq,
77 Clone,
78 FromBytes,
79 IntoBytes,
80 KnownLayout,
81 Immutable,
82 Unaligned,
83)]
84#[repr(C, packed)]
85pub struct NetfilterHeaderBuffer {
86 family: u8,
87 version: u8,
88 res_id: u16,
89}
90
91#[derive(Clone, Debug, PartialEq, Eq)]
92#[non_exhaustive]
93pub struct NetfilterHeader {
94 pub family: NetfilterProtoFamily,
95 pub version: u8,
96 pub res_id: u16,
97}
98
99impl NetfilterHeader {
100 pub fn new(family: NetfilterProtoFamily, version: u8, res_id: u16) -> Self {
101 Self {
102 family,
103 version,
104 res_id,
105 }
106 }
107
108 pub fn parse(payload: &[u8]) -> Result<Self, DecodeError> {
109 let (raw, _) = NetfilterHeaderBuffer::ref_from_prefix(payload)
110 .map_err(|_| {
111 DecodeError::buffer_too_small(
112 payload.len(),
113 NETFILTER_HEADER_LEN,
114 )
115 })?;
116 Ok(Self {
117 family: raw.family.into(),
118 version: raw.version,
119 res_id: u16::from_be(raw.res_id),
120 })
121 }
122}
123
124impl From<&NetfilterHeader> for NetfilterHeaderBuffer {
125 fn from(header: &NetfilterHeader) -> Self {
126 Self {
127 family: header.family.into(),
128 version: header.version,
129 res_id: header.res_id.to_be(),
130 }
131 }
132}
133
134impl Emitable for NetfilterHeader {
135 fn buffer_len(&self) -> usize {
136 NETFILTER_HEADER_LEN
137 }
138
139 fn emit(&self, buf: &mut [u8]) {
140 let raw = NetfilterHeaderBuffer::from(self);
141 buf[..NETFILTER_HEADER_LEN].copy_from_slice(raw.as_bytes());
142 }
143}
144
145const NFNL_SUBSYS_NONE: u8 = 0;
147const NFNL_SUBSYS_CTNETLINK: u8 = 1;
148const NFNL_SUBSYS_ULOG: u8 = 4;
149const NFNL_SUBSYS_NFTABLES: u8 = 10;
150
151#[derive(Debug, PartialEq, Eq, Clone, Copy)]
152#[non_exhaustive]
153pub enum NetfilterSubsystem {
154 None,
155 ULog,
156 Conntrack,
157 NfTables,
158 Other(u8),
159}
160
161impl From<u8> for NetfilterSubsystem {
162 fn from(value: u8) -> Self {
163 match value {
164 NFNL_SUBSYS_NONE => Self::None,
165 NFNL_SUBSYS_ULOG => Self::ULog,
166 NFNL_SUBSYS_CTNETLINK => Self::Conntrack,
167 NFNL_SUBSYS_NFTABLES => Self::NfTables,
168 v => Self::Other(v),
169 }
170 }
171}
172
173impl From<NetfilterSubsystem> for u8 {
174 fn from(value: NetfilterSubsystem) -> Self {
175 match value {
176 NetfilterSubsystem::None => NFNL_SUBSYS_NONE,
177 NetfilterSubsystem::ULog => NFNL_SUBSYS_ULOG,
178 NetfilterSubsystem::Conntrack => NFNL_SUBSYS_CTNETLINK,
179 NetfilterSubsystem::NfTables => NFNL_SUBSYS_NFTABLES,
180 NetfilterSubsystem::Other(v) => v,
181 }
182 }
183}
184
185#[derive(Debug, PartialEq, Eq, Clone)]
186#[non_exhaustive]
187pub enum NetfilterMessageInner {
188 None(ControlMessage),
189 ULog(ULogMessage),
190 Conntrack(ConntrackMessage),
191 NfTables(NfTablesMessage),
192 Other {
193 subsys: NetfilterSubsystem,
194 message_type: u8,
195 attributes: Vec<DefaultNla>,
196 },
197}
198
199impl From<ULogMessage> for NetfilterMessageInner {
200 fn from(message: ULogMessage) -> Self {
201 Self::ULog(message)
202 }
203}
204
205impl From<ConntrackMessage> for NetfilterMessageInner {
206 fn from(message: ConntrackMessage) -> Self {
207 Self::Conntrack(message)
208 }
209}
210
211impl From<NfTablesMessage> for NetfilterMessageInner {
212 fn from(message: NfTablesMessage) -> Self {
213 Self::NfTables(message)
214 }
215}
216
217impl From<ControlMessage> for NetfilterMessageInner {
218 fn from(message: ControlMessage) -> Self {
219 Self::None(message)
220 }
221}
222
223impl Emitable for NetfilterMessageInner {
224 fn buffer_len(&self) -> usize {
225 match self {
226 NetfilterMessageInner::None(message) => message.buffer_len(),
227 NetfilterMessageInner::ULog(message) => message.buffer_len(),
228 NetfilterMessageInner::Conntrack(message) => message.buffer_len(),
229 NetfilterMessageInner::NfTables(message) => message.buffer_len(),
230 NetfilterMessageInner::Other { attributes, .. } => {
231 attributes.as_slice().buffer_len()
232 }
233 }
234 }
235
236 fn emit(&self, buffer: &mut [u8]) {
237 match self {
238 NetfilterMessageInner::None(message) => message.emit(buffer),
239 NetfilterMessageInner::ULog(message) => message.emit(buffer),
240 NetfilterMessageInner::Conntrack(message) => message.emit(buffer),
241 NetfilterMessageInner::NfTables(message) => message.emit(buffer),
242 NetfilterMessageInner::Other { attributes, .. } => {
243 attributes.as_slice().emit(buffer)
244 }
245 }
246 }
247}
248
249#[derive(Debug, PartialEq, Eq, Clone)]
250#[non_exhaustive]
251pub struct NetfilterMessage {
252 pub header: NetfilterHeader,
253 pub inner: NetfilterMessageInner,
254}
255
256impl NetfilterMessage {
257 pub fn new<T: Into<NetfilterMessageInner>>(
258 header: NetfilterHeader,
259 inner: T,
260 ) -> Self {
261 Self {
262 header,
263 inner: inner.into(),
264 }
265 }
266
267 pub fn subsys(&self) -> NetfilterSubsystem {
268 match self.inner {
269 NetfilterMessageInner::None(_) => NetfilterSubsystem::None,
270 NetfilterMessageInner::ULog(_) => NetfilterSubsystem::ULog,
271 NetfilterMessageInner::Conntrack(_) => {
272 NetfilterSubsystem::Conntrack
273 }
274 NetfilterMessageInner::NfTables(_) => NetfilterSubsystem::NfTables,
275 NetfilterMessageInner::Other { subsys, .. } => subsys,
276 }
277 }
278
279 fn message_type(&self) -> u8 {
280 match self.inner {
281 NetfilterMessageInner::None(ref message) => {
282 message.message_type().into()
283 }
284 NetfilterMessageInner::ULog(ref message) => {
285 message.message_type().into()
286 }
287 NetfilterMessageInner::Conntrack(ref message) => {
288 message.message_type().into()
289 }
290 NetfilterMessageInner::NfTables(ref message) => {
291 message.message_type().into()
292 }
293 NetfilterMessageInner::Other { message_type, .. } => message_type,
294 }
295 }
296}
297
298impl ParseableParametrized<[u8], u16> for NetfilterMessage {
299 fn parse_with_param(
300 buf: &[u8],
301 message_type: u16,
302 ) -> Result<Self, DecodeError> {
303 let header = NetfilterHeader::parse(buf)
304 .context("failed to parse netfilter header")?;
305 let subsys = (message_type >> 8) as u8;
306 let message_type = message_type as u8;
307 let inner = match NetfilterSubsystem::from(subsys) {
308 NetfilterSubsystem::None => NetfilterMessageInner::None(
309 ControlMessage::parse_with_param(
310 &buf[NETFILTER_HEADER_LEN..],
311 message_type,
312 )
313 .context("failed to parse nfnetlink control message payload")?,
314 ),
315 NetfilterSubsystem::ULog => NetfilterMessageInner::ULog(
316 ULogMessage::parse_with_param(
317 &buf[NETFILTER_HEADER_LEN..],
318 message_type,
319 )
320 .context("failed to parse nflog payload")?,
321 ),
322 NetfilterSubsystem::Conntrack => NetfilterMessageInner::Conntrack(
323 ConntrackMessage::parse_with_param(
324 &buf[NETFILTER_HEADER_LEN..],
325 message_type,
326 )
327 .context("failed to parse conntrack payload")?,
328 ),
329 NetfilterSubsystem::NfTables => NetfilterMessageInner::NfTables(
330 NfTablesMessage::parse_with_param(
331 &buf[NETFILTER_HEADER_LEN..],
332 message_type,
333 )
334 .context("failed to parse nftables payload")?,
335 ),
336 subsys_enum @ NetfilterSubsystem::Other(_) => {
337 NetfilterMessageInner::Other {
338 subsys: subsys_enum,
339 message_type,
340 attributes: crate::nlas::default_nlas(
341 &buf[NETFILTER_HEADER_LEN..],
342 )?,
343 }
344 }
345 };
346 Ok(NetfilterMessage::new(header, inner))
347 }
348}
349
350impl Emitable for NetfilterMessage {
351 fn buffer_len(&self) -> usize {
352 self.header.buffer_len() + self.inner.buffer_len()
353 }
354
355 fn emit(&self, buffer: &mut [u8]) {
356 self.header.emit(buffer);
357 self.inner.emit(&mut buffer[self.header.buffer_len()..]);
358 }
359}
360
361impl NetlinkSerializable for NetfilterMessage {
362 fn message_type(&self) -> u16 {
363 ((u8::from(self.subsys()) as u16) << 8) | self.message_type() as u16
364 }
365
366 fn buffer_len(&self) -> usize {
367 <Self as Emitable>::buffer_len(self)
368 }
369
370 fn serialize(&self, buffer: &mut [u8]) {
371 self.emit(buffer)
372 }
373}
374
375impl NetlinkDeserializable for NetfilterMessage {
376 type Error = DecodeError;
377 fn deserialize(
378 header: &NetlinkHeader,
379 payload: &[u8],
380 ) -> Result<Self, Self::Error> {
381 NetfilterMessage::parse_with_param(payload, header.message_type)
382 }
383}
384
385impl From<NetfilterMessage> for NetlinkPayload<NetfilterMessage> {
386 fn from(message: NetfilterMessage) -> Self {
387 NetlinkPayload::InnerMessage(message)
388 }
389}