* [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries
@ 2024-10-09 11:48 Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 1/8] nft: Make add_log() static Phil Sutter
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
Changes since v1:
- Split the parser into a separate patch for easier backporting by
distributions.
- Make the writer opt-in, allow users to force the parser fallback at
run-time.
- Document the feature in man pages.
Time to abandon earlier attempts at providing compatibility for old
binaries, choose the next best option which is not relying upon any
kernel changes.
Basically, all extensions replaced by native bytecode are appended to
rule userdata so when nftnl rule parsing code fails, it may retry
omitting all these expressions and restoring an extension from userdata
instead.
The idea behind this is that extensions are stable which relieves native
bytecode from being the same. With this series in place, one may
(re-)start converting extensions into native nftables bytecode again.
Appending rule userdata upon creation is inactive by default and enabled
via --compat option or XTABLES_COMPAT env variable. The parser will fall
back to userdata automatically if present and parsing fails.
Patches 1-3 are preparation. Patches 4 and 5 implement the parser side,
patches 6 and 7 implement the writer and patch 8 finally extends
iptables-test.py to cover the new code.
Phil Sutter (8):
nft: Make add_log() static
nft: ruleparse: Introduce nft_parse_rule_expr()
nft: __add_{match,target}() can't fail
nft: Introduce UDATA_TYPE_COMPAT_EXT
nft-ruleparse: Fallback to compat expressions in userdata
nft: Pass nft_handle into add_{action,match}()
nft: Embed compat extensions in rule userdata
tests: iptables-test: Add nft-compat variant
configure.ac | 9 ++
iptables-test.py | 14 ++-
iptables/Makefile.am | 1 +
iptables/arptables-nft.8 | 12 ++
iptables/ebtables-nft.8 | 12 ++
iptables/iptables-restore.8.in | 12 ++
iptables/iptables.8.in | 12 ++
iptables/nft-arp.c | 2 +-
iptables/nft-bridge.c | 9 +-
iptables/nft-compat.c | 222 +++++++++++++++++++++++++++++++++
iptables/nft-compat.h | 54 ++++++++
iptables/nft-ipv4.c | 2 +-
iptables/nft-ipv6.c | 2 +-
iptables/nft-ruleparse.c | 90 ++++++++-----
iptables/nft-ruleparse.h | 4 +
iptables/nft.c | 111 ++++++++++-------
iptables/nft.h | 24 +++-
iptables/xshared.c | 7 ++
iptables/xshared.h | 1 +
iptables/xtables-arp.c | 1 +
iptables/xtables-eb.c | 4 +
iptables/xtables-nft.8 | 11 ++
iptables/xtables-restore.c | 15 ++-
iptables/xtables.c | 3 +
24 files changed, 544 insertions(+), 90 deletions(-)
create mode 100644 iptables/nft-compat.c
create mode 100644 iptables/nft-compat.h
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [iptables PATCH v2 1/8] nft: Make add_log() static
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 2/8] nft: ruleparse: Introduce nft_parse_rule_expr() Phil Sutter
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
It is not used outside of nft.c, though in the wrong position so keep
the declaration but right above its caller.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
iptables/nft.c | 4 +++-
iptables/nft.h | 1 -
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index 88be5ede5171d..2ed21bb14c253 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1595,6 +1595,8 @@ int add_verdict(struct nftnl_rule *r, int verdict)
return 0;
}
+static int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
+
int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
bool goto_set)
{
@@ -1623,7 +1625,7 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
return ret;
}
-int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
+static int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
{
struct nftnl_expr *expr;
struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
diff --git a/iptables/nft.h b/iptables/nft.h
index 8f17f3100a190..09b4341f92f8e 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -197,7 +197,6 @@ int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
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);
-int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
char *get_comment(const void *data, uint32_t data_len);
enum nft_rule_print {
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 2/8] nft: ruleparse: Introduce nft_parse_rule_expr()
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 1/8] nft: Make add_log() static Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 3/8] nft: __add_{match,target}() can't fail Phil Sutter
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
Extract the parsing of one expression into a separate function and
export it, preparing for following code changes.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
iptables/nft-ruleparse.c | 73 ++++++++++++++++++++++------------------
iptables/nft-ruleparse.h | 4 +++
2 files changed, 44 insertions(+), 33 deletions(-)
diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c
index 1ee7a94db59de..757d3c29fc816 100644
--- a/iptables/nft-ruleparse.c
+++ b/iptables/nft-ruleparse.c
@@ -887,6 +887,45 @@ static void nft_parse_range(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
}
}
+bool nft_parse_rule_expr(struct nft_handle *h,
+ struct nftnl_expr *expr,
+ struct nft_xt_ctx *ctx)
+{
+ const char *name = nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
+
+ if (strcmp(name, "counter") == 0)
+ nft_parse_counter(expr, &ctx->cs->counters);
+ else if (strcmp(name, "payload") == 0)
+ nft_parse_payload(ctx, expr);
+ else if (strcmp(name, "meta") == 0)
+ nft_parse_meta(ctx, expr);
+ else if (strcmp(name, "bitwise") == 0)
+ nft_parse_bitwise(ctx, expr);
+ else if (strcmp(name, "cmp") == 0)
+ nft_parse_cmp(ctx, expr);
+ else if (strcmp(name, "immediate") == 0)
+ nft_parse_immediate(ctx, expr);
+ else if (strcmp(name, "match") == 0)
+ nft_parse_match(ctx, expr);
+ else if (strcmp(name, "target") == 0)
+ nft_parse_target(ctx, expr);
+ else if (strcmp(name, "limit") == 0)
+ nft_parse_limit(ctx, expr);
+ else if (strcmp(name, "lookup") == 0)
+ nft_parse_lookup(ctx, h, expr);
+ else if (strcmp(name, "log") == 0)
+ nft_parse_log(ctx, expr);
+ else if (strcmp(name, "range") == 0)
+ nft_parse_range(ctx, expr);
+
+ if (ctx->errmsg) {
+ fprintf(stderr, "Error: %s\n", ctx->errmsg);
+ ctx->errmsg = NULL;
+ return false;
+ }
+ return true;
+}
+
bool nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
struct iptables_command_state *cs)
@@ -905,40 +944,8 @@ bool nft_rule_to_iptables_command_state(struct nft_handle *h,
expr = nftnl_expr_iter_next(ctx.iter);
while (expr != NULL) {
- const char *name =
- nftnl_expr_get_str(expr, NFTNL_EXPR_NAME);
-
- if (strcmp(name, "counter") == 0)
- nft_parse_counter(expr, &ctx.cs->counters);
- else if (strcmp(name, "payload") == 0)
- nft_parse_payload(&ctx, expr);
- else if (strcmp(name, "meta") == 0)
- nft_parse_meta(&ctx, expr);
- else if (strcmp(name, "bitwise") == 0)
- nft_parse_bitwise(&ctx, expr);
- else if (strcmp(name, "cmp") == 0)
- nft_parse_cmp(&ctx, expr);
- else if (strcmp(name, "immediate") == 0)
- nft_parse_immediate(&ctx, expr);
- else if (strcmp(name, "match") == 0)
- nft_parse_match(&ctx, expr);
- else if (strcmp(name, "target") == 0)
- nft_parse_target(&ctx, expr);
- else if (strcmp(name, "limit") == 0)
- nft_parse_limit(&ctx, expr);
- else if (strcmp(name, "lookup") == 0)
- nft_parse_lookup(&ctx, h, expr);
- else if (strcmp(name, "log") == 0)
- nft_parse_log(&ctx, expr);
- else if (strcmp(name, "range") == 0)
- nft_parse_range(&ctx, expr);
-
- if (ctx.errmsg) {
- fprintf(stderr, "Error: %s\n", ctx.errmsg);
- ctx.errmsg = NULL;
+ if (!nft_parse_rule_expr(h, expr, &ctx))
ret = false;
- }
-
expr = nftnl_expr_iter_next(ctx.iter);
}
diff --git a/iptables/nft-ruleparse.h b/iptables/nft-ruleparse.h
index 62c9160d77711..0377e4ae17a6e 100644
--- a/iptables/nft-ruleparse.h
+++ b/iptables/nft-ruleparse.h
@@ -133,4 +133,8 @@ int parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e, uint8_t key,
int nft_parse_hl(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
struct iptables_command_state *cs);
+bool nft_parse_rule_expr(struct nft_handle *h,
+ struct nftnl_expr *expr,
+ struct nft_xt_ctx *ctx);
+
#endif /* _NFT_RULEPARSE_H_ */
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 3/8] nft: __add_{match,target}() can't fail
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 1/8] nft: Make add_log() static Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 2/8] nft: ruleparse: Introduce nft_parse_rule_expr() Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 4/8] nft: Introduce UDATA_TYPE_COMPAT_EXT Phil Sutter
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
These functions either call xtables_error() which terminates the process
or succeed - make them return void. While at it, export them as rule
parsing code will call them in future. Also make input parameter const,
they're not supposed to alter extension data.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
iptables/nft.c | 28 ++++++++++------------------
iptables/nft.h | 2 ++
2 files changed, 12 insertions(+), 18 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index 2ed21bb14c253..e629f995b7709 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1034,7 +1034,7 @@ int nft_chain_set(struct nft_handle *h, const char *table,
return 1;
}
-static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
+void __add_match(struct nftnl_expr *e, const struct xt_entry_match *m)
{
void *info;
@@ -1044,8 +1044,6 @@ static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
info = xtables_calloc(1, m->u.match_size);
memcpy(info, m->data, m->u.match_size - sizeof(*m));
nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
-
- return 0;
}
static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
@@ -1378,11 +1376,10 @@ static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r,
if (udp->invflags > XT_UDP_INV_MASK ||
udp_all_zero(udp)) {
struct nftnl_expr *expr = nftnl_expr_alloc("match");
- int ret;
- ret = __add_match(expr, m);
+ __add_match(expr, m);
nftnl_rule_add_expr(r, expr);
- return ret;
+ return 0;
}
if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_UDP)
@@ -1431,11 +1428,10 @@ static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r,
if (tcp->invflags & ~supported || tcp->option ||
tcp_all_zero(tcp)) {
struct nftnl_expr *expr = nftnl_expr_alloc("match");
- int ret;
- ret = __add_match(expr, m);
+ __add_match(expr, m);
nftnl_rule_add_expr(r, expr);
- return ret;
+ return 0;
}
if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_TCP)
@@ -1478,7 +1474,6 @@ 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;
switch (ctx->command) {
case NFT_COMPAT_RULE_APPEND:
@@ -1503,13 +1498,13 @@ int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
if (expr == NULL)
return -ENOMEM;
- ret = __add_match(expr, m);
+ __add_match(expr, m);
nftnl_rule_add_expr(r, expr);
- return ret;
+ return 0;
}
-static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
+void __add_target(struct nftnl_expr *e, const struct xt_entry_target *t)
{
void *info;
@@ -1520,8 +1515,6 @@ static int __add_target(struct nftnl_expr *e, struct xt_entry_target *t)
info = xtables_calloc(1, t->u.target_size);
memcpy(info, t->data, t->u.target_size - sizeof(*t));
nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
-
- return 0;
}
static int add_meta_nftrace(struct nftnl_rule *r)
@@ -1549,7 +1542,6 @@ static int add_meta_nftrace(struct nftnl_rule *r)
int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
{
struct nftnl_expr *expr;
- int ret;
if (strcmp(t->u.user.name, "TRACE") == 0)
return add_meta_nftrace(r);
@@ -1558,10 +1550,10 @@ int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
if (expr == NULL)
return -ENOMEM;
- ret = __add_target(expr, t);
+ __add_target(expr, t);
nftnl_rule_add_expr(r, expr);
- return ret;
+ return 0;
}
int add_jumpto(struct nftnl_rule *r, const char *name, int verdict)
diff --git a/iptables/nft.h b/iptables/nft.h
index 09b4341f92f8e..49653ecea7330 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -192,8 +192,10 @@ bool nft_rule_is_policy_rule(struct nftnl_rule *r);
*/
int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes);
int add_verdict(struct nftnl_rule *r, int verdict);
+void __add_match(struct nftnl_expr *e, const 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);
+void __add_target(struct nftnl_expr *e, const struct xt_entry_target *t);
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.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 4/8] nft: Introduce UDATA_TYPE_COMPAT_EXT
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
` (2 preceding siblings ...)
2024-10-09 11:48 ` [iptables PATCH v2 3/8] nft: __add_{match,target}() can't fail Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 5/8] nft-ruleparse: Fallback to compat expressions in userdata Phil Sutter
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
This new rule udata attribute will contain extensions which have been
converted to native nftables expressions for rule parsers to fall back
to.
While at it, export parse_udata_cb() as rule parsing code will call it
in future.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
iptables/nft.c | 11 +++--------
iptables/nft.h | 12 ++++++++++++
2 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index e629f995b7709..2cc654e2dd91d 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1670,14 +1670,7 @@ int add_counters(struct nftnl_rule *r, uint64_t packets, uint64_t bytes)
return 0;
}
-enum udata_type {
- UDATA_TYPE_COMMENT,
- UDATA_TYPE_EBTABLES_POLICY,
- __UDATA_TYPE_MAX,
-};
-#define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
-
-static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
+int parse_udata_cb(const struct nftnl_udata *attr, void *data)
{
unsigned char *value = nftnl_udata_get(attr);
uint8_t type = nftnl_udata_type(attr);
@@ -1691,6 +1684,8 @@ static int parse_udata_cb(const struct nftnl_udata *attr, void *data)
break;
case UDATA_TYPE_EBTABLES_POLICY:
break;
+ case UDATA_TYPE_COMPAT_EXT:
+ break;
default:
return 0;
}
diff --git a/iptables/nft.h b/iptables/nft.h
index 49653ecea7330..f1a58b9e52865 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -275,4 +275,16 @@ void nft_assert_table_compatible(struct nft_handle *h,
int ebt_set_user_chain_policy(struct nft_handle *h, const char *table,
const char *chain, const char *policy);
+struct nftnl_udata;
+
+enum udata_type {
+ UDATA_TYPE_COMMENT,
+ UDATA_TYPE_EBTABLES_POLICY,
+ UDATA_TYPE_COMPAT_EXT,
+ __UDATA_TYPE_MAX,
+};
+#define UDATA_TYPE_MAX (__UDATA_TYPE_MAX - 1)
+
+int parse_udata_cb(const struct nftnl_udata *attr, void *data);
+
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 5/8] nft-ruleparse: Fallback to compat expressions in userdata
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
` (3 preceding siblings ...)
2024-10-09 11:48 ` [iptables PATCH v2 4/8] nft: Introduce UDATA_TYPE_COMPAT_EXT Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 6/8] nft: Pass nft_handle into add_{action,match}() Phil Sutter
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
If parsing of a rule fails (e.g. due to an unknown native expression),
check if userdata contains a UDATA_TYPE_COMPAT_EXT attribute and retry
parsing the rule preferring the contained extensions instead of native
expressions.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
configure.ac | 9 +++
iptables/Makefile.am | 1 +
iptables/nft-compat.c | 148 +++++++++++++++++++++++++++++++++++++++
iptables/nft-compat.h | 29 ++++++++
iptables/nft-ruleparse.c | 17 +++++
5 files changed, 204 insertions(+)
create mode 100644 iptables/nft-compat.c
create mode 100644 iptables/nft-compat.h
diff --git a/configure.ac b/configure.ac
index a19a60c03c5b2..4cc4960598822 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,6 +77,14 @@ AC_ARG_WITH([xt-lock-name], AS_HELP_STRING([--with-xt-lock-name=PATH],
AC_ARG_ENABLE([profiling],
AS_HELP_STRING([--enable-profiling], [build for use of gcov/gprof]),
[enable_profiling="$enableval"], [enable_profiling="no"])
+AC_ARG_WITH([zlib], [AS_HELP_STRING([--without-zlib],
+ [Disable payload compression of rule compat expressions])],
+ [], [with_zlib=yes])
+AS_IF([test "x$with_zlib" != xno], [
+ AC_CHECK_LIB([z], [compress], ,
+ AC_MSG_ERROR([No suitable version of zlib found]))
+ AC_DEFINE([HAVE_ZLIB], [1], [Define if you have zlib])
+])
AC_MSG_CHECKING([whether $LD knows -Wl,--no-undefined])
saved_LDFLAGS="$LDFLAGS";
@@ -289,6 +297,7 @@ echo "
nftables support: ${enable_nftables}
connlabel support: ${enable_connlabel}
profiling support: ${enable_profiling}
+ compress rule compat expressions: ${with_zlib}
Build parameters:
Put plugins into executable (static): ${enable_static}
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index 2007cd10260bd..4855c9a7c2911 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -57,6 +57,7 @@ xtables_nft_multi_SOURCES += nft.c nft.h \
nft-ruleparse-arp.c nft-ruleparse-bridge.c \
nft-ruleparse-ipv4.c nft-ruleparse-ipv6.c \
nft-shared.c nft-shared.h \
+ nft-compat.c nft-compat.h \
xtables-monitor.c \
xtables.c xtables-arp.c xtables-eb.c \
xtables-standalone.c xtables-eb-standalone.c \
diff --git a/iptables/nft-compat.c b/iptables/nft-compat.c
new file mode 100644
index 0000000000000..1edf08851c579
--- /dev/null
+++ b/iptables/nft-compat.c
@@ -0,0 +1,148 @@
+/*
+ * (C) 2024 Red Hat GmbH
+ * Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "config.h"
+#include "nft-compat.h"
+#include "nft-ruleparse.h"
+#include "nft.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <xtables.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+#include <libnftnl/udata.h>
+
+static struct rule_udata_ext *
+rule_get_udata_ext(const struct nftnl_rule *r, uint32_t *outlen)
+{
+ const struct nftnl_udata *tb[UDATA_TYPE_MAX + 1] = {};
+ struct nftnl_udata_buf *udata;
+ uint32_t udatalen;
+
+ udata = (void *)nftnl_rule_get_data(r, NFTNL_RULE_USERDATA, &udatalen);
+ if (!udata)
+ return NULL;
+
+ if (nftnl_udata_parse(udata, udatalen, parse_udata_cb, tb) < 0)
+ return NULL;
+
+ if (!tb[UDATA_TYPE_COMPAT_EXT])
+ return NULL;
+
+ if (outlen)
+ *outlen = nftnl_udata_len(tb[UDATA_TYPE_COMPAT_EXT]);
+ return nftnl_udata_get(tb[UDATA_TYPE_COMPAT_EXT]);
+}
+
+static struct nftnl_expr *
+__nftnl_expr_from_udata_ext(struct rule_udata_ext *rue, const void *data)
+{
+ struct nftnl_expr *expr = NULL;
+
+ switch (rue->flags & RUE_FLAG_TYPE_BITS) {
+ case RUE_FLAG_MATCH_TYPE:
+ expr = nftnl_expr_alloc("match");
+ __add_match(expr, data);
+ break;
+ case RUE_FLAG_TARGET_TYPE:
+ expr = nftnl_expr_alloc("target");
+ __add_target(expr, data);
+ break;
+ default:
+ fprintf(stderr,
+ "Warning: Unexpected udata extension type %d\n",
+ rue->flags & RUE_FLAG_TYPE_BITS);
+ }
+
+ return expr;
+}
+
+static struct nftnl_expr *
+nftnl_expr_from_zipped_udata_ext(struct rule_udata_ext *rue)
+{
+#ifdef HAVE_ZLIB
+ uLongf datalen = rue->orig_size;
+ struct nftnl_expr *expr = NULL;
+ void *data;
+
+ data = xtables_malloc(datalen);
+ if (uncompress(data, &datalen, rue->data, rue->size) != Z_OK) {
+ fprintf(stderr, "Warning: Failed to uncompress rule udata extension\n");
+ goto out;
+ }
+
+ expr = __nftnl_expr_from_udata_ext(rue, data);
+out:
+ free(data);
+ return expr;
+#else
+ fprintf(stderr, "Warning: Zipped udata extensions are not supported.\n");
+ return NULL;
+#endif
+}
+
+static struct nftnl_expr *nftnl_expr_from_udata_ext(struct rule_udata_ext *rue)
+{
+ if (rue->flags & RUE_FLAG_ZIP)
+ return nftnl_expr_from_zipped_udata_ext(rue);
+ else
+ return __nftnl_expr_from_udata_ext(rue, rue->data);
+}
+
+bool rule_has_udata_ext(const struct nftnl_rule *r)
+{
+ return rule_get_udata_ext(r, NULL) != NULL;
+}
+
+#define rule_udata_ext_foreach(rue, ext, extlen) \
+ for (rue = (void *)(ext); \
+ (char *)rue < (char *)(ext) + extlen; \
+ rue = (void *)((char *)rue + sizeof(*rue) + rue->size))
+
+bool rule_parse_udata_ext(struct nft_xt_ctx *ctx, const struct nftnl_rule *r)
+{
+ struct rule_udata_ext *rue;
+ struct nftnl_expr *expr;
+ uint32_t extlen;
+ bool ret = true;
+ int eidx = 0;
+ void *ext;
+
+ ext = rule_get_udata_ext(r, &extlen);
+ if (!ext)
+ return false;
+
+ rule_udata_ext_foreach(rue, ext, extlen) {
+ for (; eidx < rue->start_idx; eidx++) {
+ expr = nftnl_expr_iter_next(ctx->iter);
+ if (!nft_parse_rule_expr(ctx->h, expr, ctx))
+ ret = false;
+ }
+
+ expr = nftnl_expr_from_udata_ext(rue);
+ if (!nft_parse_rule_expr(ctx->h, expr, ctx))
+ ret = false;
+ nftnl_expr_free(expr);
+
+ for (; eidx < rue->end_idx; eidx++)
+ nftnl_expr_iter_next(ctx->iter);
+ }
+ expr = nftnl_expr_iter_next(ctx->iter);
+ while (expr != NULL) {
+ if (!nft_parse_rule_expr(ctx->h, expr, ctx))
+ ret = false;
+ expr = nftnl_expr_iter_next(ctx->iter);
+ }
+ return ret;
+}
+
diff --git a/iptables/nft-compat.h b/iptables/nft-compat.h
new file mode 100644
index 0000000000000..1147f08a0b6d5
--- /dev/null
+++ b/iptables/nft-compat.h
@@ -0,0 +1,29 @@
+#ifndef _NFT_COMPAT_H_
+#define _NFT_COMPAT_H_
+
+#include <libnftnl/rule.h>
+
+#include <linux/netfilter/x_tables.h>
+
+enum rule_udata_ext_flags {
+ RUE_FLAG_MATCH_TYPE = (1 << 0),
+ RUE_FLAG_TARGET_TYPE = (1 << 1),
+ RUE_FLAG_ZIP = (1 << 7),
+};
+#define RUE_FLAG_TYPE_BITS (RUE_FLAG_MATCH_TYPE | RUE_FLAG_TARGET_TYPE)
+
+struct rule_udata_ext {
+ uint8_t start_idx;
+ uint8_t end_idx;
+ uint8_t flags;
+ uint16_t orig_size;
+ uint16_t size;
+ unsigned char data[];
+};
+
+struct nft_xt_ctx;
+
+bool rule_has_udata_ext(const struct nftnl_rule *r);
+bool rule_parse_udata_ext(struct nft_xt_ctx *ctx, const struct nftnl_rule *r);
+
+#endif /* _NFT_COMPAT_H_ */
diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c
index 757d3c29fc816..34270e46ae888 100644
--- a/iptables/nft-ruleparse.c
+++ b/iptables/nft-ruleparse.c
@@ -10,6 +10,7 @@
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
+#include "config.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -27,6 +28,7 @@
#include <xtables.h>
+#include "nft-compat.h"
#include "nft-ruleparse.h"
#include "nft.h"
@@ -948,6 +950,21 @@ bool nft_rule_to_iptables_command_state(struct nft_handle *h,
ret = false;
expr = nftnl_expr_iter_next(ctx.iter);
}
+ if (!ret && rule_has_udata_ext(r)) {
+ fprintf(stderr,
+ "Warning: Rule parser failed, trying compat fallback\n");
+
+ h->ops->clear_cs(cs);
+ if (h->ops->init_cs)
+ h->ops->init_cs(cs);
+
+ nftnl_expr_iter_destroy(ctx.iter);
+ ctx.iter = nftnl_expr_iter_create(r);
+ if (!ctx.iter)
+ return false;
+
+ ret = rule_parse_udata_ext(&ctx, r);
+ }
nftnl_expr_iter_destroy(ctx.iter);
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 6/8] nft: Pass nft_handle into add_{action,match}()
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
` (4 preceding siblings ...)
2024-10-09 11:48 ` [iptables PATCH v2 5/8] nft-ruleparse: Fallback to compat expressions in userdata Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 7/8] nft: Embed compat extensions in rule userdata Phil Sutter
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
Creation of compat extensions in rule userdata will depend on a flag in
nft_handle.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
iptables/nft-arp.c | 2 +-
iptables/nft-bridge.c | 9 +++++----
iptables/nft-ipv4.c | 2 +-
iptables/nft-ipv6.c | 2 +-
iptables/nft.c | 9 +++++----
iptables/nft.h | 6 ++++--
6 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 264864c3fb2b2..8837c236bf2a0 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -167,7 +167,7 @@ static int nft_arp_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
ret = add_verdict(r, NFT_RETURN);
else
- ret = add_target(r, cs->target->t);
+ ret = add_target(h, r, cs->target->t);
} else if (strlen(cs->jumpto) > 0) {
/* No goto in arptables */
ret = add_jumpto(r, cs->jumpto, NFT_JUMP);
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 1623acbac0ba6..6a236846702a3 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -88,7 +88,8 @@ static int add_meta_broute(struct nftnl_rule *r)
return 0;
}
-static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
+static int _add_action(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
const char *table = nftnl_rule_get_str(r, NFTNL_RULE_TABLE);
@@ -104,7 +105,7 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
}
}
- return add_action(r, cs, false);
+ return add_action(h, r, cs, false);
}
static int
@@ -192,7 +193,7 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
if (nft_bridge_add_match(h, fw, ctx, r, iter->u.match->m))
break;
} else {
- if (add_target(r, iter->u.watcher->t))
+ if (add_target(h, r, iter->u.watcher->t))
break;
}
}
@@ -200,7 +201,7 @@ static int nft_bridge_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
return -1;
- return _add_action(r, cs);
+ return _add_action(h, r, cs);
}
static void nft_bridge_init_cs(struct iptables_command_state *cs)
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 740928757b7e2..91369ec47ba2f 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -95,7 +95,7 @@ static int nft_ipv4_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
return -1;
- return add_action(r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO));
+ return add_action(h, r, cs, !!(cs->fw.ip.flags & IPT_F_GOTO));
}
static bool nft_ipv4_is_same(const struct iptables_command_state *a,
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index b184f8af3e6ed..e68d41e56afef 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -81,7 +81,7 @@ static int nft_ipv6_add(struct nft_handle *h, struct nft_rule_ctx *ctx,
if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
return -1;
- return add_action(r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO));
+ return add_action(h, r, cs, !!(cs->fw6.ipv6.flags & IP6T_F_GOTO));
}
static bool nft_ipv6_is_same(const struct iptables_command_state *a,
diff --git a/iptables/nft.c b/iptables/nft.c
index 2cc654e2dd91d..9888debca16b4 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1539,7 +1539,8 @@ static int add_meta_nftrace(struct nftnl_rule *r)
return 0;
}
-int add_target(struct nftnl_rule *r, struct xt_entry_target *t)
+int add_target(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_target *t)
{
struct nftnl_expr *expr;
@@ -1589,8 +1590,8 @@ int add_verdict(struct nftnl_rule *r, int verdict)
static int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
-int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
- bool goto_set)
+int add_action(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs, bool goto_set)
{
int ret = 0;
@@ -1606,7 +1607,7 @@ int add_action(struct nftnl_rule *r, struct iptables_command_state *cs,
else if (strcmp(cs->jumpto, "NFLOG") == 0)
ret = add_log(r, cs);
else
- ret = add_target(r, cs->target->t);
+ ret = add_target(h, r, cs->target->t);
} else if (strlen(cs->jumpto) > 0) {
/* Not standard, then it's a go / jump to chain */
if (goto_set)
diff --git a/iptables/nft.h b/iptables/nft.h
index f1a58b9e52865..e2004ba6e8292 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -196,9 +196,11 @@ void __add_match(struct nftnl_expr *e, const 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);
void __add_target(struct nftnl_expr *e, const struct xt_entry_target *t);
-int add_target(struct nftnl_rule *r, struct xt_entry_target *t);
+int add_target(struct nft_handle *h, 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);
+int add_action(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs, bool goto_set);
char *get_comment(const void *data, uint32_t data_len);
enum nft_rule_print {
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 7/8] nft: Embed compat extensions in rule userdata
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
` (5 preceding siblings ...)
2024-10-09 11:48 ` [iptables PATCH v2 6/8] nft: Pass nft_handle into add_{action,match}() Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 8/8] tests: iptables-test: Add nft-compat variant Phil Sutter
2025-04-10 16:47 ` [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
If enabled (via --compat flag or XTABLES_COMPAT env variable), attach
any extensions for which native nftables expressions are generated to
userdata. An earlier version of the tool trying to parse the
kernel-dumped ruleset may then fall back to these extensions if native
expression parsing fails.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
Changes since v1:
- Convert type and zip bit to flags
- Add compat ext for NFLOG, too
- Export parsing code into an initial patch
- Make the feature opt-in for users
---
iptables/arptables-nft.8 | 12 ++++++
iptables/ebtables-nft.8 | 12 ++++++
iptables/iptables-restore.8.in | 12 ++++++
iptables/iptables.8.in | 12 ++++++
iptables/nft-compat.c | 74 ++++++++++++++++++++++++++++++++++
iptables/nft-compat.h | 25 ++++++++++++
iptables/nft-ruleparse.c | 2 +-
iptables/nft.c | 63 ++++++++++++++++++++++-------
iptables/nft.h | 3 ++
iptables/xshared.c | 7 ++++
iptables/xshared.h | 1 +
iptables/xtables-arp.c | 1 +
iptables/xtables-eb.c | 4 ++
iptables/xtables-nft.8 | 11 +++++
iptables/xtables-restore.c | 15 ++++++-
iptables/xtables.c | 3 ++
16 files changed, 240 insertions(+), 17 deletions(-)
diff --git a/iptables/arptables-nft.8 b/iptables/arptables-nft.8
index c48a2cc2286ba..8d1eb9fb651ed 100644
--- a/iptables/arptables-nft.8
+++ b/iptables/arptables-nft.8
@@ -234,6 +234,18 @@ counters of a rule (during
.B APPEND,
.B REPLACE
operations).
+.TP
+.B --compat
+When creating a rule, attach compatibility data to the rule's userdata section
+for use as aid in parsing the rule by an older version of the program. The old
+version obviously needs to support this, though.
+Specifying this option a second time instructs the program to default to the
+rule's compatibility data when parsing, which is mostly useful for debugging or
+testing purposes.
+
+The \fBXTABLES_COMPAT\fP environment variable can be used to override the
+default setting. The expected value is a natural number representing the number
+of times \fB--compat\fP was specified.
.SS RULE-SPECIFICATIONS
The following command line arguments make up a rule specification (as used
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
index 8698165024de1..3088bb0cce366 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -360,6 +360,18 @@ to try to automatically load missing kernel modules.
.B --concurrent
This would use a file lock to support concurrent scripts updating the ebtables
kernel tables. It is not needed with \fBebtables-nft\fP though and thus ignored.
+.TP
+.B --compat
+When creating a rule, attach compatibility data to the rule's userdata section
+for use as aid in parsing the rule by an older version of the program. The old
+version obviously needs to support this, though.
+Specifying this option a second time instructs the program to default to the
+rule's compatibility data when parsing, which is mostly useful for debugging or
+testing purposes.
+
+The \fBXTABLES_COMPAT\fP environment variable can be used to override the
+default setting. The expected value is a natural number representing the number
+of times \fB--compat\fP was specified.
.SS
RULE SPECIFICATIONS
diff --git a/iptables/iptables-restore.8.in b/iptables/iptables-restore.8.in
index aa816f794d6f3..df61b2a623f64 100644
--- a/iptables/iptables-restore.8.in
+++ b/iptables/iptables-restore.8.in
@@ -74,6 +74,18 @@ determine the executable's path.
.TP
\fB\-T\fP, \fB\-\-table\fP \fIname\fP
Restore only the named table even if the input stream contains other ones.
+.TP
+\fB\-\-compat\fP (nft-variants only)
+When creating a rule, attach compatibility data to the rule's userdata section
+for use as aid in parsing the rule by an older version of the program. The old
+version obviously needs to support this, though.
+Specifying this option a second time instructs the program to default to the
+rule's compatibility data when parsing, which is mostly useful for debugging or
+testing purposes.
+
+The \fBXTABLES_COMPAT\fP environment variable can be used to override the
+default setting. The expected value is a natural number representing the number
+of times \fB--compat\fP was specified.
.SH BUGS
None known as of iptables-1.2.1 release
.SH AUTHORS
diff --git a/iptables/iptables.8.in b/iptables/iptables.8.in
index 21fb891dc6373..41c45a4a6e991 100644
--- a/iptables/iptables.8.in
+++ b/iptables/iptables.8.in
@@ -397,6 +397,18 @@ corresponding to that rule's position in the chain.
\fB\-\-modprobe=\fP\fIcommand\fP
When adding or inserting rules into a chain, use \fIcommand\fP
to load any necessary modules (targets, match extensions, etc).
+.TP
+\fB\-\-compat\fP (nft-variants only)
+When creating a rule, attach compatibility data to the rule's userdata section
+for use as aid in parsing the rule by an older version of the program. The old
+version obviously needs to support this, though.
+Specifying this option a second time instructs the program to default to the
+rule's compatibility data when parsing, which is mostly useful for debugging or
+testing purposes.
+
+The \fBXTABLES_COMPAT\fP environment variable can be used to override the
+default setting. The expected value is a natural number representing the number
+of times \fB--compat\fP was specified.
.SH LOCK FILE
iptables uses the \fI@XT_LOCK_NAME@\fP file to take an exclusive lock at
diff --git a/iptables/nft-compat.c b/iptables/nft-compat.c
index 1edf08851c579..632733ca0cade 100644
--- a/iptables/nft-compat.c
+++ b/iptables/nft-compat.c
@@ -22,6 +22,21 @@
#include <libnftnl/udata.h>
+int nftnl_rule_expr_count(const struct nftnl_rule *r)
+{
+ struct nftnl_expr_iter *iter = nftnl_expr_iter_create(r);
+ int cnt = 0;
+
+ if (!iter)
+ return -1;
+
+ while (nftnl_expr_iter_next(iter))
+ cnt++;
+
+ nftnl_expr_iter_destroy(iter);
+ return cnt;
+}
+
static struct rule_udata_ext *
rule_get_udata_ext(const struct nftnl_rule *r, uint32_t *outlen)
{
@@ -44,6 +59,65 @@ rule_get_udata_ext(const struct nftnl_rule *r, uint32_t *outlen)
return nftnl_udata_get(tb[UDATA_TYPE_COMPAT_EXT]);
}
+static void
+pack_rule_udata_ext_data(struct rule_udata_ext *rue,
+ const void *data, size_t datalen)
+{
+ size_t datalen_out = datalen;
+#ifdef HAVE_ZLIB
+ compress(rue->data, &datalen_out, data, datalen);
+ rue->flags |= RUE_FLAG_ZIP;
+#else
+ memcpy(rue->data, data, datalen);
+#endif
+ rue->size = datalen_out;
+}
+
+void rule_add_udata_ext(struct nft_handle *h, struct nftnl_rule *r,
+ uint16_t start_idx, uint16_t end_idx,
+ uint8_t flags, uint16_t size, const void *data)
+{
+ struct rule_udata_ext *ext = NULL;
+ uint32_t extlen = 0, newextlen;
+ char *newext;
+ void *udata;
+
+ if (!h->compat)
+ return;
+
+ ext = rule_get_udata_ext(r, &extlen);
+ if (!ext)
+ extlen = 0;
+
+ udata = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udata)
+ xtables_error(OTHER_PROBLEM, "can't alloc memory!");
+
+ newextlen = sizeof(*ext) + size;
+ newext = xtables_malloc(extlen + newextlen);
+ if (extlen)
+ memcpy(newext, ext, extlen);
+ memset(newext + extlen, 0, newextlen);
+
+ ext = (struct rule_udata_ext *)(newext + extlen);
+ ext->start_idx = start_idx;
+ ext->end_idx = end_idx;
+ ext->flags = flags;
+ ext->orig_size = size;
+ pack_rule_udata_ext_data(ext, data, size);
+ newextlen = sizeof(*ext) + ext->size;
+
+ if (!nftnl_udata_put(udata, UDATA_TYPE_COMPAT_EXT,
+ extlen + newextlen, newext) ||
+ nftnl_rule_set_data(r, NFTNL_RULE_USERDATA,
+ nftnl_udata_buf_data(udata),
+ nftnl_udata_buf_len(udata)))
+ xtables_error(OTHER_PROBLEM, "can't alloc memory!");
+
+ free(newext);
+ nftnl_udata_buf_free(udata);
+}
+
static struct nftnl_expr *
__nftnl_expr_from_udata_ext(struct rule_udata_ext *rue, const void *data)
{
diff --git a/iptables/nft-compat.h b/iptables/nft-compat.h
index 1147f08a0b6d5..59b3c0267f8d0 100644
--- a/iptables/nft-compat.h
+++ b/iptables/nft-compat.h
@@ -5,6 +5,8 @@
#include <linux/netfilter/x_tables.h>
+int nftnl_rule_expr_count(const struct nftnl_rule *r);
+
enum rule_udata_ext_flags {
RUE_FLAG_MATCH_TYPE = (1 << 0),
RUE_FLAG_TARGET_TYPE = (1 << 1),
@@ -21,6 +23,29 @@ struct rule_udata_ext {
unsigned char data[];
};
+struct nft_handle;
+
+void rule_add_udata_ext(struct nft_handle *h, struct nftnl_rule *r,
+ uint16_t start_idx, uint16_t end_idx,
+ uint8_t flags, uint16_t size, const void *data);
+static inline void
+rule_add_udata_match(struct nft_handle *h, struct nftnl_rule *r,
+ uint16_t start_idx, uint16_t end_idx,
+ const struct xt_entry_match *m)
+{
+ rule_add_udata_ext(h, r, start_idx, end_idx,
+ RUE_FLAG_MATCH_TYPE, m->u.match_size, m);
+}
+
+static inline void
+rule_add_udata_target(struct nft_handle *h, struct nftnl_rule *r,
+ uint16_t start_idx, uint16_t end_idx,
+ const struct xt_entry_target *t)
+{
+ rule_add_udata_ext(h, r, start_idx, end_idx,
+ RUE_FLAG_TARGET_TYPE, t->u.target_size, t);
+}
+
struct nft_xt_ctx;
bool rule_has_udata_ext(const struct nftnl_rule *r);
diff --git a/iptables/nft-ruleparse.c b/iptables/nft-ruleparse.c
index 34270e46ae888..cdf1af4fab277 100644
--- a/iptables/nft-ruleparse.c
+++ b/iptables/nft-ruleparse.c
@@ -950,7 +950,7 @@ bool nft_rule_to_iptables_command_state(struct nft_handle *h,
ret = false;
expr = nftnl_expr_iter_next(ctx.iter);
}
- if (!ret && rule_has_udata_ext(r)) {
+ if ((!ret || h->compat > 1) && rule_has_udata_ext(r)) {
fprintf(stderr,
"Warning: Rule parser failed, trying compat fallback\n");
diff --git a/iptables/nft.c b/iptables/nft.c
index 9888debca16b4..d563a011bec5d 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -9,6 +9,7 @@
* This code has been sponsored by Sophos Astaro <http://www.sophos.com>
*/
+#include "config.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
@@ -60,6 +61,7 @@
#include "nft-cache.h"
#include "nft-shared.h"
#include "nft-bridge.h" /* EBT_NOPROTO */
+#include "nft-compat.h"
static void *nft_fn;
@@ -1046,9 +1048,11 @@ void __add_match(struct nftnl_expr *e, const struct xt_entry_match *m)
nftnl_expr_set(e, NFTNL_EXPR_MT_INFO, info, m->u.match_size - sizeof(*m));
}
-static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
+static int add_nft_limit(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_match *m)
{
struct xt_rateinfo *rinfo = (void *)m->data;
+ int i, ecnt = nftnl_rule_expr_count(r);
static const uint32_t mult[] = {
XT_LIMIT_SCALE*24*60*60, /* day */
XT_LIMIT_SCALE*60*60, /* hour */
@@ -1056,7 +1060,8 @@ static int add_nft_limit(struct nftnl_rule *r, struct xt_entry_match *m)
XT_LIMIT_SCALE, /* sec */
};
struct nftnl_expr *expr;
- int i;
+
+ rule_add_udata_match(h, r, ecnt, ecnt + 1, m);
expr = nftnl_expr_alloc("limit");
if (!expr)
@@ -1371,6 +1376,7 @@ static bool udp_all_zero(const struct xt_udp *u)
static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r,
struct xt_entry_match *m)
{
+ int ret, ecnt = nftnl_rule_expr_count(r);
struct xt_udp *udp = (void *)m->data;
if (udp->invflags > XT_UDP_INV_MASK ||
@@ -1385,8 +1391,12 @@ static int add_nft_udp(struct nft_handle *h, struct nftnl_rule *r,
if (nftnl_rule_get_u32(r, NFTNL_RULE_COMPAT_PROTO) != IPPROTO_UDP)
xtables_error(PARAMETER_PROBLEM, "UDP match requires '-p udp'");
- return add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT,
- udp->dpts, udp->invflags & XT_UDP_INV_DSTPT);
+ ret = add_nft_tcpudp(h, r, udp->spts, udp->invflags & XT_UDP_INV_SRCPT,
+ udp->dpts, udp->invflags & XT_UDP_INV_DSTPT);
+
+ rule_add_udata_match(h, r, ecnt, nftnl_rule_expr_count(r), m);
+
+ return ret;
}
static int add_nft_tcpflags(struct nft_handle *h, struct nftnl_rule *r,
@@ -1423,6 +1433,7 @@ static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r,
struct xt_entry_match *m)
{
static const uint8_t supported = XT_TCP_INV_SRCPT | XT_TCP_INV_DSTPT | XT_TCP_INV_FLAGS;
+ int ret, ecnt = nftnl_rule_expr_count(r);
struct xt_tcp *tcp = (void *)m->data;
if (tcp->invflags & ~supported || tcp->option ||
@@ -1438,23 +1449,27 @@ static int add_nft_tcp(struct nft_handle *h, struct nftnl_rule *r,
xtables_error(PARAMETER_PROBLEM, "TCP match requires '-p tcp'");
if (tcp->flg_mask) {
- int ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask,
- tcp->invflags & XT_TCP_INV_FLAGS);
+ ret = add_nft_tcpflags(h, r, tcp->flg_cmp, tcp->flg_mask,
+ tcp->invflags & XT_TCP_INV_FLAGS);
if (ret < 0)
return ret;
}
- return add_nft_tcpudp(h, r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT,
- tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT);
+ ret = add_nft_tcpudp(h, r, tcp->spts, tcp->invflags & XT_TCP_INV_SRCPT,
+ tcp->dpts, tcp->invflags & XT_TCP_INV_DSTPT);
+
+ rule_add_udata_match(h, r, ecnt, nftnl_rule_expr_count(r), m);
+
+ return ret;
}
static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r,
struct xt_entry_match *m)
{
struct xt_mark_mtinfo1 *mark = (void *)m->data;
+ int op, ecnt = nftnl_rule_expr_count(r);
uint8_t reg;
- int op;
add_meta(h, r, NFT_META_MARK, ®);
if (mark->mask != 0xffffffff)
@@ -1467,6 +1482,8 @@ static int add_nft_mark(struct nft_handle *h, struct nftnl_rule *r,
add_cmp_u32(r, mark->mark, op, reg);
+ rule_add_udata_match(h, r, ecnt, nftnl_rule_expr_count(r), m);
+
return 0;
}
@@ -1480,7 +1497,7 @@ int add_match(struct nft_handle *h, struct nft_rule_ctx *ctx,
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
if (!strcmp(m->u.user.name, "limit"))
- return add_nft_limit(r, m);
+ return add_nft_limit(h, r, m);
else if (!strcmp(m->u.user.name, "among"))
return add_nft_among(h, r, m);
else if (!strcmp(m->u.user.name, "udp"))
@@ -1517,10 +1534,14 @@ void __add_target(struct nftnl_expr *e, const struct xt_entry_target *t)
nftnl_expr_set(e, NFTNL_EXPR_TG_INFO, info, t->u.target_size - sizeof(*t));
}
-static int add_meta_nftrace(struct nftnl_rule *r)
+static int add_meta_nftrace(struct nft_handle *h, struct nftnl_rule *r,
+ struct xt_entry_target *t)
{
+ int ecnt = nftnl_rule_expr_count(r);
struct nftnl_expr *expr;
+ rule_add_udata_target(h, r, ecnt, ecnt + 2, t);
+
expr = nftnl_expr_alloc("immediate");
if (expr == NULL)
return -ENOMEM;
@@ -1545,7 +1566,7 @@ int add_target(struct nft_handle *h, struct nftnl_rule *r,
struct nftnl_expr *expr;
if (strcmp(t->u.user.name, "TRACE") == 0)
- return add_meta_nftrace(r);
+ return add_meta_nftrace(h, r, t);
expr = nftnl_expr_alloc("target");
if (expr == NULL)
@@ -1588,7 +1609,8 @@ int add_verdict(struct nftnl_rule *r, int verdict)
return 0;
}
-static int add_log(struct nftnl_rule *r, struct iptables_command_state *cs);
+static int add_log(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs);
int add_action(struct nft_handle *h, struct nftnl_rule *r,
struct iptables_command_state *cs, bool goto_set)
@@ -1605,7 +1627,7 @@ int add_action(struct nft_handle *h, struct nftnl_rule *r,
else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
ret = add_verdict(r, NFT_RETURN);
else if (strcmp(cs->jumpto, "NFLOG") == 0)
- ret = add_log(r, cs);
+ ret = add_log(h, r, cs);
else
ret = add_target(h, r, cs->target->t);
} else if (strlen(cs->jumpto) > 0) {
@@ -1618,10 +1640,14 @@ int add_action(struct nft_handle *h, struct nftnl_rule *r,
return ret;
}
-static int add_log(struct nftnl_rule *r, struct iptables_command_state *cs)
+static int add_log(struct nft_handle *h, struct nftnl_rule *r,
+ struct iptables_command_state *cs)
{
struct nftnl_expr *expr;
struct xt_nflog_info *info = (struct xt_nflog_info *)cs->target->t->data;
+ int ecnt = nftnl_rule_expr_count(r);
+
+ rule_add_udata_target(h, r, ecnt, ecnt + 1, cs->target->t);
expr = nftnl_expr_alloc("log");
if (!expr)
@@ -4047,3 +4073,10 @@ void nft_assert_table_compatible(struct nft_handle *h,
"%s%s%stable `%s' is incompatible, use 'nft' tool.",
pfx, chain, sfx, table);
}
+
+uint8_t compat_env_val(void)
+{
+ const char *val = getenv("XTABLES_COMPAT");
+
+ return val ? atoi(val) : 0;
+}
diff --git a/iptables/nft.h b/iptables/nft.h
index e2004ba6e8292..94d90bef44fb3 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -108,6 +108,7 @@ struct nft_handle {
struct nft_cache_req cache_req;
bool restore;
bool noflush;
+ uint8_t compat;
int8_t config_done;
struct list_head cmd_list;
bool cache_init;
@@ -289,4 +290,6 @@ enum udata_type {
int parse_udata_cb(const struct nftnl_udata *attr, void *data);
+uint8_t compat_env_val(void);
+
#endif
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 2a5eef09c75de..544b65e219a8f 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -1254,6 +1254,9 @@ void xtables_printhelp(struct iptables_command_state *cs)
printf(
"[!] --fragment -f match second or further fragments only\n");
+ if (strstr(xt_params->program_version, "nf_tables"))
+ printf(
+" --compat append compatibility data to new rules\n");
printf(
" --modprobe=<command> try to insert modules using this command\n"
" --set-counters -c PKTS BYTES set the counter during insert/append\n"
@@ -1918,6 +1921,10 @@ void do_parse(int argc, char *argv[],
exit_tryhelp(2, p->line);
+ case 20: /* --compat */
+ p->compat++;
+ break;
+
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
if (invert)
diff --git a/iptables/xshared.h b/iptables/xshared.h
index a111e79793b54..fdf5d6089bc6e 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -300,6 +300,7 @@ struct xt_cmd_parse {
bool restore;
int line;
int verbose;
+ uint8_t compat;
bool rule_ranges;
struct xt_cmd_parse_ops *ops;
};
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 71518a9cbdb6a..fe45c370d21db 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -78,6 +78,7 @@ static struct option original_opts[] = {
{ "line-numbers", 0, 0, '0' },
{ "modprobe", 1, 0, 'M' },
{ "set-counters", 1, 0, 'c' },
+ { "compat", 0, 0, 20 },
{ 0 }
};
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 45663a3ad0ee0..ff364ec76191f 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -131,6 +131,7 @@ struct option ebt_original_options[] =
{ "init-table" , no_argument , 0, 11 },
{ "concurrent" , no_argument , 0, 13 },
{ "check" , required_argument, 0, 14 },
+ { "compat" , no_argument , 0, 20 },
{ 0 }
};
@@ -234,6 +235,7 @@ void nft_bridge_print_help(struct iptables_command_state *cs)
"[!] --logical-out name[+] : logical bridge output interface name\n"
"--set-counters -c chain\n"
" pcnt bcnt : set the counters of the to be added rule\n"
+"--compat : append compatibility data to new rules\n"
"--modprobe -M program : try to insert modules using this program\n"
"--concurrent : use a file lock to support concurrent scripts\n"
"--verbose -v : verbose mode\n"
@@ -568,6 +570,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
.line = line,
.rule_ranges = true,
.ops = &h->ops->cmd_parse,
+ .compat = compat_env_val(),
};
int ret = 0;
@@ -577,6 +580,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
do_parse(argc, argv, &p, &cs, &args);
h->verbose = p.verbose;
+ h->compat = p.compat;
t = nft_table_builtin_find(h, p.table);
if (!t)
diff --git a/iptables/xtables-nft.8 b/iptables/xtables-nft.8
index ae54476c6cf87..2ed67ba9d471c 100644
--- a/iptables/xtables-nft.8
+++ b/iptables/xtables-nft.8
@@ -100,6 +100,17 @@ When using \-j TRACE to debug packet traversal to the ruleset, note that you wil
.B xtables\-monitor(8)
in \-\-trace mode to obtain monitoring trace events.
+Some extensions are implemented via native nf_tables expressions instead of
+\fBnft_compat\fP module. This is transparent to the user as such parts of a
+rule are detected and parsed into an extension again before listing. Also,
+run-time behaviour is supposed to be identical. Implementing extensions this
+way is beneficial from a kernel maintainer's perspective as xtables extension
+modules may at some point become unused, so increasing extension conversion is
+to be expected. Since this may break older versions parsing the ruleset
+in-kernel (a possible scenario with containers sharing a network namespace),
+there is \fB--compat\fP flag which causes the replaced extensions to be
+appended to the rule in userdata storage for the parser to fall back to.
+
.SH EXAMPLES
One basic example is creating the skeleton ruleset in nf_tables from the
xtables-nft tools, in a fresh machine:
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 23cd349819f4f..e7802b9e140bd 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -37,6 +37,7 @@ static const struct option options[] = {
{.name = "ipv6", .has_arg = false, .val = '6'},
{.name = "wait", .has_arg = 2, .val = 'w'},
{.name = "wait-interval", .has_arg = 2, .val = 'W'},
+ {.name = "compat", .has_arg = false, .val = 20 },
{NULL},
};
@@ -54,6 +55,7 @@ static void print_usage(const char *name, const char *version)
" [ --noflush ]\n"
" [ --table=<TABLE> ]\n"
" [ --modprobe=<command> ]\n"
+ " [ --compat ]\n"
" [ --ipv4 ]\n"
" [ --ipv6 ]\n", name);
}
@@ -284,6 +286,7 @@ void xtables_restore_parse(struct nft_handle *h,
static int
xtables_restore_main(int family, const char *progname, int argc, char *argv[])
{
+ uint8_t compat = compat_env_val();
struct nft_xt_restore_parse p = {
.commit = true,
.cb = &restore_cb,
@@ -337,6 +340,9 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
if (!optarg && xs_has_arg(argc, argv))
optind++;
break;
+ case 20:
+ compat++;
+ break;
default:
fprintf(stderr,
"Try `%s -h' for more information.\n",
@@ -387,6 +393,7 @@ xtables_restore_main(int family, const char *progname, int argc, char *argv[])
}
h.noflush = noflush;
h.restore = true;
+ h.compat = compat;
xtables_restore_parse(&h, &p);
@@ -419,11 +426,13 @@ static const struct nft_xt_restore_cb ebt_restore_cb = {
static const struct option ebt_restore_options[] = {
{.name = "noflush", .has_arg = 0, .val = 'n'},
{.name = "verbose", .has_arg = 0, .val = 'v'},
+ {.name = "compat", .has_arg = 0, .val = 20},
{ 0 }
};
int xtables_eb_restore_main(int argc, char *argv[])
{
+ uint8_t compat = compat_env_val();
struct nft_xt_restore_parse p = {
.in = stdin,
.cb = &ebt_restore_cb,
@@ -441,9 +450,12 @@ int xtables_eb_restore_main(int argc, char *argv[])
case 'v':
verbose++;
break;
+ case 20: /* --compat */
+ compat++;
+ break;
default:
fprintf(stderr,
- "Usage: ebtables-restore [ --verbose ] [ --noflush ]\n");
+ "Usage: ebtables-restore [ --verbose ] [ --noflush ] [ --compat ]\n");
exit(1);
break;
}
@@ -451,6 +463,7 @@ int xtables_eb_restore_main(int argc, char *argv[])
nft_init_eb(&h, "ebtables-restore");
h.noflush = noflush;
+ h.compat = compat;
xtables_restore_parse(&h, &p);
nft_fini_eb(&h);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 5d73481c25761..7d540880da471 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -82,6 +82,7 @@ static struct option original_opts[] = {
{.name = "goto", .has_arg = 1, .val = 'g'},
{.name = "ipv4", .has_arg = 0, .val = '4'},
{.name = "ipv6", .has_arg = 0, .val = '6'},
+ {.name = "compat", .has_arg = 0, .val = 20},
{NULL},
};
@@ -147,6 +148,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
.restore = restore,
.line = line,
.ops = &h->ops->cmd_parse,
+ .compat = compat_env_val(),
};
struct iptables_command_state cs = {
.jumpto = "",
@@ -161,6 +163,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table,
do_parse(argc, argv, &p, &cs, &args);
h->verbose = p.verbose;
+ h->compat = p.compat;
if (!nft_table_builtin_find(h, p.table))
xtables_error(VERSION_PROBLEM,
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [iptables PATCH v2 8/8] tests: iptables-test: Add nft-compat variant
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
` (6 preceding siblings ...)
2024-10-09 11:48 ` [iptables PATCH v2 7/8] nft: Embed compat extensions in rule userdata Phil Sutter
@ 2024-10-09 11:48 ` Phil Sutter
2025-04-10 16:47 ` [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2024-10-09 11:48 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
Test iptables-nft with forced compat extension restore as third modus
operandi.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
iptables-test.py | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/iptables-test.py b/iptables-test.py
index 77278925d7217..53af5e1150cfa 100755
--- a/iptables-test.py
+++ b/iptables-test.py
@@ -570,6 +570,8 @@ STDERR_IS_TTY = sys.stderr.isatty()
help='Check for missing tests')
parser.add_argument('-n', '--nftables', action='store_true',
help='Test iptables-over-nftables')
+ parser.add_argument('--compat', action='store_true',
+ help='Test iptables-over-nftables in forced compat mode')
parser.add_argument('-N', '--netns', action='store_const',
const='____iptables-container-test',
help='Test netnamespace path')
@@ -589,8 +591,10 @@ STDERR_IS_TTY = sys.stderr.isatty()
variants.append("legacy")
if args.nftables:
variants.append("nft")
+ if args.compat:
+ variants.append("nft-compat")
if len(variants) == 0:
- variants = [ "legacy", "nft" ]
+ variants = [ "legacy", "nft", "nft-compat" ]
if os.getuid() != 0:
print("You need to be root to run this, sorry", file=sys.stderr)
@@ -609,8 +613,14 @@ STDERR_IS_TTY = sys.stderr.isatty()
total_passed = 0
total_tests = 0
for variant in variants:
+
+ exec_infix = variant
+ if variant == "nft-compat":
+ os.putenv("XTABLES_COMPAT", "2")
+ exec_infix = "nft"
+
global EXECUTABLE
- EXECUTABLE = "xtables-" + variant + "-multi"
+ EXECUTABLE = "xtables-" + exec_infix + "-multi"
test_files = 0
tests = 0
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
` (7 preceding siblings ...)
2024-10-09 11:48 ` [iptables PATCH v2 8/8] tests: iptables-test: Add nft-compat variant Phil Sutter
@ 2025-04-10 16:47 ` Phil Sutter
8 siblings, 0 replies; 10+ messages in thread
From: Phil Sutter @ 2025-04-10 16:47 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal, Pablo Neira Ayuso, Jan Engelhardt
On Wed, Oct 09, 2024 at 01:48:11PM +0200, Phil Sutter wrote:
> Changes since v1:
> - Split the parser into a separate patch for easier backporting by
> distributions.
> - Make the writer opt-in, allow users to force the parser fallback at
> run-time.
> - Document the feature in man pages.
>
> Time to abandon earlier attempts at providing compatibility for old
> binaries, choose the next best option which is not relying upon any
> kernel changes.
>
> Basically, all extensions replaced by native bytecode are appended to
> rule userdata so when nftnl rule parsing code fails, it may retry
> omitting all these expressions and restoring an extension from userdata
> instead.
>
> The idea behind this is that extensions are stable which relieves native
> bytecode from being the same. With this series in place, one may
> (re-)start converting extensions into native nftables bytecode again.
>
> Appending rule userdata upon creation is inactive by default and enabled
> via --compat option or XTABLES_COMPAT env variable. The parser will fall
> back to userdata automatically if present and parsing fails.
>
> Patches 1-3 are preparation. Patches 4 and 5 implement the parser side,
> patches 6 and 7 implement the writer and patch 8 finally extends
> iptables-test.py to cover the new code.
>
> Phil Sutter (8):
> nft: Make add_log() static
> nft: ruleparse: Introduce nft_parse_rule_expr()
> nft: __add_{match,target}() can't fail
> nft: Introduce UDATA_TYPE_COMPAT_EXT
> nft-ruleparse: Fallback to compat expressions in userdata
> nft: Pass nft_handle into add_{action,match}()
> nft: Embed compat extensions in rule userdata
> tests: iptables-test: Add nft-compat variant
Series applied.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-04-10 16:47 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-09 11:48 [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 1/8] nft: Make add_log() static Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 2/8] nft: ruleparse: Introduce nft_parse_rule_expr() Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 3/8] nft: __add_{match,target}() can't fail Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 4/8] nft: Introduce UDATA_TYPE_COMPAT_EXT Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 5/8] nft-ruleparse: Fallback to compat expressions in userdata Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 6/8] nft: Pass nft_handle into add_{action,match}() Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 7/8] nft: Embed compat extensions in rule userdata Phil Sutter
2024-10-09 11:48 ` [iptables PATCH v2 8/8] tests: iptables-test: Add nft-compat variant Phil Sutter
2025-04-10 16:47 ` [iptables PATCH v2 0/8] nft: Implement forward compat for future binaries Phil Sutter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.