Skip to content

Commit 20a7e3f

Browse files
committed
feat: conntrack delete message type and attributes
Implemented the `Delete`/`IPCTNL_MSG_CT_DELETE` conntrack message type and the following attributes, which are required to describe a conntrack entry for deletion: * mark * status * timeout * tuple_reply Added tests for deleting TCP/IPv4 and UDP/IPv6 conntrack entries. The bitflags dependency was also bumped to v2.10.0. Signed-off-by: Shivang K Raghuvanshi <[email protected]>
1 parent c9d7dc3 commit 20a7e3f

File tree

7 files changed

+329
-7
lines changed

7 files changed

+329
-7
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ description = "netlink packet types for the netfilter subprotocol"
1313

1414
[dependencies]
1515
netlink-packet-core = { version = "0.8.1" }
16-
bitflags = "2.3"
16+
bitflags = "2.10.0"
1717
libc = "0.2.77"
1818
derive_more = "0.99.16"
1919

src/conntrack/attributes/attribute.rs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,30 @@
11
// SPDX-License-Identifier: MIT
22

33
use netlink_packet_core::{
4-
DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
5-
NlasIterator, Parseable,
4+
emit_u32_be, parse_u32_be, DecodeError, DefaultNla, Emitable, ErrorContext,
5+
Nla, NlaBuffer, NlasIterator, Parseable,
66
};
77

8-
use crate::conntrack::attributes::{protoinfo::ProtoInfo, tuple::Tuple};
8+
use crate::conntrack::attributes::{
9+
protoinfo::ProtoInfo, status::Status, tuple::Tuple,
10+
};
911

1012
const CTA_TUPLE_ORIG: u16 = 1;
13+
const CTA_TUPLE_REPLY: u16 = 2;
1114
const CTA_PROTOINFO: u16 = 4;
15+
const CTA_STATUS: u16 = 3;
16+
const CTA_TIMEOUT: u16 = 7;
17+
const CTA_MARK: u16 = 8;
1218

1319
#[derive(Clone, Debug, PartialEq, Eq)]
1420
#[non_exhaustive]
1521
pub enum ConntrackNla {
1622
CtaTupleOrig(Vec<Tuple>),
23+
CtaTupleReply(Vec<Tuple>),
1724
CtaProtoInfo(Vec<ProtoInfo>),
25+
CtaStatus(Status),
26+
CtaTimeout(u32),
27+
CtaMark(u32),
1828
Other(DefaultNla),
1929
}
2030

@@ -24,17 +34,27 @@ impl Nla for ConntrackNla {
2434
ConntrackNla::CtaTupleOrig(attr) => {
2535
attr.iter().map(|op| op.buffer_len()).sum()
2636
}
37+
ConntrackNla::CtaTupleReply(attr) => {
38+
attr.iter().map(|op| op.buffer_len()).sum()
39+
}
2740
ConntrackNla::CtaProtoInfo(attr) => {
2841
attr.iter().map(|op| op.buffer_len()).sum()
2942
}
43+
ConntrackNla::CtaStatus(_) => size_of::<u32>(),
44+
ConntrackNla::CtaTimeout(attr) => size_of_val(attr),
45+
ConntrackNla::CtaMark(attr) => size_of_val(attr),
3046
ConntrackNla::Other(attr) => attr.value_len(),
3147
}
3248
}
3349

