340 lines
12 KiB
Diff
340 lines
12 KiB
Diff
From 83ad886f653aa21e8c12903272ce8e7a863f56b3 Mon Sep 17 00:00:00 2001
|
|
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
Date: Tue, 11 Jul 2023 22:06:44 +0200
|
|
Subject: [PATCH] nft-bridge: pass context structure to ops->add() to improve
|
|
anonymous set support
|
|
|
|
Add context structure to improve bridge among support which creates an
|
|
anonymous set. This context structure specifies the command and it
|
|
allows to optionally store a anonymous set.
|
|
|
|
Use this context to generate native bytecode only if this is an
|
|
add/insert/replace command.
|
|
|
|
This fixes a dangling anonymous set that is created on rule removal.
|
|
|
|
Fixes: 26753888720d ("nft: bridge: Rudimental among extension support")
|
|
Reported-and-tested-by: Igor Raits <igor@gooddata.com>
|
|
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
(cherry picked from commit 4e95200ded923f0eb5579c33b91176193c59dbe0)
|
|
|
|
Conflicts:
|
|
iptables/nft-arp.c
|
|
iptables/nft-bridge.c
|
|
iptables/nft-ipv4.c
|
|
iptables/nft-ipv6.c
|
|
iptables/nft-shared.h
|
|
iptables/nft.c
|
|
iptables/nft.h
|
|
-> Manually applied, too many conflicts.
|
|
---
|
|
iptables/nft-arp.c | 3 ++-
|
|
iptables/nft-bridge.c | 9 +++++----
|
|
iptables/nft-cmd.c | 6 +++++-
|
|
iptables/nft-ipv4.c | 5 +++--
|
|
iptables/nft-ipv6.c | 5 +++--
|
|
iptables/nft-shared.h | 4 +++-
|
|
iptables/nft.c | 42 +++++++++++++++++++++++++++++-------------
|
|
iptables/nft.h | 9 ++++++---
|
|
8 files changed, 56 insertions(+), 27 deletions(-)
|
|
|
|
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
|
|
index fa1676e7fd878..2b6bda617e32c 100644
|
|
--- a/iptables/nft-arp.c
|
|
+++ b/iptables/nft-arp.c
|
|
@@ -54,7 +54,8 @@ static bool need_devaddr(struct arpt_devaddr_info *info)
|
|
return false;
|
|
}
|
|
|
|
-static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
|
|
+static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
+ struct nftnl_rule *r, void *data)
|
|
{
|
|
struct iptables_command_state *cs = data;
|
|
struct arpt_entry *fw = &cs->arp;
|
|
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
|
|
index 48bcda61cfb9c..11422a187097c 100644
|
|
--- a/iptables/nft-bridge.c
|
|
+++ b/iptables/nft-bridge.c
|
|
@@ -131,17 +131,18 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
|
|
|
|
static int
|
|
nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw,
|
|
- struct nftnl_rule *r, struct xt_entry_match *m)
|
|
+ struct nft_rule_ctx *ctx, struct nftnl_rule *r,
|
|
+ struct xt_entry_match *m)
|
|
{
|
|
if (!strcmp(m->u.user.name, "802_3") &&
|
|
!(fw->bitmask & EBT_802_3))
|
|
xtables_error(PARAMETER_PROBLEM,
|
|
"For 802.3 DSAP/SSAP filtering the protocol must be LENGTH");
|
|
|
|
- return add_match(h, r, m);
|
|
+ return add_match(h, ctx, r, m);
|
|
}
|
|
|
|
-static int nft_bridge_add(struct nft_handle *h,
|
|
+static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
struct nftnl_rule *r, void *data)
|
|
{
|
|
struct iptables_command_state *cs = data;
|
|
@@ -202,7 +203,7 @@ static int nft_bridge_add(struct nft_handle *h,
|
|
|
|
for (iter = cs->match_list; iter; iter = iter->next) {
|
|
if (iter->ismatch) {
|
|
- if (nft_bridge_add_match(h, fw, r, iter->u.match->m))
|
|
+ if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m))
|
|
break;
|
|
} else {
|
|
if (add_target(r, iter->u.watcher->t))
|
|
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
|
|
index fd038503d87e1..9d1c082ef62d0 100644
|
|
--- a/iptables/nft-cmd.c
|
|
+++ b/iptables/nft-cmd.c
|
|
@@ -13,12 +13,16 @@
|
|
#include <string.h>
|
|
#include "nft.h"
|
|
#include "nft-cmd.h"
|
|
+#include <libnftnl/set.h>
|
|
|
|
struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
|
|
const char *table, const char *chain,
|
|
struct iptables_command_state *state,
|
|
int rulenum, bool verbose)
|
|
{
|
|
+ struct nft_rule_ctx ctx = {
|
|
+ .command = command,
|
|
+ };
|
|
struct nftnl_rule *rule;
|
|
struct nft_cmd *cmd;
|
|
|
|
@@ -34,7 +38,7 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
|
|
cmd->verbose = verbose;
|
|
|
|
if (state) {
|
|
- rule = nft_rule_new(h, chain, table, state);
|
|
+ rule = nft_rule_new(h, &ctx, chain, table, state);
|
|
if (!rule) {
|
|
nft_cmd_free(cmd);
|
|
return NULL;
|
|
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
|
|
index a70e9ece248fe..e06d086bbf82a 100644
|
|
--- a/iptables/nft-ipv4.c
|
|
+++ b/iptables/nft-ipv4.c
|
|
@@ -26,7 +26,8 @@
|
|
#include "nft.h"
|
|
#include "nft-shared.h"
|
|
|
|
-static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
|
|
+static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
+ struct nftnl_rule *r, void *data)
|
|
{
|
|
struct iptables_command_state *cs = data;
|
|
struct xtables_rule_match *matchp;
|
|
@@ -79,7 +80,7 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
|
|
add_compat(r, cs->fw.ip.proto, cs->fw.ip.invflags & XT_INV_PROTO);
|
|
|
|
for (matchp = cs->matches; matchp; matchp = matchp->next) {
|
|
- ret = add_match(h, r, matchp->match->m);
|
|
+ ret = add_match(h, ctx, r, matchp->match->m);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
|
|
index 69d9bc41314fc..7c8e8b82cf521 100644
|
|
--- a/iptables/nft-ipv6.c
|
|
+++ b/iptables/nft-ipv6.c
|
|
@@ -25,7 +25,8 @@
|
|
#include "nft.h"
|
|
#include "nft-shared.h"
|
|
|
|
-static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
|
|
+static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
+ struct nftnl_rule *r, void *data)
|
|
{
|
|
struct iptables_command_state *cs = data;
|
|
struct xtables_rule_match *matchp;
|
|
@@ -68,7 +69,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
|
|
add_compat(r, cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags & XT_INV_PROTO);
|
|
|
|
for (matchp = cs->matches; matchp; matchp = matchp->next) {
|
|
- ret = add_match(h, r, matchp->match->m);
|
|
+ ret = add_match(h, ctx, r, matchp->match->m);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
|
|
index e3c1b202b8638..c29ad12e9151a 100644
|
|
--- a/iptables/nft-shared.h
|
|
+++ b/iptables/nft-shared.h
|
|
@@ -35,6 +35,7 @@
|
|
| FMT_NUMERIC | FMT_NOTABLE)
|
|
#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab))
|
|
|
|
+struct nft_rule_ctx;
|
|
struct xtables_args;
|
|
struct nft_handle;
|
|
struct xt_xlate;
|
|
@@ -74,7 +75,8 @@ struct nft_xt_ctx {
|
|
};
|
|
|
|
struct nft_family_ops {
|
|
- int (*add)(struct nft_handle *h, struct nftnl_rule *r, void *data);
|
|
+ int (*add)(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
+ struct nftnl_rule *r, void *data);
|
|
bool (*is_same)(const void *data_a,
|
|
const void *data_b);
|
|
void (*print_payload)(struct nftnl_expr *e,
|
|
diff --git a/iptables/nft.c b/iptables/nft.c
|
|
index 7349904896228..936204a432621 100644
|
|
--- a/iptables/nft.c
|
|
+++ b/iptables/nft.c
|
|
@@ -1064,7 +1064,8 @@ gen_lookup(uint32_t sreg, const char *set_name, uint32_t set_id, uint32_t flags)
|
|
#define NFT_DATATYPE_ETHERADDR 9
|
|
|
|
static int __add_nft_among(struct nft_handle *h, const char *table,
|
|
- struct nftnl_rule *r, struct nft_among_pair *pairs,
|
|
+ struct nft_rule_ctx *ctx, struct nftnl_rule *r,
|
|
+ struct nft_among_pair *pairs,
|
|
int cnt, bool dst, bool inv, bool ip)
|
|
{
|
|
uint32_t set_id, type = NFT_DATATYPE_ETHERADDR, len = ETH_ALEN;
|
|
@@ -1142,7 +1143,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
|
|
return 0;
|
|
}
|
|
|
|
-static int add_nft_among(struct nft_handle *h,
|
|
+static int add_nft_among(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
struct nftnl_rule *r, struct xt_entry_match *m)
|
|
{
|
|
struct nft_among_data *data = (struct nft_among_data *)m->data;
|
|
@@ -1157,25 +1158,33 @@ static int add_nft_among(struct nft_handle *h,
|
|
}
|
|
|
|
if (data->src.cnt)
|
|
- __add_nft_among(h, table, r, data->pairs, data->src.cnt,
|
|
+ __add_nft_among(h, table, ctx, r, data->pairs, data->src.cnt,
|
|
false, data->src.inv, data->src.ip);
|
|
if (data->dst.cnt)
|
|
- __add_nft_among(h, table, r, data->pairs + data->src.cnt,
|
|
+ __add_nft_among(h, table, ctx, r, data->pairs + data->src.cnt,
|
|
data->dst.cnt, true, data->dst.inv,
|
|
data->dst.ip);
|
|
return 0;
|
|
}
|
|
|
|
-int add_match(struct nft_handle *h,
|
|
+int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
struct nftnl_rule *r, struct xt_entry_match *m)
|
|
{
|
|
struct nftnl_expr *expr;
|
|
int ret;
|
|
|
|
- if (!strcmp(m->u.user.name, "limit"))
|
|
- return add_nft_limit(r, m);
|
|
- else if (!strcmp(m->u.user.name, "among"))
|
|
- return add_nft_among(h, r, m);
|
|
+ switch (ctx->command) {
|
|
+ case NFT_COMPAT_RULE_APPEND:
|
|
+ case NFT_COMPAT_RULE_INSERT:
|
|
+ case NFT_COMPAT_RULE_REPLACE:
|
|
+ if (!strcmp(m->u.user.name, "limit"))
|
|
+ return add_nft_limit(r, m);
|
|
+ else if (!strcmp(m->u.user.name, "among"))
|
|
+ return add_nft_among(h, ctx, r, m);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
|
|
expr = nftnl_expr_alloc("match");
|
|
if (expr == NULL)
|
|
@@ -1378,7 +1387,8 @@ void add_compat(struct nftnl_rule *r, uint32_t proto, bool inv)
|
|
}
|
|
|
|
struct nftnl_rule *
|
|
-nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
|
|
+nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
+ const char *chain, const char *table,
|
|
void *data)
|
|
{
|
|
struct nftnl_rule *r;
|
|
@@ -1391,7 +1401,7 @@ nft_rule_new(struct nft_handle *h, const char *chain, const char *table,
|
|
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
|
|
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
|
|
|
|
- if (h->ops->add(h, r, data) < 0)
|
|
+ if (h->ops->add(h, ctx, r, data) < 0)
|
|
goto err;
|
|
|
|
return r;
|
|
@@ -2599,6 +2609,9 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
|
|
{
|
|
struct iptables_command_state cs = {};
|
|
struct nftnl_rule *r, *new_rule;
|
|
+ struct nft_rule_ctx ctx = {
|
|
+ .command = NFT_COMPAT_RULE_APPEND,
|
|
+ };
|
|
struct nftnl_chain *c;
|
|
int ret = 0;
|
|
|
|
@@ -2617,7 +2630,7 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain,
|
|
|
|
h->ops->rule_to_cs(h, r, &cs);
|
|
cs.counters.pcnt = cs.counters.bcnt = 0;
|
|
- new_rule = nft_rule_new(h, chain, table, &cs);
|
|
+ new_rule = nft_rule_new(h, &ctx, chain, table, &cs);
|
|
h->ops->clear_cs(&cs);
|
|
|
|
if (!new_rule)
|
|
@@ -2981,6 +2994,9 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
|
|
.eb.bitmask = EBT_NOPROTO,
|
|
};
|
|
struct nftnl_udata_buf *udata;
|
|
+ struct nft_rule_ctx ctx = {
|
|
+ .command = NFT_COMPAT_RULE_APPEND,
|
|
+ };
|
|
struct nft_handle *h = data;
|
|
struct nftnl_rule *r;
|
|
const char *pname;
|
|
@@ -3008,7 +3024,7 @@ static int ebt_add_policy_rule(struct nftnl_chain *c, void *data)
|
|
|
|
command_jump(&cs, pname);
|
|
|
|
- r = nft_rule_new(h, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
|
|
+ r = nft_rule_new(h, &ctx, nftnl_chain_get_str(c, NFTNL_CHAIN_NAME),
|
|
nftnl_chain_get_str(c, NFTNL_CHAIN_TABLE), &cs);
|
|
ebt_cs_clean(&cs);
|
|
|
|
diff --git a/iptables/nft.h b/iptables/nft.h
|
|
index bd783231156b7..7baceaa44f698 100644
|
|
--- a/iptables/nft.h
|
|
+++ b/iptables/nft.h
|
|
@@ -165,9 +165,11 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
|
|
/*
|
|
* Operations with rule-set.
|
|
*/
|
|
-struct nftnl_rule;
|
|
+struct nft_rule_ctx {
|
|
+ int command;
|
|
+};
|
|
|
|
-struct nftnl_rule *nft_rule_new(struct nft_handle *h, const char *chain, const char *table, void *data);
|
|
+struct nftnl_rule *nft_rule_new(struct nft_handle *h, struct nft_rule_ctx *rule, const char *chain, const char *table, void *data);
|
|
int nft_rule_append(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, struct nftnl_rule *ref, bool verbose);
|
|
int nft_rule_insert(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, int rulenum, bool verbose);
|
|
int nft_rule_check(struct nft_handle *h, const char *chain, const char *table, struct nftnl_rule *r, bool verbose);
|
|
@@ -185,7 +187,8 @@ int nft_rule_zero_counters(struct nft_handle *h, const char *chain, const char *
|
|
*/
|
|
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes);
|
|
int add_verdict(struct nftnl_rule *r, int verdict);
|
|
-int add_match(struct nft_handle *h, struct nftnl_rule *r, struct xt_entry_match *m);
|
|
+int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
|
|
+ struct nftnl_rule *r, struct xt_entry_match *m);
|
|
int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
|
|
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict);
|
|
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs, bool goto_set);
|
|
--
|
|
2.40.0
|
|
|