nftables-napi 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
package/src/netlink/set_ops.cpp
CHANGED
|
@@ -12,6 +12,7 @@ extern "C" {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
#include <algorithm>
|
|
15
|
+
#include <cstring>
|
|
15
16
|
|
|
16
17
|
static_assert(nft::FAMILY_IPV4 == NFPROTO_IPV4, "nft::FAMILY_IPV4 must match NFPROTO_IPV4");
|
|
17
18
|
static_assert(nft::FAMILY_IPV6 == NFPROTO_IPV6, "nft::FAMILY_IPV6 must match NFPROTO_IPV6");
|
|
@@ -19,6 +20,71 @@ static_assert(nft::PROTO_SERVICE_KEY_LEN == 8, "concatenated proto.service key m
|
|
|
19
20
|
|
|
20
21
|
enum class SetElemAction { Add, Del };
|
|
21
22
|
|
|
23
|
+
// Merge overlapping or adjacent intervals per family. Required because
|
|
24
|
+
// rbtree-backed interval sets reject inserts that overlap an existing range,
|
|
25
|
+
// and adjacent ranges produce duplicate boundary keys (start of one == end
|
|
26
|
+
// marker of another). Result is sorted, disjoint by family.
|
|
27
|
+
//
|
|
28
|
+
// Wraparound intervals (end_bytes <= bytes lexicographically — e.g. a /32 of
|
|
29
|
+
// 255.255.255.255 whose exclusive end overflows to 0.0.0.0) are not merged:
|
|
30
|
+
// lex-comparison breaks down across the address-space wrap, and naive merge
|
|
31
|
+
// would silently drop the entry. They are passed through as-is.
|
|
32
|
+
static std::vector<ParsedAddr> merge_intervals(std::vector<ParsedAddr> addrs) {
|
|
33
|
+
if (addrs.size() < 2) return addrs;
|
|
34
|
+
|
|
35
|
+
std::sort(addrs.begin(), addrs.end(), [](const ParsedAddr& a, const ParsedAddr& b) {
|
|
36
|
+
if (a.family != b.family) return a.family < b.family;
|
|
37
|
+
return std::memcmp(a.bytes, b.bytes, a.len) < 0;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
auto is_wrapped = [](const ParsedAddr& p) {
|
|
41
|
+
return std::memcmp(p.end_bytes, p.bytes, p.len) <= 0;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
std::vector<ParsedAddr> merged;
|
|
45
|
+
merged.reserve(addrs.size());
|
|
46
|
+
merged.push_back(addrs[0]);
|
|
47
|
+
|
|
48
|
+
for (size_t i = 1; i < addrs.size(); ++i) {
|
|
49
|
+
ParsedAddr& last = merged.back();
|
|
50
|
+
const ParsedAddr& cur = addrs[i];
|
|
51
|
+
|
|
52
|
+
if (cur.family != last.family || is_wrapped(cur) || is_wrapped(last)) {
|
|
53
|
+
merged.push_back(cur);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Overlap or adjacency: cur.start <= last.end (end is exclusive).
|
|
58
|
+
if (std::memcmp(cur.bytes, last.end_bytes, cur.len) <= 0) {
|
|
59
|
+
// Extend end if cur reaches further.
|
|
60
|
+
if (std::memcmp(cur.end_bytes, last.end_bytes, cur.len) > 0) {
|
|
61
|
+
std::memcpy(last.end_bytes, cur.end_bytes, cur.len);
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
merged.push_back(cur);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return merged;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Drop duplicate (proto, port) pairs. Concat sets reject duplicates inside
|
|
72
|
+
// a single batch with EEXIST.
|
|
73
|
+
static std::vector<PortElem> dedup_port_elems(std::vector<PortElem> elems) {
|
|
74
|
+
if (elems.size() < 2) return elems;
|
|
75
|
+
|
|
76
|
+
std::sort(elems.begin(), elems.end(), [](const PortElem& a, const PortElem& b) {
|
|
77
|
+
if (a.proto != b.proto) return a.proto < b.proto;
|
|
78
|
+
return a.port < b.port;
|
|
79
|
+
});
|
|
80
|
+
elems.erase(std::unique(elems.begin(), elems.end(),
|
|
81
|
+
[](const PortElem& a, const PortElem& b) {
|
|
82
|
+
return a.proto == b.proto && a.port == b.port;
|
|
83
|
+
}),
|
|
84
|
+
elems.end());
|
|
85
|
+
return elems;
|
|
86
|
+
}
|
|
87
|
+
|
|
22
88
|
static NlResult bulk_set_elem_op(
|
|
23
89
|
const std::vector<ParsedAddr>& addrs,
|
|
24
90
|
NlSocket& sock,
|
|
@@ -64,14 +130,21 @@ static NlResult bulk_set_elem_op(
|
|
|
64
130
|
nftnl_set_set_u32(s.get(), NFTNL_SET_KEY_LEN, key_len);
|
|
65
131
|
|
|
66
132
|
for (size_t i = offset; i < end; ++i) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
nftnl_set_elem_set(
|
|
133
|
+
// Start element: carries the key, timeout, and counters
|
|
134
|
+
auto* e_start = nftnl_set_elem_alloc();
|
|
135
|
+
if (!e_start) return {false, "nftnl_set_elem_alloc failed"};
|
|
136
|
+
nftnl_set_elem_set(e_start, NFTNL_SET_ELEM_KEY, family_addrs[i]->bytes, family_addrs[i]->len);
|
|
71
137
|
if (timeout_ms > 0) {
|
|
72
|
-
nftnl_set_elem_set_u64(
|
|
138
|
+
nftnl_set_elem_set_u64(e_start, NFTNL_SET_ELEM_TIMEOUT, timeout_ms);
|
|
73
139
|
}
|
|
74
|
-
nftnl_set_elem_add(s.get(),
|
|
140
|
+
nftnl_set_elem_add(s.get(), e_start);
|
|
141
|
+
|
|
142
|
+
// End element: exclusive upper bound with INTERVAL_END flag
|
|
143
|
+
auto* e_end = nftnl_set_elem_alloc();
|
|
144
|
+
if (!e_end) return {false, "nftnl_set_elem_alloc failed"};
|
|
145
|
+
nftnl_set_elem_set(e_end, NFTNL_SET_ELEM_KEY, family_addrs[i]->end_bytes, family_addrs[i]->len);
|
|
146
|
+
nftnl_set_elem_set_u32(e_end, NFTNL_SET_ELEM_FLAGS, NFT_SET_ELEM_INTERVAL_END);
|
|
147
|
+
nftnl_set_elem_add(s.get(), e_end);
|
|
75
148
|
}
|
|
76
149
|
|
|
77
150
|
NlBatch batch;
|
|
@@ -100,7 +173,8 @@ BulkAddSetElemOp::BulkAddSetElemOp(std::vector<ParsedAddr> addrs, uint64_t timeo
|
|
|
100
173
|
cfg_(std::move(config)), set_idx_(set_idx) {}
|
|
101
174
|
|
|
102
175
|
NlResult BulkAddSetElemOp::execute(NlSocket& sock) {
|
|
103
|
-
|
|
176
|
+
auto merged = merge_intervals(std::move(addrs_));
|
|
177
|
+
return bulk_set_elem_op(merged, sock, SetElemAction::Add, *cfg_, set_idx_, timeout_ms_);
|
|
104
178
|
}
|
|
105
179
|
|
|
106
180
|
BulkDelSetElemOp::BulkDelSetElemOp(std::vector<ParsedAddr> addrs,
|
|
@@ -187,7 +261,8 @@ BulkAddPortElemOp::BulkAddPortElemOp(std::vector<PortElem> elems, uint64_t timeo
|
|
|
187
261
|
cfg_(std::move(config)), set_idx_(set_idx) {}
|
|
188
262
|
|
|
189
263
|
NlResult BulkAddPortElemOp::execute(NlSocket& sock) {
|
|
190
|
-
|
|
264
|
+
auto deduped = dedup_port_elems(std::move(elems_));
|
|
265
|
+
return bulk_port_elem_op(deduped, sock, SetElemAction::Add, *cfg_, set_idx_, timeout_ms_);
|
|
191
266
|
}
|
|
192
267
|
|
|
193
268
|
BulkDelPortElemOp::BulkDelPortElemOp(std::vector<PortElem> elems,
|
package/src/netlink/set_ops.h
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include <memory>
|
|
8
8
|
#include <vector>
|
|
9
9
|
|
|
10
|
+
// One-shot Op: execute() consumes addrs_ via move; do not call twice.
|
|
10
11
|
class BulkAddSetElemOp final : public NlOperation {
|
|
11
12
|
public:
|
|
12
13
|
BulkAddSetElemOp(std::vector<ParsedAddr> addrs, uint64_t timeout_ms,
|
|
@@ -37,6 +38,7 @@ struct PortElem {
|
|
|
37
38
|
uint16_t port;
|
|
38
39
|
};
|
|
39
40
|
|
|
41
|
+
// One-shot Op: execute() consumes elems_ via move; do not call twice.
|
|
40
42
|
class BulkAddPortElemOp final : public NlOperation {
|
|
41
43
|
public:
|
|
42
44
|
BulkAddPortElemOp(std::vector<PortElem> elems, uint64_t timeout_ms,
|