3450
fn kind(&self) -> u16 {
3551
match self {
3652
ConntrackNla::CtaTupleOrig(_) => CTA_TUPLE_ORIG,
53+
ConntrackNla::CtaTupleReply(_) => CTA_TUPLE_REPLY,
3754
ConntrackNla::CtaProtoInfo(_) => CTA_PROTOINFO,
55+
ConntrackNla::CtaStatus(_) => CTA_STATUS,
56+
ConntrackNla::CtaTimeout(_) => CTA_TIMEOUT,
57+
ConntrackNla::CtaMark(_) => CTA_MARK,
3858
ConntrackNla::Other(attr) => attr.kind(),
3959
}
4060
}
@@ -48,20 +68,36 @@ impl Nla for ConntrackNla {
4868
len += op.buffer_len();
4969
}
5070
}
71+
ConntrackNla::CtaTupleReply(attr) => {
72+
let mut len = 0;
73+
for op in attr {
74+
op.emit(&mut buffer[len..]);
75+
len += op.buffer_len();
76+
}
77+
}
5178
ConntrackNla::CtaProtoInfo(attr) => {
5279
let mut len = 0;
5380
for op in attr {
5481
op.emit(&mut buffer[len..]);
5582
len += op.buffer_len();
5683
}
5784
}
85+
ConntrackNla::CtaStatus(attr) => {
86+
emit_u32_be(buffer, (*attr).bits()).unwrap()
87+
}
88+
ConntrackNla::CtaTimeout(attr) => {
89+
emit_u32_be(buffer, *attr).unwrap()
90+
}
91+
ConntrackNla::CtaMark(attr) => emit_u32_be(buffer, *attr).unwrap(),
5892
ConntrackNla::Other(attr) => attr.emit_value(buffer),
5993
}
6094
}
6195
fn is_nested(&self) -> bool {
6296
matches!(
6397
self,
64-
ConntrackNla::CtaTupleOrig(_) | ConntrackNla::CtaProtoInfo(_)
98+
ConntrackNla::CtaTupleOrig(_)
99+
| ConntrackNla::CtaTupleReply(_)
100+
| ConntrackNla::CtaProtoInfo(_)
65101
)
66102
}
67103
}
@@ -81,6 +117,16 @@ impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>>
81117
}
82118
ConntrackNla::CtaTupleOrig(tuples)
83119
}
120+
CTA_TUPLE_REPLY => {
121+
let mut tuples = Vec::new();
122+
for nlas in NlasIterator::new(payload) {
123+
let nlas =
124+
&nlas.context("invalid CTA_TUPLE_REPLY value")?;
125+
126+
tuples.push(Tuple::parse(nlas)?);
127+
}
128+
ConntrackNla::CtaTupleReply(tuples)
129+
}
84130
CTA_PROTOINFO => {
85131
let mut proto_infos = Vec::new();
86132
for nlas in NlasIterator::new(payload) {
@@ -89,6 +135,15 @@ impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>>
89135
}
90136
ConntrackNla::CtaProtoInfo(proto_infos)
91137
}
138+
CTA_STATUS => ConntrackNla::CtaStatus(Status::from_bits_retain(
139+
parse_u32_be(payload).context("invalid CTA_STATUS value")?,
140+
)),
141+
CTA_TIMEOUT => ConntrackNla::CtaTimeout(
142+
parse_u32_be(payload).context("invalid CTA_TIMEOUT value")?,
143+
),
144+
CTA_MARK => ConntrackNla::CtaMark(
145+
parse_u32_be(payload).context("invalid CTA_MARK value")?,
146+
),
92147
_ => ConntrackNla::Other(DefaultNla::parse(buf)?),
93148
};
94149
Ok(nla)

src/conntrack/attributes/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod iptuple;
55
mod protoinfo;
66
mod protoinfotcp;
77
mod prototuple;
8+
mod status;
89
mod tcp_flags;
910
mod tuple;
1011

@@ -13,5 +14,6 @@ pub use iptuple::IPTuple;
1314
pub use protoinfo::ProtoInfo;
1415
pub use protoinfotcp::ProtoInfoTCP;
1516
pub use prototuple::{ProtoTuple, Protocol};
17+
pub use status::Status;
1618
pub use tcp_flags::TCPFlags;
1719
pub use tuple::Tuple;

src/conntrack/attributes/status.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
use bitflags::bitflags;
4+
5+
// Conntrack status flags from uapi/linux/netfilter/nf_conntrack_common.h
6+
const IPS_EXPECTED: u32 = 1;
7+
const IPS_SEEN_REPLY: u32 = 1 << 1;
8+
const IPS_ASSURED: u32 = 1 << 2;
9+
const IPS_CONFIRMED: u32 = 1 << 3;
10+
const IPS_SRC_NAT: u32 = 1 << 4;
11+
const IPS_DST_NAT: u32 = 1 << 5;
12+
const IPS_SEQ_ADJUST: u32 = 1 << 6;
13+
const IPS_SRC_NAT_DONE: u32 = 1 << 7;
14+
const IPS_DST_NAT_DONE: u32 = 1 << 8;
15+
const IPS_DYING: u32 = 1 << 9;
16+
const IPS_FIXED_TIMEOUT: u32 = 1 << 10;
17+
const IPS_TEMPLATE: u32 = 1 << 11;
18+
const IPS_UNTRACKED: u32 = 1 << 12;
19+
const IPS_HELPER: u32 = 1 << 13;
20+
const IPS_OFFLOAD: u32 = 1 << 14;
21+
22+
const IPS_NAT_MASK: u32 = IPS_SRC_NAT | IPS_DST_NAT;
23+
const IPS_NAT_DONE_MASK: u32 = IPS_SRC_NAT_DONE | IPS_DST_NAT_DONE;
24+
25+
bitflags! {
26+
#[non_exhaustive]
27+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28+
pub struct Status: u32 {
29+
const Expected = IPS_EXPECTED;
30+
const SeenReply = IPS_SEEN_REPLY;
31+
const Assured = IPS_ASSURED;
32+
const Confirmed = IPS_CONFIRMED;
33+
const SrcNat = IPS_SRC_NAT;
34+
const DstNat = IPS_DST_NAT;
35+
const SeqAdjust = IPS_SEQ_ADJUST;
36+
const SrcNatDone = IPS_SRC_NAT_DONE;
37+
const DstNatDone = IPS_DST_NAT_DONE;
38+
const Dying = IPS_DYING;
39+
const FixedTimeout = IPS_FIXED_TIMEOUT;
40+
const Template = IPS_TEMPLATE;
41+
const Untracked = IPS_UNTRACKED;
42+
const Helper = IPS_HELPER;
43+
const Offload = IPS_OFFLOAD;
44+
const NatMask = IPS_NAT_MASK;
45+
const NatDoneMask = IPS_NAT_DONE_MASK;
46+
const _ = !0;
47+
}
48+
}

