From 83ad886f653aa21e8c12903272ce8e7a863f56b3 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso 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 Signed-off-by: Pablo Neira Ayuso (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 #include "nft.h" #include "nft-cmd.h" +#include 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