nftables-napi 0.0.1

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.
@@ -0,0 +1,117 @@
1
+ #include "nl_socket.h"
2
+
3
+ extern "C" {
4
+ #include <linux/netfilter/nfnetlink.h>
5
+ }
6
+
7
+ #include <cerrno>
8
+ #include <cstring>
9
+ #include <sys/socket.h>
10
+
11
+ static constexpr size_t RECV_BUF_SIZE = 16384;
12
+
13
+ // Custom NLMSG_ERROR handler for mnl_cb_run2.
14
+ // Returns MNL_CB_OK for success ACKs and ignored ENOENT errors,
15
+ // allowing mnl_cb_run2 to continue processing all messages in buffer.
16
+ // Returns MNL_CB_ERROR for real errors.
17
+ struct BatchRecvCtx {
18
+ bool ignore_enoent;
19
+ bool has_error;
20
+ int error_code;
21
+ };
22
+
23
+ static int batch_error_cb(const struct nlmsghdr* nlh, void* data) {
24
+ auto* ctx = static_cast<BatchRecvCtx*>(data);
25
+
26
+ if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
27
+ ctx->has_error = true;
28
+ ctx->error_code = EBADMSG;
29
+ errno = EBADMSG;
30
+ return MNL_CB_ERROR;
31
+ }
32
+
33
+ auto* err = static_cast<struct nlmsgerr*>(mnl_nlmsg_get_payload(nlh));
34
+
35
+ if (err->error == 0)
36
+ return MNL_CB_OK; // success ACK — continue
37
+
38
+ if (ctx->ignore_enoent && err->error == -ENOENT)
39
+ return MNL_CB_OK; // ignored error — continue
40
+
41
+ ctx->has_error = true;
42
+ ctx->error_code = -err->error;
43
+ errno = -err->error;
44
+ return MNL_CB_ERROR;
45
+ }
46
+
47
+ NlSocket::NlSocket() : nl_(nullptr), portid_(0) {
48
+ nl_ = mnl_socket_open(NETLINK_NETFILTER);
49
+ if (!nl_)
50
+ return;
51
+
52
+ if (mnl_socket_bind(nl_, 0, MNL_SOCKET_AUTOPID) < 0) {
53
+ mnl_socket_close(nl_);
54
+ nl_ = nullptr;
55
+ return;
56
+ }
57
+
58
+ // Tune socket buffers for bulk batch operations.
59
+ // Failures are non-fatal; the kernel may cap at rmem_max/wmem_max.
60
+ static constexpr int SOCK_BUF_SIZE = 256 * 1024;
61
+ int fd = mnl_socket_get_fd(nl_);
62
+ // Non-fatal: kernel may reject buffer size increase
63
+ (void)setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &SOCK_BUF_SIZE, sizeof(SOCK_BUF_SIZE));
64
+ (void)setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &SOCK_BUF_SIZE, sizeof(SOCK_BUF_SIZE));
65
+
66
+ portid_ = mnl_socket_get_portid(nl_);
67
+ }
68
+
69
+ NlSocket::~NlSocket() {
70
+ if (nl_)
71
+ mnl_socket_close(nl_);
72
+ }
73
+
74
+ bool NlSocket::is_valid() const {
75
+ return nl_ != nullptr;
76
+ }
77
+
78
+ NlResult NlSocket::send_batch(struct mnl_nlmsg_batch* batch, bool ignore_enoent) {
79
+ ssize_t sent = mnl_socket_sendto(nl_,
80
+ mnl_nlmsg_batch_head(batch),
81
+ mnl_nlmsg_batch_size(batch));
82
+ if (sent < 0)
83
+ return {false, std::string("mnl_socket_sendto: ") + strerror(errno)};
84
+
85
+ BatchRecvCtx ctx{ignore_enoent, false, 0};
86
+
87
+ // Custom control callback array: override only NLMSG_ERROR (index 2).
88
+ // Array size = NLMSG_ERROR + 1 = 3, so NLMSG_DONE (3) and others
89
+ // fall through to default mnl handling.
90
+ mnl_cb_t cb_ctl[NLMSG_ERROR + 1] = {};
91
+ cb_ctl[NLMSG_ERROR] = batch_error_cb;
92
+
93
+ int fd = mnl_socket_get_fd(nl_);
94
+ char recv_buf[RECV_BUF_SIZE];
95
+
96
+ // First read: blocking (kernel response should arrive promptly)
97
+ ssize_t ret = mnl_socket_recvfrom(nl_, recv_buf, sizeof(recv_buf));
98
+ if (ret < 0)
99
+ return {false, std::string("mnl_socket_recvfrom: ") + strerror(errno)};
100
+ while (ret > 0) {
101
+ int cb_ret = mnl_cb_run2(recv_buf, static_cast<size_t>(ret), 0, portid_,
102
+ nullptr, &ctx, cb_ctl, NLMSG_ERROR + 1);
103
+ if (cb_ret <= 0)
104
+ break;
105
+
106
+ // Non-blocking read for remaining kernel responses
107
+ ret = recv(fd, recv_buf, sizeof(recv_buf), MSG_DONTWAIT);
108
+ }
109
+
110
+ // Drain any leftover messages to keep socket clean for next operation
111
+ while (recv(fd, recv_buf, sizeof(recv_buf), MSG_DONTWAIT) > 0) {}
112
+
113
+ if (ctx.has_error)
114
+ return {false, std::string("batch error: ") + strerror(ctx.error_code)};
115
+
116
+ return {true, ""};
117
+ }
@@ -0,0 +1,28 @@
1
+ #pragma once
2
+
3
+ extern "C" {
4
+ #include <libmnl/libmnl.h>
5
+ }
6
+
7
+ #include <cstdint>
8
+
9
+ #include "nl_result.h"
10
+
11
+ class NlSocket {
12
+ public:
13
+ NlSocket();
14
+ ~NlSocket();
15
+
16
+ NlSocket(const NlSocket&) = delete;
17
+ NlSocket& operator=(const NlSocket&) = delete;
18
+ NlSocket(NlSocket&&) = delete;
19
+ NlSocket& operator=(NlSocket&&) = delete;
20
+
21
+ bool is_valid() const;
22
+
23
+ NlResult send_batch(struct mnl_nlmsg_batch* batch, bool ignore_enoent = false);
24
+
25
+ private:
26
+ struct mnl_socket* nl_;
27
+ uint32_t portid_;
28
+ };
@@ -0,0 +1,11 @@
1
+ #pragma once
2
+
3
+ #include "nl_result.h"
4
+
5
+ class NlSocket;
6
+
7
+ class NlOperation {
8
+ public:
9
+ virtual ~NlOperation() = default;
10
+ virtual NlResult execute(NlSocket& sock) = 0;
11
+ };
@@ -0,0 +1,14 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+
5
+ struct ParsedAddr {
6
+ uint32_t family; // nft::FAMILY_IPV4 or nft::FAMILY_IPV6 (== NFPROTO_IPV4/IPV6)
7
+ uint8_t bytes[16];
8
+ uint32_t len; // 4 for IPv4, 16 for IPv6
9
+ };
10
+
11
+ namespace nft {
12
+ inline constexpr uint32_t FAMILY_IPV4 = 2;
13
+ inline constexpr uint32_t FAMILY_IPV6 = 10;
14
+ } // namespace nft
@@ -0,0 +1,113 @@
1
+ #include "set_ops.h"
2
+ #include "nftnl_raii.h"
3
+ #include "nl_batch.h"
4
+ #include "nl_socket.h"
5
+ #include "constants.h"
6
+ #include "nft_config.h"
7
+
8
+ extern "C" {
9
+ #include <libnftnl/set.h>
10
+ #include <linux/netfilter.h>
11
+ #include <linux/netfilter/nf_tables.h>
12
+ }
13
+
14
+ #include <algorithm>
15
+
16
+ using namespace nft;
17
+
18
+ static_assert(nft::FAMILY_IPV4 == NFPROTO_IPV4, "nft::FAMILY_IPV4 must match NFPROTO_IPV4");
19
+ static_assert(nft::FAMILY_IPV6 == NFPROTO_IPV6, "nft::FAMILY_IPV6 must match NFPROTO_IPV6");
20
+
21
+ enum class SetElemAction { Add, Del };
22
+
23
+ static NlResult bulk_set_elem_op(
24
+ const std::vector<ParsedAddr>& addrs,
25
+ NlSocket& sock,
26
+ SetElemAction action,
27
+ const nft::NftConfig& cfg,
28
+ nft::TargetSet target,
29
+ uint64_t timeout_ms = 0)
30
+ {
31
+ // Partition by family
32
+ std::vector<const ParsedAddr*> v4, v6;
33
+ for (const auto& a : addrs) {
34
+ if (a.family == NFPROTO_IPV4) v4.push_back(&a);
35
+ else v6.push_back(&a);
36
+ }
37
+
38
+ const uint16_t msg_type = (action == SetElemAction::Add)
39
+ ? NFT_MSG_NEWSETELEM : NFT_MSG_DELSETELEM;
40
+ const uint16_t flags = (action == SetElemAction::Add)
41
+ ? (NLM_F_CREATE | NLM_F_ACK) : NLM_F_ACK;
42
+ const bool ignore_enoent = (action == SetElemAction::Del);
43
+
44
+ // Helper lambda to process one family
45
+ auto process = [&](uint32_t family, const std::vector<const ParsedAddr*>& family_addrs) -> NlResult {
46
+ if (family_addrs.empty()) return {true, ""};
47
+
48
+ const char* table = (family == NFPROTO_IPV4)
49
+ ? cfg.table_v4.c_str() : cfg.table_v6.c_str();
50
+ const char* set_name = (family == NFPROTO_IPV4)
51
+ ? cfg.resolve_set_v4(target).c_str()
52
+ : cfg.resolve_set_v6(target).c_str();
53
+ uint32_t key_type = (family == NFPROTO_IPV4) ? DATATYPE_IPADDR : DATATYPE_IP6ADDR;
54
+ uint32_t key_len = (family == NFPROTO_IPV4) ? IPV4_ADDR_LEN : IPV6_ADDR_LEN;
55
+
56
+ for (size_t offset = 0; offset < family_addrs.size(); offset += BULK_CHUNK_SIZE) {
57
+ size_t end = std::min(offset + static_cast<size_t>(BULK_CHUNK_SIZE), family_addrs.size());
58
+
59
+ auto s = nft::make_set();
60
+ if (!s) return {false, "nftnl_set_alloc failed"};
61
+
62
+ nftnl_set_set_str(s.get(), NFTNL_SET_TABLE, table);
63
+ nftnl_set_set_str(s.get(), NFTNL_SET_NAME, set_name);
64
+ nftnl_set_set_u32(s.get(), NFTNL_SET_FAMILY, family);
65
+ nftnl_set_set_u32(s.get(), NFTNL_SET_KEY_TYPE, key_type);
66
+ nftnl_set_set_u32(s.get(), NFTNL_SET_KEY_LEN, key_len);
67
+
68
+ for (size_t i = offset; i < end; ++i) {
69
+ auto* e = nftnl_set_elem_alloc();
70
+ if (!e) return {false, "nftnl_set_elem_alloc failed"};
71
+ nftnl_set_elem_set(e, NFTNL_SET_ELEM_KEY, family_addrs[i]->bytes, family_addrs[i]->len);
72
+ if (timeout_ms > 0) {
73
+ nftnl_set_elem_set_u64(e, NFTNL_SET_ELEM_TIMEOUT, timeout_ms);
74
+ }
75
+ nftnl_set_elem_add(s.get(), e); // set owns e now
76
+ }
77
+
78
+ NlBatch batch;
79
+ if (!batch.is_valid()) return {false, "failed to allocate batch"};
80
+
81
+ auto* nlh = batch.add_msg(msg_type, family, flags);
82
+ if (!nlh) return {false, "failed to add message to batch"};
83
+ nftnl_set_elems_nlmsg_build_payload(nlh, s.get());
84
+
85
+ if (!batch.advance()) return {false, "batch buffer full"};
86
+
87
+ NlResult res = batch.execute(sock, ignore_enoent);
88
+ if (!res.success) return res;
89
+ }
90
+ return {true, ""};
91
+ };
92
+
93
+ NlResult res = process(NFPROTO_IPV4, v4);
94
+ if (!res.success) return res;
95
+ return process(NFPROTO_IPV6, v6);
96
+ }
97
+
98
+ BulkAddSetElemOp::BulkAddSetElemOp(std::vector<ParsedAddr> addrs, uint64_t timeout_ms,
99
+ std::shared_ptr<const nft::NftConfig> config, nft::TargetSet target)
100
+ : addrs_(std::move(addrs)), timeout_ms_(timeout_ms),
101
+ cfg_(std::move(config)), target_(target) {}
102
+
103
+ NlResult BulkAddSetElemOp::execute(NlSocket& sock) {
104
+ return bulk_set_elem_op(addrs_, sock, SetElemAction::Add, *cfg_, target_, timeout_ms_);
105
+ }
106
+
107
+ BulkDelSetElemOp::BulkDelSetElemOp(std::vector<ParsedAddr> addrs,
108
+ std::shared_ptr<const nft::NftConfig> config, nft::TargetSet target)
109
+ : addrs_(std::move(addrs)), cfg_(std::move(config)), target_(target) {}
110
+
111
+ NlResult BulkDelSetElemOp::execute(NlSocket& sock) {
112
+ return bulk_set_elem_op(addrs_, sock, SetElemAction::Del, *cfg_, target_);
113
+ }
@@ -0,0 +1,32 @@
1
+ #pragma once
2
+
3
+ #include "operation.h"
4
+ #include "nft_config.h"
5
+ #include "parsed_addr.h"
6
+ #include <memory>
7
+ #include <vector>
8
+
9
+ class BulkAddSetElemOp final : public NlOperation {
10
+ public:
11
+ BulkAddSetElemOp(std::vector<ParsedAddr> addrs, uint64_t timeout_ms,
12
+ std::shared_ptr<const nft::NftConfig> config, nft::TargetSet target);
13
+ NlResult execute(NlSocket& sock) override;
14
+
15
+ private:
16
+ std::vector<ParsedAddr> addrs_;
17
+ uint64_t timeout_ms_;
18
+ std::shared_ptr<const nft::NftConfig> cfg_;
19
+ nft::TargetSet target_;
20
+ };
21
+
22
+ class BulkDelSetElemOp final : public NlOperation {
23
+ public:
24
+ BulkDelSetElemOp(std::vector<ParsedAddr> addrs,
25
+ std::shared_ptr<const nft::NftConfig> config, nft::TargetSet target);
26
+ NlResult execute(NlSocket& sock) override;
27
+
28
+ private:
29
+ std::vector<ParsedAddr> addrs_;
30
+ std::shared_ptr<const nft::NftConfig> cfg_;
31
+ nft::TargetSet target_;
32
+ };
@@ -0,0 +1,221 @@
1
+ #include "table_ops.h"
2
+ #include "nftnl_raii.h"
3
+ #include "nl_batch.h"
4
+ #include "nl_socket.h"
5
+ #include "constants.h"
6
+ #include "nft_config.h"
7
+
8
+ extern "C" {
9
+ #include <libnftnl/table.h>
10
+ #include <libnftnl/chain.h>
11
+ #include <libnftnl/set.h>
12
+ #include <libnftnl/rule.h>
13
+ #include <libnftnl/expr.h>
14
+ #include <linux/netfilter.h>
15
+ #include <linux/netfilter/nf_tables.h>
16
+ }
17
+
18
+ using namespace nft;
19
+
20
+ static bool add_table(NlBatch& batch, uint32_t family, const char* name,
21
+ uint16_t msg_type, uint16_t extra_flags) {
22
+ auto t = nft::make_table();
23
+ if (!t) return false;
24
+ nftnl_table_set_u32(t.get(), NFTNL_TABLE_FAMILY, family);
25
+ nftnl_table_set_str(t.get(), NFTNL_TABLE_NAME, name);
26
+ struct nlmsghdr* nlh = batch.add_msg(msg_type, family, NLM_F_ACK | extra_flags);
27
+ if (!nlh) return false;
28
+ nftnl_table_nlmsg_build_payload(nlh, t.get());
29
+ return batch.advance();
30
+ }
31
+
32
+ static bool add_chain(NlBatch& batch, uint32_t family, const char* table,
33
+ const char* name, uint32_t hooknum) {
34
+ auto c = nft::make_chain();
35
+ if (!c) return false;
36
+ nftnl_chain_set_str(c.get(), NFTNL_CHAIN_TABLE, table);
37
+ nftnl_chain_set_str(c.get(), NFTNL_CHAIN_NAME, name);
38
+ nftnl_chain_set_u32(c.get(), NFTNL_CHAIN_HOOKNUM, hooknum);
39
+ nftnl_chain_set_s32(c.get(), NFTNL_CHAIN_PRIO, CHAIN_PRIORITY);
40
+ nftnl_chain_set_u32(c.get(), NFTNL_CHAIN_POLICY, NF_ACCEPT);
41
+ nftnl_chain_set_str(c.get(), NFTNL_CHAIN_TYPE, CHAIN_TYPE_FILTER);
42
+ struct nlmsghdr* nlh = batch.add_msg(NFT_MSG_NEWCHAIN, family, NLM_F_CREATE | NLM_F_ACK);
43
+ if (!nlh) return false;
44
+ nftnl_chain_nlmsg_build_payload(nlh, c.get());
45
+ return batch.advance();
46
+ }
47
+
48
+ static bool add_set(NlBatch& batch, uint32_t family, const char* table,
49
+ const char* name, uint32_t key_type, uint32_t key_len,
50
+ uint32_t set_id) {
51
+ auto s = nft::make_set();
52
+ if (!s) return false;
53
+ nftnl_set_set_str(s.get(), NFTNL_SET_TABLE, table);
54
+ nftnl_set_set_str(s.get(), NFTNL_SET_NAME, name);
55
+ nftnl_set_set_u32(s.get(), NFTNL_SET_FAMILY, family);
56
+ nftnl_set_set_u32(s.get(), NFTNL_SET_KEY_TYPE, key_type);
57
+ nftnl_set_set_u32(s.get(), NFTNL_SET_KEY_LEN, key_len);
58
+ nftnl_set_set_u32(s.get(), NFTNL_SET_FLAGS, NFT_SET_TIMEOUT);
59
+ nftnl_set_set_u32(s.get(), NFTNL_SET_ID, set_id);
60
+ struct nlmsghdr* nlh = batch.add_msg(NFT_MSG_NEWSET, family, NLM_F_CREATE | NLM_F_ACK);
61
+ if (!nlh) return false;
62
+ nftnl_set_nlmsg_build_payload(nlh, s.get());
63
+ return batch.advance();
64
+ }
65
+
66
+ static bool add_expr_payload(struct nftnl_rule* r, uint32_t base, uint32_t dreg,
67
+ uint32_t offset, uint32_t len) {
68
+ struct nftnl_expr* e = nftnl_expr_alloc("payload");
69
+ if (!e) return false;
70
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
71
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
72
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
73
+ nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
74
+ nftnl_rule_add_expr(r, e);
75
+ return true;
76
+ }
77
+
78
+ static bool add_expr_lookup(struct nftnl_rule* r, const char* set_name, uint32_t sreg) {
79
+ struct nftnl_expr* e = nftnl_expr_alloc("lookup");
80
+ if (!e) return false;
81
+ nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set_name);
82
+ nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
83
+ nftnl_rule_add_expr(r, e);
84
+ return true;
85
+ }
86
+
87
+ static bool add_expr_log(struct nftnl_rule* r, const char* prefix) {
88
+ struct nftnl_expr* e = nftnl_expr_alloc("log");
89
+ if (!e) return false;
90
+ nftnl_expr_set_str(e, NFTNL_EXPR_LOG_PREFIX, prefix);
91
+ nftnl_rule_add_expr(r, e);
92
+ return true;
93
+ }
94
+
95
+ static bool add_expr_drop(struct nftnl_rule* r) {
96
+ struct nftnl_expr* e = nftnl_expr_alloc("immediate");
97
+ if (!e) return false;
98
+ nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
99
+ nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_VERDICT, NF_DROP);
100
+ nftnl_rule_add_expr(r, e);
101
+ return true;
102
+ }
103
+
104
+ // Helper: creates a rule with table/chain/family metadata, calls build_exprs
105
+ // to populate expressions, then adds to batch. Returns false on any failure.
106
+ template<typename F>
107
+ static bool add_rule_with(NlBatch& batch, uint32_t family, const char* table,
108
+ const char* chain, F build_exprs) {
109
+ auto r = nft::make_rule();
110
+ if (!r) return false;
111
+ nftnl_rule_set_str(r.get(), NFTNL_RULE_TABLE, table);
112
+ nftnl_rule_set_str(r.get(), NFTNL_RULE_CHAIN, chain);
113
+ nftnl_rule_set_u32(r.get(), NFTNL_RULE_FAMILY, family);
114
+
115
+ if (!build_exprs(r.get())) return false;
116
+
117
+ struct nlmsghdr* nlh = batch.add_msg(NFT_MSG_NEWRULE, family,
118
+ NLM_F_CREATE | NLM_F_APPEND | NLM_F_ACK);
119
+ if (!nlh) return false;
120
+ nftnl_rule_nlmsg_build_payload(nlh, r.get());
121
+ return batch.advance();
122
+ }
123
+
124
+ static bool add_rule(NlBatch& batch, uint32_t family, const char* table,
125
+ const char* chain, const char* set_name,
126
+ uint32_t payload_offset, uint32_t addr_len,
127
+ const char* log_prefix) {
128
+ return add_rule_with(batch, family, table, chain, [&](nftnl_rule* r) {
129
+ return add_expr_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG_1, payload_offset, addr_len)
130
+ && add_expr_lookup(r, set_name, NFT_REG_1)
131
+ && add_expr_log(r, log_prefix)
132
+ && add_expr_drop(r);
133
+ });
134
+ }
135
+
136
+ CreateTableOp::CreateTableOp(std::shared_ptr<const nft::NftConfig> config)
137
+ : cfg_(std::move(config)) {}
138
+
139
+ NlResult CreateTableOp::execute(NlSocket& sock) {
140
+ {
141
+ NlBatch batch;
142
+ if (!batch.is_valid())
143
+ return {false, "failed to allocate batch"};
144
+ if (!add_table(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), NFT_MSG_DELTABLE, 0)
145
+ || !add_table(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), NFT_MSG_DELTABLE, 0))
146
+ return {false, "failed to build delete-tables batch"};
147
+ NlResult res = batch.execute(sock, true);
148
+ if (!res.success) return res;
149
+ }
150
+
151
+ NlBatch batch;
152
+ if (!batch.is_valid())
153
+ return {false, "failed to allocate batch"};
154
+
155
+ uint32_t sid = 0;
156
+
157
+ if (!add_table(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), NFT_MSG_NEWTABLE, NLM_F_CREATE)
158
+ || !add_table(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), NFT_MSG_NEWTABLE, NLM_F_CREATE))
159
+ return {false, "failed to build tables"};
160
+
161
+ // Blacklist sets
162
+ if (!add_set(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), cfg_->set_v4.c_str(),
163
+ DATATYPE_IPADDR, IPV4_ADDR_LEN, sid++)
164
+ || !add_set(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), cfg_->set_v6.c_str(),
165
+ DATATYPE_IP6ADDR, IPV6_ADDR_LEN, sid++))
166
+ return {false, "failed to build blacklist sets"};
167
+
168
+ // Droplist sets
169
+ if (!add_set(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), cfg_->drop_set_v4.c_str(),
170
+ DATATYPE_IPADDR, IPV4_ADDR_LEN, sid++)
171
+ || !add_set(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), cfg_->drop_set_v6.c_str(),
172
+ DATATYPE_IP6ADDR, IPV6_ADDR_LEN, sid++))
173
+ return {false, "failed to build droplist sets"};
174
+
175
+ if (!add_chain(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), CHAIN_INPUT, NF_INET_LOCAL_IN)
176
+ || !add_chain(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), CHAIN_FORWARD, NF_INET_FORWARD)
177
+ || !add_chain(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), CHAIN_INPUT, NF_INET_LOCAL_IN)
178
+ || !add_chain(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), CHAIN_FORWARD, NF_INET_FORWARD))
179
+ return {false, "failed to build chains"};
180
+
181
+ const char* bl_lp = cfg_->blacklist_log_prefix.c_str();
182
+
183
+ // Blacklist rules
184
+ if (!add_rule(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), CHAIN_INPUT,
185
+ cfg_->set_v4.c_str(), IPV4_SRC_OFFSET, IPV4_ADDR_LEN, bl_lp)
186
+ || !add_rule(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), CHAIN_FORWARD,
187
+ cfg_->set_v4.c_str(), IPV4_SRC_OFFSET, IPV4_ADDR_LEN, bl_lp)
188
+ || !add_rule(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), CHAIN_INPUT,
189
+ cfg_->set_v6.c_str(), IPV6_SRC_OFFSET, IPV6_ADDR_LEN, bl_lp)
190
+ || !add_rule(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), CHAIN_FORWARD,
191
+ cfg_->set_v6.c_str(), IPV6_SRC_OFFSET, IPV6_ADDR_LEN, bl_lp))
192
+ return {false, "failed to build blacklist rules"};
193
+
194
+ const char* dl_lp = cfg_->droplist_log_prefix.c_str();
195
+
196
+ // Droplist rules
197
+ if (!add_rule(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), CHAIN_INPUT,
198
+ cfg_->drop_set_v4.c_str(), IPV4_SRC_OFFSET, IPV4_ADDR_LEN, dl_lp)
199
+ || !add_rule(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), CHAIN_FORWARD,
200
+ cfg_->drop_set_v4.c_str(), IPV4_SRC_OFFSET, IPV4_ADDR_LEN, dl_lp)
201
+ || !add_rule(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), CHAIN_INPUT,
202
+ cfg_->drop_set_v6.c_str(), IPV6_SRC_OFFSET, IPV6_ADDR_LEN, dl_lp)
203
+ || !add_rule(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), CHAIN_FORWARD,
204
+ cfg_->drop_set_v6.c_str(), IPV6_SRC_OFFSET, IPV6_ADDR_LEN, dl_lp))
205
+ return {false, "failed to build droplist rules"};
206
+
207
+ return batch.execute(sock);
208
+ }
209
+
210
+ DeleteTableOp::DeleteTableOp(std::shared_ptr<const nft::NftConfig> config)
211
+ : cfg_(std::move(config)) {}
212
+
213
+ NlResult DeleteTableOp::execute(NlSocket& sock) {
214
+ NlBatch batch;
215
+ if (!batch.is_valid())
216
+ return {false, "failed to allocate batch"};
217
+ if (!add_table(batch, NFPROTO_IPV4, cfg_->table_v4.c_str(), NFT_MSG_DELTABLE, 0)
218
+ || !add_table(batch, NFPROTO_IPV6, cfg_->table_v6.c_str(), NFT_MSG_DELTABLE, 0))
219
+ return {false, "failed to build delete-tables batch"};
220
+ return batch.execute(sock, true);
221
+ }
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include "operation.h"
4
+ #include "nft_config.h"
5
+ #include <memory>
6
+
7
+ class CreateTableOp final : public NlOperation {
8
+ public:
9
+ explicit CreateTableOp(std::shared_ptr<const nft::NftConfig> config);
10
+ NlResult execute(NlSocket& sock) override;
11
+
12
+ private:
13
+ std::shared_ptr<const nft::NftConfig> cfg_;
14
+ };
15
+
16
+ class DeleteTableOp final : public NlOperation {
17
+ public:
18
+ explicit DeleteTableOp(std::shared_ptr<const nft::NftConfig> config);
19
+ NlResult execute(NlSocket& sock) override;
20
+
21
+ private:
22
+ std::shared_ptr<const nft::NftConfig> cfg_;
23
+ };