src/conntrack/message.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,29 @@ use netlink_packet_core::{
99
#[non_exhaustive]
1010
pub enum ConntrackMessage {
1111
Get(Vec<ConntrackNla>),
12+
Delete(Vec<ConntrackNla>),
1213
Other {
1314
message_type: u8,
1415
attributes: Vec<DefaultNla>,
1516
},
1617
}
1718

1819
const IPCTNL_MSG_CT_GET: u8 = 1;
20+
const IPCTNL_MSG_CT_DELETE: u8 = 2;
1921

2022
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2123
#[non_exhaustive]
2224
pub enum ConntrackMessageType {
2325
Get,
26+
Delete,
2427
Other(u8),
2528
}
2629

2730
impl From<u8> for ConntrackMessageType {
2831
fn from(value: u8) -> Self {
2932
match value {
3033
IPCTNL_MSG_CT_GET => Self::Get,
34+
IPCTNL_MSG_CT_DELETE => Self::Delete,
3135
v => Self::Other(v),
3236
}
3337
}
@@ -37,6 +41,7 @@ impl From<ConntrackMessageType> for u8 {
3741
fn from(value: ConntrackMessageType) -> Self {
3842
match value {
3943
ConntrackMessageType::Get => IPCTNL_MSG_CT_GET,
44+
ConntrackMessageType::Delete => IPCTNL_MSG_CT_DELETE,
4045
ConntrackMessageType::Other(v) => v,
4146
}
4247
}
@@ -46,6 +51,7 @@ impl ConntrackMessage {
4651
pub fn message_type(&self) -> ConntrackMessageType {
4752
match self {
4853
ConntrackMessage::Get(_) => ConntrackMessageType::Get,
54+
ConntrackMessage::Delete(_) => ConntrackMessageType::Delete,
4955
ConntrackMessage::Other { message_type, .. } => {
5056
(*message_type).into()
5157
}
@@ -59,6 +65,9 @@ impl Emitable for ConntrackMessage {
5965
ConntrackMessage::Get(attributes) => {
6066
attributes.as_slice().buffer_len()
6167
}
68+
ConntrackMessage::Delete(attributes) => {
69+
attributes.as_slice().buffer_len()
70+
}
6271
ConntrackMessage::Other { attributes, .. } => {
6372
attributes.as_slice().buffer_len()
6473
}
@@ -70,6 +79,9 @@ impl Emitable for ConntrackMessage {
7079
ConntrackMessage::Get(attributes) => {
7180
attributes.as_slice().emit(buffer)
7281
}
82+
ConntrackMessage::Delete(attributes) => {
83+
attributes.as_slice().emit(buffer)
84+
}
7385
ConntrackMessage::Other { attributes, .. } => {
7486
attributes.as_slice().emit(buffer)
7587
}
@@ -90,6 +102,11 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
90102
.parse_all_nlas(|nla_buf| ConntrackNla::parse(&nla_buf))?;
91103
ConntrackMessage::Get(attributes)
92104
}
105+
ConntrackMessageType::Delete => {
106+
let nlas = buf
107+
.parse_all_nlas(|nla_buf| ConntrackNla::parse(&nla_buf))?;
108+
ConntrackMessage::Delete(nlas)
109+
}
93110
ConntrackMessageType::Other(message_type) => {
94111
ConntrackMessage::Other {
95112
message_type,

src/conntrack/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ pub use message::{ConntrackMessage, ConntrackMessageType};
55
mod attributes;
66
pub use attributes::{
77
ConntrackNla, IPTuple, ProtoInfo, ProtoInfoTCP, ProtoTuple, Protocol,
8-
TCPFlags, Tuple,
8+
Status, TCPFlags, Tuple,
99
};

0 commit comments

Comments
 (0)