summaryrefslogtreecommitdiffstats
path: root/iptables/nft.c
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2024-02-27 18:47:39 +0100
committerPhil Sutter <phil@nwl.cc>2024-02-27 19:41:02 +0100
commitbb1a7a5b297aa271f7f59abbcb891cd94d7fb305 (patch)
tree57e06b2850481fd6466bfe357b7a4d4bfd1b6a9f /iptables/nft.c
parentff57cd48d2b0c01c1519fd8893fc0432ad211702 (diff)
nft: Fix for broken recover_rule_compat()
When IPv4 rule generator was changed to emit payload instead of meta expressions for l4proto matches, the code reinserting NFTNL_RULE_COMPAT_* attributes into rules being reused for counter zeroing was broken by accident. Make rule compat recovery aware of the alternative match, basically reinstating the effect of commit 7a373f6683afb ("nft: Fix -Z for rules with NFTA_RULE_COMPAT") but add a test case this time to make sure things stay intact. Fixes: 69278f9602b43 ("nft: use payload matching for layer 4 protocol") Signed-off-by: Phil Sutter <phil@nwl.cc>
Diffstat (limited to 'iptables/nft.c')
-rw-r--r--iptables/nft.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/iptables/nft.c b/iptables/nft.c
index dae6698d..ee63c3dc 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -3750,6 +3750,27 @@ const char *nft_strerror(int err)
return strerror(err);
}
+static int l4proto_expr_get_dreg(struct nftnl_expr *e, uint32_t *dregp)
+{
+ const char *name = nftnl_expr_get_str(e, NFTNL_EXPR_NAME);
+ uint32_t poff = offsetof(struct iphdr, protocol);
+ uint32_t pbase = NFT_PAYLOAD_NETWORK_HEADER;
+
+ if (!strcmp(name, "payload") &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_BASE) == pbase &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET) == poff &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_LEN) == sizeof(uint8_t)) {
+ *dregp = nftnl_expr_get_u32(e, NFTNL_EXPR_PAYLOAD_DREG);
+ return 0;
+ }
+ if (!strcmp(name, "meta") &&
+ nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) == NFT_META_L4PROTO) {
+ *dregp = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
+ return 0;
+ }
+ return -1;
+}
+
static int recover_rule_compat(struct nftnl_rule *r)
{
struct nftnl_expr_iter *iter;
@@ -3766,12 +3787,10 @@ next_expr:
if (!e)
goto out;
- if (strcmp("meta", nftnl_expr_get_str(e, NFTNL_EXPR_NAME)) ||
- nftnl_expr_get_u32(e, NFTNL_EXPR_META_KEY) != NFT_META_L4PROTO)
+ /* may be 'ip protocol' or 'meta l4proto' with identical RHS */
+ if (l4proto_expr_get_dreg(e, &reg) < 0)
goto next_expr;
- reg = nftnl_expr_get_u32(e, NFTNL_EXPR_META_DREG);
-
e = nftnl_expr_iter_next(iter);
if (!e)
goto out;