import iptables-1.8.5-11.el8_9

i8c-beta changed/i8c-beta/iptables-1.8.5-11.el8_9
MSVSphere Packaging Team 8 months ago
commit 882fcd5ce4

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/iptables-1.8.5.tar.bz2

@ -0,0 +1 @@
f177a58d0a71b00d68ef5792ae4676bcc0ad29e6 SOURCES/iptables-1.8.5.tar.bz2

@ -0,0 +1,41 @@
From 4806ba770a3aaadd0a3975ac1ea92dff3ea87ee4 Mon Sep 17 00:00:00 2001
From: Jan Engelhardt <jengelh@inai.de>
Date: Wed, 3 Jun 2020 15:38:48 +0200
Subject: [PATCH] build: resolve iptables-apply not getting installed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ip6tables-apply gets installed but iptables-apply does not.
That is wrong.
» make install DESTDIR=$PWD/r
» find r -name "*app*"
r/usr/local/sbin/ip6tables-apply
r/usr/local/share/man/man8/iptables-apply.8
r/usr/local/share/man/man8/ip6tables-apply.8
Fixes: v1.8.5~87
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit d4ed0c741fc789bb09d977d74d30875fdd50d08b)
---
iptables/Makefile.am | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/iptables/Makefile.am b/iptables/Makefile.am
index dc66b3cc09c08..2024dbf5cb88c 100644
--- a/iptables/Makefile.am
+++ b/iptables/Makefile.am
@@ -56,7 +56,7 @@ man_MANS = iptables.8 iptables-restore.8 iptables-save.8 \
ip6tables-save.8 iptables-extensions.8 \
iptables-apply.8 ip6tables-apply.8
-sbin_SCRIPT = iptables-apply
+sbin_SCRIPTS = iptables-apply
if ENABLE_NFTABLES
man_MANS += xtables-nft.8 xtables-translate.8 xtables-legacy.8 \
--
2.40.0

@ -0,0 +1,57 @@
From eaad1950f1952733c2770b29b593613cfe9af8a8 Mon Sep 17 00:00:00 2001
From: Arturo Borrero Gonzalez <arturo@netfilter.org>
Date: Tue, 16 Jun 2020 11:20:42 +0200
Subject: [PATCH] xtables-translate: don't fail if help was requested
If the user called `iptables-translate -h` then we have CMD_NONE and we should gracefully handle
this case in do_command_xlate().
Before this patch, you would see:
user@debian:~$ sudo iptables-translate -h
[..]
nft Unsupported command?
user@debian:~$ echo $?
1
After this patch:
user@debian:~$ sudo iptables-translate -h
[..]
user@debian:~$ echo $?
0
Fixes: d4409d449c10fa ("nft: Don't exit early after printing help texts")
Acked-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Arturo Borrero Gonzalez <arturo@netfilter.org>
(cherry picked from commit 2757c0b5e5fbbf569695469b331453cecefdf069)
---
iptables/xtables-translate.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 5aa42496b5a48..363c8be15b3fa 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -249,7 +249,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
cs.restore = restore;
- if (!restore)
+ if (!restore && p.command != CMD_NONE)
printf("nft ");
switch (p.command) {
@@ -310,6 +310,9 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
break;
case CMD_SET_POLICY:
break;
+ case CMD_NONE:
+ ret = 1;
+ break;
default:
/* We should never reach this... */
printf("Unsupported command?\n");
--
2.40.0

@ -0,0 +1,30 @@
From d9497b521e6f512f27bd1d4a88086f50418cb7b8 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 16 Jun 2020 13:06:26 +0200
Subject: [PATCH] xtables-translate: Use proper clear_cs function
Avoid memleaks by performing a full free of any allocated data in local
iptables_command_state variable.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 63fa2b1cb98be66990912d7eb42eab5440437087)
---
iptables/xtables-translate.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/iptables/xtables-translate.c b/iptables/xtables-translate.c
index 363c8be15b3fa..575fb320dc408 100644
--- a/iptables/xtables-translate.c
+++ b/iptables/xtables-translate.c
@@ -319,7 +319,7 @@ static int do_command_xlate(struct nft_handle *h, int argc, char *argv[],
exit(1);
}
- xtables_rule_matches_free(&cs.matches);
+ nft_clear_iptables_command_state(&cs);
if (h->family == AF_INET) {
free(args.s.addr.v4);
--
2.40.0

@ -0,0 +1,55 @@
From 94fcba7825b121cbb7d3ff73f4e80a798feccdee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= <maze@google.com>
Date: Tue, 23 Jun 2020 16:09:02 -0700
Subject: [PATCH] libxtables: compiler warning fixes for NO_SHARED_LIBS
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes two issues with NO_SHARED_LIBS:
- #include <dlfcn.h> is ifdef'ed out and thus dlclose()
triggers an undeclared function compiler warning
- dlreg_add() is unused and thus triggers an unused
function warning
Test: builds without warnings
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit 6cb8af1ff3951e47def7a16db39289dc9d9c61fe)
---
libxtables/xtables.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 7fe42580f9b70..8907ba2069be7 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -206,6 +206,7 @@ struct xtables_target *xtables_targets;
static bool xtables_fully_register_pending_match(struct xtables_match *me);
static bool xtables_fully_register_pending_target(struct xtables_target *me);
+#ifndef NO_SHARED_LIBS
/* registry for loaded shared objects to close later */
struct dlreg {
struct dlreg *next;
@@ -237,6 +238,7 @@ static void dlreg_free(void)
dlreg = next;
}
}
+#endif
void xtables_init(void)
{
@@ -267,7 +269,9 @@ void xtables_init(void)
void xtables_fini(void)
{
+#ifndef NO_SHARED_LIBS
dlreg_free();
+#endif
}
void xtables_set_nfproto(uint8_t nfproto)
--
2.40.0

@ -0,0 +1,63 @@
From 0323122f6a3ef9ab2ded571685d3c64851c6df86 Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Wed, 22 Jul 2020 13:04:34 +0200
Subject: [PATCH] extensions: libxt_conntrack: provide translation for DNAT and
SNAT --ctstate
iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT
nft add rule ip filter INPUT ct status dnat counter accept
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit 26ec09bf6b9b674a7e3a65fc9c12599bd81dfe0f)
---
extensions/libxt_conntrack.c | 18 +++++++++++++-----
extensions/libxt_conntrack.txlate | 7 +++++++
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 6f3503933e664..7734509c9af84 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1249,11 +1249,19 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_STATE) {
- xt_xlate_add(xl, "%sct state %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
- space = " ";
+ if ((sinfo->state_mask & XT_CONNTRACK_STATE_SNAT) ||
+ (sinfo->state_mask & XT_CONNTRACK_STATE_DNAT)) {
+ xt_xlate_add(xl, "%sct status %s%s", space,
+ sinfo->invert_flags & XT_CONNTRACK_STATUS ? "!=" : "",
+ sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat");
+ space = " ";
+ } else {
+ xt_xlate_add(xl, "%sct state %s", space,
+ sinfo->invert_flags & XT_CONNTRACK_STATE ?
+ "!= " : "");
+ state_xlate_print(xl, sinfo->state_mask);
+ space = " ";
+ }
}
if (sinfo->match_flags & XT_CONNTRACK_STATUS) {
diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate
index 8a3d0181c71ef..d374f8a035f00 100644
--- a/extensions/libxt_conntrack.txlate
+++ b/extensions/libxt_conntrack.txlate
@@ -42,3 +42,10 @@ nft add rule ip filter INPUT ct direction original counter accept
iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrc 192.168.0.1 --ctorigdst 192.168.0.1 --ctreplsrc 192.168.0.1 --ctrepldst 192.168.0.1 --ctorigsrcport 12 --ctorigdstport 14 --ctreplsrcport 16 --ctrepldstport 18 --ctexpire 10 --ctstatus SEEN_REPLY --ctdir ORIGINAL -j ACCEPT
nft add rule ip filter INPUT ct direction original ct original protocol 6 ct state new ct status seen-reply ct expiration 10 ct original saddr 192.168.0.1 ct original daddr 192.168.0.1 ct reply saddr 192.168.0.1 ct reply daddr 192.168.0.1 ct original proto-src 12 ct original proto-dst 14 ct reply proto-src 16 ct reply proto-dst 18 counter accept
+
+iptables-translate -t filter -A INPUT -m conntrack --ctstate SNAT -j ACCEPT
+nft add rule ip filter INPUT ct status snat counter accept
+
+iptables-translate -t filter -A INPUT -m conntrack --ctstate DNAT -j ACCEPT
+nft add rule ip filter INPUT ct status dnat counter accept
+
--
2.40.0

@ -0,0 +1,30 @@
From 13abbdd7789da8616a903b5b8dc5ff69fb2af2c7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 10 Jul 2020 21:12:34 +0200
Subject: [PATCH] nft: Drop pointless nft_xt_builtin_init() call
When renaming a chain, either everything is in place already or the
command will bail anyway. So just drop this superfluous call.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 7a700c47fe121c65c550ab24de3284abbb1e82f8)
---
iptables/nft.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index 0c5a74fc232c6..e795d4ae6d241 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1934,8 +1934,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0;
}
- nft_xt_builtin_init(h, table);
-
/* Config load changed errno. Ensure genuine info for our callers. */
errno = 0;
--
2.40.0

@ -0,0 +1,44 @@
From a58c38e4c579f409669b5ab82d3b039528a129af Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 7 Aug 2020 13:48:28 +0200
Subject: [PATCH] nft: Fix command name in ip6tables error message
Upon errors, ip6tables-nft would prefix its error messages with
'iptables:' instead of 'ip6tables:'. Turns out the command name was
hard-coded, use 'progname' variable instead.
While being at it, merge the two mostly identical fprintf() calls into
one.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit 3be40dcfb5af1438b6abdbda45a1e3b59c104e13)
---
iptables/xtables-standalone.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/iptables/xtables-standalone.c b/iptables/xtables-standalone.c
index dd6fb7919d2e1..7b71db62f1ea6 100644
--- a/iptables/xtables-standalone.c
+++ b/iptables/xtables-standalone.c
@@ -75,14 +75,10 @@ xtables_main(int family, const char *progname, int argc, char *argv[])
xtables_fini();
if (!ret) {
- if (errno == EINVAL) {
- fprintf(stderr, "iptables: %s. "
- "Run `dmesg' for more information.\n",
- nft_strerror(errno));
- } else {
- fprintf(stderr, "iptables: %s.\n",
- nft_strerror(errno));
- }
+ fprintf(stderr, "%s: %s.%s\n", progname, nft_strerror(errno),
+ (errno == EINVAL ?
+ " Run `dmesg' for more information." : ""));
+
if (errno == EAGAIN)
exit(RESOURCE_PROBLEM);
}
--
2.40.0

@ -0,0 +1,208 @@
From 529dee8412eb216a2432e063136ede732edb9cc1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 6 Aug 2020 18:52:34 +0200
Subject: [PATCH] tests: shell: Merge and extend return codes test
Merge scripts for iptables and ip6tables, they were widely identical.
Also extend the test by one check (removing a non-existent rule with
valid chain and target) and quote the error messages where differences
are deliberately ignored.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit cd3e83d1b04fd2683f0fb06e496ee5be08a96b4f)
---
.../testcases/ip6tables/0004-return-codes_0 | 39 ------
.../testcases/iptables/0004-return-codes_0 | 113 ++++++++++--------
2 files changed, 61 insertions(+), 91 deletions(-)
delete mode 100755 iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0 b/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
deleted file mode 100755
index c583b0ebd97c3..0000000000000
--- a/iptables/tests/shell/testcases/ip6tables/0004-return-codes_0
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-
-# make sure error return codes are as expected useful cases
-# (e.g. commands to check ruleset state)
-
-global_rc=0
-
-cmd() { # (rc, cmd, [args ...])
- rc_exp=$1; shift
-
- $XT_MULTI "$@"
- rc=$?
-
- [ $rc -eq $rc_exp ] || {
- echo "---> expected $rc_exp, got $rc for command '$@'"
- global_rc=1
- }
-}
-
-# test chain creation
-cmd 0 ip6tables -N foo
-cmd 1 ip6tables -N foo
-# iptables-nft allows this - bug or feature?
-#cmd 2 ip6tables -N "invalid name"
-
-# test rule adding
-cmd 0 ip6tables -A INPUT -j ACCEPT
-cmd 1 ip6tables -A noexist -j ACCEPT
-cmd 2 ip6tables -I INPUT -j foobar
-
-# test rule checking
-cmd 0 ip6tables -C INPUT -j ACCEPT
-cmd 1 ip6tables -C FORWARD -j ACCEPT
-cmd 1 ip6tables -C nonexist -j ACCEPT
-cmd 2 ip6tables -C INPUT -j foobar
-cmd 2 ip6tables -C INPUT -m foobar -j ACCEPT
-cmd 3 ip6tables -t foobar -C INPUT -j ACCEPT
-
-exit $global_rc
diff --git a/iptables/tests/shell/testcases/iptables/0004-return-codes_0 b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
index f730bede1f612..dcd9dfd3c0806 100755
--- a/iptables/tests/shell/testcases/iptables/0004-return-codes_0
+++ b/iptables/tests/shell/testcases/iptables/0004-return-codes_0
@@ -13,75 +13,84 @@ cmd() { # (rc, msg, cmd, [args ...])
msg_exp="$1"; shift
}
- msg="$($XT_MULTI "$@" 2>&1 >/dev/null)"
- rc=$?
+ for ipt in iptables ip6tables; do
+ msg="$($XT_MULTI $ipt "$@" 2>&1 >/dev/null)"
+ rc=$?
- [ $rc -eq $rc_exp ] || {
- echo "---> expected return code $rc_exp, got $rc for command '$@'"
- global_rc=1
- }
+ [ $rc -eq $rc_exp ] || {
+ echo "---> expected return code $rc_exp, got $rc for command '$ipt $@'"
+ global_rc=1
+ }
- [ -n "$msg_exp" ] || return
- grep -q "$msg_exp" <<< $msg || {
- echo "---> expected error message '$msg_exp', got '$msg' for command '$@'"
- global_rc=1
- }
+ [ -n "$msg_exp" ] || continue
+ msg_exp_full="${ipt}$msg_exp"
+ grep -q "$msg_exp_full" <<< $msg || {
+ echo "---> expected error message '$msg_exp_full', got '$msg' for command '$ipt $@'"
+ global_rc=1
+ }
+ done
}
-EEXIST_F="File exists."
-EEXIST="Chain already exists."
-ENOENT="No chain/target/match by that name."
-E2BIG_I="Index of insertion too big."
-E2BIG_D="Index of deletion too big."
-E2BIG_R="Index of replacement too big."
-EBADRULE="Bad rule (does a matching rule exist in that chain?)."
-ENOTGT="Couldn't load target \`foobar':No such file or directory"
-ENOMTH="Couldn't load match \`foobar':No such file or directory"
-ENOTBL="can't initialize iptables table \`foobar': Table does not exist"
+EEXIST_F=": File exists."
+EEXIST=": Chain already exists."
+ENOENT=": No chain/target/match by that name."
+E2BIG_I=": Index of insertion too big."
+E2BIG_D=": Index of deletion too big."
+E2BIG_R=": Index of replacement too big."
+EBADRULE=": Bad rule (does a matching rule exist in that chain?)."
+#ENOTGT=" v[0-9\.]* [^ ]*: Couldn't load target \`foobar':No such file or directory"
+ENOMTH=" v[0-9\.]* [^ ]*: Couldn't load match \`foobar':No such file or directory"
+ENOTBL=": can't initialize iptables table \`foobar': Table does not exist"
# test chain creation
-cmd 0 iptables -N foo
-cmd 1 "$EEXIST" iptables -N foo
+cmd 0 -N foo
+cmd 1 "$EEXIST" -N foo
# iptables-nft allows this - bug or feature?
-#cmd 2 iptables -N "invalid name"
+#cmd 2 -N "invalid name"
# test chain flushing/zeroing
-cmd 0 iptables -F foo
-cmd 0 iptables -Z foo
-cmd 1 "$ENOENT" iptables -F bar
-cmd 1 "$ENOENT" iptables -Z bar
+cmd 0 -F foo
+cmd 0 -Z foo
+cmd 1 "$ENOENT" -F bar
+cmd 1 "$ENOENT" -Z bar
# test chain rename
-cmd 0 iptables -E foo bar
-cmd 1 "$EEXIST_F" iptables -E foo bar
-cmd 1 "$ENOENT" iptables -E foo bar2
-cmd 0 iptables -N foo2
-cmd 1 "$EEXIST_F" iptables -E foo2 bar
+cmd 0 -E foo bar
+cmd 1 "$EEXIST_F" -E foo bar
+cmd 1 "$ENOENT" -E foo bar2
+cmd 0 -N foo2
+cmd 1 "$EEXIST_F" -E foo2 bar
# test rule adding
-cmd 0 iptables -A INPUT -j ACCEPT
-cmd 1 "$ENOENT" iptables -A noexist -j ACCEPT
-cmd 2 "" iptables -I INPUT -j foobar
-cmd 2 "" iptables -R INPUT 1 -j foobar
-cmd 2 "" iptables -D INPUT -j foobar
+cmd 0 -A INPUT -j ACCEPT
+cmd 1 "$ENOENT" -A noexist -j ACCEPT
+# next three differ:
+# legacy: Couldn't load target `foobar':No such file or directory
+# nft: Chain 'foobar' does not exist
+cmd 2 "" -I INPUT -j foobar
+cmd 2 "" -R INPUT 1 -j foobar
+cmd 2 "" -D INPUT -j foobar
+cmd 1 "$EBADRULE" -D INPUT -p tcp --dport 22 -j ACCEPT
# test rulenum commands
-cmd 1 "$E2BIG_I" iptables -I INPUT 23 -j ACCEPT
-cmd 1 "$E2BIG_D" iptables -D INPUT 23
-cmd 1 "$E2BIG_R" iptables -R INPUT 23 -j ACCEPT
-cmd 1 "$ENOENT" iptables -I nonexist 23 -j ACCEPT
-cmd 1 "$ENOENT" iptables -D nonexist 23
-cmd 1 "$ENOENT" iptables -R nonexist 23 -j ACCEPT
+cmd 1 "$E2BIG_I" -I INPUT 23 -j ACCEPT
+cmd 1 "$E2BIG_D" -D INPUT 23
+cmd 1 "$E2BIG_R" -R INPUT 23 -j ACCEPT
+cmd 1 "$ENOENT" -I nonexist 23 -j ACCEPT
+cmd 1 "$ENOENT" -D nonexist 23
+cmd 1 "$ENOENT" -R nonexist 23 -j ACCEPT
# test rule checking
-cmd 0 iptables -C INPUT -j ACCEPT
-cmd 1 "$EBADRULE" iptables -C FORWARD -j ACCEPT
-cmd 1 "$BADRULE" iptables -C nonexist -j ACCEPT
-cmd 2 "$ENOMTH" iptables -C INPUT -m foobar -j ACCEPT
+cmd 0 -C INPUT -j ACCEPT
+cmd 1 "$EBADRULE" -C FORWARD -j ACCEPT
+cmd 1 "$BADRULE" -C nonexist -j ACCEPT
+cmd 2 "$ENOMTH" -C INPUT -m foobar -j ACCEPT
# messages of those don't match, but iptables-nft ones are actually nicer.
-#cmd 2 "$ENOTGT" iptables -C INPUT -j foobar
-#cmd 3 "$ENOTBL" iptables -t foobar -C INPUT -j ACCEPT
-cmd 2 "" iptables -C INPUT -j foobar
-cmd 3 "" iptables -t foobar -C INPUT -j ACCEPT
+# legacy: Couldn't load target `foobar':No such file or directory
+# nft: Chain 'foobar' does not exist
+cmd 2 "" -C INPUT -j foobar
+# legacy: can't initialize ip6tables table `foobar': Table does not exist (do you need to insmod?)
+# nft: table 'foobar' does not exist
+cmd 3 "" -t foobar -C INPUT -j ACCEPT
exit $global_rc
--
2.40.0

@ -0,0 +1,37 @@
From fe5db6f78145aeac1b18d21c38c178b99cd7c04a Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 7 Aug 2020 16:42:07 +0200
Subject: [PATCH] xtables-monitor: Fix ip6tables rule printing
When printing an ip6tables rule event, false family ops are used as they
are initially looked up for AF_INET and reused no matter the current
rule's family. In practice, this means that nft_rule_print_save() calls
the wrong rule_to_cs, save_rule and clear_cs callbacks. Therefore, if a
rule specifies a source or destination address, the address is not
printed.
Fix this by performing a family lookup each time rule_cb is called.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit ca69b0290dc509d72118f0a054a5c740cb913875)
---
iptables/xtables-monitor.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 57def83e2eea0..4008cc00d4694 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -93,6 +93,8 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
if (arg->nfproto && arg->nfproto != family)
goto err_free;
+ arg->h->ops = nft_family_ops_lookup(family);
+
if (arg->is_event)
printf(" EVENT: ");
switch (family) {
--
2.40.0

@ -0,0 +1,39 @@
From 895077fbd8f11b717fd414a02d22dae99d94b390 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 29 Jul 2020 15:39:31 +0200
Subject: [PATCH] nft: cache: Check consistency with NFT_CL_FAKE, too
Athough this cache level fetches table names only, it shouldn't skip the
consistency check.
Fixes: f42bfb344af82 ("nft: cache: Re-establish cache consistency check")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit b531365ce32f386d91c6a0bbc80ec4076e4babdd)
---
iptables/nft-cache.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/iptables/nft-cache.c b/iptables/nft-cache.c
index 638b18bc7e382..434cc10b82ce7 100644
--- a/iptables/nft-cache.c
+++ b/iptables/nft-cache.c
@@ -511,14 +511,14 @@ __nft_build_cache(struct nft_handle *h)
if (req->level >= NFT_CL_TABLES)
fetch_table_cache(h);
if (req->level == NFT_CL_FAKE)
- return;
+ goto genid_check;
if (req->level >= NFT_CL_CHAINS)
fetch_chain_cache(h, t, chains);
if (req->level >= NFT_CL_SETS)
fetch_set_cache(h, t, NULL);
if (req->level >= NFT_CL_RULES)
fetch_rule_cache(h, t);
-
+genid_check:
mnl_genid_get(h, &genid_check);
if (h->nft_genid != genid_check) {
flush_cache(h, h->cache, NULL);
--
2.40.0

@ -0,0 +1,59 @@
From ba2da85b5a8940035f57dd395205c726c0c68ec7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 28 Sep 2020 18:57:18 +0200
Subject: [PATCH] nft: Fix for broken address mask match detection
Trying to decide whether a bitwise expression is needed to match parts
of a source or destination address only, add_addr() checks if all bytes
in 'mask' are 0xff or not. The check is apparently broken though as each
byte in 'mask' is cast to a signed char before comparing against 0xff,
therefore the bitwise is always added:
| # ./bad/iptables-nft -A foo -s 10.0.0.1 -j ACCEPT
| # ./good/iptables-nft -A foo -s 10.0.0.2 -j ACCEPT
| # nft --debug=netlink list chain ip filter foo
| ip filter foo 5
| [ payload load 4b @ network header + 12 => reg 1 ]
| [ bitwise reg 1 = (reg=1 & 0xffffffff ) ^ 0x00000000 ]
| [ cmp eq reg 1 0x0100000a ]
| [ counter pkts 0 bytes 0 ]
| [ immediate reg 0 accept ]
|
| ip filter foo 6 5
| [ payload load 4b @ network header + 12 => reg 1 ]
| [ cmp eq reg 1 0x0200000a ]
| [ counter pkts 0 bytes 0 ]
| [ immediate reg 0 accept ]
|
| table ip filter {
| chain foo {
| ip saddr 10.0.0.1 counter packets 0 bytes 0 accept
| ip saddr 10.0.0.2 counter packets 0 bytes 0 accept
| }
| }
Fix the cast, safe an extra op and gain 100% performance in ideal cases.
Fixes: 56859380eb328 ("xtables-compat: avoid unneeded bitwise ops")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 72ed608bf1ea550ac13b5b880afc7ad3ffa0afd0)
---
iptables/nft-shared.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index c5a8f3fcc051d..7741d23befc5a 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -165,7 +165,7 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
void add_addr(struct nftnl_rule *r, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
- const char *m = mask;
+ const unsigned char *m = mask;
int i;
add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
--
2.40.0

@ -0,0 +1,51 @@
From e674863343bf3233d2d1cdd9e17adad5381796a9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 6 Oct 2020 19:07:19 +0200
Subject: [PATCH] extensions: libipt_icmp: Fix translation of type 'any'
By itself, '-m icmp --icmp-type any' is a noop, it matches any icmp
types. Yet nft_ipv4_xlate() does not emit an 'ip protocol' match if
there's an extension with same name present in the rule. Luckily, legacy
iptables demands icmp match to be prepended by '-p icmp', so we can
assume this is present and just emit the 'ip protocol' match from icmp
xlate callback.
Fixes: aa158ca0fda65 ("extensions: libipt_icmp: Add translation to nft")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit ad4b17b98bbedf93d2182a4dc9a37e9cf3adfe1b)
---
extensions/libipt_icmp.c | 5 +++++
extensions/libipt_icmp.txlate | 3 +++
2 files changed, 8 insertions(+)
diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c
index e76257c54708c..e5e236613f39f 100644
--- a/extensions/libipt_icmp.c
+++ b/extensions/libipt_icmp.c
@@ -256,6 +256,11 @@ static int icmp_xlate(struct xt_xlate *xl,
if (!type_xlate_print(xl, info->type, info->code[0],
info->code[1]))
return 0;
+ } else {
+ /* '-m icmp --icmp-type any' is a noop by itself,
+ * but it eats a (mandatory) previous '-p icmp' so
+ * emit it here */
+ xt_xlate_add(xl, "ip protocol icmp");
}
return 1;
}
diff --git a/extensions/libipt_icmp.txlate b/extensions/libipt_icmp.txlate
index 434f8cc4eb1ae..a2aec8e26df75 100644
--- a/extensions/libipt_icmp.txlate
+++ b/extensions/libipt_icmp.txlate
@@ -6,3 +6,6 @@ nft add rule ip filter INPUT icmp type destination-unreachable counter accept
iptables-translate -t filter -A INPUT -m icmp ! --icmp-type 3 -j ACCEPT
nft add rule ip filter INPUT icmp type != destination-unreachable counter accept
+
+iptables-translate -t filter -A INPUT -m icmp --icmp-type any -j ACCEPT
+nft add rule ip filter INPUT ip protocol icmp counter accept
--
2.40.0

@ -0,0 +1,127 @@
From 4616623e18cb1868960194cd7f695969c594a35b Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 21 Sep 2020 13:42:06 +0200
Subject: [PATCH] libxtables: Make sure extensions register in revision order
Insert extensions into pending lists in ordered fashion: Group by
extension name (and, for matches, family) and order groups by descending
revision number.
This allows to simplify the later full registration considerably. Since
that involves kernel compatibility checks, the extra cycles here pay off
eventually.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit b3ac87038f4e45141831d9ab485a2f627daba3f1)
---
libxtables/xtables.c | 71 +++++++++++++++++++++++++++++++++++++++-----
1 file changed, 64 insertions(+), 7 deletions(-)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 8907ba2069be7..de52e3e2bbc15 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -948,8 +948,14 @@ static void xtables_check_options(const char *name, const struct option *opt)
}
}
+static int xtables_match_prefer(const struct xtables_match *a,
+ const struct xtables_match *b);
+
void xtables_register_match(struct xtables_match *me)
{
+ struct xtables_match **pos;
+ bool seen_myself = false;
+
if (me->next) {
fprintf(stderr, "%s: match \"%s\" already registered\n",
xt_params->program_name, me->name);
@@ -1001,10 +1007,34 @@ void xtables_register_match(struct xtables_match *me)
if (me->extra_opts != NULL)
xtables_check_options(me->name, me->extra_opts);
-
- /* place on linked list of matches pending full registration */
- me->next = xtables_pending_matches;
- xtables_pending_matches = me;
+ /* order into linked list of matches pending full registration */
+ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
+ /* group by name and family */
+ if (strcmp(me->name, (*pos)->name) ||
+ me->family != (*pos)->family) {
+ if (seen_myself)
+ break; /* end of own group, append to it */
+ continue;
+ }
+ /* found own group */
+ seen_myself = true;
+ if (xtables_match_prefer(me, *pos) >= 0)
+ break; /* put preferred items first in group */
+ }
+ /* if own group was not found, prepend item */
+ if (!*pos && !seen_myself)
+ pos = &xtables_pending_matches;
+
+ me->next = *pos;
+ *pos = me;
+#ifdef DEBUG
+ printf("%s: inserted match %s (family %d, revision %d):\n",
+ __func__, me->name, me->family, me->revision);
+ for (pos = &xtables_pending_matches; *pos; pos = &(*pos)->next) {
+ printf("%s:\tmatch %s (family %d, revision %d)\n", __func__,
+ (*pos)->name, (*pos)->family, (*pos)->revision);
+ }
+#endif
}
/**
@@ -1143,6 +1173,9 @@ void xtables_register_matches(struct xtables_match *match, unsigned int n)
void xtables_register_target(struct xtables_target *me)
{
+ struct xtables_target **pos;
+ bool seen_myself = false;
+
if (me->next) {
fprintf(stderr, "%s: target \"%s\" already registered\n",
xt_params->program_name, me->name);
@@ -1198,9 +1231,33 @@ void xtables_register_target(struct xtables_target *me)
if (me->family != afinfo->family && me->family != AF_UNSPEC)
return;
- /* place on linked list of targets pending full registration */
- me->next = xtables_pending_targets;
- xtables_pending_targets = me;
+ /* order into linked list of targets pending full registration */
+ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
+ /* group by name */
+ if (!extension_cmp(me->name, (*pos)->name, (*pos)->family)) {
+ if (seen_myself)
+ break; /* end of own group, append to it */
+ continue;
+ }
+ /* found own group */
+ seen_myself = true;
+ if (xtables_target_prefer(me, *pos) >= 0)
+ break; /* put preferred items first in group */
+ }
+ /* if own group was not found, prepend item */
+ if (!*pos && !seen_myself)
+ pos = &xtables_pending_targets;
+
+ me->next = *pos;
+ *pos = me;
+#ifdef DEBUG
+ printf("%s: inserted target %s (family %d, revision %d):\n",
+ __func__, me->name, me->family, me->revision);
+ for (pos = &xtables_pending_targets; *pos; pos = &(*pos)->next) {
+ printf("%s:\ttarget %s (family %d, revision %d)\n", __func__,
+ (*pos)->name, (*pos)->family, (*pos)->revision);
+ }
+#endif
}
static bool xtables_fully_register_pending_target(struct xtables_target *me)
--
2.40.0

@ -0,0 +1,240 @@
From 4b5e9e71fbad66aef1db079905cba2db032a7515 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 18 Sep 2020 18:48:14 +0200
Subject: [PATCH] libxtables: Simplify pending extension registration
Assuming that pending extensions are sorted by first name and family,
then descending revision, the decision where to insert a newly
registered extension may be simplified by memorizing the previous
registration (which obviously is of same name and family and higher
revision).
As a side-effect, fix for unsupported old extension revisions lingering
in pending extension list forever and being retried with every use of
the given extension. Any revision being rejected by the kernel may
safely be dropped iff a previous (read: higher) revision was accepted
already.
Yet another side-effect of this change is the removal of an unwanted
recursion by xtables_fully_register_pending_*() into itself via
xtables_find_*().
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit a1eaaceb0460b338294e40bdd5bc5186320a478c)
---
libxtables/xtables.c | 128 +++++++++++--------------------------------
1 file changed, 33 insertions(+), 95 deletions(-)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index de52e3e2bbc15..10d4e70328500 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -203,8 +203,10 @@ struct xtables_match *xtables_matches;
struct xtables_target *xtables_targets;
/* Fully register a match/target which was previously partially registered. */
-static bool xtables_fully_register_pending_match(struct xtables_match *me);
-static bool xtables_fully_register_pending_target(struct xtables_target *me);
+static bool xtables_fully_register_pending_match(struct xtables_match *me,
+ struct xtables_match *prev);
+static bool xtables_fully_register_pending_target(struct xtables_target *me,
+ struct xtables_target *prev);
#ifndef NO_SHARED_LIBS
/* registry for loaded shared objects to close later */
@@ -662,6 +664,7 @@ struct xtables_match *
xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_rule_match **matches)
{
+ struct xtables_match *prev = NULL;
struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
@@ -683,8 +686,12 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_match(ptr))
+ if (xtables_fully_register_pending_match(ptr, prev)) {
+ prev = ptr;
continue;
+ } else if (prev) {
+ continue;
+ }
*dptr = ptr;
}
dptr = &((*dptr)->next);
@@ -778,6 +785,7 @@ xtables_find_match_revision(const char *name, enum xtables_tryload tryload,
struct xtables_target *
xtables_find_target(const char *name, enum xtables_tryload tryload)
{
+ struct xtables_target *prev = NULL;
struct xtables_target **dptr;
struct xtables_target *ptr;
@@ -794,8 +802,12 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_target(ptr))
+ if (xtables_fully_register_pending_target(ptr, prev)) {
+ prev = ptr;
continue;
+ } else if (prev) {
+ continue;
+ }
*dptr = ptr;
}
dptr = &((*dptr)->next);
@@ -1098,64 +1110,27 @@ static int xtables_target_prefer(const struct xtables_target *a,
b->revision, b->family);
}
-static bool xtables_fully_register_pending_match(struct xtables_match *me)
+static bool xtables_fully_register_pending_match(struct xtables_match *me,
+ struct xtables_match *prev)
{
- struct xtables_match **i, *old, *pos = NULL;
+ struct xtables_match **i;
const char *rn;
- int compare;
/* See if new match can be used. */
rn = (me->real_name != NULL) ? me->real_name : me->name;
if (!compatible_match_revision(rn, me->revision))
return false;
- old = xtables_find_match(me->name, XTF_DURING_LOAD, NULL);
- while (old) {
- compare = xtables_match_prefer(old, me);
- if (compare == 0) {
- fprintf(stderr,
- "%s: match `%s' already registered.\n",
- xt_params->program_name, me->name);
- exit(1);
- }
-
- /* Now we have two (or more) options, check compatibility. */
- rn = (old->real_name != NULL) ? old->real_name : old->name;
- if (compare > 0) {
- /* Kernel tells old isn't compatible anymore??? */
- if (!compatible_match_revision(rn, old->revision)) {
- /* Delete old one. */
- for (i = &xtables_matches; *i != old;)
- i = &(*i)->next;
- *i = old->next;
- }
- pos = old;
- old = old->next;
- if (!old)
- break;
- if (!extension_cmp(me->name, old->name, old->family))
- break;
- continue;
- }
-
- /* Found right old */
- pos = old;
- break;
- }
-
- if (!pos) {
+ if (!prev) {
/* Append to list. */
for (i = &xtables_matches; *i; i = &(*i)->next);
- } else if (compare < 0) {
- /* Prepend it */
- for (i = &xtables_matches; *i != pos; i = &(*i)->next);
- } else if (compare > 0) {
+ } else {
/* Append it */
- i = &pos->next;
- pos = pos->next;
+ i = &prev->next;
+ prev = prev->next;
}
- me->next = pos;
+ me->next = prev;
*i = me;
me->m = NULL;
@@ -1260,11 +1235,11 @@ void xtables_register_target(struct xtables_target *me)
#endif
}
-static bool xtables_fully_register_pending_target(struct xtables_target *me)
+static bool xtables_fully_register_pending_target(struct xtables_target *me,
+ struct xtables_target *prev)
{
- struct xtables_target **i, *old, *pos = NULL;
+ struct xtables_target **i;
const char *rn;
- int compare;
if (strcmp(me->name, "standard") != 0) {
/* See if new target can be used. */
@@ -1273,54 +1248,17 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me)
return false;
}
- old = xtables_find_target(me->name, XTF_DURING_LOAD);
- while (old) {
- compare = xtables_target_prefer(old, me);
- if (compare == 0) {
- fprintf(stderr,
- "%s: target `%s' already registered.\n",
- xt_params->program_name, me->name);
- exit(1);
- }
-
- /* Now we have two (or more) options, check compatibility. */
- rn = (old->real_name != NULL) ? old->real_name : old->name;
- if (compare > 0) {
- /* Kernel tells old isn't compatible anymore??? */
- if (!compatible_target_revision(rn, old->revision)) {
- /* Delete old one. */
- for (i = &xtables_targets; *i != old;)
- i = &(*i)->next;
- *i = old->next;
- }
- pos = old;
- old = old->next;
- if (!old)
- break;
- if (!extension_cmp(me->name, old->name, old->family))
- break;
- continue;
- }
-
- /* Found right old */
- pos = old;
- break;
- }
-
- if (!pos) {
+ if (!prev) {
/* Prepend to list. */
i = &xtables_targets;
- pos = xtables_targets;
- } else if (compare < 0) {
- /* Prepend it */
- for (i = &xtables_targets; *i != pos; i = &(*i)->next);
- } else if (compare > 0) {
+ prev = xtables_targets;
+ } else {
/* Append it */
- i = &pos->next;
- pos = pos->next;
+ i = &prev->next;
+ prev = prev->next;
}
- me->next = pos;
+ me->next = prev;
*i = me;
me->t = NULL;
--
2.40.0

@ -0,0 +1,51 @@
From 1ae06e3a2da1c21a75b55609b99d1ab3ef6cf709 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 22 Sep 2020 20:01:15 +0200
Subject: [PATCH] libxtables: Register multiple extensions in ascending order
The newly introduced ordered insert algorithm in
xtables_register_{match,target}() works best if extensions of same name
are passed in ascending revisions. Since this is the case in about all
extensions' arrays, iterate over them from beginning to end.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit b5f1a3beac1d1f2b96c8be8ebec450f5ea758090)
---
libxtables/xtables.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 10d4e70328500..7152c6576cd63 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -1141,9 +1141,10 @@ static bool xtables_fully_register_pending_match(struct xtables_match *me,
void xtables_register_matches(struct xtables_match *match, unsigned int n)
{
- do {
- xtables_register_match(&match[--n]);
- } while (n > 0);
+ int i;
+
+ for (i = 0; i < n; i++)
+ xtables_register_match(&match[i]);
}
void xtables_register_target(struct xtables_target *me)
@@ -1269,9 +1270,10 @@ static bool xtables_fully_register_pending_target(struct xtables_target *me,
void xtables_register_targets(struct xtables_target *target, unsigned int n)
{
- do {
- xtables_register_target(&target[--n]);
- } while (n > 0);
+ int i;
+
+ for (i = 0; i < n; i++)
+ xtables_register_target(&target[i]);
}
/* receives a list of xtables_rule_match, release them */
--
2.40.0

@ -0,0 +1,161 @@
From 99bf566bfcabce101940b28a12f61c637ccfb489 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Sat, 3 Oct 2020 17:46:09 +0200
Subject: [PATCH] nft: Make batch_add_chain() return the added batch object
Do this so in a later patch the 'skip' field can be adjusted.
While being at it, simplify a few callers and eliminate the need for a
'ret' variable.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 0d77e64e8d9b8a3984b01a4951524dc40f61f4b6)
---
iptables/nft.c | 35 +++++++++++++++++------------------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index e795d4ae6d241..ec5f7457e4784 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -389,10 +389,11 @@ batch_set_add(struct nft_handle *h, enum obj_update_type type,
return batch_add(h, type, s);
}
-static int batch_chain_add(struct nft_handle *h, enum obj_update_type type,
+static struct obj_update *
+batch_chain_add(struct nft_handle *h, enum obj_update_type type,
struct nftnl_chain *c)
{
- return batch_add(h, type, c) ? 0 : -1;
+ return batch_add(h, type, c);
}
static struct obj_update *
@@ -920,7 +921,6 @@ int nft_chain_set(struct nft_handle *h, const char *table,
const struct xt_counters *counters)
{
struct nftnl_chain *c = NULL;
- int ret;
nft_fn = nft_chain_set;
@@ -934,10 +934,11 @@ int nft_chain_set(struct nft_handle *h, const char *table,
if (c == NULL)
return 0;
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_UPDATE, c))
+ return 0;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
static int __add_match(struct nftnl_expr *e, struct xt_entry_match *m)
@@ -1752,7 +1753,6 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
{
struct nftnl_chain_list *list;
struct nftnl_chain *c;
- int ret;
nft_fn = nft_chain_user_add;
@@ -1772,14 +1772,15 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
if (h->family == NFPROTO_BRIDGE)
nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
+ return 0;
list = nft_chain_list_get(h, table, chain);
if (list)
nftnl_chain_list_add(c, list);
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
@@ -1787,7 +1788,6 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
struct nftnl_chain_list *list;
struct nftnl_chain *c;
bool created = false;
- int ret;
c = nft_chain_find(h, table, chain);
if (c) {
@@ -1812,14 +1812,15 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
if (!created)
return 1;
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
+ return 0;
list = nft_chain_list_get(h, table, chain);
if (list)
nftnl_chain_list_add(c, list);
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
/* From linux/netlink.h */
@@ -1837,7 +1838,6 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
{
struct chain_user_del_data *d = data;
struct nft_handle *h = d->handle;
- int ret;
/* don't delete built-in chain */
if (nft_chain_builtin(c))
@@ -1849,8 +1849,7 @@ static int __nft_chain_user_del(struct nftnl_chain *c, void *data)
/* XXX This triggers a fast lookup from the kernel. */
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c);
- if (ret)
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_DEL, c))
return -1;
nftnl_chain_list_del(c);
@@ -1925,7 +1924,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
{
struct nftnl_chain *c;
uint64_t handle;
- int ret;
nft_fn = nft_chain_user_rename;
@@ -1954,10 +1952,11 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, newname);
nftnl_chain_set_u64(c, NFTNL_CHAIN_HANDLE, handle);
- ret = batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c);
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_RENAME, c))
+ return 0;
/* the core expects 1 for success and 0 for error */
- return ret == 0 ? 1 : 0;
+ return 1;
}
bool nft_table_find(struct nft_handle *h, const char *tablename)
@@ -3404,7 +3403,7 @@ static int __nft_chain_zero_counters(struct nftnl_chain *c, void *data)
nftnl_chain_set_u64(c, NFTNL_CHAIN_PACKETS, 0);
nftnl_chain_set_u64(c, NFTNL_CHAIN_BYTES, 0);
nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
- if (batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
+ if (!batch_chain_add(h, NFT_COMPAT_CHAIN_ZERO, c))
return -1;
}
--
2.40.0

@ -0,0 +1,41 @@
From 8ab5e29f192187bc12a2064036cf406de60b2cd5 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 5 Oct 2020 15:54:35 +0200
Subject: [PATCH] nft: Fix error reporting for refreshed transactions
When preparing a batch from the list of batch objects in nft_action(),
the sequence number used for each object is stored within that object
for later matching against returned error messages. Though if the
transaction has to be refreshed, some of those objects may be skipped,
other objects take over their sequence number and errors are matched to
skipped objects. Avoid this by resetting the skipped object's sequence
number to zero.
Fixes: 58d7de0181f61 ("xtables: handle concurrent ruleset modifications")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit e98b825a037807bf6c918eb66ee9682cc4c46183)
---
iptables/nft.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index ec5f7457e4784..d3eb0840a9fc0 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -2832,9 +2832,10 @@ static int nft_action(struct nft_handle *h, int action)
h->nft_genid++;
list_for_each_entry(n, &h->obj_list, head) {
-
- if (n->skip)
+ if (n->skip) {
+ n->seq = 0;
continue;
+ }
n->seq = seq++;
switch (n->type) {
--
2.40.0

@ -0,0 +1,235 @@
From 412c52e9ab9d5d1d1a1e5e09a122cca43895451a Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 5 Oct 2020 16:06:49 +0200
Subject: [PATCH] nft: Fix for concurrent noflush restore calls
Transaction refresh was broken with regards to nft_chain_restore(): It
created a rule flush batch object only if the chain was found in cache
and a chain add object only if the chain was not found. Yet with
concurrent ruleset updates, one has to expect both situations:
* If a chain vanishes, the rule flush job must be skipped and instead
the chain add job become active.
* If a chain appears, the chain add job must be skipped and instead
rules flushed.
Change the code accordingly: Create both batch objects and set their
'skip' field depending on the situation in cache and adjust both in
nft_refresh_transaction().
As a side-effect, the implicit rule flush becomes explicit and all
handling of implicit batch jobs is dropped along with the related field
indicating such.
Reuse the 'implicit' parameter of __nft_rule_flush() to control the
initial 'skip' field value instead.
A subtle caveat is vanishing of existing chains: Creating the chain add
job based on the chain in cache causes a netlink message containing that
chain's handle which the kernel dislikes. Therefore unset the chain's
handle in that case.
Fixes: 58d7de0181f61 ("xtables: handle concurrent ruleset modifications")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit dac904bdcd9a18aabafee7275ccf0c2bd53800f3)
---
iptables/nft.c | 58 ++++++++++---------
.../ipt-restore/0016-concurrent-restores_0 | 53 +++++++++++++++++
2 files changed, 83 insertions(+), 28 deletions(-)
create mode 100755 iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
diff --git a/iptables/nft.c b/iptables/nft.c
index d3eb0840a9fc0..bdb633a82a655 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -265,7 +265,6 @@ struct obj_update {
struct list_head head;
enum obj_update_type type:8;
uint8_t skip:1;
- uint8_t implicit:1;
unsigned int seq;
union {
struct nftnl_table *table;
@@ -1668,7 +1667,7 @@ struct nftnl_set *nft_set_batch_lookup_byid(struct nft_handle *h,
static void
__nft_rule_flush(struct nft_handle *h, const char *table,
- const char *chain, bool verbose, bool implicit)
+ const char *chain, bool verbose, bool skip)
{
struct obj_update *obj;
struct nftnl_rule *r;
@@ -1690,7 +1689,7 @@ __nft_rule_flush(struct nft_handle *h, const char *table,
return;
}
- obj->implicit = implicit;
+ obj->skip = skip;
}
int nft_rule_flush(struct nft_handle *h, const char *chain, const char *table,
@@ -1786,17 +1785,12 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table)
{
struct nftnl_chain_list *list;
+ struct obj_update *obj;
struct nftnl_chain *c;
bool created = false;
c = nft_chain_find(h, table, chain);
- if (c) {
- /* Apparently -n still flushes existing user defined
- * chains that are redefined.
- */
- if (h->noflush)
- __nft_rule_flush(h, table, chain, false, true);
- } else {
+ if (!c) {
c = nftnl_chain_alloc();
if (!c)
return 0;
@@ -1804,20 +1798,26 @@ int nft_chain_restore(struct nft_handle *h, const char *chain, const char *table
nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table);
nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, chain);
created = true;
- }
- if (h->family == NFPROTO_BRIDGE)
- nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, NF_ACCEPT);
+ list = nft_chain_list_get(h, table, chain);
+ if (list)
+ nftnl_chain_list_add(c, list);
+ } else {
+ /* If the chain should vanish meanwhile, kernel genid changes
+ * and the transaction is refreshed enabling the chain add
+ * object. With the handle still set, kernel interprets it as a
+ * chain replace job and errors since it is not found anymore.
+ */
+ nftnl_chain_unset(c, NFTNL_CHAIN_HANDLE);
+ }
- if (!created)
- return 1;
+ __nft_rule_flush(h, table, chain, false, created);
- if (!batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c))
+ obj = batch_chain_add(h, NFT_COMPAT_CHAIN_USER_ADD, c);
+ if (!obj)
return 0;
- list = nft_chain_list_get(h, table, chain);
- if (list)
- nftnl_chain_list_add(c, list);
+ obj->skip = !created;
/* the core expects 1 for success and 0 for error */
return 1;
@@ -2751,11 +2751,6 @@ static void nft_refresh_transaction(struct nft_handle *h)
h->error.lineno = 0;
list_for_each_entry_safe(n, tmp, &h->obj_list, head) {
- if (n->implicit) {
- batch_obj_del(h, n);
- continue;
- }
-
switch (n->type) {
case NFT_COMPAT_TABLE_FLUSH:
tablename = nftnl_table_get_str(n->table, NFTNL_TABLE_NAME);
@@ -2781,14 +2776,22 @@ static void nft_refresh_transaction(struct nft_handle *h)
c = nft_chain_find(h, tablename, chainname);
if (c) {
- /* -restore -n flushes existing rules from redefined user-chain */
- __nft_rule_flush(h, tablename,
- chainname, false, true);
n->skip = 1;
} else if (!c) {
n->skip = 0;
}
break;
+ case NFT_COMPAT_RULE_FLUSH:
+ tablename = nftnl_rule_get_str(n->rule, NFTNL_RULE_TABLE);
+ if (!tablename)
+ continue;
+
+ chainname = nftnl_rule_get_str(n->rule, NFTNL_RULE_CHAIN);
+ if (!chainname)
+ continue;
+
+ n->skip = !nft_chain_find(h, tablename, chainname);
+ break;
case NFT_COMPAT_TABLE_ADD:
case NFT_COMPAT_CHAIN_ADD:
case NFT_COMPAT_CHAIN_ZERO:
@@ -2800,7 +2803,6 @@ static void nft_refresh_transaction(struct nft_handle *h)
case NFT_COMPAT_RULE_INSERT:
case NFT_COMPAT_RULE_REPLACE:
case NFT_COMPAT_RULE_DELETE:
- case NFT_COMPAT_RULE_FLUSH:
case NFT_COMPAT_SET_ADD:
case NFT_COMPAT_RULE_LIST:
case NFT_COMPAT_RULE_CHECK:
diff --git a/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0 b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
new file mode 100755
index 0000000000000..53ec12fa368af
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+set -e
+
+RS="*filter
+:INPUT ACCEPT [12024:3123388]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [12840:2144421]
+:FOO - [0:0]
+:BAR0 - [0:0]
+:BAR1 - [0:0]
+:BAR2 - [0:0]
+:BAR3 - [0:0]
+:BAR4 - [0:0]
+:BAR5 - [0:0]
+:BAR6 - [0:0]
+:BAR7 - [0:0]
+:BAR8 - [0:0]
+:BAR9 - [0:0]
+"
+
+RS1="$RS
+-X BAR3
+-X BAR6
+-X BAR9
+-A FOO -s 9.9.0.1/32 -j BAR1
+-A FOO -s 9.9.0.2/32 -j BAR2
+-A FOO -s 9.9.0.4/32 -j BAR4
+-A FOO -s 9.9.0.5/32 -j BAR5
+-A FOO -s 9.9.0.7/32 -j BAR7
+-A FOO -s 9.9.0.8/32 -j BAR8
+COMMIT
+"
+
+RS2="$RS
+-X BAR2
+-X BAR5
+-X BAR7
+-A FOO -s 9.9.0.1/32 -j BAR1
+-A FOO -s 9.9.0.3/32 -j BAR3
+-A FOO -s 9.9.0.4/32 -j BAR4
+-A FOO -s 9.9.0.6/32 -j BAR6
+-A FOO -s 9.9.0.8/32 -j BAR8
+-A FOO -s 9.9.0.9/32 -j BAR9
+COMMIT
+"
+
+for n in $(seq 1 10); do
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS1" &
+ $XT_MULTI iptables-restore --noflush -w <<< "$RS2" &
+ wait -n
+ wait -n
+done
--
2.40.0

@ -0,0 +1,54 @@
From bb80a77e8b0b2b557c4a2afd88446853e19236da Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 26 Oct 2020 17:25:03 +0100
Subject: [PATCH] tests: shell: Improve concurrent noflush restore test a bit
The described issue happens only if chain FOO does not exist at program
start so flush the ruleset after each iteration to make sure this is the
case. Sadly the bug is still not 100% reproducible on my testing VM.
While being at it, add a paragraph describing what exact situation the
test is trying to provoke.
Fixes: dac904bdcd9a1 ("nft: Fix for concurrent noflush restore calls")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit ed8c8b9316451a4499eeb592d2cf7d782bbe4e9a)
---
.../ipt-restore/0016-concurrent-restores_0 | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0 b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
index 53ec12fa368af..aa746ab458a3c 100755
--- a/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
+++ b/iptables/tests/shell/testcases/ipt-restore/0016-concurrent-restores_0
@@ -1,5 +1,14 @@
#!/bin/bash
+# test for iptables-restore --noflush skipping an explicitly requested chain
+# flush because the chain did not exist when cache was fetched. In order to
+# expect for that chain to appear when refreshing the transaction (due to a
+# concurrent ruleset change), the chain flush job has to be present in batch
+# job list (although disabled at first).
+# The input line requesting chain flush is ':FOO - [0:0]'. RS1 and RS2 contents
+# are crafted to cause EBUSY when deleting the BAR* chains if FOO is not
+# flushed in the same transaction.
+
set -e
RS="*filter
@@ -45,7 +54,12 @@ RS2="$RS
COMMIT
"
+NORS="*filter
+COMMIT
+"
+
for n in $(seq 1 10); do
+ $XT_MULTI iptables-restore <<< "$NORS"
$XT_MULTI iptables-restore --noflush -w <<< "$RS1" &
$XT_MULTI iptables-restore --noflush -w <<< "$RS2" &
wait -n
--
2.40.0

@ -0,0 +1,149 @@
From a48e8c5a7433c8f7d0f28ed321081b25f3b63a4a Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 2 Oct 2020 09:44:38 +0200
Subject: [PATCH] nft: Optimize class-based IP prefix matches
Payload expression works on byte-boundaries, leverage this with suitable
prefix lengths.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 323259001d617ae359430a03ee3d3e7f107684e0)
---
iptables/nft-arp.c | 11 ++++++++---
iptables/nft-ipv4.c | 6 ++++--
iptables/nft-ipv6.c | 6 ++++--
iptables/nft-shared.c | 14 ++++++++++----
iptables/nft-shared.h | 4 ++++
5 files changed, 30 insertions(+), 11 deletions(-)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 67f4529d93652..952f0c6916e59 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -303,7 +303,8 @@ static bool nft_arp_parse_devaddr(struct nft_xt_ctx *ctx,
memcpy(info->mask, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(info->mask, 0xff, ETH_ALEN);
+ memset(info->mask, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
return inv;
@@ -360,7 +361,9 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &fw->arp.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- fw->arp.smsk.s_addr = 0xffffffff;
+ memset(&fw->arp.smsk, 0xff,
+ min(ctx->payload.len,
+ sizeof(struct in_addr)));
}
if (inv)
@@ -380,7 +383,9 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &fw->arp.tmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- fw->arp.tmsk.s_addr = 0xffffffff;
+ memset(&fw->arp.tmsk, 0xff,
+ min(ctx->payload.len,
+ sizeof(struct in_addr)));
}
if (inv)
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index afdecf9711e64..ce702041af0f4 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -199,7 +199,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- cs->fw.ip.smsk.s_addr = 0xffffffff;
+ memset(&cs->fw.ip.smsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in_addr)));
}
if (inv)
@@ -212,7 +213,8 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv4(ctx, &cs->fw.ip.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- cs->fw.ip.dmsk.s_addr = 0xffffffff;
+ memset(&cs->fw.ip.dmsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in_addr)));
}
if (inv)
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 4008b7eab4f2a..c877ec6d10887 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -146,7 +146,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.smsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&cs->fw6.ipv6.smsk, 0xff, sizeof(struct in6_addr));
+ memset(&cs->fw6.ipv6.smsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in6_addr)));
}
if (inv)
@@ -159,7 +160,8 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
parse_mask_ipv6(ctx, &cs->fw6.ipv6.dmsk);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&cs->fw6.ipv6.dmsk, 0xff, sizeof(struct in6_addr));
+ memset(&cs->fw6.ipv6.dmsk, 0xff,
+ min(ctx->payload.len, sizeof(struct in6_addr)));
}
if (inv)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 7741d23befc5a..545e9c60fa015 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -166,16 +166,22 @@ void add_addr(struct nftnl_rule *r, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
const unsigned char *m = mask;
+ bool bitwise = false;
int i;
- add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
-
for (i = 0; i < len; i++) {
- if (m[i] != 0xff)
+ if (m[i] != 0xff) {
+ bitwise = m[i] != 0;
break;
+ }
}
- if (i != len)
+ if (!bitwise)
+ len = i;
+
+ add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
+
+ if (bitwise)
add_bitwise(r, mask, len);
add_cmp_ptr(r, op, data, len);
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 94437ffe7990c..811fb9a1ebe76 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -246,4 +246,8 @@ void xtables_restore_parse(struct nft_handle *h,
const struct nft_xt_restore_parse *p);
void nft_check_xt_legacy(int family, bool is_ipt_save);
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
#endif
--
2.40.0

@ -0,0 +1,217 @@
From 06f53a3a19c829417c4083fdbbbeba14c92c7b04 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 30 Oct 2020 14:08:33 +0100
Subject: [PATCH] ebtables: Optimize masked MAC address matches
Just like with class-based prefix matches in iptables-nft, optimize
masked MAC address matches if the mask is on a byte-boundary.
To reuse the logic in add_addr(), extend it to accept the payload base
value via parameter.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 274cb05edc58d6fa982a34c84b2f4cf6acc3e335)
---
iptables/nft-arp.c | 12 ++++++++----
iptables/nft-bridge.c | 22 ++++++++++------------
iptables/nft-ipv4.c | 6 ++++--
iptables/nft-ipv6.c | 6 ++++--
iptables/nft-shared.c | 5 ++---
iptables/nft-shared.h | 3 ++-
6 files changed, 30 insertions(+), 24 deletions(-)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 952f0c6916e59..5dc38da831aa0 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -178,7 +178,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (need_devaddr(&fw->arp.src_devaddr)) {
op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR);
- add_addr(r, sizeof(struct arphdr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr),
&fw->arp.src_devaddr.addr,
&fw->arp.src_devaddr.mask,
fw->arp.arhln, op);
@@ -189,7 +190,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
fw->arp.smsk.s_addr != 0 ||
fw->arp.invflags & ARPT_INV_SRCIP) {
op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCIP);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln,
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln,
&fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
sizeof(struct in_addr), op);
}
@@ -197,7 +199,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (need_devaddr(&fw->arp.tgt_devaddr)) {
op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
&fw->arp.tgt_devaddr.addr,
&fw->arp.tgt_devaddr.mask,
fw->arp.arhln, op);
@@ -207,7 +210,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
fw->arp.tmsk.s_addr != 0 ||
fw->arp.invflags & ARPT_INV_TGTIP) {
op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTIP);
- add_addr(r, sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
&fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
sizeof(struct in_addr), op);
}
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index dbf11eb5e1fa8..c1a2c209cc1aa 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -159,20 +159,16 @@ static int nft_bridge_add(struct nft_handle *h,
if (fw->bitmask & EBT_ISOURCE) {
op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
- add_payload(r, offsetof(struct ethhdr, h_source), 6,
- NFT_PAYLOAD_LL_HEADER);
- if (!mac_all_ones(fw->sourcemsk))
- add_bitwise(r, fw->sourcemsk, 6);
- add_cmp_ptr(r, op, fw->sourcemac, 6);
+ add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_source),
+ fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
}
if (fw->bitmask & EBT_IDEST) {
op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
- add_payload(r, offsetof(struct ethhdr, h_dest), 6,
- NFT_PAYLOAD_LL_HEADER);
- if (!mac_all_ones(fw->destmsk))
- add_bitwise(r, fw->destmsk, 6);
- add_cmp_ptr(r, op, fw->destmac, 6);
+ add_addr(r, NFT_PAYLOAD_LL_HEADER,
+ offsetof(struct ethhdr, h_dest),
+ fw->destmac, fw->destmsk, ETH_ALEN, op);
}
if ((fw->bitmask & EBT_NOPROTO) == 0) {
@@ -258,7 +254,8 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&fw->destmsk, 0xff, ETH_ALEN);
+ memset(&fw->destmsk, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
fw->bitmask |= EBT_IDEST;
break;
@@ -272,7 +269,8 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN);
ctx->flags &= ~NFT_XT_CTX_BITWISE;
} else {
- memset(&fw->sourcemsk, 0xff, ETH_ALEN);
+ memset(&fw->sourcemsk, 0xff,
+ min(ctx->payload.len, ETH_ALEN));
}
fw->bitmask |= EBT_ISOURCE;
break;
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index ce702041af0f4..fdc15c6f04066 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -50,13 +50,15 @@ static int nft_ipv4_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (cs->fw.ip.src.s_addr || cs->fw.ip.smsk.s_addr || cs->fw.ip.invflags & IPT_INV_SRCIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_SRCIP);
- add_addr(r, offsetof(struct iphdr, saddr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct iphdr, saddr),
&cs->fw.ip.src.s_addr, &cs->fw.ip.smsk.s_addr,
sizeof(struct in_addr), op);
}
if (cs->fw.ip.dst.s_addr || cs->fw.ip.dmsk.s_addr || cs->fw.ip.invflags & IPT_INV_DSTIP) {
op = nft_invflags2cmp(cs->fw.ip.invflags, IPT_INV_DSTIP);
- add_addr(r, offsetof(struct iphdr, daddr),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct iphdr, daddr),
&cs->fw.ip.dst.s_addr, &cs->fw.ip.dmsk.s_addr,
sizeof(struct in_addr), op);
}
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index c877ec6d10887..130ad3e6e7c44 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -51,7 +51,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.smsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_SRCIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_SRCIP);
- add_addr(r, offsetof(struct ip6_hdr, ip6_src),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct ip6_hdr, ip6_src),
&cs->fw6.ipv6.src, &cs->fw6.ipv6.smsk,
sizeof(struct in6_addr), op);
}
@@ -59,7 +60,8 @@ static int nft_ipv6_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dmsk) ||
(cs->fw6.ipv6.invflags & IPT_INV_DSTIP)) {
op = nft_invflags2cmp(cs->fw6.ipv6.invflags, IPT_INV_DSTIP);
- add_addr(r, offsetof(struct ip6_hdr, ip6_dst),
+ add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
+ offsetof(struct ip6_hdr, ip6_dst),
&cs->fw6.ipv6.dst, &cs->fw6.ipv6.dmsk,
sizeof(struct in6_addr), op);
}
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 545e9c60fa015..10553ab26823b 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -20,7 +20,6 @@
#include <xtables.h>
-#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/xt_comment.h>
#include <linux/netfilter/xt_limit.h>
@@ -162,7 +161,7 @@ void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
add_cmp_ptr(r, op, iface, iface_len + 1);
}
-void add_addr(struct nftnl_rule *r, int offset,
+void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op)
{
const unsigned char *m = mask;
@@ -179,7 +178,7 @@ void add_addr(struct nftnl_rule *r, int offset,
if (!bitwise)
len = i;
- add_payload(r, offset, len, NFT_PAYLOAD_NETWORK_HEADER);
+ add_payload(r, offset, len, base);
if (bitwise)
add_bitwise(r, mask, len);
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 811fb9a1ebe76..6fc81d9ce08ef 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -8,6 +8,7 @@
#include <libnftnl/chain.h>
#include <linux/netfilter_arp/arp_tables.h>
+#include <linux/netfilter/nf_tables.h>
#include "xshared.h"
@@ -121,7 +122,7 @@ void add_cmp_u16(struct nftnl_rule *r, uint16_t val, uint32_t op);
void add_cmp_u32(struct nftnl_rule *r, uint32_t val, uint32_t op);
void add_iniface(struct nftnl_rule *r, char *iface, uint32_t op);
void add_outiface(struct nftnl_rule *r, char *iface, uint32_t op);
-void add_addr(struct nftnl_rule *r, int offset,
+void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
void *data, void *mask, size_t len, uint32_t op);
void add_proto(struct nftnl_rule *r, int offset, size_t len,
uint8_t proto, uint32_t op);
--
2.40.0

@ -0,0 +1,365 @@
From f07a5fdd6c2a5ffe962ba77b8bfa08673f3b9408 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 10 Nov 2020 14:50:46 +0100
Subject: [PATCH] tests/shell: Add test for bitwise avoidance fixes
Masked address matching was recently improved to avoid bitwise
expression if the given mask covers full bytes. Make use of nft netlink
debug output to assert iptables-nft generates the right bytecode for
each situation.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 81a2e128512837b53e5b9ea501b6c8dc64eeca78)
---
.../nft-only/0009-needless-bitwise_0 | 339 ++++++++++++++++++
1 file changed, 339 insertions(+)
create mode 100755 iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
diff --git a/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0 b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
new file mode 100755
index 0000000000000..c5c6e706a1029
--- /dev/null
+++ b/iptables/tests/shell/testcases/nft-only/0009-needless-bitwise_0
@@ -0,0 +1,339 @@
+#!/bin/bash -x
+
+[[ $XT_MULTI == *xtables-nft-multi ]] || { echo "skip $XT_MULTI"; exit 0; }
+set -e
+
+nft flush ruleset
+
+(
+ echo "*filter"
+ for plen in "" 32 30 24 16 8 0; do
+ addr="10.1.2.3${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore
+
+(
+ echo "*filter"
+ for plen in "" 128 124 120 112 88 80 64 48 16 8 0; do
+ addr="feed:c0ff:ee00:0102:0304:0506:0708:090A${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ echo "COMMIT"
+) | $XT_MULTI ip6tables-restore
+
+masks="
+ff:ff:ff:ff:ff:ff
+ff:ff:ff:ff:ff:f0
+ff:ff:ff:ff:ff:00
+ff:ff:ff:ff:00:00
+ff:ff:ff:00:00:00
+ff:ff:00:00:00:00
+ff:00:00:00:00:00
+"
+(
+ echo "*filter"
+ for plen in "" 32 30 24 16 8 0; do
+ addr="10.1.2.3${plen:+/}$plen"
+ echo "-A OUTPUT -d $addr"
+ done
+ for mask in $masks; do
+ echo "-A OUTPUT --destination-mac fe:ed:00:c0:ff:ee/$mask"
+ done
+ echo "COMMIT"
+) | $XT_MULTI arptables-restore
+
+(
+ echo "*filter"
+ for mask in $masks; do
+ echo "-A OUTPUT -d fe:ed:00:c0:ff:ee/$mask"
+ done
+ echo "COMMIT"
+) | $XT_MULTI ebtables-restore
+
+EXPECT="ip filter OUTPUT 4
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 5 4
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 6 5
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ bitwise reg 1 = (reg=1 & 0xfcffffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 7 6
+ [ payload load 3b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 8 7
+ [ payload load 2b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0000010a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 9 8
+ [ payload load 1b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ counter pkts 0 bytes 0 ]
+
+ip filter OUTPUT 10 9
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 4
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 5 4
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x0a090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 6 5
+ [ payload load 16b @ network header + 24 => reg 1 ]
+ [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0xffffffff 0xf0ffffff ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 7 6
+ [ payload load 15b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00090807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 8 7
+ [ payload load 14b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x06050403 0x00000807 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 9 8
+ [ payload load 11b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00050403 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 10 9
+ [ payload load 10b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee 0x00000403 ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 11 10
+ [ payload load 8b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x020100ee ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 12 11
+ [ payload load 6b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xffc0edfe 0x000000ee ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 13 12
+ [ payload load 2b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 14 13
+ [ payload load 1b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+
+ip6 filter OUTPUT 15 14
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 3
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 4 3
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0302010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 5 4
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 24 => reg 1 ]
+ [ bitwise reg 1 = (reg=1 & 0xfcffffff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 6 5
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 3b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0002010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 7 6
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 2b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000010a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 8 7
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 1b @ network header + 24 => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 9 8
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 10 9
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000eeff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 11 10
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 6b @ network header + 18 => reg 1 ]
+ [ bitwise reg 1 = (reg=1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 12 11
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 5b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x000000ff ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 13 12
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 4b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 14 13
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 3b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 15 14
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 2b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+arp filter OUTPUT 16 15
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 1b @ network header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ network header + 5 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+ [ payload load 1b @ network header + 18 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 4
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000eeff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 5 4
+ [ payload load 6b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = (reg=1 & 0xffffffff 0x0000f0ff ) ^ 0x00000000 0x00000000 ]
+ [ cmp eq reg 1 0xc000edfe 0x0000e0ff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 6 5
+ [ payload load 5b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe 0x000000ff ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 7 6
+ [ payload load 4b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0xc000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 8 7
+ [ payload load 3b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 9 8
+ [ payload load 2b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x0000edfe ]
+ [ counter pkts 0 bytes 0 ]
+
+bridge filter OUTPUT 10 9
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x000000fe ]
+ [ counter pkts 0 bytes 0 ]
+"
+
+diff -u -Z <(echo "$EXPECT") <(nft --debug=netlink list ruleset | awk '/^table/{exit} {print}')
--
2.40.0

@ -0,0 +1,61 @@
From d4e535422a9f4908b6d4b331b9e9cffe7ef161f3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 17 Nov 2020 11:38:27 +0100
Subject: [PATCH] ebtables: Fix for broken chain renaming
Loading extensions pollutes 'errno' value, hence before using it to
indicate failure it should be sanitized. This was done by the called
function before the parsing/netlink split and not migrated by accident.
Move it into calling code to clarify the connection.
Fixes: a7f1e208cdf9c ("nft: split parsing from netlink commands")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 55b7c71dce7144f4dc0297c17abf0f04879ee247)
---
iptables/nft.c | 3 ---
iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 | 4 ++++
iptables/xtables-eb.c | 1 +
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index bdb633a82a655..bdf252198f155 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1932,9 +1932,6 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
return 0;
}
- /* Config load changed errno. Ensure genuine info for our callers. */
- errno = 0;
-
/* Find the old chain to be renamed */
c = nft_chain_find(h, table, chain);
if (c == NULL) {
diff --git a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0 b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
index 0c1eb4ca66f52..6f11bd12593dd 100755
--- a/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
+++ b/iptables/tests/shell/testcases/ebtables/0001-ebtables-basic_0
@@ -86,4 +86,8 @@ if [ $? -eq 0 ]; then
exit 1
fi
+$XT_MULTI ebtables -t filter -E FOO BAZ || exit 1
+$XT_MULTI ebtables -t filter -L | grep -q FOO && exit 1
+$XT_MULTI ebtables -t filter -L | grep -q BAZ || exit 1
+
$XT_MULTI ebtables -t $t -F || exit 0
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 375a95d1d5c75..6df5839f07436 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -853,6 +853,7 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
else if (strchr(argv[optind], ' ') != NULL)
xtables_error(PARAMETER_PROBLEM, "Use of ' ' not allowed in chain names");
+ errno = 0;
ret = nft_cmd_chain_user_rename(h, chain, *table,
argv[optind]);
if (ret != 0 && errno == ENOENT)
--
2.40.0

@ -0,0 +1,374 @@
From 38e8df1b4409387145c79fc358419d59b5ec3800 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 3 Nov 2020 12:21:29 +0100
Subject: [PATCH] xtables-arp: Don't use ARPT_INV_*
Arptables invflags are partly identical to IPT_INV_* ones but the bits
are differently assigned. Eliminate this incompatibility by definition
of the unique invflags in nft-arp.h on bits that don't collide with
IPT_INV_* ones, then use those in combination with IPT_INV_* ones in
arptables-specific code.
Note that ARPT_INV_ARPPRO is replaced by IPT_INV_PROTO although these
are in fact different options - yet since '-p' option is not supported
by arptables, this does not lead to a collision.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 44457c0805905ea22b4ecf9156648e774dd29155)
---
iptables/nft-arp.c | 92 ++++++++++++++++--------------------------
iptables/nft-arp.h | 7 ++++
iptables/xtables-arp.c | 22 +++++-----
3 files changed, 53 insertions(+), 68 deletions(-)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 5dc38da831aa0..c82ffdc95e300 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -134,34 +134,34 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
int ret = 0;
if (fw->arp.iniface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_IN);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_IN);
add_iniface(r, fw->arp.iniface, op);
}
if (fw->arp.outiface[0] != '\0') {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_VIA_OUT);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_VIA_OUT);
add_outiface(r, fw->arp.outiface, op);
}
if (fw->arp.arhrd != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHRD) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHRD);
+ fw->arp.invflags & IPT_INV_ARPHRD) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHRD);
add_payload(r, offsetof(struct arphdr, ar_hrd), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arhrd, op);
}
if (fw->arp.arpro != 0 ||
- fw->arp.invflags & ARPT_INV_ARPPRO) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPPRO);
+ fw->arp.invflags & IPT_INV_PROTO) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_PROTO);
add_payload(r, offsetof(struct arphdr, ar_pro), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arpro, op);
}
if (fw->arp.arhln != 0 ||
- fw->arp.invflags & ARPT_INV_ARPHLN) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPHLN);
+ fw->arp.invflags & IPT_INV_ARPHLN) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPHLN);
add_proto(r, offsetof(struct arphdr, ar_hln), 1,
fw->arp.arhln, op);
}
@@ -169,15 +169,15 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
add_proto(r, offsetof(struct arphdr, ar_pln), 1, 4, NFT_CMP_EQ);
if (fw->arp.arpop != 0 ||
- fw->arp.invflags & ARPT_INV_ARPOP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_ARPOP);
+ fw->arp.invflags & IPT_INV_ARPOP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_ARPOP);
add_payload(r, offsetof(struct arphdr, ar_op), 2,
NFT_PAYLOAD_NETWORK_HEADER);
add_cmp_u16(r, fw->arp.arpop, op);
}
if (need_devaddr(&fw->arp.src_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCDEVADDR);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCDEVADDR);
add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr),
&fw->arp.src_devaddr.addr,
@@ -188,8 +188,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (fw->arp.src.s_addr != 0 ||
fw->arp.smsk.s_addr != 0 ||
- fw->arp.invflags & ARPT_INV_SRCIP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_SRCIP);
+ fw->arp.invflags & IPT_INV_SRCIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_SRCIP);
add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr) + fw->arp.arhln,
&fw->arp.src.s_addr, &fw->arp.smsk.s_addr,
@@ -198,7 +198,7 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (need_devaddr(&fw->arp.tgt_devaddr)) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTDEVADDR);
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_TGTDEVADDR);
add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr),
&fw->arp.tgt_devaddr.addr,
@@ -208,8 +208,8 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
if (fw->arp.tgt.s_addr != 0 ||
fw->arp.tmsk.s_addr != 0 ||
- fw->arp.invflags & ARPT_INV_TGTIP) {
- op = nft_invflags2cmp(fw->arp.invflags, ARPT_INV_TGTIP);
+ fw->arp.invflags & IPT_INV_DSTIP) {
+ op = nft_invflags2cmp(fw->arp.invflags, IPT_INV_DSTIP);
add_addr(r, NFT_PAYLOAD_NETWORK_HEADER,
sizeof(struct arphdr) + fw->arp.arhln + sizeof(struct in_addr) + fw->arp.arhln,
&fw->arp.tgt.s_addr, &fw->arp.tmsk.s_addr,
@@ -240,28 +240,6 @@ static int nft_arp_add(struct nft_handle *h, struct nftnl_rule *r, void *data)
return ret;
}
-static uint16_t ipt_to_arpt_flags(uint8_t invflags)
-{
- uint16_t result = 0;
-
- if (invflags & IPT_INV_VIA_IN)
- result |= ARPT_INV_VIA_IN;
-
- if (invflags & IPT_INV_VIA_OUT)
- result |= ARPT_INV_VIA_OUT;
-
- if (invflags & IPT_INV_SRCIP)
- result |= ARPT_INV_SRCIP;
-
- if (invflags & IPT_INV_DSTIP)
- result |= ARPT_INV_TGTIP;
-
- if (invflags & IPT_INV_PROTO)
- result |= ARPT_INV_ARPPRO;
-
- return result;
-}
-
static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data)
{
@@ -273,7 +251,7 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
fw->arp.outiface, fw->arp.outiface_mask,
&flags);
- fw->arp.invflags |= ipt_to_arpt_flags(flags);
+ fw->arp.invflags |= flags;
}
static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
@@ -330,33 +308,33 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
fw->arp.arhrd = ar_hrd;
fw->arp.arhrd_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPHRD;
+ fw->arp.invflags |= IPT_INV_ARPHRD;
break;
case offsetof(struct arphdr, ar_pro):
get_cmp_data(e, &ar_pro, sizeof(ar_pro), &inv);
fw->arp.arpro = ar_pro;
fw->arp.arpro_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPPRO;
+ fw->arp.invflags |= IPT_INV_PROTO;
break;
case offsetof(struct arphdr, ar_op):
get_cmp_data(e, &ar_op, sizeof(ar_op), &inv);
fw->arp.arpop = ar_op;
fw->arp.arpop_mask = 0xffff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPOP;
+ fw->arp.invflags |= IPT_INV_ARPOP;
break;
case offsetof(struct arphdr, ar_hln):
get_cmp_data(e, &ar_hln, sizeof(ar_hln), &inv);
fw->arp.arhln = ar_hln;
fw->arp.arhln_mask = 0xff;
if (inv)
- fw->arp.invflags |= ARPT_INV_ARPOP;
+ fw->arp.invflags |= IPT_INV_ARPOP;
break;
default:
if (ctx->payload.offset == sizeof(struct arphdr)) {
if (nft_arp_parse_devaddr(ctx, e, &fw->arp.src_devaddr))
- fw->arp.invflags |= ARPT_INV_SRCDEVADDR;
+ fw->arp.invflags |= IPT_INV_SRCDEVADDR;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln) {
get_cmp_data(e, &addr, sizeof(addr), &inv);
@@ -371,12 +349,12 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
}
if (inv)
- fw->arp.invflags |= ARPT_INV_SRCIP;
+ fw->arp.invflags |= IPT_INV_SRCIP;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln +
sizeof(struct in_addr)) {
if (nft_arp_parse_devaddr(ctx, e, &fw->arp.tgt_devaddr))
- fw->arp.invflags |= ARPT_INV_TGTDEVADDR;
+ fw->arp.invflags |= IPT_INV_TGTDEVADDR;
} else if (ctx->payload.offset == sizeof(struct arphdr) +
fw->arp.arhln +
sizeof(struct in_addr) +
@@ -393,7 +371,7 @@ static void nft_arp_parse_payload(struct nft_xt_ctx *ctx,
}
if (inv)
- fw->arp.invflags |= ARPT_INV_TGTIP;
+ fw->arp.invflags |= IPT_INV_DSTIP;
}
break;
}
@@ -448,7 +426,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
else strcat(iface, "any");
}
if (print_iface) {
- printf("%s%s-i %s", sep, fw->arp.invflags & ARPT_INV_VIA_IN ?
+ printf("%s%s-i %s", sep, fw->arp.invflags & IPT_INV_VIA_IN ?
"! " : "", iface);
sep = " ";
}
@@ -466,13 +444,13 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
else strcat(iface, "any");
}
if (print_iface) {
- printf("%s%s-o %s", sep, fw->arp.invflags & ARPT_INV_VIA_OUT ?
+ printf("%s%s-o %s", sep, fw->arp.invflags & IPT_INV_VIA_OUT ?
"! " : "", iface);
sep = " ";
}
if (fw->arp.smsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCIP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
@@ -489,7 +467,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devsrc;
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_SRCDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCDEVADDR
? "! " : "");
printf("--src-mac ");
xtables_print_mac_and_mask((unsigned char *)fw->arp.src_devaddr.addr,
@@ -498,7 +476,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
after_devsrc:
if (fw->arp.tmsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTIP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP
? "! " : "");
if (format & FMT_NUMERIC)
sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
@@ -515,7 +493,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
break;
if (i == ARPT_DEV_ADDR_LEN_MAX)
goto after_devdst;
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_TGTDEVADDR
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_TGTDEVADDR
? "! " : "");
printf("--dst-mac ");
xtables_print_mac_and_mask((unsigned char *)fw->arp.tgt_devaddr.addr,
@@ -525,7 +503,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
after_devdst:
if (fw->arp.arhln_mask != 255 || fw->arp.arhln != 6) {
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHLN
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHLN
? "! " : "");
printf("--h-length %d", fw->arp.arhln);
if (fw->arp.arhln_mask != 255)
@@ -536,7 +514,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
if (fw->arp.arpop_mask != 0) {
int tmp = ntohs(fw->arp.arpop);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPOP
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPOP
? "! " : "");
if (tmp <= NUMOPCODES && !(format & FMT_NUMERIC))
printf("--opcode %s", arp_opcodes[tmp-1]);
@@ -551,7 +529,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
if (fw->arp.arhrd_mask != 65535 || fw->arp.arhrd != htons(1)) {
uint16_t tmp = ntohs(fw->arp.arhrd);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPHRD
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_ARPHRD
? "! " : "");
if (tmp == 1 && !(format & FMT_NUMERIC))
printf("--h-type %s", "Ethernet");
@@ -565,7 +543,7 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
if (fw->arp.arpro_mask != 0) {
int tmp = ntohs(fw->arp.arpro);
- printf("%s%s", sep, fw->arp.invflags & ARPT_INV_ARPPRO
+ printf("%s%s", sep, fw->arp.invflags & IPT_INV_PROTO
? "! " : "");
if (tmp == 0x0800 && !(format & FMT_NUMERIC))
printf("--proto-type %s", "IPv4");
diff --git a/iptables/nft-arp.h b/iptables/nft-arp.h
index 3411fc3d7c7b3..0d93a31f563b1 100644
--- a/iptables/nft-arp.h
+++ b/iptables/nft-arp.h
@@ -4,4 +4,11 @@
extern char *arp_opcodes[];
#define NUMOPCODES 9
+/* define invflags which won't collide with IPT ones */
+#define IPT_INV_SRCDEVADDR 0x0080
+#define IPT_INV_TGTDEVADDR 0x0100
+#define IPT_INV_ARPHLN 0x0200
+#define IPT_INV_ARPOP 0x0400
+#define IPT_INV_ARPHRD 0x0800
+
#endif
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 8632774dfb705..3a35dcd107e19 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -113,22 +113,22 @@ struct xtables_globals arptables_globals = {
static int inverse_for_options[] =
{
/* -n */ 0,
-/* -s */ ARPT_INV_SRCIP,
-/* -d */ ARPT_INV_TGTIP,
+/* -s */ IPT_INV_SRCIP,
+/* -d */ IPT_INV_DSTIP,
/* -p */ 0,
/* -j */ 0,
/* -v */ 0,
/* -x */ 0,
-/* -i */ ARPT_INV_VIA_IN,
-/* -o */ ARPT_INV_VIA_OUT,
+/* -i */ IPT_INV_VIA_IN,
+/* -o */ IPT_INV_VIA_OUT,
/*--line*/ 0,
/* -c */ 0,
-/* 2 */ ARPT_INV_SRCDEVADDR,
-/* 3 */ ARPT_INV_TGTDEVADDR,
-/* -l */ ARPT_INV_ARPHLN,
-/* 4 */ ARPT_INV_ARPOP,
-/* 5 */ ARPT_INV_ARPHRD,
-/* 6 */ ARPT_INV_ARPPRO,
+/* 2 */ IPT_INV_SRCDEVADDR,
+/* 3 */ IPT_INV_TGTDEVADDR,
+/* -l */ IPT_INV_ARPHLN,
+/* 4 */ IPT_INV_ARPOP,
+/* 5 */ IPT_INV_ARPHRD,
+/* 6 */ IPT_INV_PROTO,
};
/***********************************************/
@@ -901,7 +901,7 @@ int do_commandarp(struct nft_handle *h, int argc, char *argv[], char **table,
&dmasks, &ndaddrs);
if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.arp.arp.invflags & (ARPT_INV_SRCIP | ARPT_INV_TGTIP)))
+ (cs.arp.arp.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
" source or destination IP addresses");
--
2.40.0

@ -0,0 +1,517 @@
From 003b063b1b40503bc996a4f88c1941c91a0c550b Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 30 Oct 2020 12:42:57 +0100
Subject: [PATCH] xshared: Merge some command option-related code
Add OPT_FRAGMENT define into the enum of other OPT_* defines at the
right position and adjust the arptables-specific ones that follow
accordingly. Appropriately adjust inverse_for_options array in
xtables-arp.c.
Extend optflags from iptables.c by the arptables values for the sake of
completeness, then move it to xshared.h along with NUMBER_OF_OPT
definition. As a side-effect, this fixes for wrong ordering of entries
in arptables' 'optflags' copy.
Add arptables-specific bits to commands_v_options table (the speicific
options are matches on ARP header fields, just treat them like '-s'
option. This is also just a cosmetic change, arptables doesn't have a
generic_opt_check() implementation and hence doesn't use such a table.
With things potentially ready for common use, move commands_v_options
table along with generic_opt_check() and opt2char() into xshared.c and
drop the local (identical) implementations from iptables.c, ip6tables.c
xtables.c and xtables-arp.c. While doing so, fix ordering of entries in
that table: the row for CMD_ZERO_NUM was in the wrong position. Since
all moved rows though are identical, this had no effect in practice.
Fixes: d960a991350ca ("xtables-arp: Integrate OPT_* defines into xshared.h")
Fixes: 384958620abab ("use nf_tables and nf_tables compatibility interface")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 8bd4b4f79b5de483353a8c0d0962e71934b7bdd2)
---
iptables/ip6tables.c | 79 -----------------------------------------
iptables/iptables.c | 80 ------------------------------------------
iptables/xshared.c | 74 ++++++++++++++++++++++++++++++++++++++
iptables/xshared.h | 20 +++++++----
iptables/xtables-arp.c | 14 +-------
iptables/xtables.c | 80 ------------------------------------------
6 files changed, 89 insertions(+), 258 deletions(-)
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index 576c2cf8b0d9f..c95355b091568 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -45,10 +45,6 @@
#include "ip6tables-multi.h"
#include "xshared.h"
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c'};
-
static const char unsupported_rev[] = " [unsupported revision]";
static struct option original_opts[] = {
@@ -100,36 +96,6 @@ struct xtables_globals ip6tables_globals = {
.compat_rev = xtables_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' '},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x'},
-};
-
static const unsigned int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -264,51 +230,6 @@ ip6tables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 88ef6cf666d4b..7d6183116d265 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -41,11 +41,6 @@
#include <fcntl.h>
#include "xshared.h"
-#define OPT_FRAGMENT 0x00800U
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
-
static const char unsupported_rev[] = " [unsupported revision]";
static struct option original_opts[] = {
@@ -99,36 +94,6 @@ struct xtables_globals iptables_globals = {
.compat_rev = xtables_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c -f */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-};
-
static const int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -263,51 +228,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
diff --git a/iptables/xshared.c b/iptables/xshared.c
index c1d1371a6d54a..fe37c30a085d6 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -774,3 +774,77 @@ int parse_rulenumber(const char *rule)
return rulenum;
}
+
+/* Table of legal combinations of commands and options. If any of the
+ * given commands make an option legal, that option is legal (applies to
+ * CMD_LIST and CMD_ZERO only).
+ * Key:
+ * + compulsory
+ * x illegal
+ * optional
+ */
+static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
+/* Well, it's better than "Re: Linux vs FreeBSD" */
+{
+ /* -n -s -d -p -j -v -x -i -o --line -c -f 2 3 l 4 5 6 */
+/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
+/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' ',' ',' ',' ',' ',' ',' '},
+/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x','x','x','x','x','x','x'},
+/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x','x','x','x','x','x','x'},
+/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x','x','x','x','x','x','x'},
+/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' ',' ',' ',' ',' ',' ',' '},
+};
+
+void generic_opt_check(int command, int options)
+{
+ int i, j, legal = 0;
+
+ /* Check that commands are valid with options. Complicated by the
+ * fact that if an option is legal with *any* command given, it is
+ * legal overall (ie. -z and -l).
+ */
+ for (i = 0; i < NUMBER_OF_OPT; i++) {
+ legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
+
+ for (j = 0; j < NUMBER_OF_CMD; j++) {
+ if (!(command & (1<<j)))
+ continue;
+
+ if (!(options & (1<<i))) {
+ if (commands_v_options[j][i] == '+')
+ xtables_error(PARAMETER_PROBLEM,
+ "You need to supply the `-%c' "
+ "option for this command\n",
+ optflags[i]);
+ } else {
+ if (commands_v_options[j][i] != 'x')
+ legal = 1;
+ else if (legal == 0)
+ legal = -1;
+ }
+ }
+ if (legal == -1)
+ xtables_error(PARAMETER_PROBLEM,
+ "Illegal option `-%c' with this command\n",
+ optflags[i]);
+ }
+}
+
+char opt2char(int option)
+{
+ const char *ptr;
+
+ for (ptr = optflags; option > 1; option >>= 1, ptr++)
+ ;
+
+ return *ptr;
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index c41bd054bf36f..9159b2b1f3768 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -30,15 +30,20 @@ enum {
OPT_VIANAMEOUT = 1 << 8,
OPT_LINENUMBERS = 1 << 9,
OPT_COUNTERS = 1 << 10,
+ OPT_FRAGMENT = 1 << 11,
/* below are for arptables only */
- OPT_S_MAC = 1 << 11,
- OPT_D_MAC = 1 << 12,
- OPT_H_LENGTH = 1 << 13,
- OPT_OPCODE = 1 << 14,
- OPT_H_TYPE = 1 << 15,
- OPT_P_TYPE = 1 << 16,
+ OPT_S_MAC = 1 << 12,
+ OPT_D_MAC = 1 << 13,
+ OPT_H_LENGTH = 1 << 14,
+ OPT_OPCODE = 1 << 15,
+ OPT_H_TYPE = 1 << 16,
+ OPT_P_TYPE = 1 << 17,
};
+#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
+static const char optflags[]
+= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f', 2, 3, 'l', 4, 5, 6 };
+
enum {
CMD_NONE = 0,
CMD_INSERT = 1 << 0,
@@ -216,4 +221,7 @@ void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert);
int parse_rulenumber(const char *rule);
+void generic_opt_check(int command, int options);
+char opt2char(int option);
+
#endif /* IPTABLES_XSHARED_H */
diff --git a/iptables/xtables-arp.c b/iptables/xtables-arp.c
index 3a35dcd107e19..0695504892b74 100644
--- a/iptables/xtables-arp.c
+++ b/iptables/xtables-arp.c
@@ -53,10 +53,6 @@
#include "nft-arp.h"
#include <linux/netfilter_arp/arp_tables.h>
-#define NUMBER_OF_OPT 16
-static const char optflags[NUMBER_OF_OPT]
-= { 'n', 's', 'd', 2, 3, 7, 8, 4, 5, 6, 'j', 'v', 'i', 'o', '0', 'c'};
-
static struct option original_opts[] = {
{ "append", 1, 0, 'A' },
{ "delete", 1, 0, 'D' },
@@ -123,6 +119,7 @@ static int inverse_for_options[] =
/* -o */ IPT_INV_VIA_OUT,
/*--line*/ 0,
/* -c */ 0,
+/* -f */ 0,
/* 2 */ IPT_INV_SRCDEVADDR,
/* 3 */ IPT_INV_TGTDEVADDR,
/* -l */ IPT_INV_ARPHLN,
@@ -327,15 +324,6 @@ printhelp(void)
}
}
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
static int
check_inverse(const char option[], int *invert, int *optidx, int argc)
{
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 9d2e441e0b773..9779bd83d53b3 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -43,11 +43,6 @@
#include "nft-shared.h"
#include "nft.h"
-#define OPT_FRAGMENT 0x00800U
-#define NUMBER_OF_OPT ARRAY_SIZE(optflags)
-static const char optflags[]
-= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'};
-
static struct option original_opts[] = {
{.name = "append", .has_arg = 1, .val = 'A'},
{.name = "delete", .has_arg = 1, .val = 'D'},
@@ -99,36 +94,6 @@ struct xtables_globals xtables_globals = {
.compat_rev = nft_compatible_revision,
};
-/* Table of legal combinations of commands and options. If any of the
- * given commands make an option legal, that option is legal (applies to
- * CMD_LIST and CMD_ZERO only).
- * Key:
- * + compulsory
- * x illegal
- * optional
- */
-
-static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
-/* Well, it's better than "Re: Linux vs FreeBSD" */
-{
- /* -n -s -d -p -j -v -x -i -o --line -c -f */
-/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '},
-/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'},
-/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'},
-/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'},
-/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '},
-};
-
static const int inverse_for_options[NUMBER_OF_OPT] =
{
/* -n */ 0,
@@ -262,51 +227,6 @@ xtables_exit_error(enum xtables_exittype status, const char *msg, ...)
exit(status);
}
-static void
-generic_opt_check(int command, int options)
-{
- int i, j, legal = 0;
-
- /* Check that commands are valid with options. Complicated by the
- * fact that if an option is legal with *any* command given, it is
- * legal overall (ie. -z and -l).
- */
- for (i = 0; i < NUMBER_OF_OPT; i++) {
- legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */
-
- for (j = 0; j < NUMBER_OF_CMD; j++) {
- if (!(command & (1<<j)))
- continue;
-
- if (!(options & (1<<i))) {
- if (commands_v_options[j][i] == '+')
- xtables_error(PARAMETER_PROBLEM,
- "You need to supply the `-%c' "
- "option for this command\n",
- optflags[i]);
- } else {
- if (commands_v_options[j][i] != 'x')
- legal = 1;
- else if (legal == 0)
- legal = -1;
- }
- }
- if (legal == -1)
- xtables_error(PARAMETER_PROBLEM,
- "Illegal option `-%c' with this command\n",
- optflags[i]);
- }
-}
-
-static char
-opt2char(int option)
-{
- const char *ptr;
- for (ptr = optflags; option > 1; option >>= 1, ptr++);
-
- return *ptr;
-}
-
/*
* All functions starting with "parse" should succeed, otherwise
* the program fails.
--
2.40.0

@ -0,0 +1,52 @@
From 8d0f11ea353caa254b65b4fde240e5d3a8fe12a7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 4 Dec 2020 17:44:51 +0100
Subject: [PATCH] tests/shell: Test for fixed extension registration
Use strace to look at iptables-restore behaviour with typically
problematic input (conntrack revision 0 is no longer supported by
current kernels) to make sure the fix in commit a1eaaceb0460b
("libxtables: Simplify pending extension registration") is still
effective.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 93d0c97e8b6713f51ba679e01a1338d4f9076e7c)
---
.../0017-pointless-compat-checks_0 | 25 +++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100755 iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
diff --git a/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0 b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
new file mode 100755
index 0000000000000..cf73de32df409
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-restore/0017-pointless-compat-checks_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# A bug in extension registration would leave unsupported older extension
+# revisions in pending list and get compatibility checked again for each rule
+# using them. With SELinux enabled, the resulting socket() call per rule leads
+# to significant slowdown (~50% performance in worst cases).
+
+set -e
+
+strace --version >/dev/null || { echo "skip for missing strace"; exit 0; }
+
+RULESET="$(
+ echo "*filter"
+ for ((i = 0; i < 100; i++)); do
+ echo "-A FORWARD -m conntrack --ctstate NEW"
+ done
+ echo "COMMIT"
+)"
+
+cmd="$XT_MULTI iptables-restore"
+socketcount=$(strace -esocket $cmd <<< "$RULESET" 2>&1 | wc -l)
+
+# unpatched iptables-restore would open 111 sockets,
+# patched only 12 but keep a certain margin for future changes
+[[ $socketcount -lt 20 ]]
--
2.40.0

@ -0,0 +1,176 @@
From 8a10ad0e149cf1c6d0c34bd554a8e0a35cdf3e8d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 2 Dec 2020 13:37:06 +0100
Subject: [PATCH] extensions: dccp: Fix for DCCP type 'INVALID'
Support for matching on invalid DCCP type field values was pretty
broken: While RFC4340 declares any type value from 10 to 15 invalid, the
extension's type name 'INVALID' mapped to type value 10 only. Fix this
by introduction of INVALID_OTHER_TYPE_MASK which has the remaining
invalid type's bits set and apply it if bit 10 is set after parsing the
type list. When printing, stop searching type names after printing
'INVALID' - unless numeric output was requested. The latter prints all
actual type values. Since parsing types in numeric form is not
supported, changing the output should not break existing scripts.
When translating into nftables syntax, the code returned prematurely if
'INVALID' was among the list of types - thereby emitting invalid syntax.
Instead print a real match for invalid types by use of a range
expression.
While being at it, fix syntax of translator output: If only
'--dccp-types' was translated, the output contained an extra 'dccp'. On
the other hand, if '--sport' and '--dport' was present, a required
'dccp' between the translations of both was missing.
Fixes: e40b11d7ef827 ("add support for new 'dccp' protocol match")
Fixes: c94a998724143 ("extensions: libxt_dccp: Add translation to nft")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 4bcbc8e11a2764f4537dc405962f83cd072cccfe)
---
extensions/libxt_dccp.c | 58 ++++++++++++++++++++++--------------
extensions/libxt_dccp.txlate | 12 ++++++--
2 files changed, 45 insertions(+), 25 deletions(-)
diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c
index 5e67c264db2a9..aea3e20be4818 100644
--- a/extensions/libxt_dccp.c
+++ b/extensions/libxt_dccp.c
@@ -76,6 +76,9 @@ static const char *const dccp_pkt_types[] = {
[DCCP_PKT_INVALID] = "INVALID",
};
+/* Bits for type values 11-15 */
+#define INVALID_OTHER_TYPE_MASK 0xf800
+
static uint16_t
parse_dccp_types(const char *typestring)
{
@@ -95,6 +98,9 @@ parse_dccp_types(const char *typestring)
xtables_error(PARAMETER_PROBLEM,
"Unknown DCCP type `%s'", ptr);
}
+ if (typemask & (1 << DCCP_PKT_INVALID))
+ typemask |= INVALID_OTHER_TYPE_MASK;
+
free(buffer);
return typemask;
@@ -193,9 +199,13 @@ print_types(uint16_t types, int inverted, int numeric)
if (numeric)
printf("%u", i);
- else
+ else {
printf("%s", dccp_pkt_types[i]);
+ if (i == DCCP_PKT_INVALID)
+ break;
+ }
+
types &= ~(1 << i);
}
}
@@ -288,6 +298,7 @@ static const char *const dccp_pkt_types_xlate[] = {
[DCCP_PKT_RESET] = "reset",
[DCCP_PKT_SYNC] = "sync",
[DCCP_PKT_SYNCACK] = "syncack",
+ [DCCP_PKT_INVALID] = "10-15",
};
static int dccp_type_xlate(const struct xt_dccp_info *einfo,
@@ -296,10 +307,10 @@ static int dccp_type_xlate(const struct xt_dccp_info *einfo,
bool have_type = false, set_need = false;
uint16_t types = einfo->typemask;
- if (types & (1 << DCCP_PKT_INVALID))
- return 0;
-
- xt_xlate_add(xl, " dccp type%s ", einfo->invflags ? " !=" : "");
+ if (types & INVALID_OTHER_TYPE_MASK) {
+ types &= ~INVALID_OTHER_TYPE_MASK;
+ types |= 1 << DCCP_PKT_INVALID;
+ }
if ((types != 0) && !(types == (types & -types))) {
xt_xlate_add(xl, "{");
@@ -335,34 +346,37 @@ static int dccp_xlate(struct xt_xlate *xl,
char *space = "";
int ret = 1;
- xt_xlate_add(xl, "dccp ");
-
if (einfo->flags & XT_DCCP_SRC_PORTS) {
+ xt_xlate_add(xl, "dccp sport%s %u",
+ einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
+ einfo->spts[0]);
+
if (einfo->spts[0] != einfo->spts[1])
- xt_xlate_add(xl, "sport%s %u-%u",
- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
- einfo->spts[0], einfo->spts[1]);
- else
- xt_xlate_add(xl, "sport%s %u",
- einfo->invflags & XT_DCCP_SRC_PORTS ? " !=" : "",
- einfo->spts[0]);
+ xt_xlate_add(xl, "-%u", einfo->spts[1]);
+
space = " ";
}
if (einfo->flags & XT_DCCP_DEST_PORTS) {
+ xt_xlate_add(xl, "%sdccp dport%s %u", space,
+ einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
+ einfo->dpts[0]);
+
if (einfo->dpts[0] != einfo->dpts[1])
- xt_xlate_add(xl, "%sdport%s %u-%u", space,
- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
- einfo->dpts[0], einfo->dpts[1]);
- else
- xt_xlate_add(xl, "%sdport%s %u", space,
- einfo->invflags & XT_DCCP_DEST_PORTS ? " !=" : "",
- einfo->dpts[0]);
+ xt_xlate_add(xl, "-%u", einfo->dpts[1]);
+
+ space = " ";
}
- if (einfo->flags & XT_DCCP_TYPE)
+ if (einfo->flags & XT_DCCP_TYPE && einfo->typemask) {
+ xt_xlate_add(xl, "%sdccp type%s ", space,
+ einfo->invflags & XT_DCCP_TYPE ? " !=" : "");
ret = dccp_type_xlate(einfo, xl);
+ space = " ";
+ }
+
+ /* FIXME: no dccp option support in nftables yet */
if (einfo->flags & XT_DCCP_OPTION)
ret = 0;
diff --git a/extensions/libxt_dccp.txlate b/extensions/libxt_dccp.txlate
index b47dc65f5bc4f..ea853f6acf627 100644
--- a/extensions/libxt_dccp.txlate
+++ b/extensions/libxt_dccp.txlate
@@ -7,8 +7,14 @@ nft add rule ip filter INPUT dccp dport 100-200 counter
iptables-translate -A INPUT -p dccp -m dccp ! --dport 100
nft add rule ip filter INPUT dccp dport != 100 counter
-iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK
-nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack} counter
+iptables-translate -A INPUT -p dccp -m dccp --dccp-types CLOSE
+nft add rule ip filter INPUT dccp type close counter
+
+iptables-translate -A INPUT -p dccp -m dccp --dccp-types INVALID
+nft add rule ip filter INPUT dccp type 10-15 counter
+
+iptables-translate -A INPUT -p dccp -m dccp --dport 100 --dccp-types REQUEST,RESPONSE,DATA,ACK,DATAACK,CLOSEREQ,CLOSE,SYNC,SYNCACK,INVALID
+nft add rule ip filter INPUT dccp dport 100 dccp type {request, response, data, ack, dataack, closereq, close, sync, syncack, 10-15} counter
iptables-translate -A INPUT -p dccp -m dccp --sport 200 --dport 100
-nft add rule ip filter INPUT dccp sport 200 dport 100 counter
+nft add rule ip filter INPUT dccp sport 200 dccp dport 100 counter
--
2.40.0

@ -0,0 +1,85 @@
From 524f17b1027cb3b6bd5484c644d4dc226d137d91 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Sat, 12 Dec 2020 16:15:32 +0100
Subject: [PATCH] xtables-monitor: fix rule printing
trace_print_rule does a rule dump. This prints unrelated rules
in the same chain. Instead the function should only request the
specific handle.
Furthermore, flush output buffer afterwards so this plays nice when
output isn't a terminal.
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 07af4da52ab3002c9cb510863b4eb7aaca4fb43b)
---
iptables/xtables-monitor.c | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 4008cc00d4694..364e600e1b38a 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -227,12 +227,12 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
exit(EXIT_FAILURE);
}
- nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, NLM_F_DUMP, 0);
+ nlh = nftnl_chain_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, 0, 0);
nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, chain);
nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table);
- nftnl_rule_set_u64(r, NFTNL_RULE_POSITION, handle);
+ nftnl_rule_set_u64(r, NFTNL_RULE_HANDLE, handle);
nftnl_rule_nlmsg_build_payload(nlh, r);
nftnl_rule_free(r);
@@ -248,24 +248,21 @@ static void trace_print_rule(const struct nftnl_trace *nlt, struct cb_arg *args)
}
portid = mnl_socket_get_portid(nl);
- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
- perror("mnl_socket_send");
- exit(EXIT_FAILURE);
- }
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
+ perror("mnl_socket_send");
+ exit(EXIT_FAILURE);
+ }
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- while (ret > 0) {
+ if (ret > 0) {
args->is_event = false;
- ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
- if (ret <= 0)
- break;
- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- }
- if (ret == -1) {
- perror("error");
- exit(EXIT_FAILURE);
- }
- mnl_socket_close(nl);
+ ret = mnl_cb_run(buf, ret, 0, portid, rule_cb, args);
+ }
+ if (ret == -1) {
+ perror("error");
+ exit(EXIT_FAILURE);
+ }
+ mnl_socket_close(nl);
}
static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *args)
@@ -531,6 +528,7 @@ static int trace_cb(const struct nlmsghdr *nlh, struct cb_arg *arg)
err_free:
nftnl_trace_free(nlt);
err:
+ fflush(stdout);
return MNL_CB_OK;
}
--
2.40.0

@ -0,0 +1,38 @@
From 7de2651bdbbabfc08ef040d2cb9867c8375e3984 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Sat, 12 Dec 2020 16:15:33 +0100
Subject: [PATCH] xtables-monitor: fix packet family protocol
This prints the family passed on the command line (which might be 0).
Print the table family instead.
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 946923b640afc2249cf98743ff60a97291108701)
---
iptables/xtables-monitor.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 364e600e1b38a..8850a12032d26 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -273,14 +273,14 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
uint32_t mark;
char name[IFNAMSIZ];
- printf("PACKET: %d %08x ", args->nfproto, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
+ family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
+ printf("PACKET: %d %08x ", family, nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID));
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_IIF))
printf("IN=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_IIF), name));
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_OIF))
printf("OUT=%s ", if_indextoname(nftnl_trace_get_u32(nlt, NFTNL_TRACE_OIF), name));
- family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
nfproto = family;
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) {
nfproto = nftnl_trace_get_u32(nlt, NFTNL_TRACE_NFPROTO);
--
2.40.0

@ -0,0 +1,101 @@
From 46fffddb8ae11d3e46f55ca0bb356a2549671652 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Sat, 12 Dec 2020 16:15:34 +0100
Subject: [PATCH] xtables-monitor: print packet first
The trace mode should first print the packet that was received and
then the rule/verdict.
Furthermore, the monitor did sometimes print an extra newline.
After this patch, output is more consistent with nft monitor.
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 180ba723d0b305fab9287d3bc5f845a43d9eb793)
---
iptables/xtables-monitor.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 8850a12032d26..e6b6e76b9fdc9 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -106,6 +106,7 @@ static int rule_cb(const struct nlmsghdr *nlh, void *data)
printf("-0 ");
break;
default:
+ puts("");
goto err_free;
}
@@ -433,9 +434,18 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
mark = nftnl_trace_get_u32(nlt, NFTNL_TRACE_MARK);
if (mark)
printf("MARK=0x%x ", mark);
+ puts("");
+}
+
+static void trace_print_hdr(const struct nftnl_trace *nlt)
+{
+ printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
+ nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
+ nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
}
-static void print_verdict(struct nftnl_trace *nlt, uint32_t verdict)
+static void print_verdict(const struct nftnl_trace *nlt, uint32_t verdict)
{
const char *chain;
@@ -496,35 +506,37 @@ static int trace_cb(const struct nlmsghdr *nlh, struct cb_arg *arg)
arg->nfproto != nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY))
goto err_free;
- printf(" TRACE: %d %08x %s:%s", nftnl_trace_get_u32(nlt, NFTNL_TABLE_FAMILY),
- nftnl_trace_get_u32(nlt, NFTNL_TRACE_ID),
- nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE),
- nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN));
-
switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
case NFT_TRACETYPE_RULE:
verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_VERDICT);
- printf(":rule:0x%llx:", (unsigned long long)nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
- print_verdict(nlt, verdict);
- if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE))
- trace_print_rule(nlt, arg);
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
trace_print_packet(nlt, arg);
+
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE)) {
+ trace_print_hdr(nlt);
+ printf(":rule:0x%" PRIx64":", nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE));
+ print_verdict(nlt, verdict);
+ printf(" ");
+ trace_print_rule(nlt, arg);
+ }
break;
case NFT_TRACETYPE_POLICY:
+ trace_print_hdr(nlt);
printf(":policy:");
verdict = nftnl_trace_get_u32(nlt, NFTNL_TRACE_POLICY);
print_verdict(nlt, verdict);
+ puts("");
break;
case NFT_TRACETYPE_RETURN:
+ trace_print_hdr(nlt);
printf(":return:");
trace_print_return(nlt);
+ puts("");
break;
}
- puts("");
err_free:
nftnl_trace_free(nlt);
err:
--
2.40.0

@ -0,0 +1,30 @@
From bc9b418dc22fb7d81bfded431c74ea84f62340bd Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Mon, 14 Dec 2020 17:11:23 +0100
Subject: [PATCH] xtables-monitor:
'LL=0x304' is not very convenient, print LOOPBACK instead.
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 98ed6f6fc6d97663a33de67afff60196052880b1)
---
iptables/xtables-monitor.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index e6b6e76b9fdc9..4b9809805fb5b 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -306,6 +306,9 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
printf("MACDST=%s ", ether_ntoa((const void *)eh->h_dest));
printf("MACPROTO=%04x ", ntohs(eh->h_proto));
break;
+ case ARPHRD_LOOPBACK:
+ printf("LOOPBACK ");
+ break;
default:
printf("LL=0x%x ", type);
for (i = 0 ; i < len; i++)
--
2.40.0

@ -0,0 +1,41 @@
From 06bf588263f81b0d254d49b584b26445a788638d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 23 Sep 2020 19:13:45 +0200
Subject: [PATCH] nft: Fix selective chain compatibility checks
Since commit 80251bc2a56ed ("nft: remove cache build calls"), 'chain'
parameter passed to nft_chain_list_get() is no longer effective.
Before, it was used to fetch only that single chain from kernel when
populating the cache. So the returned list of chains for which
compatibility checks are done would contain only that single chain.
Re-establish the single chain compat checking by introducing a dedicated
code path to nft_is_chain_compatible() doing so.
Fixes: 80251bc2a56ed ("nft: remove cache build calls")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 694612adf87fb614f16a2b678f32745d5c9d7876)
---
iptables/nft.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/iptables/nft.c b/iptables/nft.c
index bdf252198f155..7f87d46dcc44c 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -3575,6 +3575,12 @@ bool nft_is_table_compatible(struct nft_handle *h,
{
struct nftnl_chain_list *clist;
+ if (chain) {
+ struct nftnl_chain *c = nft_chain_find(h, table, chain);
+
+ return c && !nft_is_chain_compatible(c, h);
+ }
+
clist = nft_chain_list_get(h, table, chain);
if (clist == NULL)
return false;
--
2.40.0

@ -0,0 +1,104 @@
From 4f52c310cf3854a64ef9a518c223e0581ec9a308 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Wed, 24 Feb 2021 11:08:02 +0100
Subject: [PATCH] iptables-nft: fix -Z option
it zeroes the rule counters, so it needs fully populated cache.
Add a test case to cover this.
Fixes: 9d07514ac5c7a ("nft: calculate cache requirements from list of commands")
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 5f1fcacebf9b4529950b6e3f88327049a0ea7cd2)
---
iptables/nft-cmd.c | 2 +-
.../testcases/iptables/0007-zero-counters_0 | 64 +++++++++++++++++++
2 files changed, 65 insertions(+), 1 deletion(-)
create mode 100755 iptables/tests/shell/testcases/iptables/0007-zero-counters_0
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
index 9c0901e78703a..ed53c061edc6f 100644
--- a/iptables/nft-cmd.c
+++ b/iptables/nft-cmd.c
@@ -185,7 +185,7 @@ int nft_cmd_chain_zero_counters(struct nft_handle *h, const char *chain,
if (!cmd)
return 0;
- nft_cache_level_set(h, NFT_CL_CHAINS, cmd);
+ nft_cache_level_set(h, NFT_CL_RULES, cmd);
return 1;
}
diff --git a/iptables/tests/shell/testcases/iptables/0007-zero-counters_0 b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0
new file mode 100755
index 0000000000000..36da1907e3b22
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0007-zero-counters_0
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+RC=0
+COUNTR=$RANDOM$RANDOM
+
+$XT_MULTI iptables-restore -c <<EOF
+*filter
+:INPUT ACCEPT [1:23]
+:FOO - [0:0]
+[12:345] -A INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+[22:123] -A FOO -m comment --comment one
+[44:123] -A FOO -m comment --comment two
+COMMIT
+EOF
+EXPECT="*filter
+:INPUT ACCEPT [0:0]
+:FORWARD ACCEPT [0:0]
+:OUTPUT ACCEPT [0:0]
+:FOO - [0:0]
+[0:0] -A INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+[0:0] -A FOO -m comment --comment one
+[0:0] -A FOO -m comment --comment two
+COMMIT"
+
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+if [ $COUNTER != "[12:345]" ]; then
+ echo "Counter $COUNTER is wrong, expected 12:345"
+ RC=1
+fi
+
+$XT_MULTI iptables -Z FOO
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+if [ $COUNTER = "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should not have been zeroed"
+ RC=1
+fi
+
+for c in one two; do
+ COUNTER=$($XT_MULTI iptables-save -c |grep "comment $c"| cut -f 1 -d " ")
+ if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, should have been zeroed at rule $c"
+ RC=1
+ fi
+done
+
+$XT_MULTI iptables -Z
+COUNTER=$($XT_MULTI iptables-save -c |grep "comment $COUNTR"| cut -f 1 -d " ")
+
+if [ $COUNTER != "[0:0]" ]; then
+ echo "Counter $COUNTER is wrong, expected 0:0 after -Z"
+ RC=1
+fi
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI iptables-save -c | grep -v '^#')
+if [ $? -ne 0 ]; then
+ echo "Diff error: counters were not zeroed"
+ RC=1
+fi
+
+$XT_MULTI iptables -D INPUT -i lo -p icmp -m comment --comment "$COUNTR"
+$XT_MULTI iptables -D FOO -m comment --comment one
+$XT_MULTI iptables -D FOO -m comment --comment two
+$XT_MULTI iptables -X FOO
+exit $RC
--
2.40.0

@ -0,0 +1,73 @@
From 7b60fadf23fd4b712dd7522c06b6e7b4f3190fc6 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 19 Feb 2021 16:54:57 +0100
Subject: [PATCH] nft: Fix bitwise expression avoidance detection
Byte-boundary prefix detection was too sloppy: Any data following the
first zero-byte was ignored. Add a follow-up loop making sure there are
no stray bits in the designated host part.
Fixes: 323259001d617 ("nft: Optimize class-based IP prefix matches")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 330f5df03ad589b46865ceedf2a54cf10a4225ba)
---
iptables/nft-shared.c | 4 +++-
.../testcases/ip6tables/0004-address-masks_0 | 24 +++++++++++++++++++
2 files changed, 27 insertions(+), 1 deletion(-)
create mode 100755 iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 10553ab26823b..c1664b50f9383 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -166,7 +166,7 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
{
const unsigned char *m = mask;
bool bitwise = false;
- int i;
+ int i, j;
for (i = 0; i < len; i++) {
if (m[i] != 0xff) {
@@ -174,6 +174,8 @@ void add_addr(struct nftnl_rule *r, enum nft_payload_bases base, int offset,
break;
}
}
+ for (j = i + 1; !bitwise && j < len; j++)
+ bitwise = !!m[j];
if (!bitwise)
len = i;
diff --git a/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0 b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
new file mode 100755
index 0000000000000..7eb42f08da975
--- /dev/null
+++ b/iptables/tests/shell/testcases/ip6tables/0004-address-masks_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+$XT_MULTI ip6tables-restore <<EOF
+*filter
+-A FORWARD -s feed:babe::/ffff::0
+-A FORWARD -s feed:babe::/ffff:ff00::0
+-A FORWARD -s feed:babe::/ffff:fff0::0
+-A FORWARD -s feed:babe::/ffff:ffff::0
+-A FORWARD -s feed:babe::/0:ffff::0
+-A FORWARD -s feed:c0ff::babe:f00/ffff::ffff:0
+COMMIT
+EOF
+
+EXPECT='-P FORWARD ACCEPT
+-A FORWARD -s feed::/16
+-A FORWARD -s feed:ba00::/24
+-A FORWARD -s feed:bab0::/28
+-A FORWARD -s feed:babe::/32
+-A FORWARD -s 0:babe::/0:ffff::
+-A FORWARD -s feed::babe:0/ffff::ffff:0'
+
+diff -u -Z <(echo -e "$EXPECT") <($XT_MULTI ip6tables -S FORWARD)
--
2.40.0

@ -0,0 +1,196 @@
From 810da6ff3a0a0b9bdb608edc0b68fc5cedac97e0 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 2 Mar 2021 14:50:07 +0100
Subject: [PATCH] xtables-translate: Fix translation of odd netmasks
Iptables supports netmasks which are not prefixes to match on (or
ignore) arbitrary bits in an address. Yet nftables' prefix notation is
available for real prefixes only, so translation is not as trivial -
print bitmask syntax for those cases.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 46f9d3a9a61ee80fa94b7fa7b3b36045c92606ae)
---
extensions/generic.txlate | 48 +++++++++++++++++++++++++++++++++++++
extensions/libxt_standard.t | 12 ++++++++++
iptables/nft-ipv4.c | 42 ++++++++++++++++++++++----------
iptables/nft-ipv6.c | 19 ++++++++++++---
4 files changed, 106 insertions(+), 15 deletions(-)
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
index 0e256c3727559..9ae9a5b54c1b9 100644
--- a/extensions/generic.txlate
+++ b/extensions/generic.txlate
@@ -10,6 +10,54 @@ nft insert rule ip filter INPUT iifname "iifname" ip saddr 10.0.0.0/8 counter
iptables-translate -A INPUT -i iif+ ! -d 10.0.0.0/8
nft add rule ip filter INPUT iifname "iif*" ip daddr != 10.0.0.0/8 counter
+iptables-translate -I INPUT -s 10.11.12.13/255.255.0.0
+nft insert rule ip filter INPUT ip saddr 10.11.0.0/16 counter
+
+iptables-translate -I INPUT -s 10.11.12.13/255.0.255.0
+nft insert rule ip filter INPUT ip saddr & 255.0.255.0 == 10.0.12.0 counter
+
+iptables-translate -I INPUT -s 10.11.12.13/0.255.0.255
+nft insert rule ip filter INPUT ip saddr & 0.255.0.255 == 0.11.0.13 counter
+
+iptables-translate -I INPUT ! -s 10.11.12.13/0.255.0.255
+nft insert rule ip filter INPUT ip saddr & 0.255.0.255 != 0.11.0.13 counter
+
+iptables-translate -I INPUT -s 0.0.0.0/16
+nft insert rule ip filter INPUT ip saddr 0.0.0.0/16 counter
+
+iptables-translate -I INPUT -s 0.0.0.0/0
+nft insert rule ip filter INPUT counter
+
+iptables-translate -I INPUT ! -s 0.0.0.0/0
+nft insert rule ip filter INPUT ip saddr != 0.0.0.0/0 counter
+
+ip6tables-translate -I INPUT -i iifname -s feed::/16
+nft insert rule ip6 filter INPUT iifname "iifname" ip6 saddr feed::/16 counter
+
+ip6tables-translate -A INPUT -i iif+ ! -d feed::/16
+nft add rule ip6 filter INPUT iifname "iif*" ip6 daddr != feed::/16 counter
+
+ip6tables-translate -I INPUT -s feed:babe::1/ffff:ff00::
+nft insert rule ip6 filter INPUT ip6 saddr feed:ba00::/24 counter
+
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/ffff:0:ffff:0:ffff:0:ffff:0
+nft insert rule ip6 filter INPUT ip6 saddr & ffff:0:ffff:0:ffff:0:ffff:0 == feed:0:c0ff:0:c0be:0:5678:0 counter
+
+ip6tables-translate -I INPUT -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
+nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff == 0:babe:0:ee00:0:1234:0:90ab counter
+
+ip6tables-translate -I INPUT ! -s feed:babe:c0ff:ee00:c0be:1234:5678:90ab/0:ffff:0:ffff:0:ffff:0:ffff
+nft insert rule ip6 filter INPUT ip6 saddr & 0:ffff:0:ffff:0:ffff:0:ffff != 0:babe:0:ee00:0:1234:0:90ab counter
+
+ip6tables-translate -I INPUT -s ::/16
+nft insert rule ip6 filter INPUT ip6 saddr ::/16 counter
+
+ip6tables-translate -I INPUT -s ::/0
+nft insert rule ip6 filter INPUT counter
+
+ip6tables-translate -I INPUT ! -s ::/0
+nft insert rule ip6 filter INPUT ip6 saddr != ::/0 counter
+
ebtables-translate -I INPUT -i iname --logical-in ilogname -s 0:0:0:0:0:0
nft insert rule bridge filter INPUT iifname "iname" meta ibrname "ilogname" ether saddr 00:00:00:00:00:00 counter
diff --git a/extensions/libxt_standard.t b/extensions/libxt_standard.t
index 4313f7b7bac9d..56d6da2e5884e 100644
--- a/extensions/libxt_standard.t
+++ b/extensions/libxt_standard.t
@@ -9,3 +9,15 @@
-j ACCEPT;=;OK
-j RETURN;=;OK
! -p 0 -j ACCEPT;=;FAIL
+-s 10.11.12.13/8;-s 10.0.0.0/8;OK
+-s 10.11.12.13/9;-s 10.0.0.0/9;OK
+-s 10.11.12.13/10;-s 10.0.0.0/10;OK
+-s 10.11.12.13/11;-s 10.0.0.0/11;OK
+-s 10.11.12.13/12;-s 10.0.0.0/12;OK
+-s 10.11.12.13/30;-s 10.11.12.12/30;OK
+-s 10.11.12.13/31;-s 10.11.12.12/31;OK
+-s 10.11.12.13/32;-s 10.11.12.13/32;OK
+-s 10.11.12.13/255.0.0.0;-s 10.0.0.0/8;OK
+-s 10.11.12.13/255.128.0.0;-s 10.0.0.0/9;OK
+-s 10.11.12.13/255.0.255.0;-s 10.0.12.0/255.0.255.0;OK
+-s 10.11.12.13/255.0.12.0;-s 10.0.12.0/255.0.12.0;OK
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index fdc15c6f04066..0d32a30010519 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -383,6 +383,32 @@ static void nft_ipv4_post_parse(int command,
" source or destination IP addresses");
}
+static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr,
+ const struct in_addr *mask,
+ bool inv, struct xt_xlate *xl)
+{
+ const char *op = inv ? "!= " : "";
+ int cidr;
+
+ if (!inv && !addr->s_addr && !mask->s_addr)
+ return;
+
+ cidr = xtables_ipmask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ /* inet_ntoa() is not reentrant */
+ xt_xlate_add(xl, "%s & %s ", selector, inet_ntoa(*mask));
+ xt_xlate_add(xl, "%s %s ", inv ? "!=" : "==", inet_ntoa(*addr));
+ break;
+ case 32:
+ xt_xlate_add(xl, "%s %s%s ", selector, op, inet_ntoa(*addr));
+ break;
+ default:
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, inet_ntoa(*addr),
+ cidr);
+ }
+}
+
static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
{
const struct iptables_command_state *cs = data;
@@ -417,18 +443,10 @@ static int nft_ipv4_xlate(const void *data, struct xt_xlate *xl)
}
}
- if (cs->fw.ip.src.s_addr != 0) {
- xt_xlate_add(xl, "ip saddr %s%s%s ",
- cs->fw.ip.invflags & IPT_INV_SRCIP ? "!= " : "",
- inet_ntoa(cs->fw.ip.src),
- xtables_ipmask_to_numeric(&cs->fw.ip.smsk));
- }
- if (cs->fw.ip.dst.s_addr != 0) {
- xt_xlate_add(xl, "ip daddr %s%s%s ",
- cs->fw.ip.invflags & IPT_INV_DSTIP ? "!= " : "",
- inet_ntoa(cs->fw.ip.dst),
- xtables_ipmask_to_numeric(&cs->fw.ip.dmsk));
- }
+ xlate_ipv4_addr("ip saddr", &cs->fw.ip.src, &cs->fw.ip.smsk,
+ cs->fw.ip.invflags & IPT_INV_SRCIP, xl);
+ xlate_ipv4_addr("ip daddr", &cs->fw.ip.dst, &cs->fw.ip.dmsk,
+ cs->fw.ip.invflags & IPT_INV_DSTIP, xl);
ret = xlate_matches(cs, xl);
if (!ret)
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 130ad3e6e7c44..46008fc5e762a 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -337,14 +337,27 @@ static void xlate_ipv6_addr(const char *selector, const struct in6_addr *addr,
const struct in6_addr *mask,
int invert, struct xt_xlate *xl)
{
+ const char *op = invert ? "!= " : "";
char addr_str[INET6_ADDRSTRLEN];
+ int cidr;
- if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr))
+ if (!invert && IN6_IS_ADDR_UNSPECIFIED(addr) && IN6_IS_ADDR_UNSPECIFIED(mask))
return;
inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
- xt_xlate_add(xl, "%s %s%s%s ", selector, invert ? "!= " : "", addr_str,
- xtables_ip6mask_to_numeric(mask));
+ cidr = xtables_ip6mask_to_cidr(mask);
+ switch (cidr) {
+ case -1:
+ xt_xlate_add(xl, "%s & %s %s %s ", selector,
+ xtables_ip6addr_to_numeric(mask),
+ invert ? "!=" : "==", addr_str);
+ break;
+ case 128:
+ xt_xlate_add(xl, "%s %s%s ", selector, op, addr_str);
+ break;
+ default:
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, addr_str, cidr);
+ }
}
static int nft_ipv6_xlate(const void *data, struct xt_xlate *xl)
--
2.40.0

@ -0,0 +1,129 @@
From db7d25c14b8db7f7ea514e1f81acb82fafb3c9d7 Mon Sep 17 00:00:00 2001
From: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Date: Thu, 1 Apr 2021 16:47:07 +0300
Subject: [PATCH] extensions: libxt_conntrack: use bitops for state negation
Currently, state_xlate_print function prints statemask as comma-separated sequence of enabled
statemask flags. But if we have inverted conntrack ctstate condition then we have to use more
complex expression because nft not supports syntax like "ct state != related,established".
Reproducer:
$ iptables -A INPUT -d 127.0.0.1/32 -p tcp -m conntrack ! --ctstate RELATED,ESTABLISHED -j DROP
$ nft list ruleset
...
meta l4proto tcp ip daddr 127.0.0.1 ct state != related,established counter packets 0 bytes 0 drop
...
it will fail if we try to load this rule:
$ nft -f nft_test
../nft_test:6:97-97: Error: syntax error, unexpected comma, expecting newline or semicolon
Cc: Florian Westphal <fw@strlen.de>
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 18e334da7363ba186edb1700056e26ded27ca5ba)
---
extensions/libxt_conntrack.c | 38 ++++++++++++++++++++-----------
extensions/libxt_conntrack.txlate | 5 +++-
2 files changed, 29 insertions(+), 14 deletions(-)
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 7734509c9af84..91f9e4aa994f8 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1148,30 +1148,43 @@ static void state_save(const void *ip, const struct xt_entry_match *match)
state_print_state(sinfo->statemask);
}
-static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask)
+static void state_xlate_print(struct xt_xlate *xl, unsigned int statemask, int inverted)
{
const char *sep = "";
+ int one_flag_set;
+
+ one_flag_set = !(statemask & (statemask - 1));
+
+ if (inverted && !one_flag_set)
+ xt_xlate_add(xl, "& (");
+ else if (inverted)
+ xt_xlate_add(xl, "& ");
if (statemask & XT_CONNTRACK_STATE_INVALID) {
xt_xlate_add(xl, "%s%s", sep, "invalid");
- sep = ",";
+ sep = inverted && !one_flag_set ? "|" : ",";
}
if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) {
xt_xlate_add(xl, "%s%s", sep, "new");
- sep = ",";
+ sep = inverted && !one_flag_set ? "|" : ",";
}
if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) {
xt_xlate_add(xl, "%s%s", sep, "related");
- sep = ",";
+ sep = inverted && !one_flag_set ? "|" : ",";
}
if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) {
xt_xlate_add(xl, "%s%s", sep, "established");
- sep = ",";
+ sep = inverted && !one_flag_set ? "|" : ",";
}
if (statemask & XT_CONNTRACK_STATE_UNTRACKED) {
xt_xlate_add(xl, "%s%s", sep, "untracked");
- sep = ",";
+ sep = inverted && !one_flag_set ? "|" : ",";
}
+
+ if (inverted && !one_flag_set)
+ xt_xlate_add(xl, ") == 0");
+ else if (inverted)
+ xt_xlate_add(xl, " == 0");
}
static int state_xlate(struct xt_xlate *xl,
@@ -1180,9 +1193,9 @@ static int state_xlate(struct xt_xlate *xl,
const struct xt_conntrack_mtinfo3 *sinfo =
(const void *)params->match->data;
- xt_xlate_add(xl, "ct state %s", sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
+ xt_xlate_add(xl, "ct state ");
+ state_xlate_print(xl, sinfo->state_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATE);
xt_xlate_add(xl, " ");
return 1;
}
@@ -1256,10 +1269,9 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
sinfo->state_mask & XT_CONNTRACK_STATE_SNAT ? "snat" : "dnat");
space = " ";
} else {
- xt_xlate_add(xl, "%sct state %s", space,
- sinfo->invert_flags & XT_CONNTRACK_STATE ?
- "!= " : "");
- state_xlate_print(xl, sinfo->state_mask);
+ xt_xlate_add(xl, "%sct state ", space);
+ state_xlate_print(xl, sinfo->state_mask,
+ sinfo->invert_flags & XT_CONNTRACK_STATE);
space = " ";
}
}
diff --git a/extensions/libxt_conntrack.txlate b/extensions/libxt_conntrack.txlate
index d374f8a035f00..5ab85b177c396 100644
--- a/extensions/libxt_conntrack.txlate
+++ b/extensions/libxt_conntrack.txlate
@@ -2,7 +2,10 @@ iptables-translate -t filter -A INPUT -m conntrack --ctstate NEW,RELATED -j ACCE
nft add rule ip filter INPUT ct state new,related counter accept
ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW,RELATED -j ACCEPT
-nft add rule ip6 filter INPUT ct state != new,related counter accept
+nft add rule ip6 filter INPUT ct state & (new|related) == 0 counter accept
+
+ip6tables-translate -t filter -A INPUT -m conntrack ! --ctstate NEW -j ACCEPT
+nft add rule ip6 filter INPUT ct state & new == 0 counter accept
iptables-translate -t filter -A INPUT -m conntrack --ctproto UDP -j ACCEPT
nft add rule ip filter INPUT ct original protocol 17 counter accept
--
2.40.0

@ -0,0 +1,120 @@
From ca4b90e5fc460fe522ceff2206ae5d32d32d2b40 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 27 Apr 2021 09:12:53 +0200
Subject: [PATCH] Eliminate inet_aton() and inet_ntoa()
Both functions are obsolete, replace them by equivalent calls to
inet_pton() and inet_ntop().
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit acac2dbe64e5120394fa715bb5fe95c42d08b8b3)
---
extensions/libebt_among.c | 6 ++++--
iptables/nft-ipv4.c | 23 ++++++++++++++---------
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
index 2b9a1b6566684..7eb898f984bba 100644
--- a/extensions/libebt_among.c
+++ b/extensions/libebt_among.c
@@ -66,7 +66,7 @@ parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip)
if (sep) {
*sep = '\0';
- if (!inet_aton(sep + 1, &pair->in))
+ if (!inet_pton(AF_INET, sep + 1, &pair->in))
xtables_error(PARAMETER_PROBLEM,
"Invalid IP address '%s'\n", sep + 1);
}
@@ -194,6 +194,7 @@ static void __bramong_print(struct nft_among_pair *pairs,
int cnt, bool inv, bool have_ip)
{
const char *isep = inv ? "! " : "";
+ char abuf[INET_ADDRSTRLEN];
int i;
for (i = 0; i < cnt; i++) {
@@ -202,7 +203,8 @@ static void __bramong_print(struct nft_among_pair *pairs,
printf("%s", ether_ntoa(&pairs[i].ether));
if (pairs[i].in.s_addr != INADDR_ANY)
- printf("=%s", inet_ntoa(pairs[i].in));
+ printf("=%s", inet_ntop(AF_INET, &pairs[i].in,
+ abuf, sizeof(abuf)));
}
printf(" ");
}
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index 0d32a30010519..a5b835b1f681d 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -136,7 +136,7 @@ static void get_frag(struct nft_xt_ctx *ctx, struct nftnl_expr *e, bool *inv)
static const char *mask_to_str(uint32_t mask)
{
- static char mask_str[sizeof("255.255.255.255")];
+ static char mask_str[INET_ADDRSTRLEN];
uint32_t bits, hmask = ntohl(mask);
struct in_addr mask_addr = {
.s_addr = mask,
@@ -155,7 +155,7 @@ static const char *mask_to_str(uint32_t mask)
if (i >= 0)
sprintf(mask_str, "%u", i);
else
- sprintf(mask_str, "%s", inet_ntoa(mask_addr));
+ inet_ntop(AF_INET, &mask_addr, mask_str, sizeof(mask_str));
return mask_str;
}
@@ -298,10 +298,13 @@ static void nft_ipv4_print_rule(struct nft_handle *h, struct nftnl_rule *r,
static void save_ipv4_addr(char letter, const struct in_addr *addr,
uint32_t mask, int invert)
{
+ char addrbuf[INET_ADDRSTRLEN];
+
if (!mask && !invert && !addr->s_addr)
return;
- printf("%s-%c %s/%s ", invert ? "! " : "", letter, inet_ntoa(*addr),
+ printf("%s-%c %s/%s ", invert ? "! " : "", letter,
+ inet_ntop(AF_INET, addr, addrbuf, sizeof(addrbuf)),
mask_to_str(mask));
}
@@ -387,25 +390,27 @@ static void xlate_ipv4_addr(const char *selector, const struct in_addr *addr,
const struct in_addr *mask,
bool inv, struct xt_xlate *xl)
{
+ char mbuf[INET_ADDRSTRLEN], abuf[INET_ADDRSTRLEN];
const char *op = inv ? "!= " : "";
int cidr;
if (!inv && !addr->s_addr && !mask->s_addr)
return;
+ inet_ntop(AF_INET, addr, abuf, sizeof(abuf));
+
cidr = xtables_ipmask_to_cidr(mask);
switch (cidr) {
case -1:
- /* inet_ntoa() is not reentrant */
- xt_xlate_add(xl, "%s & %s ", selector, inet_ntoa(*mask));
- xt_xlate_add(xl, "%s %s ", inv ? "!=" : "==", inet_ntoa(*addr));
+ xt_xlate_add(xl, "%s & %s %s %s ", selector,
+ inet_ntop(AF_INET, mask, mbuf, sizeof(mbuf)),
+ inv ? "!=" : "==", abuf);
break;
case 32:
- xt_xlate_add(xl, "%s %s%s ", selector, op, inet_ntoa(*addr));
+ xt_xlate_add(xl, "%s %s%s ", selector, op, abuf);
break;
default:
- xt_xlate_add(xl, "%s %s%s/%d ", selector, op, inet_ntoa(*addr),
- cidr);
+ xt_xlate_add(xl, "%s %s%s/%d ", selector, op, abuf, cidr);
}
}
--
2.40.0

@ -0,0 +1,181 @@
From ab2ec9ca900843d6cb9fa839a9afe0ea968ce263 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 27 Apr 2021 10:02:34 +0200
Subject: [PATCH] nft-arp: Make use of ipv4_addr_to_string()
This eliminates quite a bit of redundant code apart from also dropping
use of obsolete function gethostbyaddr().
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 1e984079817a3c804eae25dea937d63d18c57a6c)
---
iptables/nft-arp.c | 99 ++++------------------------------------------
iptables/xshared.c | 6 +--
iptables/xshared.h | 3 ++
3 files changed, 14 insertions(+), 94 deletions(-)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index c82ffdc95e300..2a9387a18dffe 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -42,78 +42,6 @@ char *arp_opcodes[] =
"ARP_NAK",
};
-static char *
-addr_to_dotted(const struct in_addr *addrp)
-{
- static char buf[20];
- const unsigned char *bytep;
-
- bytep = (const unsigned char *) &(addrp->s_addr);
- sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
- return buf;
-}
-
-static char *
-addr_to_host(const struct in_addr *addr)
-{
- struct hostent *host;
-
- if ((host = gethostbyaddr((char *) addr,
- sizeof(struct in_addr), AF_INET)) != NULL)
- return (char *) host->h_name;
-
- return (char *) NULL;
-}
-
-static char *
-addr_to_network(const struct in_addr *addr)
-{
- struct netent *net;
-
- if ((net = getnetbyaddr((long) ntohl(addr->s_addr), AF_INET)) != NULL)
- return (char *) net->n_name;
-
- return (char *) NULL;
-}
-
-static char *
-addr_to_anyname(const struct in_addr *addr)
-{
- char *name;
-
- if ((name = addr_to_host(addr)) != NULL ||
- (name = addr_to_network(addr)) != NULL)
- return name;
-
- return addr_to_dotted(addr);
-}
-
-static char *
-mask_to_dotted(const struct in_addr *mask)
-{
- int i;
- static char buf[22];
- u_int32_t maskaddr, bits;
-
- maskaddr = ntohl(mask->s_addr);
-
- if (maskaddr == 0xFFFFFFFFL)
- /* we don't want to see "/32" */
- return "";
-
- i = 32;
- bits = 0xFFFFFFFEL;
- while (--i >= 0 && maskaddr != bits)
- bits <<= 1;
- if (i >= 0)
- sprintf(buf, "/%d", i);
- else
- /* mask was not a decent combination of 1's and 0's */
- snprintf(buf, sizeof(buf), "/%s", addr_to_dotted(mask));
-
- return buf;
-}
-
static bool need_devaddr(struct arpt_devaddr_info *info)
{
int i;
@@ -403,7 +331,6 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
unsigned int format)
{
const struct arpt_entry *fw = &cs->arp;
- char buf[BUFSIZ];
char iface[IFNAMSIZ+2];
const char *sep = "";
int print_iface = 0;
@@ -450,15 +377,10 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
}
if (fw->arp.smsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & IPT_INV_SRCIP
- ? "! " : "");
- if (format & FMT_NUMERIC)
- sprintf(buf, "%s", addr_to_dotted(&(fw->arp.src)));
- else
- sprintf(buf, "%s", addr_to_anyname(&(fw->arp.src)));
- strncat(buf, mask_to_dotted(&(fw->arp.smsk)),
- sizeof(buf) - strlen(buf) - 1);
- printf("-s %s", buf);
+ printf("%s%s-s %s", sep,
+ fw->arp.invflags & IPT_INV_SRCIP ? "! " : "",
+ ipv4_addr_to_string(&fw->arp.src,
+ &fw->arp.smsk, format));
sep = " ";
}
@@ -476,15 +398,10 @@ static void nft_arp_print_rule_details(const struct iptables_command_state *cs,
after_devsrc:
if (fw->arp.tmsk.s_addr != 0L) {
- printf("%s%s", sep, fw->arp.invflags & IPT_INV_DSTIP
- ? "! " : "");
- if (format & FMT_NUMERIC)
- sprintf(buf, "%s", addr_to_dotted(&(fw->arp.tgt)));
- else
- sprintf(buf, "%s", addr_to_anyname(&(fw->arp.tgt)));
- strncat(buf, mask_to_dotted(&(fw->arp.tmsk)),
- sizeof(buf) - strlen(buf) - 1);
- printf("-d %s", buf);
+ printf("%s%s-d %s", sep,
+ fw->arp.invflags & IPT_INV_DSTIP ? "! " : "",
+ ipv4_addr_to_string(&fw->arp.tgt,
+ &fw->arp.tmsk, format));
sep = " ";
}
diff --git a/iptables/xshared.c b/iptables/xshared.c
index fe37c30a085d6..3bcf24735c8fb 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -545,9 +545,9 @@ void debug_print_argv(struct argv_store *store)
}
#endif
-static const char *ipv4_addr_to_string(const struct in_addr *addr,
- const struct in_addr *mask,
- unsigned int format)
+const char *ipv4_addr_to_string(const struct in_addr *addr,
+ const struct in_addr *mask,
+ unsigned int format)
{
static char buf[BUFSIZ];
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 9159b2b1f3768..1e86aba8b2375 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -206,6 +206,9 @@ void debug_print_argv(struct argv_store *store);
# define debug_print_argv(...) /* nothing */
#endif
+const char *ipv4_addr_to_string(const struct in_addr *addr,
+ const struct in_addr *mask,
+ unsigned int format);
void print_ipv4_addresses(const struct ipt_entry *fw, unsigned int format);
void print_ipv6_addresses(const struct ip6t_entry *fw6, unsigned int format);
--
2.40.0

@ -0,0 +1,177 @@
From b16a9bc7fa224139763686d3ecc1741b891ac6ce Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 29 Apr 2021 15:28:59 +0200
Subject: [PATCH] extensions: SECMARK: Implement revision 1
The changed data structure for communication with kernel allows to
exclude the field 'secid' which is populated on kernel side. Thus
this fixes the formerly always failing extension comparison breaking
rule check and rule delete by content.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 616800af0da86d151cb695f1376d5ec6ede6fa72)
---
extensions/libxt_SECMARK.c | 90 +++++++++++++++++++++-------
extensions/libxt_SECMARK.t | 4 ++
include/linux/netfilter/xt_SECMARK.h | 6 ++
3 files changed, 80 insertions(+), 20 deletions(-)
create mode 100644 extensions/libxt_SECMARK.t
diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c
index 6ba8606355daa..24249bd618ffe 100644
--- a/extensions/libxt_SECMARK.c
+++ b/extensions/libxt_SECMARK.c
@@ -29,6 +29,13 @@ static const struct xt_option_entry SECMARK_opts[] = {
XTOPT_TABLEEND,
};
+static const struct xt_option_entry SECMARK_opts_v1[] = {
+ {.name = "selctx", .id = O_SELCTX, .type = XTTYPE_STRING,
+ .flags = XTOPT_MAND | XTOPT_PUT,
+ XTOPT_POINTER(struct xt_secmark_target_info_v1, secctx)},
+ XTOPT_TABLEEND,
+};
+
static void SECMARK_parse(struct xt_option_call *cb)
{
struct xt_secmark_target_info *info = cb->data;
@@ -37,15 +44,23 @@ static void SECMARK_parse(struct xt_option_call *cb)
info->mode = SECMARK_MODE_SEL;
}
-static void print_secmark(const struct xt_secmark_target_info *info)
+static void SECMARK_parse_v1(struct xt_option_call *cb)
+{
+ struct xt_secmark_target_info_v1 *info = cb->data;
+
+ xtables_option_parse(cb);
+ info->mode = SECMARK_MODE_SEL;
+}
+
+static void print_secmark(__u8 mode, const char *secctx)
{
- switch (info->mode) {
+ switch (mode) {
case SECMARK_MODE_SEL:
- printf("selctx %s", info->secctx);
+ printf("selctx %s", secctx);
break;
-
+
default:
- xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", info->mode);
+ xtables_error(OTHER_PROBLEM, PFX "invalid mode %hhu\n", mode);
}
}
@@ -56,7 +71,17 @@ static void SECMARK_print(const void *ip, const struct xt_entry_target *target,
(struct xt_secmark_target_info*)(target)->data;
printf(" SECMARK ");
- print_secmark(info);
+ print_secmark(info->mode, info->secctx);
+}
+
+static void SECMARK_print_v1(const void *ip,
+ const struct xt_entry_target *target, int numeric)
+{
+ const struct xt_secmark_target_info_v1 *info =
+ (struct xt_secmark_target_info_v1 *)(target)->data;
+
+ printf(" SECMARK ");
+ print_secmark(info->mode, info->secctx);
}
static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
@@ -65,24 +90,49 @@ static void SECMARK_save(const void *ip, const struct xt_entry_target *target)
(struct xt_secmark_target_info*)target->data;
printf(" --");
- print_secmark(info);
+ print_secmark(info->mode, info->secctx);
}
-static struct xtables_target secmark_target = {
- .family = NFPROTO_UNSPEC,
- .name = "SECMARK",
- .version = XTABLES_VERSION,
- .revision = 0,
- .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
- .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
- .help = SECMARK_help,
- .print = SECMARK_print,
- .save = SECMARK_save,
- .x6_parse = SECMARK_parse,
- .x6_options = SECMARK_opts,
+static void SECMARK_save_v1(const void *ip,
+ const struct xt_entry_target *target)
+{
+ const struct xt_secmark_target_info_v1 *info =
+ (struct xt_secmark_target_info_v1 *)target->data;
+
+ printf(" --");
+ print_secmark(info->mode, info->secctx);
+}
+
+static struct xtables_target secmark_tg_reg[] = {
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "SECMARK",
+ .version = XTABLES_VERSION,
+ .revision = 0,
+ .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)),
+ .help = SECMARK_help,
+ .print = SECMARK_print,
+ .save = SECMARK_save,
+ .x6_parse = SECMARK_parse,
+ .x6_options = SECMARK_opts,
+ },
+ {
+ .family = NFPROTO_UNSPEC,
+ .name = "SECMARK",
+ .version = XTABLES_VERSION,
+ .revision = 1,
+ .size = XT_ALIGN(sizeof(struct xt_secmark_target_info_v1)),
+ .userspacesize = XT_ALIGN(offsetof(struct xt_secmark_target_info_v1, secid)),
+ .help = SECMARK_help,
+ .print = SECMARK_print_v1,
+ .save = SECMARK_save_v1,
+ .x6_parse = SECMARK_parse_v1,
+ .x6_options = SECMARK_opts_v1,
+ }
};
void _init(void)
{
- xtables_register_target(&secmark_target);
+ xtables_register_targets(secmark_tg_reg, ARRAY_SIZE(secmark_tg_reg));
}
diff --git a/extensions/libxt_SECMARK.t b/extensions/libxt_SECMARK.t
new file mode 100644
index 0000000000000..39d4c09348bf4
--- /dev/null
+++ b/extensions/libxt_SECMARK.t
@@ -0,0 +1,4 @@
+:INPUT,FORWARD,OUTPUT
+*security
+-j SECMARK --selctx system_u:object_r:firewalld_exec_t:s0;=;OK
+-j SECMARK;;FAIL
diff --git a/include/linux/netfilter/xt_SECMARK.h b/include/linux/netfilter/xt_SECMARK.h
index 989092bd6274b..31760a286a854 100644
--- a/include/linux/netfilter/xt_SECMARK.h
+++ b/include/linux/netfilter/xt_SECMARK.h
@@ -19,4 +19,10 @@ struct xt_secmark_target_info {
char secctx[SECMARK_SECCTX_MAX];
};
+struct xt_secmark_target_info_v1 {
+ __u8 mode;
+ char secctx[SECMARK_SECCTX_MAX];
+ __u32 secid;
+};
+
#endif /*_XT_SECMARK_H_target */
--
2.40.0

@ -0,0 +1,156 @@
From adc559b69fc2b8d95a7c3bae96ca12faa0ba5d1d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 17 Nov 2020 00:57:10 +0100
Subject: [PATCH] Use proto_to_name() from xshared in more places
Share the common proto name lookup code. While being at it, make proto
number variable 16bit, values may exceed 256.
This aligns iptables-nft '-p' argument printing with legacy iptables. In
practice, this should make a difference only in corner cases.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 556f704458cdb509d395ddb7d2629987d60e762e)
---
include/xtables.h | 2 +-
iptables/ip6tables.c | 22 +++++-----------------
iptables/iptables.c | 20 +++++---------------
iptables/nft-shared.c | 6 +++---
iptables/xshared.c | 2 +-
iptables/xshared.h | 2 +-
6 files changed, 16 insertions(+), 38 deletions(-)
diff --git a/include/xtables.h b/include/xtables.h
index 5044dd08e86d3..a7b36979398ba 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -395,7 +395,7 @@ struct xtables_rule_match {
*/
struct xtables_pprot {
const char *name;
- uint8_t num;
+ uint16_t num;
};
enum xtables_tryload {
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index c95355b091568..ce01ce8c04af6 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -796,28 +796,16 @@ print_iface(char letter, const char *iface, const unsigned char *mask,
}
}
-/* The ip6tables looks up the /etc/protocols. */
static void print_proto(uint16_t proto, int invert)
{
if (proto) {
- unsigned int i;
+ const char *pname = proto_to_name(proto, 0);
const char *invertstr = invert ? " !" : "";
- const struct protoent *pent = getprotobynumber(proto);
- if (pent) {
- printf("%s -p %s",
- invertstr, pent->p_name);
- return;
- }
-
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto) {
- printf("%s -p %s",
- invertstr, xtables_chain_protos[i].name);
- return;
- }
-
- printf("%s -p %u", invertstr, proto);
+ if (pname)
+ printf("%s -p %s", invertstr, pname);
+ else
+ printf("%s -p %u", invertstr, proto);
}
}
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 7d6183116d265..514238d924780 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -764,23 +764,13 @@ list_entries(const xt_chainlabel chain, int rulenum, int verbose, int numeric,
static void print_proto(uint16_t proto, int invert)
{
if (proto) {
- unsigned int i;
+ const char *pname = proto_to_name(proto, 0);
const char *invertstr = invert ? " !" : "";
- const struct protoent *pent = getprotobynumber(proto);
- if (pent) {
- printf("%s -p %s", invertstr, pent->p_name);
- return;
- }
-
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto) {
- printf("%s -p %s",
- invertstr, xtables_chain_protos[i].name);
- return;
- }
-
- printf("%s -p %u", invertstr, proto);
+ if (pname)
+ printf("%s -p %s", invertstr, pname);
+ else
+ printf("%s -p %u", invertstr, proto);
}
}
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index c1664b50f9383..4253b08196d29 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -826,13 +826,13 @@ void save_rule_details(const struct iptables_command_state *cs,
}
if (proto > 0) {
- const struct protoent *pent = getprotobynumber(proto);
+ const char *pname = proto_to_name(proto, 0);
if (invflags & XT_INV_PROTO)
printf("! ");
- if (pent)
- printf("-p %s ", pent->p_name);
+ if (pname)
+ printf("-p %s ", pname);
else
printf("-p %u ", proto);
}
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 3bcf24735c8fb..9a17a8fdf11cd 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -48,7 +48,7 @@ void print_extension_helps(const struct xtables_target *t,
}
const char *
-proto_to_name(uint8_t proto, int nolookup)
+proto_to_name(uint16_t proto, int nolookup)
{
unsigned int i;
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 1e86aba8b2375..7c881c56a25da 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -152,7 +152,7 @@ enum {
extern void print_extension_helps(const struct xtables_target *,
const struct xtables_rule_match *);
-extern const char *proto_to_name(uint8_t, int);
+extern const char *proto_to_name(uint16_t, int);
extern int command_default(struct iptables_command_state *,
struct xtables_globals *);
extern struct xtables_match *load_proto(struct iptables_command_state *);
--
2.40.0

@ -0,0 +1,80 @@
From 867ccfc5a9394b8a0957db9f2828befb7efabd7c Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 4 May 2021 16:03:24 +0200
Subject: [PATCH] extensions: sctp: Fix nftables translation
If both sport and dport was present, incorrect nft syntax was generated.
Fixes: defc7bd2bac89 ("extensions: libxt_sctp: Add translation to nft")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit a61282ec6a1697bfb40f19d13a28a74559050167)
---
extensions/libxt_sctp.c | 10 ++++------
extensions/libxt_sctp.txlate | 10 +++++-----
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c
index 140de2653b1ef..ee4e99ebf11bf 100644
--- a/extensions/libxt_sctp.c
+++ b/extensions/libxt_sctp.c
@@ -495,15 +495,13 @@ static int sctp_xlate(struct xt_xlate *xl,
if (!einfo->flags)
return 0;
- xt_xlate_add(xl, "sctp ");
-
if (einfo->flags & XT_SCTP_SRC_PORTS) {
if (einfo->spts[0] != einfo->spts[1])
- xt_xlate_add(xl, "sport%s %u-%u",
+ xt_xlate_add(xl, "sctp sport%s %u-%u",
einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
einfo->spts[0], einfo->spts[1]);
else
- xt_xlate_add(xl, "sport%s %u",
+ xt_xlate_add(xl, "sctp sport%s %u",
einfo->invflags & XT_SCTP_SRC_PORTS ? " !=" : "",
einfo->spts[0]);
space = " ";
@@ -511,11 +509,11 @@ static int sctp_xlate(struct xt_xlate *xl,
if (einfo->flags & XT_SCTP_DEST_PORTS) {
if (einfo->dpts[0] != einfo->dpts[1])
- xt_xlate_add(xl, "%sdport%s %u-%u", space,
+ xt_xlate_add(xl, "%ssctp dport%s %u-%u", space,
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0], einfo->dpts[1]);
else
- xt_xlate_add(xl, "%sdport%s %u", space,
+ xt_xlate_add(xl, "%ssctp dport%s %u", space,
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0]);
}
diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate
index 72f4641ab021c..0d6c59e183675 100644
--- a/extensions/libxt_sctp.txlate
+++ b/extensions/libxt_sctp.txlate
@@ -23,16 +23,16 @@ iptables-translate -A INPUT -p sctp ! --dport 50:56 -j ACCEPT
nft add rule ip filter INPUT sctp dport != 50-56 counter accept
iptables-translate -A INPUT -p sctp --dport 80 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport 80 counter accept
+nft add rule ip filter INPUT sctp sport 50 sctp dport 80 counter accept
iptables-translate -A INPUT -p sctp --dport 80:100 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport 80-100 counter accept
+nft add rule ip filter INPUT sctp sport 50 sctp dport 80-100 counter accept
iptables-translate -A INPUT -p sctp --dport 80 --sport 50:55 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50-55 dport 80 counter accept
+nft add rule ip filter INPUT sctp sport 50-55 sctp dport 80 counter accept
iptables-translate -A INPUT -p sctp ! --dport 80:100 --sport 50 -j ACCEPT
-nft add rule ip filter INPUT sctp sport 50 dport != 80-100 counter accept
+nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept
iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT
-nft add rule ip filter INPUT sctp sport != 50-55 dport 80 counter accept
+nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept
--
2.40.0

@ -0,0 +1,159 @@
From 448d1ff5807a52ec34759a6dddd348c5f3e96704 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 4 May 2021 16:26:42 +0200
Subject: [PATCH] extensions: sctp: Translate --chunk-types option
The translation is not fully complete as it is not possible to map 'any'
match type into nft syntax with a single rule. Also, 'only' match type
translation is a bit poor as it explicitly lists all chunk types that
are supposed to be missing.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 5818be177110a09120dd8fe4bd2533acbf8da301)
---
extensions/libxt_sctp.c | 91 ++++++++++++++++++++++++++++--------
extensions/libxt_sctp.txlate | 6 +++
2 files changed, 78 insertions(+), 19 deletions(-)
diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c
index ee4e99ebf11bf..5d8ab85cacf42 100644
--- a/extensions/libxt_sctp.c
+++ b/extensions/libxt_sctp.c
@@ -92,28 +92,29 @@ struct sctp_chunk_names {
const char *name;
unsigned int chunk_type;
const char *valid_flags;
+ const char *nftname;
};
/*'ALL' and 'NONE' will be treated specially. */
static const struct sctp_chunk_names sctp_chunk_names[]
-= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE"},
- { .name = "INIT", .chunk_type = 1, .valid_flags = "--------"},
- { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------"},
- { .name = "SACK", .chunk_type = 3, .valid_flags = "--------"},
- { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------"},
- { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------"},
- { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T"},
- { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------"},
- { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------"},
- { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------"},
- { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------"},
- { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------"},
- { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------"},
- { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------"},
- { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T"},
- { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------"},
- { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------"},
- { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------"},
+= { { .name = "DATA", .chunk_type = 0, .valid_flags = "----IUBE", .nftname = "data" },
+ { .name = "INIT", .chunk_type = 1, .valid_flags = "--------", .nftname = "init" },
+ { .name = "INIT_ACK", .chunk_type = 2, .valid_flags = "--------", .nftname = "init-ack" },
+ { .name = "SACK", .chunk_type = 3, .valid_flags = "--------", .nftname = "sack" },
+ { .name = "HEARTBEAT", .chunk_type = 4, .valid_flags = "--------", .nftname = "heartbeat" },
+ { .name = "HEARTBEAT_ACK", .chunk_type = 5, .valid_flags = "--------", .nftname = "heartbeat-ack" },
+ { .name = "ABORT", .chunk_type = 6, .valid_flags = "-------T", .nftname = "abort" },
+ { .name = "SHUTDOWN", .chunk_type = 7, .valid_flags = "--------", .nftname = "shutdown" },
+ { .name = "SHUTDOWN_ACK", .chunk_type = 8, .valid_flags = "--------", .nftname = "shutdown-ack" },
+ { .name = "ERROR", .chunk_type = 9, .valid_flags = "--------", .nftname = "error" },
+ { .name = "COOKIE_ECHO", .chunk_type = 10, .valid_flags = "--------", .nftname = "cookie-echo" },
+ { .name = "COOKIE_ACK", .chunk_type = 11, .valid_flags = "--------", .nftname = "cookie-ack" },
+ { .name = "ECN_ECNE", .chunk_type = 12, .valid_flags = "--------", .nftname = "ecne" },
+ { .name = "ECN_CWR", .chunk_type = 13, .valid_flags = "--------", .nftname = "cwr" },
+ { .name = "SHUTDOWN_COMPLETE", .chunk_type = 14, .valid_flags = "-------T", .nftname = "shutdown-complete" },
+ { .name = "ASCONF", .chunk_type = 193, .valid_flags = "--------", .nftname = "asconf" },
+ { .name = "ASCONF_ACK", .chunk_type = 128, .valid_flags = "--------", .nftname = "asconf-ack" },
+ { .name = "FORWARD_TSN", .chunk_type = 192, .valid_flags = "--------", .nftname = "forward-tsn" },
};
static void
@@ -485,12 +486,52 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match)
}
}
+static const char *sctp_xlate_chunk(struct xt_xlate *xl, const char *space,
+ const struct xt_sctp_info *einfo,
+ const struct sctp_chunk_names *scn)
+{
+ bool inv = einfo->invflags & XT_SCTP_CHUNK_TYPES;
+ const struct xt_sctp_flag_info *flag_info = NULL;
+ int i;
+
+ if (!scn->nftname)
+ return space;
+
+ if (!SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, scn->chunk_type)) {
+ if (einfo->chunk_match_type != SCTP_CHUNK_MATCH_ONLY)
+ return space;
+
+ xt_xlate_add(xl, "%ssctp chunk %s %s", space,
+ scn->nftname, inv ? "exists" : "missing");
+ return " ";
+ }
+
+ for (i = 0; i < einfo->flag_count; i++) {
+ if (einfo->flag_info[i].chunktype == scn->chunk_type) {
+ flag_info = &einfo->flag_info[i];
+ break;
+ }
+ }
+
+ if (!flag_info) {
+ xt_xlate_add(xl, "%ssctp chunk %s %s", space,
+ scn->nftname, inv ? "missing" : "exists");
+ return " ";
+ }
+
+ xt_xlate_add(xl, "%ssctp chunk %s flags & 0x%x %s 0x%x", space,
+ scn->nftname, flag_info->flag_mask,
+ inv ? "!=" : "==", flag_info->flag);
+
+ return " ";
+}
+
static int sctp_xlate(struct xt_xlate *xl,
const struct xt_xlate_mt_params *params)
{
const struct xt_sctp_info *einfo =
(const struct xt_sctp_info *)params->match->data;
- char *space = "";
+ const char *space = "";
if (!einfo->flags)
return 0;
@@ -516,6 +557,18 @@ static int sctp_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, "%ssctp dport%s %u", space,
einfo->invflags & XT_SCTP_DEST_PORTS ? " !=" : "",
einfo->dpts[0]);
+ space = " ";
+ }
+
+ if (einfo->flags & XT_SCTP_CHUNK_TYPES) {
+ int i;
+
+ if (einfo->chunk_match_type == SCTP_CHUNK_MATCH_ANY)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(sctp_chunk_names); i++)
+ space = sctp_xlate_chunk(xl, space, einfo,
+ &sctp_chunk_names[i]);
}
return 1;
diff --git a/extensions/libxt_sctp.txlate b/extensions/libxt_sctp.txlate
index 0d6c59e183675..bb817525db8d8 100644
--- a/extensions/libxt_sctp.txlate
+++ b/extensions/libxt_sctp.txlate
@@ -36,3 +36,9 @@ nft add rule ip filter INPUT sctp sport 50 sctp dport != 80-100 counter accept
iptables-translate -A INPUT -p sctp --dport 80 ! --sport 50:55 -j ACCEPT
nft add rule ip filter INPUT sctp sport != 50-55 sctp dport 80 counter accept
+
+iptables-translate -A INPUT -p sctp --chunk-types all INIT,DATA:iUbE,SACK,ABORT:T -j ACCEPT
+nft add rule ip filter INPUT sctp chunk data flags & 0xf == 0x5 sctp chunk init exists sctp chunk sack exists sctp chunk abort flags & 0x1 == 0x1 counter accept
+
+iptables-translate -A INPUT -p sctp --chunk-types only SHUTDOWN_COMPLETE -j ACCEPT
+nft add rule ip filter INPUT sctp chunk data missing sctp chunk init missing sctp chunk init-ack missing sctp chunk sack missing sctp chunk heartbeat missing sctp chunk heartbeat-ack missing sctp chunk abort missing sctp chunk shutdown missing sctp chunk shutdown-ack missing sctp chunk error missing sctp chunk cookie-echo missing sctp chunk cookie-ack missing sctp chunk ecne missing sctp chunk cwr missing sctp chunk shutdown-complete exists sctp chunk asconf missing sctp chunk asconf-ack missing sctp chunk forward-tsn missing counter accept
--
2.40.0

@ -0,0 +1,33 @@
From e9dd197e783556dcb514ec624c4f6efeb782e7c7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 13 Nov 2020 21:04:39 +0100
Subject: [PATCH] libxtables: Drop leftover variable in
xtables_numeric_to_ip6addr()
Variable 'err' was only used in removed debug code, so drop it as well.
Fixes: 7f526c9373c17 ("libxtables: xtables: remove unnecessary debug code")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 97fabae738a74bd04a7793e1199cd2b8a69122bc)
---
libxtables/xtables.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 7152c6576cd63..7f40b6f1b327b 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -1812,9 +1812,8 @@ const char *xtables_ip6mask_to_numeric(const struct in6_addr *addrp)
struct in6_addr *xtables_numeric_to_ip6addr(const char *num)
{
static struct in6_addr ap;
- int err;
- if ((err = inet_pton(AF_INET6, num, &ap)) == 1)
+ if (inet_pton(AF_INET6, num, &ap) == 1)
return &ap;
return NULL;
--
2.40.0

@ -0,0 +1,49 @@
From 89bd91cfdf6f81971324dca1b0df7c6c5537a2ab Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 13 Nov 2020 21:13:50 +0100
Subject: [PATCH] extensions: libebt_ip6: Drop unused variables
They are being assigned to but never read.
Fixes: 5c8ce9c6aede0 ("ebtables-compat: add 'ip6' match extension")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 8bb5bcae57c83066c224efa5fd29ed4822a766fc)
---
extensions/libebt_ip6.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c
index b8a5a5d8c3a92..301bed9aadefd 100644
--- a/extensions/libebt_ip6.c
+++ b/extensions/libebt_ip6.c
@@ -250,9 +250,8 @@ static void brip6_init(struct xt_entry_match *match)
static struct in6_addr *numeric_to_addr(const char *num)
{
static struct in6_addr ap;
- int err;
- if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
+ if (inet_pton(AF_INET6, num, &ap) == 1)
return &ap;
return (struct in6_addr *)NULL;
}
@@ -292,7 +291,6 @@ static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct i
char buf[256];
char *p;
int i;
- int err;
strncpy(buf, address, sizeof(buf) - 1);
/* first the mask */
@@ -309,7 +307,7 @@ static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct i
if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any)))
strcpy(buf, "::");
- if ((err=inet_pton(AF_INET6, buf, addr)) < 1) {
+ if (inet_pton(AF_INET6, buf, addr) < 1) {
xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Address '%s' specified", buf);
return;
}
--
2.40.0

@ -0,0 +1,29 @@
From e672c567d978bf99652a8c3681e105d5a212552f Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 2 Jun 2021 11:04:30 +0200
Subject: [PATCH] libxtables: Fix memleak in xtopt_parse_hostmask()
The allocated hostmask duplicate needs to be freed again.
Fixes: 66266abd17adc ("libxtables: XTTYPE_HOSTMASK support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit ffe88f8f01263687e82ef4d3d2bdc0cb5444711e)
---
libxtables/xtoptions.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/libxtables/xtoptions.c b/libxtables/xtoptions.c
index d329f2ff7979e..0dcdf607f4678 100644
--- a/libxtables/xtoptions.c
+++ b/libxtables/xtoptions.c
@@ -763,6 +763,7 @@ static void xtopt_parse_hostmask(struct xt_option_call *cb)
cb->arg = p;
xtopt_parse_plenmask(cb);
cb->arg = orig_arg;
+ free(work);
}
static void xtopt_parse_ethermac(struct xt_option_call *cb)
--
2.40.0

@ -0,0 +1,34 @@
From bee29f2820cafde1e04ebef049bc4c40c4dbbe18 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 2 Jun 2021 11:55:20 +0200
Subject: [PATCH] nft: Avoid memleak in error path of nft_cmd_new()
If rule allocation fails, free the allocated 'cmd' before returning to
caller.
Fixes: a7f1e208cdf9c ("nft: split parsing from netlink commands")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit eab75ed36a4f204ddab0c40ba42c5a300634d5c3)
---
iptables/nft-cmd.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/iptables/nft-cmd.c b/iptables/nft-cmd.c
index ed53c061edc6f..fd038503d87e1 100644
--- a/iptables/nft-cmd.c
+++ b/iptables/nft-cmd.c
@@ -35,8 +35,10 @@ struct nft_cmd *nft_cmd_new(struct nft_handle *h, int command,
if (state) {
rule = nft_rule_new(h, chain, table, state);
- if (!rule)
+ if (!rule) {
+ nft_cmd_free(cmd);
return NULL;
+ }
cmd->obj.rule = rule;
--
2.40.0

@ -0,0 +1,29 @@
From 2f80e6d896590f42c932de32ae8c3d597cbf940b Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 2 Jun 2021 12:50:57 +0200
Subject: [PATCH] iptables-apply: Drop unused variable
It was assigned to but never read.
Fixes: b45b4e3903414 ("iptables-apply: script and manpage update")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 084671d5acaaf749648e828c2ed3b319de651764)
---
iptables/iptables-apply | 1 -
1 file changed, 1 deletion(-)
diff --git a/iptables/iptables-apply b/iptables/iptables-apply
index 4683b1b402d08..3a7df5e3cbc1f 100755
--- a/iptables/iptables-apply
+++ b/iptables/iptables-apply
@@ -231,7 +231,6 @@ case "$MODE" in
"$RUNCMD" &
CMD_PID=$!
( sleep "$TIMEOUT"; kill "$CMD_PID" 2>/dev/null; exit 0 ) &
- CMDTIMEOUT_PID=$!
if ! wait "$CMD_PID"; then
echo "failed."
echo "Error: unknown error running command: $RUNCMD" >&2
--
2.40.0

@ -0,0 +1,130 @@
From 9a617399d5e0776b43f093b9d63d10f72e882fee Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 28 Jul 2021 17:53:53 +0200
Subject: [PATCH] doc: ebtables-nft.8: Adjust for missing atomic-options
Drop any reference to them (and the environment variable) but list them
in BUGS section hinting at ebtables-save and -restore tools.
Fixes: 1939cbc25e6f5 ("doc: Adjust ebtables man page")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit 765bf04ecc228783cb88c810c85bc0c769579c39)
---
iptables/ebtables-nft.8 | 64 ++++++-----------------------------------
1 file changed, 8 insertions(+), 56 deletions(-)
diff --git a/iptables/ebtables-nft.8 b/iptables/ebtables-nft.8
index 1fa5ad9388cc0..08e9766f2cc74 100644
--- a/iptables/ebtables-nft.8
+++ b/iptables/ebtables-nft.8
@@ -44,12 +44,6 @@ ebtables \- Ethernet bridge frame table administration (nft-based)
.br
.BR "ebtables " [ -t " table ] " --init-table
.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-commit
-.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-init
-.br
-.BR "ebtables " [ -t " table ] [" --atomic-file " file] " --atomic-save
-.br
.SH DESCRIPTION
.B ebtables
@@ -149,11 +143,9 @@ a table, the commands apply to the default filter table.
Only one command may be used on the command line at a time, except when
the commands
.BR -L " and " -Z
-are combined, the commands
+are combined or the commands
.BR -N " and " -P
-are combined, or when
-.B --atomic-file
-is used.
+are combined.
.TP
.B "-A, --append"
Append a rule to the end of the selected chain.
@@ -313,39 +305,6 @@ of the ebtables kernel table.
.TP
.B "--init-table"
Replace the current table data by the initial table data.
-.TP
-.B "--atomic-init"
-Copy the kernel's initial data of the table to the specified
-file. This can be used as the first action, after which rules are added
-to the file. The file can be specified using the
-.B --atomic-file
-command or through the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
-.B "--atomic-save"
-Copy the kernel's current data of the table to the specified
-file. This can be used as the first action, after which rules are added
-to the file. The file can be specified using the
-.B --atomic-file
-command or through the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
-.B "--atomic-commit"
-Replace the kernel table data with the data contained in the specified
-file. This is a useful command that allows you to load all your rules of a
-certain table into the kernel at once, saving the kernel a lot of precious
-time and allowing atomic updates of the tables. The file which contains
-the table data is constructed by using either the
-.B "--atomic-init"
-or the
-.B "--atomic-save"
-command to generate a starting file. After that, using the
-.B "--atomic-file"
-command when constructing rules or setting the
-.IR EBTABLES_ATOMIC_FILE " environment variable"
-allows you to extend the file and build the complete table before
-committing it to the kernel. This command can be very useful in boot scripts
-to populate the ebtables tables in a fast way.
.SS MISCELLANOUS COMMANDS
.TP
.B "-V, --version"
@@ -371,16 +330,6 @@ a target extension (see
.BR "TARGET EXTENSIONS" ")"
or a user-defined chain name.
.TP
-.B --atomic-file "\fIfile\fP"
-Let the command operate on the specified
-.IR file .
-The data of the table to
-operate on will be extracted from the file and the result of the operation
-will be saved back into the file. If specified, this option should come
-before the command specification. An alternative that should be preferred,
-is setting the
-.IR EBTABLES_ATOMIC_FILE " environment variable."
-.TP
.B -M, --modprobe "\fIprogram\fP"
When talking to the kernel, use this
.I program
@@ -1100,8 +1049,6 @@ arp message and the hardware address length in the arp header is 6 bytes.
.br
.SH FILES
.I /etc/ethertypes
-.SH ENVIRONMENT VARIABLES
-.I EBTABLES_ATOMIC_FILE
.SH MAILINGLISTS
.BR "" "See " http://netfilter.org/mailinglists.html
.SH BUGS
@@ -1109,7 +1056,12 @@ The version of ebtables this man page ships with does not support the
.B broute
table. Also there is no support for
.B string
-match. And finally, this list is probably not complete.
+match. Further, support for atomic-options
+.RB ( --atomic-file ", " --atomic-init ", " --atomic-save ", " --atomic-commit )
+has not been implemented, although
+.BR ebtables-save " and " ebtables-restore
+might replace them entirely given the inherent atomicity of nftables.
+Finally, this list is probably not complete.
.SH SEE ALSO
.BR xtables-nft "(8), " iptables "(8), " ip (8)
.PP
--
2.40.0

@ -0,0 +1,102 @@
From ec0a69df9ac073b1a6e951c08c049fec47a12b5c Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 30 Jul 2021 12:25:10 +0200
Subject: [PATCH] ebtables: Dump atomic waste
With ebtables-nft.8 now educating people about the missing
functionality, get rid of atomic remains in source code. This eliminates
mostly comments except for --atomic-commit which was treated as alias of
--init-table. People not using the latter are probably trying to
atomic-commit from an atomic-file which in turn is not supported, so no
point keeping it.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 263186372dc4ae6a54a29bea644bcf1fc8dc3fc0)
---
iptables/xtables-eb.c | 53 -------------------------------------------
1 file changed, 53 deletions(-)
diff --git a/iptables/xtables-eb.c b/iptables/xtables-eb.c
index 6df5839f07436..d07adad2d73c3 100644
--- a/iptables/xtables-eb.c
+++ b/iptables/xtables-eb.c
@@ -262,10 +262,6 @@ struct option ebt_original_options[] =
{ "new-chain" , required_argument, 0, 'N' },
{ "rename-chain" , required_argument, 0, 'E' },
{ "delete-chain" , optional_argument, 0, 'X' },
- { "atomic-init" , no_argument , 0, 7 },
- { "atomic-commit" , no_argument , 0, 8 },
- { "atomic-file" , required_argument, 0, 9 },
- { "atomic-save" , no_argument , 0, 10 },
{ "init-table" , no_argument , 0, 11 },
{ "concurrent" , no_argument , 0, 13 },
{ 0 }
@@ -371,10 +367,6 @@ static void print_help(const struct xtables_target *t,
"--new-chain -N chain : create a user defined chain\n"
"--rename-chain -E old new : rename a chain\n"
"--delete-chain -X [chain] : delete a user defined chain\n"
-"--atomic-commit : update the kernel w/t table contained in <FILE>\n"
-"--atomic-init : put the initial kernel table into <FILE>\n"
-"--atomic-save : put the current kernel table into <FILE>\n"
-"--atomic-file file : set <FILE> to file\n\n"
"Options:\n"
"--proto -p [!] proto : protocol hexadecimal, by name or LENGTH\n"
"--src -s [!] address[/mask]: source mac address\n"
@@ -1135,54 +1127,9 @@ int do_commandeb(struct nft_handle *h, int argc, char *argv[], char **table,
"Use --Lmac2 with -L");
flags |= LIST_MAC2;
break;
- case 8 : /* atomic-commit */
-/*
- replace->command = c;
- if (OPT_COMMANDS)
- ebt_print_error2("Multiple commands are not allowed");
- replace->flags |= OPT_COMMAND;
- if (!replace->filename)
- ebt_print_error2("No atomic file specified");*/
- /* Get the information from the file */
- /*ebt_get_table(replace, 0);*/
- /* We don't want the kernel giving us its counters,
- * they would overwrite the counters extracted from
- * the file */
- /*replace->num_counters = 0;*/
- /* Make sure the table will be written to the kernel */
- /*free(replace->filename);
- replace->filename = NULL;
- break;*/
- /*case 7 :*/ /* atomic-init */
- /*case 10:*/ /* atomic-save */
case 11: /* init-table */
nft_cmd_table_flush(h, *table);
return 1;
- /*
- replace->command = c;
- if (OPT_COMMANDS)
- ebt_print_error2("Multiple commands are not allowed");
- if (c != 11 && !replace->filename)
- ebt_print_error2("No atomic file specified");
- replace->flags |= OPT_COMMAND;
- {
- char *tmp = replace->filename;*/
-
- /* Get the kernel table */
- /*replace->filename = NULL;
- ebt_get_kernel_table(replace, c == 10 ? 0 : 1);
- replace->filename = tmp;
- }
- break;
- case 9 :*/ /* atomic */
- /*
- if (OPT_COMMANDS)
- ebt_print_error2("--atomic has to come before the command");*/
- /* A possible memory leak here, but this is not
- * executed in daemon mode */
- /*replace->filename = (char *)malloc(strlen(optarg) + 1);
- strcpy(replace->filename, optarg);
- break; */
case 13 :
break;
case 1 :
--
2.40.0

@ -0,0 +1,31 @@
From 59c41217b2acc9409ba50a76a40aaa994c83f454 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 3 Aug 2021 10:55:20 +0200
Subject: [PATCH] nft: Fix for non-verbose check command
Check command was unconditionally verbose since v1.8.5. Make it respect
--verbose option again.
Fixes: a7f1e208cdf9c ("nft: split parsing from netlink commands")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 57d1422dbbc41c36ed2e9f6c67aa040c65a429a0)
---
iptables/nft.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index 7f87d46dcc44c..f8534c6cd56fb 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -3160,7 +3160,7 @@ static int nft_prepare(struct nft_handle *h)
case NFT_COMPAT_RULE_CHECK:
assert_chain_exists(h, cmd->table, cmd->jumpto);
ret = nft_rule_check(h, cmd->chain, cmd->table,
- cmd->obj.rule, cmd->rulenum);
+ cmd->obj.rule, cmd->verbose);
break;
case NFT_COMPAT_RULE_ZERO:
ret = nft_rule_zero_counters(h, cmd->chain, cmd->table,
--
2.40.0

@ -0,0 +1,41 @@
From 07cfafd077bbd247bf75c0a3399569af58a63915 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 9 Aug 2021 18:48:58 +0200
Subject: [PATCH] extensions: hashlimit: Fix tests with HZ=100
With the kernel ticking at 100Hz, a limit of 1/day with burst 5 does not
overflow in kernel, making the test unstable depending on kernel config.
Change it to not overflow with 1000Hz either by increasing the burst
value by a factor of 100.
Fixes: fcf9f6f25db11 ("extensions: libxt_hashlimit: add unit test")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit bef9dc575625a98a5e6ed8ca37e49031cdba5937)
---
extensions/libxt_hashlimit.t | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
index ccd0d1e6a2a1a..8369933786f68 100644
--- a/extensions/libxt_hashlimit.t
+++ b/extensions/libxt_hashlimit.t
@@ -3,14 +3,12 @@
-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
--m hashlimit --hashlimit-above 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-above 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-# kernel says "xt_hashlimit: overflow, try lower: 864000000/5"
--m hashlimit --hashlimit-upto 1/day --hashlimit-burst 5 --hashlimit-name mini1;;FAIL
+-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
--
2.40.0

@ -0,0 +1,31 @@
From 71f9eda379a3d70b5b2cd9327e41ba5446c618e1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 31 Aug 2021 12:26:20 +0200
Subject: [PATCH] nft: Use xtables_malloc() in mnl_err_list_node_add()
The function called malloc() without checking for memory allocation
failure. Simply replace the call by xtables_malloc() to fix that.
Fixes: 4e2020952d6f9 ("xtables: use libnftnl batch API")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit ca11c7b7036b5821c17b8d08dc2a29f55b461a93)
---
iptables/nft.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index f8534c6cd56fb..ba59cfb8c47af 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -143,7 +143,7 @@ struct mnl_err {
static void mnl_err_list_node_add(struct list_head *err_list, int error,
int seqnum)
{
- struct mnl_err *err = malloc(sizeof(struct mnl_err));
+ struct mnl_err *err = xtables_malloc(sizeof(struct mnl_err));
err->seqnum = seqnum;
err->err = error;
--
2.40.0

@ -0,0 +1,47 @@
From c51304d536c3f91b58dc24b14131de157d741a9f Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Mon, 8 Nov 2021 17:03:21 +0100
Subject: [PATCH] extensions: hashlimit: Fix tests with HZ=1000
In an attempt to fix for failing hashlimit tests with HZ=100, the
expected failures were changed so they are expected to pass and the
parameters changed to seemingly fix them. Yet while the new parameters
worked on HZ=100 systems, with higher tick rates they didn't so the
observed problem moved from the test failing on HZ=100 to failing on
HZ=1000 instead.
Kernel's error message "try lower: 864000000/5" turned out to be a red
herring: The burst value does not act as a dividor but a multiplier
instead, so in order to lower the overflow-checked value, a lower burst
value must be chosen. Inded, using a burst value of 1 makes the kernel
accept the rule in both HZ=100 and HZ=1000 configurations.
Fixes: bef9dc575625a ("extensions: hashlimit: Fix tests with HZ=100")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 1eab8e83aec0e6965f11f8cad460add1caeae629)
---
extensions/libxt_hashlimit.t | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/extensions/libxt_hashlimit.t b/extensions/libxt_hashlimit.t
index 8369933786f68..206d92935f2e2 100644
--- a/extensions/libxt_hashlimit.t
+++ b/extensions/libxt_hashlimit.t
@@ -3,12 +3,12 @@
-m hashlimit --hashlimit-above 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-above 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
--m hashlimit --hashlimit-above 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-above 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1000000/sec --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/min --hashlimit-burst 5 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/hour --hashlimit-burst 5 --hashlimit-name mini1;=;OK
--m hashlimit --hashlimit-upto 1/day --hashlimit-burst 500 --hashlimit-name mini1;=;OK
+-m hashlimit --hashlimit-upto 1/day --hashlimit-burst 1 --hashlimit-name mini1;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode srcip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
-m hashlimit --hashlimit-upto 1/sec --hashlimit-burst 1 --hashlimit-mode dstip --hashlimit-name mini1 --hashlimit-htable-expire 2000;=;OK
--
2.40.0

@ -0,0 +1,164 @@
From 655e919be08b6ca9b5529f16c659ee93572b867d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 5 Apr 2019 13:21:19 +0200
Subject: [PATCH] xshared: Merge and share parse_chain()
Have a common routine to perform chain name checks, combining all
variants' requirements.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 1189d830ea4fd269da87761d400ebabca02e1ef3)
Conflicts:
iptables/ip6tables.c
iptables/xshared.c
-> Context change due to missing commit 9dc50b5b8e441
("xshared: Merge invflags handling code").
---
iptables/ip6tables.c | 26 --------------------------
iptables/iptables.c | 25 -------------------------
iptables/xshared.c | 24 ++++++++++++++++++++++++
iptables/xshared.h | 1 +
iptables/xtables.c | 9 +--------
5 files changed, 26 insertions(+), 59 deletions(-)
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index ce01ce8c04af6..6db91c807bcea 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -248,32 +248,6 @@ static int is_exthdr(uint16_t proto)
proto == IPPROTO_DSTOPTS);
}
-static void
-parse_chain(const char *chainname)
-{
- const char *ptr;
-
- if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- chainname, XT_EXTENSION_MAXNAMELEN);
-
- if (*chainname == '-' || *chainname == '!')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *chainname);
-
- if (xtables_find_target(chainname, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
-
- for (ptr = chainname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s'", chainname);
-}
-
static void
set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
int invert)
diff --git a/iptables/iptables.c b/iptables/iptables.c
index 514238d924780..a33416a887ed4 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -239,31 +239,6 @@ iptables_exit_error(enum xtables_exittype status, const char *msg, ...)
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
-static void
-parse_chain(const char *chainname)
-{
- const char *ptr;
-
- if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "chain name `%s' too long (must be under %u chars)",
- chainname, XT_EXTENSION_MAXNAMELEN);
-
- if (*chainname == '-' || *chainname == '!')
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *chainname);
-
- if (xtables_find_target(chainname, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
-
- for (ptr = chainname; *ptr; ptr++)
- if (isspace(*ptr))
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s'", chainname);
-}
static void
set_option(unsigned int *options, unsigned int option, uint8_t *invflg,
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 9a17a8fdf11cd..5ae158908b109 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -848,3 +848,27 @@ char opt2char(int option)
return *ptr;
}
+
+void parse_chain(const char *chainname)
+{
+ const char *ptr;
+
+ if (strlen(chainname) >= XT_EXTENSION_MAXNAMELEN)
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name `%s' too long (must be under %u chars)",
+ chainname, XT_EXTENSION_MAXNAMELEN);
+
+ if (*chainname == '-' || *chainname == '!')
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name not allowed to start with `%c'\n",
+ *chainname);
+
+ if (xtables_find_target(chainname, XTF_TRY_LOAD))
+ xtables_error(PARAMETER_PROBLEM,
+ "chain name may not clash with target name\n");
+
+ for (ptr = chainname; *ptr; ptr++)
+ if (isspace(*ptr))
+ xtables_error(PARAMETER_PROBLEM,
+ "Invalid chain name `%s'", chainname);
+}
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 7c881c56a25da..10f6e0b5a0e98 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -223,6 +223,7 @@ char cmd2char(int option);
void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert);
int parse_rulenumber(const char *rule);
+void parse_chain(const char *chainname);
void generic_opt_check(int command, int options);
char opt2char(int option);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 9779bd83d53b3..54f887f80497e 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -587,14 +587,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case 'N':
- if (optarg && (*optarg == '-' || *optarg == '!'))
- xtables_error(PARAMETER_PROBLEM,
- "chain name not allowed to start "
- "with `%c'\n", *optarg);
- if (xtables_find_target(optarg, XTF_TRY_LOAD))
- xtables_error(PARAMETER_PROBLEM,
- "chain name may not clash "
- "with target name\n");
+ parse_chain(optarg);
add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
cs->invert);
p->chain = optarg;
--
2.40.0

@ -0,0 +1,58 @@
From e004e9e1d0e7ef4d9756d9f01feef8efef02300b Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Sat, 6 Nov 2021 01:09:37 +0100
Subject: [PATCH] nft-shared: Drop unused function print_proto()
The last users vanished back in 2013. There is identical code in
save_rule_details(), but with only a single user there's not much point
in keeping the function.
Fixes: cdc78b1d6bd7b ("nft: convert rule into a command state structure")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit cf14b92bc1a3f5040437234dffe5cf6aa59711a5)
---
iptables/nft-shared.c | 15 ---------------
iptables/nft-shared.h | 1 -
2 files changed, 16 deletions(-)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 4253b08196d29..f270f610a8f67 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -373,21 +373,6 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->h->ops->parse_match(match, ctx->cs);
}
-void print_proto(uint16_t proto, int invert)
-{
- const struct protoent *pent = getprotobynumber(proto);
-
- if (invert)
- printf("! ");
-
- if (pent) {
- printf("-p %s ", pent->p_name);
- return;
- }
-
- printf("-p %u ", proto);
-}
-
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
{
uint32_t len;
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 6fc81d9ce08ef..519118a2daf6c 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -139,7 +139,6 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *iniface_mask, char *outiface,
unsigned char *outiface_mask, uint8_t *invflags);
-void print_proto(uint16_t proto, int invert);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
void nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
--
2.40.0

@ -0,0 +1,48 @@
From 9b1dc489369e19ffd78a69de31f4ac653070eaf8 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Sat, 6 Nov 2021 01:32:47 +0100
Subject: [PATCH] xshared: Make load_proto() static
The last outside users vanished ten years ago.
Fixes: 449cdd6bcc8d1 ("src: combine default_command functions")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 7213561d9d7a17c4db29c867b2607241941dae5a)
Conflicts:
iptables/xshared.h
-> Context change due to missing commit 3664249f52030
("xshared: Eliminate iptables_command_state->invert").
---
iptables/xshared.c | 2 +-
iptables/xshared.h | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 5ae158908b109..26e938309eab3 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -106,7 +106,7 @@ static bool should_load_proto(struct iptables_command_state *cs)
return !cs->proto_used;
}
-struct xtables_match *load_proto(struct iptables_command_state *cs)
+static struct xtables_match *load_proto(struct iptables_command_state *cs)
{
if (!should_load_proto(cs))
return NULL;
diff --git a/iptables/xshared.h b/iptables/xshared.h
index 10f6e0b5a0e98..d80c8beee1894 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -155,7 +155,6 @@ extern void print_extension_helps(const struct xtables_target *,
extern const char *proto_to_name(uint16_t, int);
extern int command_default(struct iptables_command_state *,
struct xtables_globals *);
-extern struct xtables_match *load_proto(struct iptables_command_state *);
extern int subcmd_main(int, char **, const struct subcommand *);
extern void xs_init_target(struct xtables_target *);
extern void xs_init_match(struct xtables_match *);
--
2.40.0

@ -0,0 +1,40 @@
From 4572ecb1f222ec63f0d5669d0924d2cf1e879290 Mon Sep 17 00:00:00 2001
From: Jeremy Sowden <jeremy@azazel.net>
Date: Fri, 1 Oct 2021 18:41:39 +0100
Subject: [PATCH] extensions: libxt_NFLOG: fix `--nflog-prefix` Python
test-cases
The `iptables-save` includes an extra space between `--nflog-prefix` and
the prefix.
The maximum length of prefixes includes the trailing NUL character.
NFLOG silently truncates prefixes which exceed the maximum length.
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit f0d02998883d2efcb316cd6f524e2f7b3c4d055b)
---
extensions/libxt_NFLOG.t | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t
index 933fa22160e59..69b0255a891b1 100644
--- a/extensions/libxt_NFLOG.t
+++ b/extensions/libxt_NFLOG.t
@@ -12,10 +12,8 @@
-j NFLOG --nflog-size 4294967295;=;OK
-j NFLOG --nflog-size 4294967296;;FAIL
-j NFLOG --nflog-size -1;;FAIL
-# ERROR: cannot find: iptables -I INPUT -j NFLOG --nflog-prefix xxxxxx [...]
-# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
-# ERROR: should fail: iptables -A INPUT -j NFLOG --nflog-prefix xxxxxxx [...]
-# -j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;;FAIL
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK
-j NFLOG --nflog-threshold 1;=;OK
# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
# -j NFLOG --nflog-threshold 0;;FAIL
--
2.40.0

@ -0,0 +1,53 @@
From c83d8cec2a2c70776ca569699983f0cf3e11fb99 Mon Sep 17 00:00:00 2001
From: Jeremy Sowden <jeremy@azazel.net>
Date: Fri, 1 Oct 2021 18:41:40 +0100
Subject: [PATCH] extensions: libxt_NFLOG: remove extra space when saving
targets with prefixes
When printing out NFLOG targets an extra space was inserted between
`--nflog-prefix` and the prefix itself:
$ sudo /usr/sbin/iptables -A INPUT -j NFLOG --nflog-prefix test
$ sudo /usr/sbin/iptables-save | grep NFLOG
-A INPUT -j NFLOG --nflog-prefix test
^^
Fixes: 73866357e4a7 ("iptables: do not print trailing whitespaces")
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 05286bab77a6e0f9502e8fb99e1c53ed15663f3f)
---
extensions/libxt_NFLOG.c | 2 +-
extensions/libxt_NFLOG.t | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c
index 02a1b4aa35a3b..80c0263510f1e 100644
--- a/extensions/libxt_NFLOG.c
+++ b/extensions/libxt_NFLOG.c
@@ -78,7 +78,7 @@ static void NFLOG_check(struct xt_fcheck_call *cb)
static void nflog_print(const struct xt_nflog_info *info, char *prefix)
{
if (info->prefix[0] != '\0') {
- printf(" %snflog-prefix ", prefix);
+ printf(" %snflog-prefix", prefix);
xtables_save_string(info->prefix);
}
if (info->group)
diff --git a/extensions/libxt_NFLOG.t b/extensions/libxt_NFLOG.t
index 69b0255a891b1..bc529b19fc3ff 100644
--- a/extensions/libxt_NFLOG.t
+++ b/extensions/libxt_NFLOG.t
@@ -12,8 +12,8 @@
-j NFLOG --nflog-size 4294967295;=;OK
-j NFLOG --nflog-size 4294967296;;FAIL
-j NFLOG --nflog-size -1;;FAIL
--j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
--j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;=;OK
+-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;-j NFLOG --nflog-prefix xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;OK
-j NFLOG --nflog-threshold 1;=;OK
# ERROR: line 13 (should fail: iptables -A INPUT -j NFLOG --nflog-threshold 0
# -j NFLOG --nflog-threshold 0;;FAIL
--
2.40.0

@ -0,0 +1,135 @@
From 84d19c668db246556fac766cff8652ea6f3a4076 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 18 Jan 2022 22:39:08 +0100
Subject: [PATCH] xshared: Fix response to unprivileged users
Expected behaviour in both variants is:
* Print help without error, append extension help if -m and/or -j
options are present
* Indicate lack of permissions in an error message for anything else
With iptables-nft, this was broken basically from day 1. Shared use of
do_parse() then somewhat broke legacy: it started complaining about
inability to create a lock file.
Fix this by making iptables-nft assume extension revision 0 is present
if permissions don't allow to verify. This is consistent with legacy.
Second part is to exit directly after printing help - this avoids having
to make the following code "nop-aware" to prevent privileged actions.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 26ecdf53960658771c0fc582f72a4025e2887f75)
Conflicts:
iptables/xshared.c
-> Adjusted to missing commit 62c3c93d4b0f5
("xshared: Move do_parse to shared space").
---
iptables/nft.c | 5 ++
.../testcases/iptables/0008-unprivileged_0 | 60 +++++++++++++++++++
iptables/xtables.c | 3 +-
3 files changed, 66 insertions(+), 2 deletions(-)
create mode 100755 iptables/tests/shell/testcases/iptables/0008-unprivileged_0
diff --git a/iptables/nft.c b/iptables/nft.c
index ba59cfb8c47af..da9d24f5c86e2 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -3294,6 +3294,11 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
err:
mnl_socket_close(nl);
+ /* pretend revision 0 is valid if not permitted to check -
+ * this is required for printing extension help texts as user */
+ if (ret < 0 && errno == EPERM && rev == 0)
+ return 1;
+
return ret < 0 ? 0 : 1;
}
diff --git a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
new file mode 100755
index 0000000000000..43e3bc8721dbd
--- /dev/null
+++ b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
@@ -0,0 +1,60 @@
+#!/bin/bash
+
+# iptables may print match/target specific help texts
+# help output should work for unprivileged users
+
+run() {
+ echo "running: $*" >&2
+ runuser -u nobody -- "$@"
+}
+
+grep_or_rc() {
+ declare -g rc
+ grep -q "$*" && return 0
+ echo "missing in output: $*" >&2
+ return 1
+}
+
+out=$(run $XT_MULTI iptables --help)
+let "rc+=$?"
+grep_or_rc "iptables -h (print this help information)" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -m limit --help)
+let "rc+=$?"
+grep_or_rc "limit match options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -p tcp --help)
+let "rc+=$?"
+grep_or_rc "tcp match options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "DNAT target options:" <<< "$out"
+let "rc+=$?"
+
+out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "tcp match options:" <<< "$out"
+let "rc+=$?"
+out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
+let "rc+=$?"
+grep_or_rc "DNAT target options:" <<< "$out"
+let "rc+=$?"
+
+
+run $XT_MULTI iptables -L 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+run $XT_MULTI iptables -A FORWARD -p tcp --dport 123 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+run $XT_MULTI iptables -A FORWARD -j DNAT --to-destination 1.2.3.4 2>&1 | \
+ grep_or_rc "Permission denied"
+let "rc+=$?"
+
+exit $rc
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 54f887f80497e..7ef1702a0cd50 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -637,8 +637,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
XTF_TRY_LOAD, &cs->matches);
printhelp(cs->matches);
- p->command = CMD_NONE;
- return;
+ exit(0);
/*
* Option selection
--
2.40.0

@ -0,0 +1,64 @@
From da4e3255df89367a3fcf0625df2f161724ef591c Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 11 Feb 2022 17:39:24 +0100
Subject: [PATCH] libxtables: Register only the highest revision extension
When fully registering extensions, ignore all consecutive ones with same
name and family value. Since commit b3ac87038f4e4 ("libxtables: Make
sure extensions register in revision order"), one may safely assume the
list of pending extensions has highest revision numbers first. Since
iptables is only interested in the highest revision the kernel supports,
registration and compatibility checks may be skipped once the first
matching extension in pending list has validated.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 2dbb49d15fb44ddd521a734eca3be3f940b7c1ba)
---
libxtables/xtables.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 7f40b6f1b327b..3f7b9768897ac 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -668,6 +668,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_match **dptr;
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
+ bool found = false;
if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -686,7 +687,9 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_match(ptr, prev)) {
+ if (!found &&
+ xtables_fully_register_pending_match(ptr, prev)) {
+ found = true;
prev = ptr;
continue;
} else if (prev) {
@@ -788,6 +791,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
struct xtables_target *prev = NULL;
struct xtables_target **dptr;
struct xtables_target *ptr;
+ bool found = false;
/* Standard target? */
if (strcmp(name, "") == 0
@@ -802,7 +806,9 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
- if (xtables_fully_register_pending_target(ptr, prev)) {
+ if (!found &&
+ xtables_fully_register_pending_target(ptr, prev)) {
+ found = true;
prev = ptr;
continue;
} else if (prev) {
--
2.40.0

@ -0,0 +1,84 @@
From 8da52ae6b1eabcbce070e25342c9b5b6f84cbf7f Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 11 Feb 2022 17:47:22 +0100
Subject: [PATCH] Improve error messages for unsupported extensions
If a given extension was not supported by the kernel, iptables would
print a rather confusing error message if extension parameters were
given:
| # rm /lib/modules/$(uname -r)/kernel/net/netfilter/xt_LOG.ko
| # iptables -A FORWARD -j LOG --log-prefix foo
| iptables v1.8.7 (legacy): unknown option "--log-prefix"
Avoid this by pretending extension revision 0 is always supported. It is
the same hack as used to successfully print extension help texts as
unprivileged user, extended to all error codes to serve privileged ones
as well.
In addition, print a warning if kernel rejected revision 0 and it's not
a permissions problem. This helps users find out which extension in a
rule the kernel didn't like.
Finally, the above commands result in these messages:
| Warning: Extension LOG revision 0 not supported, missing kernel module?
| iptables: No chain/target/match by that name.
Or, for iptables-nft:
| Warning: Extension LOG revision 0 not supported, missing kernel module?
| iptables v1.8.7 (nf_tables): RULE_APPEND failed (No such file or directory): rule in chain FORWARD
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 17534cb18ed0a5052dc45c117401251359dba6aa)
---
iptables/nft.c | 12 +++++++++---
libxtables/xtables.c | 7 ++++++-
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index da9d24f5c86e2..2393940d7f64a 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -3294,10 +3294,16 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
err:
mnl_socket_close(nl);
- /* pretend revision 0 is valid if not permitted to check -
- * this is required for printing extension help texts as user */
- if (ret < 0 && errno == EPERM && rev == 0)
+ /* pretend revision 0 is valid -
+ * this is required for printing extension help texts as user, also
+ * helps error messaging on unavailable kernel extension */
+ if (ret < 0 && rev == 0) {
+ if (errno != EPERM)
+ fprintf(stderr,
+ "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
+ name);
return 1;
+ }
return ret < 0 ? 0 : 1;
}
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 3f7b9768897ac..6ded6cc720ea8 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -929,7 +929,12 @@ int xtables_compatible_revision(const char *name, uint8_t revision, int opt)
/* Definitely don't support this? */
if (errno == ENOENT || errno == EPROTONOSUPPORT) {
close(sockfd);
- return 0;
+ /* Pretend revision 0 support for better error messaging */
+ if (revision == 0)
+ fprintf(stderr,
+ "Warning: Extension %s revision 0 not supported, missing kernel module?\n",
+ name);
+ return (revision == 0);
} else if (errno == ENOPROTOOPT) {
close(sockfd);
/* Assume only revision 0 support (old kernel) */
--
2.40.0

@ -0,0 +1,199 @@
From 4f6e933bd26243e2e3c644544d609ada04d46873 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 1 Mar 2022 18:59:31 +0100
Subject: [PATCH] nft: Simplify immediate parsing
Implementations of parse_immediate callback are mostly trivial, the only
relevant part is access to family-specific parts of struct
iptables_command_state when setting goto flag for iptables and
ip6tables. Refactor them into simple set_goto_flag callbacks.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit b5f2faea325a315bfb932ebc634f3298d4824cae)
---
iptables/nft-arp.c | 9 ---------
iptables/nft-bridge.c | 9 ---------
iptables/nft-ipv4.c | 12 +++---------
iptables/nft-ipv6.c | 12 +++---------
iptables/nft-shared.c | 17 +++++++----------
iptables/nft-shared.h | 2 +-
6 files changed, 14 insertions(+), 47 deletions(-)
diff --git a/iptables/nft-arp.c b/iptables/nft-arp.c
index 2a9387a18dffe..d55e06572b283 100644
--- a/iptables/nft-arp.c
+++ b/iptables/nft-arp.c
@@ -182,14 +182,6 @@ static void nft_arp_parse_meta(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
fw->arp.invflags |= flags;
}
-static void nft_arp_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-}
-
static void parse_mask_ipv4(struct nft_xt_ctx *ctx, struct in_addr *mask)
{
mask->s_addr = ctx->bitwise.mask[0];
@@ -552,7 +544,6 @@ struct nft_family_ops nft_family_ops_arp = {
.print_payload = NULL,
.parse_meta = nft_arp_parse_meta,
.parse_payload = nft_arp_parse_payload,
- .parse_immediate = nft_arp_parse_immediate,
.print_header = nft_arp_print_header,
.print_rule = nft_arp_print_rule,
.save_rule = nft_arp_save_rule,
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index c1a2c209cc1aa..94febc9890674 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -284,14 +284,6 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
-{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-}
-
/* return 0 if saddr, 1 if daddr, -1 on error */
static int
lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len)
@@ -922,7 +914,6 @@ struct nft_family_ops nft_family_ops_bridge = {
.print_payload = NULL,
.parse_meta = nft_bridge_parse_meta,
.parse_payload = nft_bridge_parse_payload,
- .parse_immediate = nft_bridge_parse_immediate,
.parse_lookup = nft_bridge_parse_lookup,
.parse_match = nft_bridge_parse_match,
.parse_target = nft_bridge_parse_target,
diff --git a/iptables/nft-ipv4.c b/iptables/nft-ipv4.c
index a5b835b1f681d..76c76b67100ca 100644
--- a/iptables/nft-ipv4.c
+++ b/iptables/nft-ipv4.c
@@ -241,15 +241,9 @@ static void nft_ipv4_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_ipv4_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
+static void nft_ipv4_set_goto_flag(struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-
- if (nft_goto)
- cs->fw.ip.flags |= IPT_F_GOTO;
+ cs->fw.ip.flags |= IPT_F_GOTO;
}
static void print_fragment(unsigned int flags, unsigned int invflags,
@@ -473,7 +467,7 @@ struct nft_family_ops nft_family_ops_ipv4 = {
.is_same = nft_ipv4_is_same,
.parse_meta = nft_ipv4_parse_meta,
.parse_payload = nft_ipv4_parse_payload,
- .parse_immediate = nft_ipv4_parse_immediate,
+ .set_goto_flag = nft_ipv4_set_goto_flag,
.print_header = print_header,
.print_rule = nft_ipv4_print_rule,
.save_rule = nft_ipv4_save_rule,
diff --git a/iptables/nft-ipv6.c b/iptables/nft-ipv6.c
index 46008fc5e762a..fac0f16cfe815 100644
--- a/iptables/nft-ipv6.c
+++ b/iptables/nft-ipv6.c
@@ -180,15 +180,9 @@ static void nft_ipv6_parse_payload(struct nft_xt_ctx *ctx,
}
}
-static void nft_ipv6_parse_immediate(const char *jumpto, bool nft_goto,
- void *data)
+static void nft_ipv6_set_goto_flag(struct iptables_command_state *cs)
{
- struct iptables_command_state *cs = data;
-
- cs->jumpto = jumpto;
-
- if (nft_goto)
- cs->fw6.ipv6.flags |= IP6T_F_GOTO;
+ cs->fw6.ipv6.flags |= IP6T_F_GOTO;
}
static void nft_ipv6_print_rule(struct nft_handle *h, struct nftnl_rule *r,
@@ -415,7 +409,7 @@ struct nft_family_ops nft_family_ops_ipv6 = {
.is_same = nft_ipv6_is_same,
.parse_meta = nft_ipv6_parse_meta,
.parse_payload = nft_ipv6_parse_payload,
- .parse_immediate = nft_ipv6_parse_immediate,
+ .set_goto_flag = nft_ipv6_set_goto_flag,
.print_header = print_header,
.print_rule = nft_ipv6_print_rule,
.save_rule = nft_ipv6_save_rule,
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index f270f610a8f67..894407f7d9b57 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -495,9 +495,7 @@ static void nft_parse_counter(struct nftnl_expr *e, struct xt_counters *counters
static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
- const char *jumpto = NULL;
- bool nft_goto = false;
- void *data = ctx->cs;
+ struct iptables_command_state *cs = ctx->cs;
int verdict;
if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
@@ -520,23 +518,22 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
/* Standard target? */
switch(verdict) {
case NF_ACCEPT:
- jumpto = "ACCEPT";
+ cs->jumpto = "ACCEPT";
break;
case NF_DROP:
- jumpto = "DROP";
+ cs->jumpto = "DROP";
break;
case NFT_RETURN:
- jumpto = "RETURN";
+ cs->jumpto = "RETURN";
break;;
case NFT_GOTO:
- nft_goto = true;
+ if (ctx->h->ops->set_goto_flag)
+ ctx->h->ops->set_goto_flag(cs);
/* fall through */
case NFT_JUMP:
- jumpto = chain;
+ cs->jumpto = chain;
break;
}
-
- ctx->h->ops->parse_immediate(jumpto, nft_goto, data);
}
static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 519118a2daf6c..2c5f2cfc012d5 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -89,7 +89,7 @@ struct nft_family_ops {
void *data);
void (*parse_lookup)(struct nft_xt_ctx *ctx, struct nftnl_expr *e,
void *data);
- void (*parse_immediate)(const char *jumpto, bool nft_goto, void *data);
+ void (*set_goto_flag)(struct iptables_command_state *cs);
void (*print_table_header)(const char *tablename);
void (*print_header)(unsigned int format, const char *chain,
--
2.40.0

@ -0,0 +1,119 @@
From 1a3d13b637e71f1f207eda17f816c58a9425971e Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 1 Mar 2022 19:46:21 +0100
Subject: [PATCH] nft: Speed up immediate parsing
Parsing of rules which jump to a chain pointlessly causes a call to
xtables_find_target() despite the code already knowing the outcome.
Avoid the significant delay for rulesets with many chain jumps by
performing the (standard) target lookup only for accept/drop/return
verdicts.
From a biased test-case on my VM:
| # iptables-nft-save | grep -c -- '-j'
| 133943
| # time ./old/iptables-nft-save >/dev/null
| real 0m45.566s
| user 0m1.308s
| sys 0m8.430s
| # time ./new/iptables-nft-save >/dev/null
| real 0m3.547s
| user 0m0.762s
| sys 0m2.476s
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 07ee529f5a62838d68be59683be99bf6a7cda0f2)
---
iptables/nft-bridge.c | 1 +
iptables/nft-shared.c | 37 ++++++++++++++++++-------------------
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 94febc9890674..9cc6f87b28fe0 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -539,6 +539,7 @@ static void nft_bridge_parse_target(struct xtables_target *t, void *data)
}
cs->target = t;
+ cs->jumpto = t->name;
}
static void nft_rule_to_ebtables_command_state(struct nft_handle *h,
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 894407f7d9b57..6c643a8c06aaa 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -496,6 +496,8 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
{
const char *chain = nftnl_expr_get_str(e, NFTNL_EXPR_IMM_CHAIN);
struct iptables_command_state *cs = ctx->cs;
+ struct xt_entry_target *t;
+ uint32_t size;
int verdict;
if (nftnl_expr_is_set(e, NFTNL_EXPR_IMM_DATA)) {
@@ -532,8 +534,21 @@ static void nft_parse_immediate(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
/* fall through */
case NFT_JUMP:
cs->jumpto = chain;
- break;
+ /* fall through */
+ default:
+ return;
}
+
+ cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
+ if (!cs->target)
+ return;
+
+ size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
+ t = xtables_calloc(1, size);
+ t->u.target_size = size;
+ t->u.user.revision = cs->target->revision;
+ strcpy(t->u.user.name, cs->jumpto);
+ cs->target->t = t;
}
static void nft_parse_limit(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
@@ -661,25 +676,8 @@ void nft_rule_to_iptables_command_state(struct nft_handle *h,
}
}
- if (cs->target != NULL) {
- cs->jumpto = cs->target->name;
- } else if (cs->jumpto != NULL) {
- struct xt_entry_target *t;
- uint32_t size;
-
- cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD);
- if (!cs->target)
- return;
-
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + cs->target->size;
- t = xtables_calloc(1, size);
- t->u.target_size = size;
- t->u.user.revision = cs->target->revision;
- strcpy(t->u.user.name, cs->jumpto);
- cs->target->t = t;
- } else {
+ if (!cs->jumpto)
cs->jumpto = "";
- }
}
void nft_clear_iptables_command_state(struct iptables_command_state *cs)
@@ -968,6 +966,7 @@ void nft_ipv46_parse_target(struct xtables_target *t, void *data)
struct iptables_command_state *cs = data;
cs->target = t;
+ cs->jumpto = t->name;
}
void nft_check_xt_legacy(int family, bool is_ipt_save)
--
2.40.0

@ -0,0 +1,104 @@
From 38ddff6cd616cf9d6869bcf8fa3c01e186446cb4 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 1 Mar 2022 23:05:29 +0100
Subject: [PATCH] xshared: Prefer xtables_chain_protos lookup over getprotoent
When dumping a large ruleset, common protocol matches such as for TCP
port number significantly slow down rule printing due to repeated calls
for getprotobynumber(). The latter does not involve any caching, so
/etc/protocols is consulted over and over again.
As a simple countermeasure, make functions converting between proto
number and name prefer the built-in list of "well-known" protocols. This
is not a perfect solution, repeated rules for protocol names libxtables
does not cache (e.g. igmp or dccp) will still be slow. Implementing
getprotoent() result caching could solve this.
As a side-effect, explicit check for pseudo-protocol "all" may be
dropped as it is contained in the built-in list and therefore immutable.
Also update xtables_chain_protos entries a bit to align with typical
/etc/protocols contents. The testsuite assumes those names, so the
preferred ones prior to this patch are indeed uncommon nowadays.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit b6196c7504d4d41827cea86c167926125cdbf1f3)
---
iptables/xshared.c | 8 ++++----
libxtables/xtables.c | 19 ++++++-------------
2 files changed, 10 insertions(+), 17 deletions(-)
diff --git a/iptables/xshared.c b/iptables/xshared.c
index 26e938309eab3..f7581967efc28 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -52,16 +52,16 @@ proto_to_name(uint16_t proto, int nolookup)
{
unsigned int i;
+ for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
+ if (xtables_chain_protos[i].num == proto)
+ return xtables_chain_protos[i].name;
+
if (proto && !nolookup) {
struct protoent *pent = getprotobynumber(proto);
if (pent)
return pent->p_name;
}
- for (i = 0; xtables_chain_protos[i].name != NULL; ++i)
- if (xtables_chain_protos[i].num == proto)
- return xtables_chain_protos[i].name;
-
return NULL;
}
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 6ded6cc720ea8..cb380ad61ccb5 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -2077,10 +2077,11 @@ const struct xtables_pprot xtables_chain_protos[] = {
{"udp", IPPROTO_UDP},
{"udplite", IPPROTO_UDPLITE},
{"icmp", IPPROTO_ICMP},
- {"icmpv6", IPPROTO_ICMPV6},
{"ipv6-icmp", IPPROTO_ICMPV6},
+ {"icmpv6", IPPROTO_ICMPV6},
{"esp", IPPROTO_ESP},
{"ah", IPPROTO_AH},
+ {"mobility-header", IPPROTO_MH},
{"ipv6-mh", IPPROTO_MH},
{"mh", IPPROTO_MH},
{"all", 0},
@@ -2096,23 +2097,15 @@ xtables_parse_protocol(const char *s)
if (xtables_strtoui(s, NULL, &proto, 0, UINT8_MAX))
return proto;
- /* first deal with the special case of 'all' to prevent
- * people from being able to redefine 'all' in nsswitch
- * and/or provoke expensive [not working] ldap/nis/...
- * lookups */
- if (strcmp(s, "all") == 0)
- return 0;
+ for (i = 0; xtables_chain_protos[i].name != NULL; ++i) {
+ if (strcmp(s, xtables_chain_protos[i].name) == 0)
+ return xtables_chain_protos[i].num;
+ }
pent = getprotobyname(s);
if (pent != NULL)
return pent->p_proto;
- for (i = 0; i < ARRAY_SIZE(xtables_chain_protos); ++i) {
- if (xtables_chain_protos[i].name == NULL)
- continue;
- if (strcmp(s, xtables_chain_protos[i].name) == 0)
- return xtables_chain_protos[i].num;
- }
xt_params->exit_err(PARAMETER_PROBLEM,
"unknown protocol \"%s\" specified", s);
return -1;
--
2.40.0

@ -0,0 +1,41 @@
From f6915482a365373c5892752f87086740b84fe2d3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 15 Mar 2022 12:17:25 +0100
Subject: [PATCH] libxtables: Fix for warning in xtables_ipmask_to_numeric
Gcc complains:
| xtables.c: In function 'xtables_ipmask_to_numeric':
| xtables.c:1491:34: warning: '__builtin___sprintf_chk' may write a terminating nul past the end of the destination [-Wformat-overflow=]
| 1491 | sprintf(buf, "/%s", xtables_ipaddr_to_numeric(mask));
| | ^
Indeed, xtables_ipaddr_to_numeric() returns a pointer to a 20 byte
buffer and xtables_ipmask_to_numeric() writes its content into a buffer
of same size at offset 1. Yet length of returned string is deterministic
as it is an IPv4 address. So shrink it to the minimum of 16 bytes which
eliminates the warning as well.
Fixes: a96166c24eaac ("libxtables: add xtables_ip[6]mask_to_cidr")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 0c8e253595bd80e4ddd73230d079e33cd5420b32)
---
libxtables/xtables.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index cb380ad61ccb5..2e6c68292f16a 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -1389,7 +1389,7 @@ void xtables_param_act(unsigned int status, const char *p1, ...)
const char *xtables_ipaddr_to_numeric(const struct in_addr *addrp)
{
- static char buf[20];
+ static char buf[16];
const unsigned char *bytep = (const void *)&addrp->s_addr;
sprintf(buf, "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
--
2.40.0

@ -0,0 +1,118 @@
From 0a2bf490dde3b55fd2607976aa07a853a18e15f7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 16 Mar 2022 17:14:07 +0100
Subject: [PATCH] nft: Reject standard targets as chain names when restoring
Reuse parse_chain() called from do_parse() for '-N' and rename it for a
better description of what it does.
Note that by itself, this patch will likely kill iptables-restore
performance for big rulesets due to the extra extension lookup for chain
lines. A following patch announcing those chains to libxtables will
alleviate that.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit b1aee6b2238794446feba41778f88703784560f7)
Conflicts:
iptables/xshared.c
-> Context change due to missing commit 9dc50b5b8e441
("xshared: Merge invflags handling code").
-> Adjust to missing commits 62c3c93d4b0f5
("xshared: Move do_parse to shared space"), 9baf3bf0e77da
("iptables: Use xtables' do_parse() function") and 5c2c2eea2fff3
("ip6tables: Use the shared do_parse, too").
---
iptables/ip6tables.c | 2 +-
iptables/iptables.c | 2 +-
iptables/xshared.c | 2 +-
iptables/xshared.h | 2 +-
iptables/xtables-restore.c | 5 +----
iptables/xtables.c | 2 +-
6 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/iptables/ip6tables.c b/iptables/ip6tables.c
index 6db91c807bcea..897f30d5ef4b0 100644
--- a/iptables/ip6tables.c
+++ b/iptables/ip6tables.c
@@ -1156,7 +1156,7 @@ int do_command6(int argc, char *argv[], char **table,
break;
case 'N':
- parse_chain(optarg);
+ assert_valid_chain_name(optarg);
add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
cs.invert);
chain = optarg;
diff --git a/iptables/iptables.c b/iptables/iptables.c
index a33416a887ed4..9964d14ed8195 100644
--- a/iptables/iptables.c
+++ b/iptables/iptables.c
@@ -1153,7 +1153,7 @@ int do_command4(int argc, char *argv[], char **table,
break;
case 'N':
- parse_chain(optarg);
+ assert_valid_chain_name(optarg);
add_command(&command, CMD_NEW_CHAIN, CMD_NONE,
cs.invert);
chain = optarg;
diff --git a/iptables/xshared.c b/iptables/xshared.c
index f7581967efc28..b052b849b2069 100644
--- a/iptables/xshared.c
+++ b/iptables/xshared.c
@@ -849,7 +849,7 @@ char opt2char(int option)
return *ptr;
}
-void parse_chain(const char *chainname)
+void assert_valid_chain_name(const char *chainname)
{
const char *ptr;
diff --git a/iptables/xshared.h b/iptables/xshared.h
index d80c8beee1894..c512f20afd33a 100644
--- a/iptables/xshared.h
+++ b/iptables/xshared.h
@@ -222,7 +222,7 @@ char cmd2char(int option);
void add_command(unsigned int *cmd, const int newcmd,
const int othercmds, int invert);
int parse_rulenumber(const char *rule);
-void parse_chain(const char *chainname);
+void assert_valid_chain_name(const char *chainname);
void generic_opt_check(int command, int options);
char opt2char(int option);
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index a3bb4f00e79c6..5d0e44843b285 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -156,10 +156,7 @@ static void xtables_restore_parse_line(struct nft_handle *h,
"%s: line %u chain name invalid\n",
xt_params->program_name, line);
- if (strlen(chain) >= XT_EXTENSION_MAXNAMELEN)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid chain name `%s' (%u chars max)",
- chain, XT_EXTENSION_MAXNAMELEN - 1);
+ assert_valid_chain_name(chain);
policy = strtok(NULL, " \t\n");
DEBUGP("line %u, policy '%s'\n", line, policy);
diff --git a/iptables/xtables.c b/iptables/xtables.c
index 7ef1702a0cd50..3c7b3fc45b6f6 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -587,7 +587,7 @@ void do_parse(struct nft_handle *h, int argc, char *argv[],
break;
case 'N':
- parse_chain(optarg);
+ assert_valid_chain_name(optarg);
add_command(&p->command, CMD_NEW_CHAIN, CMD_NONE,
cs->invert);
p->chain = optarg;
--
2.40.0

@ -0,0 +1,140 @@
From 064d7af6927b7b47d13d7fa7ad815f99d83d5006 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 15 Dec 2020 15:40:56 +0100
Subject: [PATCH] libxtables: Implement notargets hash table
Target lookup is relatively costly due to the filesystem access. Avoid
this overhead in huge rulesets which contain many chain jumps by caching
the failed lookups into a hashtable for later.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit f58b0d7406451afbb4b9b6c7888990c964fa7c79)
---
libxtables/xtables.c | 75 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 2e6c68292f16a..b2b3eddf78dbc 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -48,6 +48,7 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <libiptc/libxtc.h>
+#include <libiptc/linux_list.h>
#ifndef NO_SHARED_LIBS
#include <dlfcn.h>
@@ -242,6 +243,71 @@ static void dlreg_free(void)
}
#endif
+struct notarget {
+ struct hlist_node node;
+ char name[];
+};
+
+#define NOTARGET_HSIZE 512
+static struct hlist_head notargets[NOTARGET_HSIZE];
+
+static void notargets_hlist_init(void)
+{
+ int i;
+
+ for (i = 0; i < NOTARGET_HSIZE; i++)
+ INIT_HLIST_HEAD(&notargets[i]);
+}
+
+static void notargets_hlist_free(void)
+{
+ struct hlist_node *pos, *n;
+ struct notarget *cur;
+ int i;
+
+ for (i = 0; i < NOTARGET_HSIZE; i++) {
+ hlist_for_each_entry_safe(cur, pos, n, &notargets[i], node) {
+ hlist_del(&cur->node);
+ free(cur);
+ }
+ }
+}
+
+static uint32_t djb_hash(const char *key)
+{
+ uint32_t i, hash = 5381;
+
+ for (i = 0; i < strlen(key); i++)
+ hash = ((hash << 5) + hash) + key[i];
+
+ return hash;
+}
+
+static struct notarget *notargets_hlist_lookup(const char *name)
+{
+ uint32_t key = djb_hash(name) % NOTARGET_HSIZE;
+ struct hlist_node *node;
+ struct notarget *cur;
+
+ hlist_for_each_entry(cur, node, &notargets[key], node) {
+ if (!strcmp(name, cur->name))
+ return cur;
+ }
+ return NULL;
+}
+
+static void notargets_hlist_insert(const char *name)
+{
+ struct notarget *cur;
+
+ if (!name)
+ return;
+
+ cur = xtables_malloc(sizeof(*cur) + strlen(name) + 1);
+ strcpy(cur->name, name);
+ hlist_add_head(&cur->node, &notargets[djb_hash(name) % NOTARGET_HSIZE]);
+}
+
void xtables_init(void)
{
xtables_libdir = getenv("XTABLES_LIBDIR");
@@ -267,6 +333,8 @@ void xtables_init(void)
return;
}
xtables_libdir = XTABLES_LIBDIR;
+
+ notargets_hlist_init();
}
void xtables_fini(void)
@@ -274,6 +342,7 @@ void xtables_fini(void)
#ifndef NO_SHARED_LIBS
dlreg_free();
#endif
+ notargets_hlist_free();
}
void xtables_set_nfproto(uint8_t nfproto)
@@ -800,6 +869,10 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
|| strcmp(name, XTC_LABEL_QUEUE) == 0
|| strcmp(name, XTC_LABEL_RETURN) == 0)
name = "standard";
+ /* known non-target? */
+ else if (notargets_hlist_lookup(name) &&
+ tryload != XTF_LOAD_MUST_SUCCEED)
+ return NULL;
/* Trigger delayed initialization */
for (dptr = &xtables_pending_targets; *dptr; ) {
@@ -865,6 +938,8 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (ptr)
ptr->used = 1;
+ else
+ notargets_hlist_insert(name);
return ptr;
}
--
2.40.0

@ -0,0 +1,86 @@
From 2fb92babbf460de158cc435f66c46f0642763193 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 4 Mar 2022 12:50:01 +0100
Subject: [PATCH] libxtables: Boost rule target checks by announcing chain
names
When restoring a ruleset, feed libxtables with chain names from
respective lines to avoid an extension search.
While the user's intention is clear, this effectively disables the
sanity check for clashes with target extensions. But:
* The check yielded only a warning and the clashing chain was finally
accepted.
* Users crafting iptables dumps for feeding into iptables-restore likely
know what they're doing.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit ac4c84cc63d3cc021ca532692885a644fcde4518)
---
include/xtables.h | 3 +++
iptables/iptables-restore.c | 1 +
iptables/xtables-restore.c | 1 +
libxtables/xtables.c | 6 ++++++
4 files changed, 11 insertions(+)
diff --git a/include/xtables.h b/include/xtables.h
index a7b36979398ba..3c0d0f78e8d1a 100644
--- a/include/xtables.h
+++ b/include/xtables.h
@@ -633,6 +633,9 @@ void xt_xlate_add_comment(struct xt_xlate *xl, const char *comment);
const char *xt_xlate_get_comment(struct xt_xlate *xl);
const char *xt_xlate_get(struct xt_xlate *xl);
+/* informed target lookups */
+void xtables_announce_chain(const char *name);
+
#ifdef XTABLES_INTERNAL
/* Shipped modules rely on this... */
diff --git a/iptables/iptables-restore.c b/iptables/iptables-restore.c
index cc2c2b8b10086..a34d95015c93c 100644
--- a/iptables/iptables-restore.c
+++ b/iptables/iptables-restore.c
@@ -311,6 +311,7 @@ ip46tables_restore_main(const struct iptables_restore_cb *cb,
cb->ops->strerror(errno));
}
+ xtables_announce_chain(chain);
ret = 1;
} else if (in_table) {
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 5d0e44843b285..b3c8dbaa7e2cc 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -156,6 +156,7 @@ static void xtables_restore_parse_line(struct nft_handle *h,
"%s: line %u chain name invalid\n",
xt_params->program_name, line);
+ xtables_announce_chain(chain);
assert_valid_chain_name(chain);
policy = strtok(NULL, " \t\n");
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index b2b3eddf78dbc..803551053c15f 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -308,6 +308,12 @@ static void notargets_hlist_insert(const char *name)
hlist_add_head(&cur->node, &notargets[djb_hash(name) % NOTARGET_HSIZE]);
}
+void xtables_announce_chain(const char *name)
+{
+ if (!notargets_hlist_lookup(name))
+ notargets_hlist_insert(name);
+}
+
void xtables_init(void)
{
xtables_libdir = getenv("XTABLES_LIBDIR");
--
2.40.0

@ -0,0 +1,31 @@
From ef0405f9267dc23f51bb2b84e63e31ba484f3196 Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 21 Apr 2022 16:53:33 +0200
Subject: [PATCH] nft-shared: update context register for bitwise expression
Update the destination register, otherwise nft_parse_cmp() gives up on
interpreting the cmp expression when bitwise sreg != dreg.
Fixes: 2c4a34c30cb4 ("iptables-compat: fix address prefix")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
(cherry picked from commit 4c70c42fe8d937a2ca2709daa9efe96275d194da)
---
iptables/nft-shared.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 6c643a8c06aaa..2b934ffc17756 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -459,6 +459,8 @@ static void nft_parse_bitwise(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
if (ctx->reg && reg != ctx->reg)
return;
+ reg = nftnl_expr_get_u32(e, NFTNL_EXPR_BITWISE_DREG);
+ ctx->reg = reg;
data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_XOR, &len);
memcpy(ctx->bitwise.xor, data, len);
data = nftnl_expr_get(e, NFTNL_EXPR_BITWISE_MASK, &len);
--
2.40.0

@ -0,0 +1,29 @@
From 1f7fa039057778f229c5190d816551bf75955d5a Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 5 May 2022 18:00:14 +0200
Subject: [PATCH] extensions: MARK: Drop extra newline at end of help
Fixes: f4b737fb0c52a ("libxt_MARK r2")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit adbfec0b3e3275ea5e7c933b630756cf01a4f8c6)
---
extensions/libxt_MARK.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c
index b765af6c35304..1536563d0f4c7 100644
--- a/extensions/libxt_MARK.c
+++ b/extensions/libxt_MARK.c
@@ -77,8 +77,7 @@ static void mark_tg_help(void)
" --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n"
" --and-mark bits Binary AND the nfmark with bits\n"
" --or-mark bits Binary OR the nfmark with bits\n"
-" --xor-mark bits Binary XOR the nfmark with bits\n"
-"\n");
+" --xor-mark bits Binary XOR the nfmark with bits\n");
}
static void MARK_parse_v0(struct xt_option_call *cb)
--
2.40.0

@ -0,0 +1,28 @@
From 32ae030336b73b57ebe0f5e74ea17e09834f3870 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 24 Mar 2022 11:06:24 +0100
Subject: [PATCH] extensions: LOG: Document --log-macdecode in man page
Help text already contains it, so no update needed there.
Fixes: 127647892c7ca ("extensions: libipt_LOG/libip6t_LOG: support macdecode option")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit ce9195c6e2fa6c6daa3c34b94353a539237b3809)
---
extensions/libxt_LOG.man | 3 +++
1 file changed, 3 insertions(+)
diff --git a/extensions/libxt_LOG.man b/extensions/libxt_LOG.man
index 354edf4cc2916..1d5071ba720b9 100644
--- a/extensions/libxt_LOG.man
+++ b/extensions/libxt_LOG.man
@@ -30,3 +30,6 @@ Log options from the IP/IPv6 packet header.
.TP
\fB\-\-log\-uid\fP
Log the userid of the process which generated the packet.
+.TP
+\fB\-\-log\-macdecode\fP
+Log MAC addresses and protocol.
--
2.40.0

@ -0,0 +1,65 @@
From 26dc3496694dc71c95164b6885c7422196802c6d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 4 May 2022 11:19:16 +0200
Subject: [PATCH] nft: Fix EPERM handling for extensions without rev 0
Treating revision 0 as compatible in EPERM case works fine as long as
there is a revision 0 of that extension defined in DSO. Fix the code for
others: Extend the EPERM handling to all revisions and keep the existing
warning for revision 0.
Fixes: 17534cb18ed0a ("Improve error messages for unsupported extensions")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 8468fd4f7c85c21ab375402bc80d0188412b6cbf)
---
iptables/nft.c | 11 +++++++----
.../shell/testcases/iptables/0008-unprivileged_0 | 6 ++++++
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/iptables/nft.c b/iptables/nft.c
index 2393940d7f64a..c130369f78348 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -3294,15 +3294,18 @@ int nft_compatible_revision(const char *name, uint8_t rev, int opt)
err:
mnl_socket_close(nl);
- /* pretend revision 0 is valid -
+ /* ignore EPERM and errors for revision 0 -
* this is required for printing extension help texts as user, also
* helps error messaging on unavailable kernel extension */
- if (ret < 0 && rev == 0) {
- if (errno != EPERM)
+ if (ret < 0) {
+ if (errno == EPERM)
+ return 1;
+ if (rev == 0) {
fprintf(stderr,
"Warning: Extension %s revision 0 not supported, missing kernel module?\n",
name);
- return 1;
+ return 1;
+ }
}
return ret < 0 ? 0 : 1;
diff --git a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0 b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
index 43e3bc8721dbd..983531fef4720 100755
--- a/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
+++ b/iptables/tests/shell/testcases/iptables/0008-unprivileged_0
@@ -35,6 +35,12 @@ let "rc+=$?"
grep_or_rc "DNAT target options:" <<< "$out"
let "rc+=$?"
+# TEE has no revision 0
+out=$(run $XT_MULTI iptables -j TEE --help)
+let "rc+=$?"
+grep_or_rc "TEE target options:" <<< "$out"
+let "rc+=$?"
+
out=$(run $XT_MULTI iptables -p tcp -j DNAT --help)
let "rc+=$?"
grep_or_rc "tcp match options:" <<< "$out"
--
2.40.0

@ -0,0 +1,61 @@
From a40839b6c6d5d9742a5316ed3b4bd13516537ee1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 2 Jun 2022 13:44:45 +0200
Subject: [PATCH] tests: shell: Check overhead in iptables-save and -restore
Some repeated calls have been reduced recently, assert this in a test
evaluating strace output.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 0416ae5dea134b33e22c97e68b64010d679debe1)
---
.../shell/testcases/ipt-save/0007-overhead_0 | 37 +++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100755 iptables/tests/shell/testcases/ipt-save/0007-overhead_0
diff --git a/iptables/tests/shell/testcases/ipt-save/0007-overhead_0 b/iptables/tests/shell/testcases/ipt-save/0007-overhead_0
new file mode 100755
index 0000000000000..b86d71f209471
--- /dev/null
+++ b/iptables/tests/shell/testcases/ipt-save/0007-overhead_0
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# Test recent performance improvements in iptables-save due to reduced
+# overhead.
+
+strace --version >/dev/null || { echo "skip for missing strace"; exit 0; }
+
+RULESET=$(
+ echo "*filter"
+ for ((i = 0; i < 100; i++)); do
+ echo ":mychain$i -"
+ echo "-A FORWARD -p tcp --dport 22 -j mychain$i"
+ done
+ echo "COMMIT"
+)
+
+RESTORE_STRACE=$(strace $XT_MULTI iptables-restore <<< "$RULESET" 2>&1 >/dev/null)
+SAVE_STRACE=$(strace $XT_MULTI iptables-save 2>&1 >/dev/null)
+
+do_grep() { # (name, threshold, pattern)
+ local cnt=$(grep -c "$3")
+ [[ $cnt -le $2 ]] && return 0
+ echo "ERROR: Too many $3 lookups for $1: $cnt > $2"
+ exit 1
+}
+
+# iptables prefers hard-coded protocol names instead of looking them up first
+
+do_grep "$XT_MULTI iptables-restore" 0 /etc/protocols <<< "$RESTORE_STRACE"
+do_grep "$XT_MULTI iptables-save" 0 /etc/protocols <<< "$SAVE_STRACE"
+
+# iptables-nft-save pointlessly checked whether chain jumps are targets
+
+do_grep "$XT_MULTI iptables-restore" 10 libxt_ <<< "$RESTORE_STRACE"
+do_grep "$XT_MULTI iptables-save" 10 libxt_ <<< "$SAVE_STRACE"
+
+exit 0
--
2.40.0

@ -0,0 +1,33 @@
From 88416b4ac4fabde5098f2ff22dc634e5e6f6da51 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 1 Jun 2022 19:29:28 +0200
Subject: [PATCH] iptables-legacy: Drop redundant include of xtables-multi.h
The header is included unconditionally first, so no point in doing it a
second time of ENABLE_NFTABLES is defined.
Fixes: be70918eab26e ("xtables: rename xt-multi binaries to -nft, -legacy")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit ef5d0c68261611d72ccecb3ae05c24448fbc91f5)
---
iptables/xtables-legacy-multi.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/iptables/xtables-legacy-multi.c b/iptables/xtables-legacy-multi.c
index 3b7905ff76b13..2c71931551b5c 100644
--- a/iptables/xtables-legacy-multi.c
+++ b/iptables/xtables-legacy-multi.c
@@ -14,10 +14,6 @@
#include "ip6tables-multi.h"
#endif
-#ifdef ENABLE_NFTABLES
-#include "xtables-multi.h"
-#endif
-
static const struct subcommand multi_subcommands[] = {
#ifdef ENABLE_IPV4
{"iptables", iptables_main},
--
2.40.0

@ -0,0 +1,55 @@
From 9fb89d10d071076c3178749b4237c669db93aa39 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 20 May 2021 11:40:18 +0200
Subject: [PATCH] tests: shell: Add some more rules to 0002-verbose-output_0
This increases coverage of function print_match() from 0 to 86.6%.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit a219f8d407ee22d69bf74478b6c7331c602b28c6)
---
.../testcases/ip6tables/0002-verbose-output_0 | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
index 7b0e64686c6b6..7624cbab655ad 100755
--- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
+++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
@@ -9,12 +9,24 @@ RULE1='-i eth2 -o eth3 -s feed:babe::1 -d feed:babe::2 -j ACCEPT'
VOUT1='ACCEPT all opt in eth2 out eth3 feed:babe::1 -> feed:babe::2'
RULE2='-i eth2 -o eth3 -s feed:babe::4 -d feed:babe::5 -j ACCEPT'
VOUT2='ACCEPT all opt in eth2 out eth3 feed:babe::4 -> feed:babe::5'
+RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route'
+VOUT3=' ipv6-icmp opt in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0'
+RULE4='-m dst --dst-len 42 -m rt --rt-type 23'
+VOUT4=' all opt in * out * ::/0 -> ::/0 dst length:42 rt type:23'
+RULE5='-m frag --fragid 1337 -j LOG'
+VOUT5='LOG all opt in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4'
diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -A FORWARD $RULE1)
diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -I FORWARD 2 $RULE2)
+diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI ip6tables -v -A FORWARD $RULE3)
+diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI ip6tables -v -A FORWARD $RULE4)
+diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI ip6tables -v -A FORWARD $RULE5)
diff -u -Z <(echo -e "$VOUT1") <($XT_MULTI ip6tables -v -C FORWARD $RULE1)
diff -u -Z <(echo -e "$VOUT2") <($XT_MULTI ip6tables -v -C FORWARD $RULE2)
+diff -u -Z <(echo -e "$VOUT3") <($XT_MULTI ip6tables -v -C FORWARD $RULE3)
+diff -u -Z <(echo -e "$VOUT4") <($XT_MULTI ip6tables -v -C FORWARD $RULE4)
+diff -u -Z <(echo -e "$VOUT5") <($XT_MULTI ip6tables -v -C FORWARD $RULE5)
EXPECT='Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
@@ -23,6 +35,9 @@ Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all eth2 eth3 feed:babe::1 feed:babe::2
0 0 ACCEPT all eth2 eth3 feed:babe::4 feed:babe::5
+ 0 0 ipv6-icmp * * ::/0 ::/0 ipv6-icmptype 1 code 0
+ 0 0 all * * ::/0 ::/0 dst length:42 rt type:23
+ 0 0 LOG all * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination'
--
2.40.0

@ -0,0 +1,39 @@
From 30c3d8d215c63b7d9244f853c94958a6194153b7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 8 Jun 2022 13:28:10 +0200
Subject: [PATCH] extensions: string: Do not print default --to value
Default value is UINT16_MAX, not 0. Fix the conditional printing.
Fixes: c6fbf41cdd157 ("update string match to reflect new kernel implementation (Pablo Neira)")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 1bfb1d916e467e2bcbc44ce1a50a2be5c12b7ef8)
---
extensions/libxt_string.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c
index 7c6366cbbf1b3..f6496f6403498 100644
--- a/extensions/libxt_string.c
+++ b/extensions/libxt_string.c
@@ -269,7 +269,7 @@ string_print(const void *ip, const struct xt_entry_match *match, int numeric)
printf(" ALGO name %s", info->algo);
if (info->from_offset != 0)
printf(" FROM %u", info->from_offset);
- if (info->to_offset != 0)
+ if (info->to_offset != UINT16_MAX)
printf(" TO %u", info->to_offset);
if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
printf(" ICASE");
@@ -293,7 +293,7 @@ static void string_save(const void *ip, const struct xt_entry_match *match)
printf(" --algo %s", info->algo);
if (info->from_offset != 0)
printf(" --from %u", info->from_offset);
- if (info->to_offset != 0)
+ if (info->to_offset != UINT16_MAX)
printf(" --to %u", info->to_offset);
if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE)
printf(" --icase");
--
2.40.0

@ -0,0 +1,45 @@
From 40096cbbdd59f0bd431395f69bd30ade35ec1427 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Anton=20Luka=20=C5=A0ijanec?= <anton@sijanec.eu>
Date: Wed, 22 Jun 2022 21:56:47 +0200
Subject: [PATCH] xtables-monitor: add missing spaces in printed str
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
when printing the ID and OPTs in iptables/xtables-monitor.c, a space is
missing after the string, thereby concatenating the number with the next
item in the printed PACKET line.
Fixes: d26c538b9a549 ("xtables: add xtables-monitor")
Signed-off-by: Anton Luka Šijanec <anton@sijanec.eu>
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 6c12201b5ff08d9e1524477ff63bb8810198d638)
---
iptables/xtables-monitor.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/iptables/xtables-monitor.c b/iptables/xtables-monitor.c
index 4b9809805fb5b..89c739d5aacd1 100644
--- a/iptables/xtables-monitor.c
+++ b/iptables/xtables-monitor.c
@@ -340,7 +340,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
inet_ntop(AF_INET, &iph->daddr, addrbuf, sizeof(addrbuf));
printf("DST=%s ", addrbuf);
- printf("LEN=%d TOS=0x%x TTL=%d ID=%d", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id));
+ printf("LEN=%d TOS=0x%x TTL=%d ID=%d ", ntohs(iph->tot_len), iph->tos, iph->ttl, ntohs(iph->id));
if (iph->frag_off & htons(0x8000))
printf("CE ");
if (iph->frag_off & htons(IP_DF))
@@ -363,7 +363,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, struct cb_arg *arg
printf("OPT (");
for (i = 0; i < optsize; i++)
printf("%02X", op[i]);
- printf(")");
+ printf(") ");
}
break;
}
--
2.40.0

@ -0,0 +1,91 @@
From a9527fc387066ed774bdce38598d21eb8e52d899 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 30 Jun 2022 18:04:39 +0200
Subject: [PATCH] libxtables: Fix unsupported extension warning corner case
Some extensions are not supported in revision 0 by user space anymore,
for those the warning in xtables_compatible_revision() does not print as
no revision 0 is tried.
To fix this, one has to track if none of the user space supported
revisions were accepted by the kernel. Therefore add respective logic to
xtables_find_{target,match}().
Note that this does not lead to duplicated warnings for unsupported
extensions that have a revision 0 because xtables_compatible_revision()
returns true for them to allow for extension's help output.
For the record, these ip6tables extensions are affected: set/SET,
socket, tos/TOS, TPROXY and SNAT. In addition to that, TEE is affected
for both families.
Fixes: 17534cb18ed0a ("Improve error messages for unsupported extensions")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 552c4a2f9e5706fef5f7abb27d1492a78bbb2a37)
---
libxtables/xtables.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/libxtables/xtables.c b/libxtables/xtables.c
index 803551053c15f..598e43988e1a3 100644
--- a/libxtables/xtables.c
+++ b/libxtables/xtables.c
@@ -744,6 +744,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
struct xtables_match *ptr;
const char *icmp6 = "icmp6";
bool found = false;
+ bool seen = false;
if (strlen(name) >= XT_EXTENSION_MAXNAMELEN)
xtables_error(PARAMETER_PROBLEM,
@@ -762,6 +763,7 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
+ seen = true;
if (!found &&
xtables_fully_register_pending_match(ptr, prev)) {
found = true;
@@ -775,6 +777,11 @@ xtables_find_match(const char *name, enum xtables_tryload tryload,
dptr = &((*dptr)->next);
}
+ if (seen && !found)
+ fprintf(stderr,
+ "Warning: Extension %s is not supported, missing kernel module?\n",
+ name);
+
for (ptr = xtables_matches; ptr; ptr = ptr->next) {
if (extension_cmp(name, ptr->name, ptr->family)) {
struct xtables_match *clone;
@@ -867,6 +874,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
struct xtables_target **dptr;
struct xtables_target *ptr;
bool found = false;
+ bool seen = false;
/* Standard target? */
if (strcmp(name, "") == 0
@@ -885,6 +893,7 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
if (extension_cmp(name, (*dptr)->name, (*dptr)->family)) {
ptr = *dptr;
*dptr = (*dptr)->next;
+ seen = true;
if (!found &&
xtables_fully_register_pending_target(ptr, prev)) {
found = true;
@@ -898,6 +907,11 @@ xtables_find_target(const char *name, enum xtables_tryload tryload)
dptr = &((*dptr)->next);
}
+ if (seen && !found)
+ fprintf(stderr,
+ "Warning: Extension %s is not supported, missing kernel module?\n",
+ name);
+
for (ptr = xtables_targets; ptr; ptr = ptr->next) {
if (extension_cmp(name, ptr->name, ptr->family)) {
struct xtables_target *clone;
--
2.40.0

@ -0,0 +1,61 @@
From f41e10de4d82377b01e0db057bde3e68159f7531 Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Sat, 23 Jul 2022 20:25:49 +0200
Subject: [PATCH] extensions: libxt_conntrack: remove always-false conditionals
libxt_conntrack.c:1292: warning: the comparison will always evaluate as
false for the address of origsrc_addr will never be NULL [-Waddress]
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit e88085ac41b4c962e1d85dcc8dc6fa0d1f80dc12)
---
extensions/libxt_conntrack.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c
index 91f9e4aa994f8..6ab5c99133d3c 100644
--- a/extensions/libxt_conntrack.c
+++ b/extensions/libxt_conntrack.c
@@ -1297,9 +1297,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_ORIGSRC) {
- if (&sinfo->origsrc_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct original saddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_ORIGSRC ?
"!= " : "");
@@ -1309,9 +1306,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_ORIGDST) {
- if (&sinfo->origdst_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct original daddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_ORIGDST ?
"!= " : "");
@@ -1321,9 +1315,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_REPLSRC) {
- if (&sinfo->replsrc_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct reply saddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_REPLSRC ?
"!= " : "");
@@ -1333,9 +1324,6 @@ static int _conntrack3_mt_xlate(struct xt_xlate *xl,
}
if (sinfo->match_flags & XT_CONNTRACK_REPLDST) {
- if (&sinfo->repldst_addr == 0L)
- return 0;
-
xt_xlate_add(xl, "%sct reply daddr %s", space,
sinfo->invert_flags & XT_CONNTRACK_REPLDST ?
"!= " : "");
--
2.40.0

@ -0,0 +1,958 @@
From 2fd494ffd99924931206c93d5c6d2806df1718ef Mon Sep 17 00:00:00 2001
From: Florian Westphal <fw@strlen.de>
Date: Thu, 22 Sep 2022 13:33:50 +0200
Subject: [PATCH] nft: un-break among match with concatenation
The kernel commit 88cccd908d51 ("netfilter: nf_tables: NFTA_SET_ELEM_KEY_END requires concat and interval flags")
breaks ebtables-nft 'among' emulation, it sets NFTA_SET_ELEM_KEY_END but
doesn't set the CONCAT flag.
Update uapi header and also set CONCAT.
Signed-off-by: Florian Westphal <fw@strlen.de>
(cherry picked from commit 32efb4ffc33ae874b3f26f3380e2184ad6ceb26f)
---
include/linux/netfilter/nf_tables.h | 483 +++++++++++++++++++++++++++-
iptables/nft.c | 2 +-
2 files changed, 476 insertions(+), 9 deletions(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 66dceee0ae307..e94d1fa554cb2 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -8,6 +8,7 @@
#define NFT_SET_MAXNAMELEN NFT_NAME_MAXLEN
#define NFT_OBJ_MAXNAMELEN NFT_NAME_MAXLEN
#define NFT_USERDATA_MAXLEN 256
+#define NFT_OSF_MAXGENRELEN 16
/**
* enum nft_registers - nf_tables registers
@@ -47,6 +48,7 @@ enum nft_registers {
#define NFT_REG_SIZE 16
#define NFT_REG32_SIZE 4
+#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1)
/**
* enum nft_verdicts - nf_tables internal verdicts
@@ -131,7 +133,7 @@ enum nf_tables_msg_types {
* @NFTA_LIST_ELEM: list element (NLA_NESTED)
*/
enum nft_list_attributes {
- NFTA_LIST_UNPEC,
+ NFTA_LIST_UNSPEC,
NFTA_LIST_ELEM,
__NFTA_LIST_MAX
};
@@ -143,12 +145,14 @@ enum nft_list_attributes {
* @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
* @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
* @NFTA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED)
*/
enum nft_hook_attributes {
NFTA_HOOK_UNSPEC,
NFTA_HOOK_HOOKNUM,
NFTA_HOOK_PRIORITY,
NFTA_HOOK_DEV,
+ NFTA_HOOK_DEVS,
__NFTA_HOOK_MAX
};
#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1)
@@ -160,7 +164,10 @@ enum nft_hook_attributes {
*/
enum nft_table_flags {
NFT_TABLE_F_DORMANT = 0x1,
+ NFT_TABLE_F_OWNER = 0x2,
};
+#define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \
+ NFT_TABLE_F_OWNER)
/**
* enum nft_table_attributes - nf_tables table netlink attributes
@@ -168,6 +175,8 @@ enum nft_table_flags {
* @NFTA_TABLE_NAME: name of the table (NLA_STRING)
* @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
* @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
+ * @NFTA_TABLE_USERDATA: user data (NLA_BINARY)
+ * @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32)
*/
enum nft_table_attributes {
NFTA_TABLE_UNSPEC,
@@ -176,10 +185,21 @@ enum nft_table_attributes {
NFTA_TABLE_USE,
NFTA_TABLE_HANDLE,
NFTA_TABLE_PAD,
+ NFTA_TABLE_USERDATA,
+ NFTA_TABLE_OWNER,
__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
+enum nft_chain_flags {
+ NFT_CHAIN_BASE = (1 << 0),
+ NFT_CHAIN_HW_OFFLOAD = (1 << 1),
+ NFT_CHAIN_BINDING = (1 << 2),
+};
+#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \
+ NFT_CHAIN_HW_OFFLOAD | \
+ NFT_CHAIN_BINDING)
+
/**
* enum nft_chain_attributes - nf_tables chain netlink attributes
*
@@ -191,6 +211,9 @@ enum nft_table_attributes {
* @NFTA_CHAIN_USE: number of references to this chain (NLA_U32)
* @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
+ * @NFTA_CHAIN_FLAGS: chain flags
+ * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
+ * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
@@ -203,6 +226,9 @@ enum nft_chain_attributes {
NFTA_CHAIN_TYPE,
NFTA_CHAIN_COUNTERS,
NFTA_CHAIN_PAD,
+ NFTA_CHAIN_FLAGS,
+ NFTA_CHAIN_ID,
+ NFTA_CHAIN_USERDATA,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
@@ -218,6 +244,7 @@ enum nft_chain_attributes {
* @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64)
* @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
* @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
+ * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
*/
enum nft_rule_attributes {
NFTA_RULE_UNSPEC,
@@ -230,6 +257,8 @@ enum nft_rule_attributes {
NFTA_RULE_USERDATA,
NFTA_RULE_PAD,
NFTA_RULE_ID,
+ NFTA_RULE_POSITION_ID,
+ NFTA_RULE_CHAIN_ID,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
@@ -266,8 +295,10 @@ enum nft_rule_compat_attributes {
* @NFT_SET_INTERVAL: set contains intervals
* @NFT_SET_MAP: set is used as a dictionary
* @NFT_SET_TIMEOUT: set uses timeouts
- * @NFT_SET_EVAL: set contains expressions for evaluation
+ * @NFT_SET_EVAL: set can be updated from the evaluation path
* @NFT_SET_OBJECT: set contains stateful objects
+ * @NFT_SET_CONCAT: set contains a concatenation
+ * @NFT_SET_EXPR: set contains expressions
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
@@ -277,6 +308,8 @@ enum nft_set_flags {
NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
NFT_SET_OBJECT = 0x40,
+ NFT_SET_CONCAT = 0x80,
+ NFT_SET_EXPR = 0x100,
};
/**
@@ -294,14 +327,28 @@ enum nft_set_policies {
* enum nft_set_desc_attributes - set element description
*
* @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
+ * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED)
*/
enum nft_set_desc_attributes {
NFTA_SET_DESC_UNSPEC,
NFTA_SET_DESC_SIZE,
+ NFTA_SET_DESC_CONCAT,
__NFTA_SET_DESC_MAX
};
#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
+/**
+ * enum nft_set_field_attributes - attributes of concatenated fields
+ *
+ * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32)
+ */
+enum nft_set_field_attributes {
+ NFTA_SET_FIELD_UNSPEC,
+ NFTA_SET_FIELD_LEN,
+ __NFTA_SET_FIELD_MAX
+};
+#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1)
+
/**
* enum nft_set_attributes - nf_tables set netlink attributes
*
@@ -320,6 +367,8 @@ enum nft_set_desc_attributes {
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
* @NFTA_SET_HANDLE: set handle (NLA_U64)
+ * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -339,6 +388,8 @@ enum nft_set_attributes {
NFTA_SET_PAD,
NFTA_SET_OBJ_TYPE,
NFTA_SET_HANDLE,
+ NFTA_SET_EXPR,
+ NFTA_SET_EXPRESSIONS,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -347,9 +398,11 @@ enum nft_set_attributes {
* enum nft_set_elem_flags - nf_tables set element flags
*
* @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ * @NFT_SET_ELEM_CATCHALL: special catch-all element
*/
enum nft_set_elem_flags {
NFT_SET_ELEM_INTERVAL_END = 0x1,
+ NFT_SET_ELEM_CATCHALL = 0x2,
};
/**
@@ -363,6 +416,8 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
+ * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -375,6 +430,8 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_EXPR,
NFTA_SET_ELEM_PAD,
NFTA_SET_ELEM_OBJREF,
+ NFTA_SET_ELEM_KEY_END,
+ NFTA_SET_ELEM_EXPRESSIONS,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -440,11 +497,13 @@ enum nft_data_attributes {
*
* @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
* @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
*/
enum nft_verdict_attributes {
NFTA_VERDICT_UNSPEC,
NFTA_VERDICT_CODE,
NFTA_VERDICT_CHAIN,
+ NFTA_VERDICT_CHAIN_ID,
__NFTA_VERDICT_MAX
};
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
@@ -477,6 +536,20 @@ enum nft_immediate_attributes {
};
#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1)
+/**
+ * enum nft_bitwise_ops - nf_tables bitwise operations
+ *
+ * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and
+ * XOR boolean operations
+ * @NFT_BITWISE_LSHIFT: left-shift operation
+ * @NFT_BITWISE_RSHIFT: right-shift operation
+ */
+enum nft_bitwise_ops {
+ NFT_BITWISE_BOOL,
+ NFT_BITWISE_LSHIFT,
+ NFT_BITWISE_RSHIFT,
+};
+
/**
* enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
*
@@ -485,16 +558,20 @@ enum nft_immediate_attributes {
* @NFTA_BITWISE_LEN: length of operands (NLA_U32)
* @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes)
* @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops)
+ * @NFTA_BITWISE_DATA: argument for non-boolean operations
+ * (NLA_NESTED: nft_data_attributes)
*
- * The bitwise expression performs the following operation:
+ * The bitwise expression supports boolean and shift operations. It implements
+ * the boolean operations by performing the following operation:
*
* dreg = (sreg & mask) ^ xor
*
- * which allow to express all bitwise operations:
+ * with these mask and xor values:
*
* mask xor
* NOT: 1 1
- * OR: 0 x
+ * OR: ~x x
* XOR: 1 x
* AND: x 0
*/
@@ -505,6 +582,8 @@ enum nft_bitwise_attributes {
NFTA_BITWISE_LEN,
NFTA_BITWISE_MASK,
NFTA_BITWISE_XOR,
+ NFTA_BITWISE_OP,
+ NFTA_BITWISE_DATA,
__NFTA_BITWISE_MAX
};
#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
@@ -631,10 +710,12 @@ enum nft_lookup_attributes {
enum nft_dynset_ops {
NFT_DYNSET_OP_ADD,
NFT_DYNSET_OP_UPDATE,
+ NFT_DYNSET_OP_DELETE,
};
enum nft_dynset_flags {
NFT_DYNSET_F_INV = (1 << 0),
+ NFT_DYNSET_F_EXPR = (1 << 1),
};
/**
@@ -648,6 +729,7 @@ enum nft_dynset_flags {
* @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
* @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_DYNSET_FLAGS: flags (NLA_U32)
+ * @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_dynset_attributes {
NFTA_DYNSET_UNSPEC,
@@ -660,6 +742,7 @@ enum nft_dynset_attributes {
NFTA_DYNSET_EXPR,
NFTA_DYNSET_PAD,
NFTA_DYNSET_FLAGS,
+ NFTA_DYNSET_EXPRESSIONS,
__NFTA_DYNSET_MAX,
};
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
@@ -682,10 +765,12 @@ enum nft_payload_bases {
*
* @NFT_PAYLOAD_CSUM_NONE: no checksumming
* @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
+ * @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309)
*/
enum nft_payload_csum_types {
NFT_PAYLOAD_CSUM_NONE,
NFT_PAYLOAD_CSUM_INET,
+ NFT_PAYLOAD_CSUM_SCTP,
};
enum nft_payload_csum_flags {
@@ -727,10 +812,14 @@ enum nft_exthdr_flags {
*
* @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
* @NFT_EXTHDR_OP_TCP: match against tcp options
+ * @NFT_EXTHDR_OP_IPV4: match against ipv4 options
+ * @NFT_EXTHDR_OP_SCTP: match against sctp chunks
*/
enum nft_exthdr_op {
NFT_EXTHDR_OP_IPV6,
NFT_EXTHDR_OP_TCPOPT,
+ NFT_EXTHDR_OP_IPV4,
+ NFT_EXTHDR_OP_SCTP,
__NFT_EXTHDR_OP_MAX
};
#define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1)
@@ -788,6 +877,15 @@ enum nft_exthdr_attributes {
* @NFT_META_CGROUP: socket control group (skb->sk->sk_classid)
* @NFT_META_PRANDOM: a 32bit pseudo-random number
* @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp)
+ * @NFT_META_IIFKIND: packet input interface kind name (dev->rtnl_link_ops->kind)
+ * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind)
+ * @NFT_META_BRI_IIFPVID: packet input bridge port pvid
+ * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto
+ * @NFT_META_TIME_NS: time since epoch (in nanoseconds)
+ * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday)
+ * @NFT_META_TIME_HOUR: hour of day (in seconds)
+ * @NFT_META_SDIF: slave device interface index
+ * @NFT_META_SDIFNAME: slave device interface name
*/
enum nft_meta_keys {
NFT_META_LEN,
@@ -816,6 +914,15 @@ enum nft_meta_keys {
NFT_META_CGROUP,
NFT_META_PRANDOM,
NFT_META_SECPATH,
+ NFT_META_IIFKIND,
+ NFT_META_OIFKIND,
+ NFT_META_BRI_IIFPVID,
+ NFT_META_BRI_IIFVPROTO,
+ NFT_META_TIME_NS,
+ NFT_META_TIME_DAY,
+ NFT_META_TIME_HOUR,
+ NFT_META_SDIF,
+ NFT_META_SDIFNAME,
};
/**
@@ -825,13 +932,17 @@ enum nft_meta_keys {
* @NFT_RT_NEXTHOP4: routing nexthop for IPv4
* @NFT_RT_NEXTHOP6: routing nexthop for IPv6
* @NFT_RT_TCPMSS: fetch current path tcp mss
+ * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL
*/
enum nft_rt_keys {
NFT_RT_CLASSID,
NFT_RT_NEXTHOP4,
NFT_RT_NEXTHOP6,
NFT_RT_TCPMSS,
+ NFT_RT_XFRM,
+ __NFT_RT_MAX
};
+#define NFT_RT_MAX (__NFT_RT_MAX - 1)
/**
* enum nft_hash_types - nf_tables hash expression types
@@ -854,6 +965,8 @@ enum nft_hash_types {
* @NFTA_HASH_SEED: seed value (NLA_U32)
* @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32)
* @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types)
+ * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_HASH_SET_ID: id of the map (NLA_U32)
*/
enum nft_hash_attributes {
NFTA_HASH_UNSPEC,
@@ -864,6 +977,8 @@ enum nft_hash_attributes {
NFTA_HASH_SEED,
NFTA_HASH_OFFSET,
NFTA_HASH_TYPE,
+ NFTA_HASH_SET_NAME, /* deprecated */
+ NFTA_HASH_SET_ID, /* deprecated */
__NFTA_HASH_MAX,
};
#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
@@ -898,6 +1013,39 @@ enum nft_rt_attributes {
};
#define NFTA_RT_MAX (__NFTA_RT_MAX - 1)
+/**
+ * enum nft_socket_attributes - nf_tables socket expression netlink attributes
+ *
+ * @NFTA_SOCKET_KEY: socket key to match
+ * @NFTA_SOCKET_DREG: destination register
+ * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
+ */
+enum nft_socket_attributes {
+ NFTA_SOCKET_UNSPEC,
+ NFTA_SOCKET_KEY,
+ NFTA_SOCKET_DREG,
+ NFTA_SOCKET_LEVEL,
+ __NFTA_SOCKET_MAX
+};
+#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
+
+/*
+ * enum nft_socket_keys - nf_tables socket expression keys
+ *
+ * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
+ * @NFT_SOCKET_MARK: Value of the socket mark
+ * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
+ * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
+ */
+enum nft_socket_keys {
+ NFT_SOCKET_TRANSPARENT,
+ NFT_SOCKET_MARK,
+ NFT_SOCKET_WILDCARD,
+ NFT_SOCKET_CGROUPV2,
+ __NFT_SOCKET_MAX
+};
+#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
+
/**
* enum nft_ct_keys - nf_tables ct expression keys
*
@@ -909,8 +1057,8 @@ enum nft_rt_attributes {
* @NFT_CT_EXPIRATION: relative conntrack expiration time in ms
* @NFT_CT_HELPER: connection tracking helper assigned to conntrack
* @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol
- * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address)
- * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address)
+ * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address, deprecated)
+ * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address, deprecated)
* @NFT_CT_PROTOCOL: conntrack layer 4 protocol
* @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source
* @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination
@@ -920,6 +1068,11 @@ enum nft_rt_attributes {
* @NFT_CT_AVGPKT: conntrack average bytes per packet
* @NFT_CT_ZONE: conntrack zone
* @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack
+ * @NFT_CT_SRC_IP: conntrack layer 3 protocol source (IPv4 address)
+ * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address)
+ * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address)
+ * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address)
+ * @NFT_CT_ID: conntrack id
*/
enum nft_ct_keys {
NFT_CT_STATE,
@@ -941,7 +1094,14 @@ enum nft_ct_keys {
NFT_CT_AVGPKT,
NFT_CT_ZONE,
NFT_CT_EVENTMASK,
+ NFT_CT_SRC_IP,
+ NFT_CT_DST_IP,
+ NFT_CT_SRC_IP6,
+ NFT_CT_DST_IP6,
+ NFT_CT_ID,
+ __NFT_CT_MAX
};
+#define NFT_CT_MAX (__NFT_CT_MAX - 1)
/**
* enum nft_ct_attributes - nf_tables ct expression netlink attributes
@@ -1002,6 +1162,24 @@ enum nft_limit_attributes {
};
#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1)
+enum nft_connlimit_flags {
+ NFT_CONNLIMIT_F_INV = (1 << 0),
+};
+
+/**
+ * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes
+ *
+ * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32)
+ * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags)
+ */
+enum nft_connlimit_attributes {
+ NFTA_CONNLIMIT_UNSPEC,
+ NFTA_CONNLIMIT_COUNT,
+ NFTA_CONNLIMIT_FLAGS,
+ __NFTA_CONNLIMIT_MAX
+};
+#define NFTA_CONNLIMIT_MAX (__NFTA_CONNLIMIT_MAX - 1)
+
/**
* enum nft_counter_attributes - nf_tables counter expression netlink attributes
*
@@ -1017,6 +1195,21 @@ enum nft_counter_attributes {
};
#define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1)
+/**
+ * enum nft_last_attributes - nf_tables last expression netlink attributes
+ *
+ * @NFTA_LAST_SET: last update has been set, zero means never updated (NLA_U32)
+ * @NFTA_LAST_MSECS: milliseconds since last update (NLA_U64)
+ */
+enum nft_last_attributes {
+ NFTA_LAST_UNSPEC,
+ NFTA_LAST_SET,
+ NFTA_LAST_MSECS,
+ NFTA_LAST_PAD,
+ __NFTA_LAST_MAX
+};
+#define NFTA_LAST_MAX (__NFTA_LAST_MAX - 1)
+
/**
* enum nft_log_attributes - nf_tables log expression netlink attributes
*
@@ -1039,6 +1232,33 @@ enum nft_log_attributes {
};
#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1)
+/**
+ * enum nft_log_level - nf_tables log levels
+ *
+ * @NFT_LOGLEVEL_EMERG: system is unusable
+ * @NFT_LOGLEVEL_ALERT: action must be taken immediately
+ * @NFT_LOGLEVEL_CRIT: critical conditions
+ * @NFT_LOGLEVEL_ERR: error conditions
+ * @NFT_LOGLEVEL_WARNING: warning conditions
+ * @NFT_LOGLEVEL_NOTICE: normal but significant condition
+ * @NFT_LOGLEVEL_INFO: informational
+ * @NFT_LOGLEVEL_DEBUG: debug-level messages
+ * @NFT_LOGLEVEL_AUDIT: enabling audit logging
+ */
+enum nft_log_level {
+ NFT_LOGLEVEL_EMERG,
+ NFT_LOGLEVEL_ALERT,
+ NFT_LOGLEVEL_CRIT,
+ NFT_LOGLEVEL_ERR,
+ NFT_LOGLEVEL_WARNING,
+ NFT_LOGLEVEL_NOTICE,
+ NFT_LOGLEVEL_INFO,
+ NFT_LOGLEVEL_DEBUG,
+ NFT_LOGLEVEL_AUDIT,
+ __NFT_LOGLEVEL_MAX
+};
+#define NFT_LOGLEVEL_MAX (__NFT_LOGLEVEL_MAX - 1)
+
/**
* enum nft_queue_attributes - nf_tables queue expression netlink attributes
*
@@ -1083,6 +1303,21 @@ enum nft_quota_attributes {
};
#define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1)
+/**
+ * enum nft_secmark_attributes - nf_tables secmark object netlink attributes
+ *
+ * @NFTA_SECMARK_CTX: security context (NLA_STRING)
+ */
+enum nft_secmark_attributes {
+ NFTA_SECMARK_UNSPEC,
+ NFTA_SECMARK_CTX,
+ __NFTA_SECMARK_MAX,
+};
+#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1)
+
+/* Max security context length */
+#define NFT_SECMARK_CTX_MAXLEN 256
+
/**
* enum nft_reject_types - nf_tables reject expression reject types
*
@@ -1164,6 +1399,22 @@ enum nft_nat_attributes {
};
#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1)
+/**
+ * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes
+ *
+ * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers)
+ * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers)
+ * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers)
+ */
+enum nft_tproxy_attributes {
+ NFTA_TPROXY_UNSPEC,
+ NFTA_TPROXY_FAMILY,
+ NFTA_TPROXY_REG_ADDR,
+ NFTA_TPROXY_REG_PORT,
+ __NFTA_TPROXY_MAX
+};
+#define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1)
+
/**
* enum nft_masq_attributes - nf_tables masquerade expression attributes
*
@@ -1214,10 +1465,14 @@ enum nft_dup_attributes {
* enum nft_fwd_attributes - nf_tables fwd expression netlink attributes
*
* @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register)
+ * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register)
+ * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto)
*/
enum nft_fwd_attributes {
NFTA_FWD_UNSPEC,
NFTA_FWD_SREG_DEV,
+ NFTA_FWD_SREG_ADDR,
+ NFTA_FWD_NFPROTO,
__NFTA_FWD_MAX
};
#define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1)
@@ -1302,12 +1557,38 @@ enum nft_ct_helper_attributes {
};
#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1)
+enum nft_ct_timeout_timeout_attributes {
+ NFTA_CT_TIMEOUT_UNSPEC,
+ NFTA_CT_TIMEOUT_L3PROTO,
+ NFTA_CT_TIMEOUT_L4PROTO,
+ NFTA_CT_TIMEOUT_DATA,
+ __NFTA_CT_TIMEOUT_MAX,
+};
+#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1)
+
+enum nft_ct_expectation_attributes {
+ NFTA_CT_EXPECT_UNSPEC,
+ NFTA_CT_EXPECT_L3PROTO,
+ NFTA_CT_EXPECT_L4PROTO,
+ NFTA_CT_EXPECT_DPORT,
+ NFTA_CT_EXPECT_TIMEOUT,
+ NFTA_CT_EXPECT_SIZE,
+ __NFTA_CT_EXPECT_MAX,
+};
+#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1)
+
#define NFT_OBJECT_UNSPEC 0
#define NFT_OBJECT_COUNTER 1
#define NFT_OBJECT_QUOTA 2
#define NFT_OBJECT_CT_HELPER 3
#define NFT_OBJECT_LIMIT 4
-#define __NFT_OBJECT_MAX 5
+#define NFT_OBJECT_CONNLIMIT 5
+#define NFT_OBJECT_TUNNEL 6
+#define NFT_OBJECT_CT_TIMEOUT 7
+#define NFT_OBJECT_SECMARK 8
+#define NFT_OBJECT_CT_EXPECT 9
+#define NFT_OBJECT_SYNPROXY 10
+#define __NFT_OBJECT_MAX 11
#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1)
/**
@@ -1319,6 +1600,7 @@ enum nft_ct_helper_attributes {
* @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
* @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
* @NFTA_OBJ_HANDLE: object handle (NLA_U64)
+ * @NFTA_OBJ_USERDATA: user data (NLA_BINARY)
*/
enum nft_object_attributes {
NFTA_OBJ_UNSPEC,
@@ -1329,10 +1611,24 @@ enum nft_object_attributes {
NFTA_OBJ_USE,
NFTA_OBJ_HANDLE,
NFTA_OBJ_PAD,
+ NFTA_OBJ_USERDATA,
__NFTA_OBJ_MAX
};
#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
+/**
+ * enum nft_flowtable_flags - nf_tables flowtable flags
+ *
+ * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled
+ * @NFT_FLOWTABLE_COUNTER: enable flow counters
+ */
+enum nft_flowtable_flags {
+ NFT_FLOWTABLE_HW_OFFLOAD = 0x1,
+ NFT_FLOWTABLE_COUNTER = 0x2,
+ NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD |
+ NFT_FLOWTABLE_COUNTER)
+};
+
/**
* enum nft_flowtable_attributes - nf_tables flow table netlink attributes
*
@@ -1341,6 +1637,7 @@ enum nft_object_attributes {
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
*/
enum nft_flowtable_attributes {
NFTA_FLOWTABLE_UNSPEC,
@@ -1350,6 +1647,7 @@ enum nft_flowtable_attributes {
NFTA_FLOWTABLE_USE,
NFTA_FLOWTABLE_HANDLE,
NFTA_FLOWTABLE_PAD,
+ NFTA_FLOWTABLE_FLAGS,
__NFTA_FLOWTABLE_MAX
};
#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
@@ -1370,6 +1668,42 @@ enum nft_flowtable_hook_attributes {
};
#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1)
+/**
+ * enum nft_osf_attributes - nftables osf expression netlink attributes
+ *
+ * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers)
+ * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8)
+ * @NFTA_OSF_FLAGS: flags (NLA_U32)
+ */
+enum nft_osf_attributes {
+ NFTA_OSF_UNSPEC,
+ NFTA_OSF_DREG,
+ NFTA_OSF_TTL,
+ NFTA_OSF_FLAGS,
+ __NFTA_OSF_MAX,
+};
+#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1)
+
+enum nft_osf_flags {
+ NFT_OSF_F_VERSION = (1 << 0),
+};
+
+/**
+ * enum nft_synproxy_attributes - nf_tables synproxy expression netlink attributes
+ *
+ * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16)
+ * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8)
+ * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32)
+ */
+enum nft_synproxy_attributes {
+ NFTA_SYNPROXY_UNSPEC,
+ NFTA_SYNPROXY_MSS,
+ NFTA_SYNPROXY_WSCALE,
+ NFTA_SYNPROXY_FLAGS,
+ __NFTA_SYNPROXY_MAX,
+};
+#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1)
+
/**
* enum nft_device_attributes - nf_tables device netlink attributes
*
@@ -1382,6 +1716,35 @@ enum nft_devices_attributes {
};
#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1)
+/*
+ * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes
+ *
+ * @NFTA_XFRM_DREG: destination register (NLA_U32)
+ * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32)
+ * @NFTA_XFRM_DIR: direction (NLA_U8)
+ * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32)
+ */
+enum nft_xfrm_attributes {
+ NFTA_XFRM_UNSPEC,
+ NFTA_XFRM_DREG,
+ NFTA_XFRM_KEY,
+ NFTA_XFRM_DIR,
+ NFTA_XFRM_SPNUM,
+ __NFTA_XFRM_MAX
+};
+#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1)
+
+enum nft_xfrm_keys {
+ NFT_XFRM_KEY_UNSPEC,
+ NFT_XFRM_KEY_DADDR_IP4,
+ NFT_XFRM_KEY_DADDR_IP6,
+ NFT_XFRM_KEY_SADDR_IP4,
+ NFT_XFRM_KEY_SADDR_IP6,
+ NFT_XFRM_KEY_REQID,
+ NFT_XFRM_KEY_SPI,
+ __NFT_XFRM_KEY_MAX,
+};
+#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1)
/**
* enum nft_trace_attributes - nf_tables trace netlink attributes
@@ -1442,6 +1805,8 @@ enum nft_trace_types {
* @NFTA_NG_MODULUS: maximum counter value (NLA_U32)
* @NFTA_NG_TYPE: operation type (NLA_U32)
* @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32)
+ * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING)
+ * @NFTA_NG_SET_ID: id of the map (NLA_U32)
*/
enum nft_ng_attributes {
NFTA_NG_UNSPEC,
@@ -1449,6 +1814,8 @@ enum nft_ng_attributes {
NFTA_NG_MODULUS,
NFTA_NG_TYPE,
NFTA_NG_OFFSET,
+ NFTA_NG_SET_NAME, /* deprecated */
+ NFTA_NG_SET_ID, /* deprecated */
__NFTA_NG_MAX
};
#define NFTA_NG_MAX (__NFTA_NG_MAX - 1)
@@ -1460,4 +1827,104 @@ enum nft_ng_types {
};
#define NFT_NG_MAX (__NFT_NG_MAX - 1)
+enum nft_tunnel_key_ip_attributes {
+ NFTA_TUNNEL_KEY_IP_UNSPEC,
+ NFTA_TUNNEL_KEY_IP_SRC,
+ NFTA_TUNNEL_KEY_IP_DST,
+ __NFTA_TUNNEL_KEY_IP_MAX
+};
+#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1)
+
+enum nft_tunnel_ip6_attributes {
+ NFTA_TUNNEL_KEY_IP6_UNSPEC,
+ NFTA_TUNNEL_KEY_IP6_SRC,
+ NFTA_TUNNEL_KEY_IP6_DST,
+ NFTA_TUNNEL_KEY_IP6_FLOWLABEL,
+ __NFTA_TUNNEL_KEY_IP6_MAX
+};
+#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1)
+
+enum nft_tunnel_opts_attributes {
+ NFTA_TUNNEL_KEY_OPTS_UNSPEC,
+ NFTA_TUNNEL_KEY_OPTS_VXLAN,
+ NFTA_TUNNEL_KEY_OPTS_ERSPAN,
+ NFTA_TUNNEL_KEY_OPTS_GENEVE,
+ __NFTA_TUNNEL_KEY_OPTS_MAX
+};
+#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
+
+enum nft_tunnel_opts_vxlan_attributes {
+ NFTA_TUNNEL_KEY_VXLAN_UNSPEC,
+ NFTA_TUNNEL_KEY_VXLAN_GBP,
+ __NFTA_TUNNEL_KEY_VXLAN_MAX
+};
+#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1)
+
+enum nft_tunnel_opts_erspan_attributes {
+ NFTA_TUNNEL_KEY_ERSPAN_UNSPEC,
+ NFTA_TUNNEL_KEY_ERSPAN_VERSION,
+ NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX,
+ NFTA_TUNNEL_KEY_ERSPAN_V2_HWID,
+ NFTA_TUNNEL_KEY_ERSPAN_V2_DIR,
+ __NFTA_TUNNEL_KEY_ERSPAN_MAX
+};
+#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
+
+enum nft_tunnel_opts_geneve_attributes {
+ NFTA_TUNNEL_KEY_GENEVE_UNSPEC,
+ NFTA_TUNNEL_KEY_GENEVE_CLASS,
+ NFTA_TUNNEL_KEY_GENEVE_TYPE,
+ NFTA_TUNNEL_KEY_GENEVE_DATA,
+ __NFTA_TUNNEL_KEY_GENEVE_MAX
+};
+#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1)
+
+enum nft_tunnel_flags {
+ NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
+ NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),
+ NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2),
+};
+#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \
+ NFT_TUNNEL_F_DONT_FRAGMENT | \
+ NFT_TUNNEL_F_SEQ_NUMBER)
+
+enum nft_tunnel_key_attributes {
+ NFTA_TUNNEL_KEY_UNSPEC,
+ NFTA_TUNNEL_KEY_ID,
+ NFTA_TUNNEL_KEY_IP,
+ NFTA_TUNNEL_KEY_IP6,
+ NFTA_TUNNEL_KEY_FLAGS,
+ NFTA_TUNNEL_KEY_TOS,
+ NFTA_TUNNEL_KEY_TTL,
+ NFTA_TUNNEL_KEY_SPORT,
+ NFTA_TUNNEL_KEY_DPORT,
+ NFTA_TUNNEL_KEY_OPTS,
+ __NFTA_TUNNEL_KEY_MAX
+};
+#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1)
+
+enum nft_tunnel_keys {
+ NFT_TUNNEL_PATH,
+ NFT_TUNNEL_ID,
+ __NFT_TUNNEL_MAX
+};
+#define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1)
+
+enum nft_tunnel_mode {
+ NFT_TUNNEL_MODE_NONE,
+ NFT_TUNNEL_MODE_RX,
+ NFT_TUNNEL_MODE_TX,
+ __NFT_TUNNEL_MODE_MAX
+};
+#define NFT_TUNNEL_MODE_MAX (__NFT_TUNNEL_MODE_MAX - 1)
+
+enum nft_tunnel_attributes {
+ NFTA_TUNNEL_UNSPEC,
+ NFTA_TUNNEL_KEY,
+ NFTA_TUNNEL_DREG,
+ NFTA_TUNNEL_MODE,
+ __NFTA_TUNNEL_MAX
+};
+#define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1)
+
#endif /* _LINUX_NF_TABLES_H */
diff --git a/iptables/nft.c b/iptables/nft.c
index c130369f78348..0ec7679d25289 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -1086,7 +1086,7 @@ static int __add_nft_among(struct nft_handle *h, const char *table,
type = type << CONCAT_TYPE_BITS | NFT_DATATYPE_IPADDR;
len += sizeof(struct in_addr) + NETLINK_ALIGN - 1;
len &= ~(NETLINK_ALIGN - 1);
- flags = NFT_SET_INTERVAL;
+ flags = NFT_SET_INTERVAL | NFT_SET_CONCAT;
}
s = add_anon_set(h, table, flags, type, len, cnt);
--
2.40.0

@ -0,0 +1,67 @@
From 116427bbf1365e2d284e7410a125205a983c0b1b Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 27 Sep 2022 23:15:37 +0200
Subject: [PATCH] nft-shared: Introduce __get_cmp_data()
This is an inner function to get_cmp_data() returning the op value as-is
for caller examination.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 8dc22798bf813ce92aaac58a6fe8749fe3fc18dc)
Conflicts:
iptables/nft-shared.h
-> Context change due to missing commit aa92ec96078d0
("nft: pass struct nft_xt_ctx to parse_meta()").
---
iptables/nft-shared.c | 17 ++++++++++-------
iptables/nft-shared.h | 1 +
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/iptables/nft-shared.c b/iptables/nft-shared.c
index 2b934ffc17756..cb1c2d61f52c1 100644
--- a/iptables/nft-shared.c
+++ b/iptables/nft-shared.c
@@ -373,17 +373,20 @@ static void nft_parse_match(struct nft_xt_ctx *ctx, struct nftnl_expr *e)
ctx->h->ops->parse_match(match, ctx->cs);
}
-void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
+void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op)
{
uint32_t len;
- uint8_t op;
memcpy(data, nftnl_expr_get(e, NFTNL_EXPR_CMP_DATA, &len), dlen);
- op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
- if (op == NFT_CMP_NEQ)
- *inv = true;
- else
- *inv = false;
+ *op = nftnl_expr_get_u32(e, NFTNL_EXPR_CMP_OP);
+}
+
+void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv)
+{
+ uint8_t op;
+
+ __get_cmp_data(e, data, dlen, &op);
+ *inv = (op == NFT_CMP_NEQ);
}
static void nft_meta_set_to_target(struct nft_xt_ctx *ctx)
diff --git a/iptables/nft-shared.h b/iptables/nft-shared.h
index 2c5f2cfc012d5..3531631bd8acd 100644
--- a/iptables/nft-shared.h
+++ b/iptables/nft-shared.h
@@ -139,6 +139,7 @@ bool is_same_interfaces(const char *a_iniface, const char *a_outiface,
int parse_meta(struct nftnl_expr *e, uint8_t key, char *iniface,
unsigned char *iniface_mask, char *outiface,
unsigned char *outiface_mask, uint8_t *invflags);
+void __get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, uint8_t *op);
void get_cmp_data(struct nftnl_expr *e, void *data, size_t dlen, bool *inv);
void nft_rule_to_iptables_command_state(struct nft_handle *h,
const struct nftnl_rule *r,
--
2.40.0

@ -0,0 +1,228 @@
From 07007c27ceebffcb6e3223768fa876c907b0d55d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Tue, 27 Sep 2022 23:19:34 +0200
Subject: [PATCH] ebtables: Support '-p Length'
To match on Ethernet frames using the etherproto field as length value,
ebtables accepts the special protocol name "LENGTH". Implement this in
ebtables-nft using a native match for 'ether type < 0x0600'.
Since extension 802_3 matches are valid only with such Ethernet frames,
add a local add_match() wrapper which complains if the extension is used
without '-p Length' parameter. Legacy ebtables does this within the
extension's final_check callback, but it's not possible here due for lack of
fw->bitmask field access.
While being at it, add xlate support, adjust tests and make ebtables-nft
print the case-insensitive argument with capital 'L' like legacy
ebtables does.
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit aa0b8b03f7c7e741ccd96360bd64d90ea8c3c3aa)
Conflicts:
iptables/nft-bridge.c
-> Adjusted to missing commit 7e38890c6b4fb
("nft: prepare for dynamic register allocation").
-> Context change due to missing commits 0c0cd4340ed88
("nft: Don't pass command state opaque to family ops callbacks") and
b5881e7f22d42 ("nft: Change whitespace printing in save_rule callback").
---
extensions/generic.txlate | 6 +++
extensions/libebt_802_3.t | 6 ++-
iptables/nft-bridge.c | 47 +++++++++++++++----
.../ebtables/0002-ebtables-save-restore_0 | 12 ++---
4 files changed, 53 insertions(+), 18 deletions(-)
diff --git a/extensions/generic.txlate b/extensions/generic.txlate
index 9ae9a5b54c1b9..6779d6f86dec8 100644
--- a/extensions/generic.txlate
+++ b/extensions/generic.txlate
@@ -67,6 +67,12 @@ nft add rule bridge filter FORWARD iifname != "iname" meta ibrname "ilogname" oi
ebtables-translate -I INPUT -p ip -d 1:2:3:4:5:6/ff:ff:ff:ff:00:00
nft insert rule bridge filter INPUT ether type 0x800 ether daddr 01:02:03:04:00:00 and ff:ff:ff:ff:00:00 == 01:02:03:04:00:00 counter
+ebtables-translate -I INPUT -p Length
+nft insert rule bridge filter INPUT ether type < 0x0600 counter
+
+ebtables-translate -I INPUT -p ! Length
+nft insert rule bridge filter INPUT ether type >= 0x0600 counter
+
# asterisk is not special in iptables and it is even a valid interface name
iptables-translate -A FORWARD -i '*' -o 'eth*foo'
nft add rule ip filter FORWARD iifname "\*" oifname "eth\*foo" counter
diff --git a/extensions/libebt_802_3.t b/extensions/libebt_802_3.t
index ddfb2f0a72baf..a138f35d2c756 100644
--- a/extensions/libebt_802_3.t
+++ b/extensions/libebt_802_3.t
@@ -1,3 +1,5 @@
:INPUT,FORWARD,OUTPUT
---802_3-sap ! 0x0a -j CONTINUE;=;OK
---802_3-type 0x000a -j RETURN;=;OK
+--802_3-sap ! 0x0a -j CONTINUE;=;FAIL
+--802_3-type 0x000a -j RETURN;=;FAIL
+-p Length --802_3-sap ! 0x0a -j CONTINUE;=;OK
+-p Length --802_3-type 0x000a -j RETURN;=;OK
diff --git a/iptables/nft-bridge.c b/iptables/nft-bridge.c
index 9cc6f87b28fe0..fbed1616253a6 100644
--- a/iptables/nft-bridge.c
+++ b/iptables/nft-bridge.c
@@ -129,6 +129,18 @@ static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
return add_action(r, cs, false);
}
+static int
+nft_bridge_add_match(struct nft_handle *h, const struct ebt_entry *fw,
+ 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);
+}
+
static int nft_bridge_add(struct nft_handle *h,
struct nftnl_rule *r, void *data)
{
@@ -172,17 +184,25 @@ static int nft_bridge_add(struct nft_handle *h,
}
if ((fw->bitmask & EBT_NOPROTO) == 0) {
+ uint16_t ethproto = fw->ethproto;
+
op = nft_invflags2cmp(fw->invflags, EBT_IPROTO);
add_payload(r, offsetof(struct ethhdr, h_proto), 2,
NFT_PAYLOAD_LL_HEADER);
- add_cmp_u16(r, fw->ethproto, op);
+
+ if (fw->bitmask & EBT_802_3) {
+ op = (op == NFT_CMP_EQ ? NFT_CMP_LT : NFT_CMP_GTE);
+ ethproto = htons(0x0600);
+ }
+
+ add_cmp_u16(r, ethproto, op);
}
add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO);
for (iter = cs->match_list; iter; iter = iter->next) {
if (iter->ismatch) {
- if (add_match(h, r, iter->u.match->m))
+ if (nft_bridge_add_match(h, fw, r, iter->u.match->m))
break;
} else {
if (add_target(r, iter->u.watcher->t))
@@ -239,6 +259,7 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
struct ebt_entry *fw = &cs->eb;
unsigned char addr[ETH_ALEN];
unsigned short int ethproto;
+ uint8_t op;
bool inv;
int i;
@@ -275,8 +296,14 @@ static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
fw->bitmask |= EBT_ISOURCE;
break;
case offsetof(struct ethhdr, h_proto):
- get_cmp_data(e, &ethproto, sizeof(ethproto), &inv);
- fw->ethproto = ethproto;
+ __get_cmp_data(e, &ethproto, sizeof(ethproto), &op);
+ if (ethproto == htons(0x0600)) {
+ fw->bitmask |= EBT_802_3;
+ inv = (op == NFT_CMP_GTE);
+ } else {
+ fw->ethproto = ethproto;
+ inv = (op == NFT_CMP_NEQ);
+ }
if (inv)
fw->invflags |= EBT_IPROTO;
fw->bitmask &= ~EBT_NOPROTO;
@@ -620,7 +647,7 @@ static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
printf("! ");
if (bitmask & EBT_802_3) {
- printf("length ");
+ printf("Length ");
return;
}
@@ -635,7 +662,7 @@ static void nft_bridge_save_rule(const void *data, unsigned int format)
{
const struct iptables_command_state *cs = data;
- if (cs->eb.ethproto)
+ if (!(cs->eb.bitmask & EBT_NOPROTO))
print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO,
cs->eb.bitmask);
if (cs->eb.bitmask & EBT_ISOURCE)
@@ -866,7 +893,10 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
xlate_ifname(xl, "meta obrname", cs->eb.logical_out,
cs->eb.invflags & EBT_ILOGICALOUT);
- if ((cs->eb.bitmask & EBT_NOPROTO) == 0) {
+ if (cs->eb.bitmask & EBT_802_3) {
+ xt_xlate_add(xl, "ether type %s 0x0600 ",
+ cs->eb.invflags & EBT_IPROTO ? ">=" : "<");
+ } else if ((cs->eb.bitmask & EBT_NOPROTO) == 0) {
const char *implicit = NULL;
switch (ntohs(cs->eb.ethproto)) {
@@ -889,9 +919,6 @@ static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
ntohs(cs->eb.ethproto));
}
- if (cs->eb.bitmask & EBT_802_3)
- return 0;
-
if (cs->eb.bitmask & EBT_ISOURCE)
nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE,
cs->eb.sourcemac, cs->eb.sourcemsk);
diff --git a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0 b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
index b84f63a7c3672..a4fc31548e323 100755
--- a/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
+++ b/iptables/tests/shell/testcases/ebtables/0002-ebtables-save-restore_0
@@ -13,8 +13,8 @@ $XT_MULTI ebtables -A INPUT -p IPv4 -i lo -j ACCEPT
$XT_MULTI ebtables -P FORWARD DROP
$XT_MULTI ebtables -A OUTPUT -s ff:ff:ff:ff:ff:ff/ff:ff:ff:ff:ff:ff -j DROP
$XT_MULTI ebtables -N foo
-$XT_MULTI ebtables -A foo --802_3-sap 0x23 -j ACCEPT
-$XT_MULTI ebtables -A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
+$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 -j ACCEPT
+$XT_MULTI ebtables -A foo -p length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
#$XT_MULTI ebtables -A foo --among-dst fe:ed:ba:be:00:01,fe:ed:ba:be:00:02,fe:ed:ba:be:00:03 -j ACCEPT
$XT_MULTI ebtables -A foo -p ARP --arp-gratuitous -j ACCEPT
$XT_MULTI ebtables -A foo -p ARP --arp-opcode Request -j ACCEPT
@@ -44,7 +44,7 @@ $XT_MULTI ebtables -A foo --pkttype-type multicast -j ACCEPT
$XT_MULTI ebtables -A foo --stp-type config -j ACCEPT
#$XT_MULTI ebtables -A foo --vlan-id 42 -j ACCEPT
-$XT_MULTI ebtables -A foo --802_3-sap 0x23 --limit 100 -j ACCEPT
+$XT_MULTI ebtables -A foo -p length --802_3-sap 0x23 --limit 100 -j ACCEPT
$XT_MULTI ebtables -A foo --pkttype-type multicast --log
$XT_MULTI ebtables -A foo --pkttype-type multicast --limit 100 -j ACCEPT
@@ -75,8 +75,8 @@ DUMP='*filter
-A INPUT -p IPv4 -i lo -j ACCEPT
-A FORWARD -j foo
-A OUTPUT -s Broadcast -j DROP
--A foo --802_3-sap 0x23 -j ACCEPT
--A foo --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
+-A foo -p Length --802_3-sap 0x23 -j ACCEPT
+-A foo -p Length --802_3-sap 0xaa --802_3-type 0x1337 -j ACCEPT
-A foo -p ARP --arp-gratuitous -j ACCEPT
-A foo -p ARP --arp-op Request -j ACCEPT
-A foo -p ARP --arp-ip-src 10.0.0.1 -j ACCEPT
@@ -96,7 +96,7 @@ DUMP='*filter
-A foo --nflog-group 1 -j CONTINUE
-A foo --pkttype-type multicast -j ACCEPT
-A foo --stp-type config -j ACCEPT
--A foo --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT
+-A foo -p Length --802_3-sap 0x23 --limit 100/sec --limit-burst 5 -j ACCEPT
-A foo --pkttype-type multicast --log-level notice --log-prefix "" -j CONTINUE
-A foo --pkttype-type multicast --limit 100/sec --limit-burst 5 -j ACCEPT
*nat
--
2.40.0

@ -0,0 +1,36 @@
From bf73dcb492c75cc03aeb945b749a49a529090ae3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 29 Sep 2022 19:11:55 +0200
Subject: [PATCH] extensions: among: Remove pointless fall through
This seems to be a leftover from an earlier version of the switch().
This fall through is never effective as the next case's code will never
apply. So just break instead.
Fixes: 26753888720d8 ("nft: bridge: Rudimental among extension support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit eafe731a50058ed59305ee4ab1ea2d63d6c4e86e)
---
extensions/libebt_among.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
index 7eb898f984bba..c607a775539d3 100644
--- a/extensions/libebt_among.c
+++ b/extensions/libebt_among.c
@@ -152,10 +152,9 @@ static int bramong_parse(int c, char **argv, int invert,
xtables_error(PARAMETER_PROBLEM,
"File should only contain one line");
optarg[flen-1] = '\0';
- /* fall through */
+ break;
case AMONG_DST:
- if (c == AMONG_DST)
- dst = true;
+ dst = true;
/* fall through */
case AMONG_SRC:
break;
--
2.40.0

@ -0,0 +1,57 @@
From 6a7b38bdb0253cfac68893ff7704f1f9cbfe891a Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 30 Sep 2022 17:51:55 +0200
Subject: [PATCH] extensions: among: Fix for use with ebtables-restore
When restoring multiple rules which use among match, new size may be
smaller than the old one which caused invalid writes by the memcpy()
call. Expect this and realloc the match only if it needs to grow. Also
use realloc instead of freeing and allocating from scratch.
Fixes: 26753888720d8 ("nft: bridge: Rudimental among extension support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit fca04aa7a53252464c289997e71de10189971da6)
---
extensions/libebt_among.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
diff --git a/extensions/libebt_among.c b/extensions/libebt_among.c
index c607a775539d3..1eab201984408 100644
--- a/extensions/libebt_among.c
+++ b/extensions/libebt_among.c
@@ -119,7 +119,6 @@ static int bramong_parse(int c, char **argv, int invert,
struct xt_entry_match **match)
{
struct nft_among_data *data = (struct nft_among_data *)(*match)->data;
- struct xt_entry_match *new_match;
bool have_ip, dst = false;
size_t new_size, cnt;
struct stat stats;
@@ -170,18 +169,17 @@ static int bramong_parse(int c, char **argv, int invert,
new_size *= sizeof(struct nft_among_pair);
new_size += XT_ALIGN(sizeof(struct xt_entry_match)) +
sizeof(struct nft_among_data);
- new_match = xtables_calloc(1, new_size);
- memcpy(new_match, *match, (*match)->u.match_size);
- new_match->u.match_size = new_size;
- data = (struct nft_among_data *)new_match->data;
+ if (new_size > (*match)->u.match_size) {
+ *match = xtables_realloc(*match, new_size);
+ (*match)->u.match_size = new_size;
+ data = (struct nft_among_data *)(*match)->data;
+ }
+
have_ip = nft_among_pairs_have_ip(optarg);
poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip);
parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip);
- free(*match);
- *match = new_match;
-
if (c == AMONG_DST_F || c == AMONG_SRC_F) {
munmap(argv, flen);
close(fd);
--
2.40.0

@ -0,0 +1,34 @@
From 67ce94bf558361cf45a72957d0d563dc2742a0c2 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Sat, 1 Oct 2022 00:15:35 +0200
Subject: [PATCH] extensions: libebt_stp: Eliminate duplicate space in output
No need for print_range() to print a trailing whitespace, caller does
this already.
Fixes: fd8d7d7e5d911 ("ebtables-nft: add stp match")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 262dff31a998ef8e2507bbfd9349d761769888da)
---
extensions/libebt_stp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/extensions/libebt_stp.c b/extensions/libebt_stp.c
index 06cf93b8d8449..9270bf822a711 100644
--- a/extensions/libebt_stp.c
+++ b/extensions/libebt_stp.c
@@ -145,9 +145,9 @@ static int parse_range(const char *portstring, void *lower, void *upper,
static void print_range(unsigned int l, unsigned int u)
{
if (l == u)
- printf("%u ", l);
+ printf("%u", l);
else
- printf("%u:%u ", l, u);
+ printf("%u:%u", l, u);
}
static int brstp_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask)
--
2.40.0

@ -0,0 +1,41 @@
From bea48d4a3323ce41973674e2edd64b990f8a849e Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Sat, 1 Oct 2022 00:17:50 +0200
Subject: [PATCH] extensions: libip6t_dst: Fix output for empty options
If no --dst-opts were given, print_options() would print just a
whitespace.
Fixes: 73866357e4a7a ("iptables: do not print trailing whitespaces")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 11e06cbb3a87739a3d958ba4c2f08fea7b100a68)
---
extensions/libip6t_dst.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c
index fe7e3403468ce..ba8cd66b13182 100644
--- a/extensions/libip6t_dst.c
+++ b/extensions/libip6t_dst.c
@@ -127,15 +127,15 @@ static void
print_options(unsigned int optsnr, uint16_t *optsp)
{
unsigned int i;
+ char sep = ' ';
- printf(" ");
for(i = 0; i < optsnr; i++) {
- printf("%d", (optsp[i] & 0xFF00) >> 8);
+ printf("%c%d", sep, (optsp[i] & 0xFF00) >> 8);
if ((optsp[i] & 0x00FF) != 0x00FF)
printf(":%d", (optsp[i] & 0x00FF));
- printf("%c", (i != optsnr - 1) ? ',' : ' ');
+ sep = ',';
}
}
--
2.40.0

@ -0,0 +1,55 @@
From 6e857353e3ce7231fc852c6187df0c6dd81767ba Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Sat, 1 Oct 2022 00:36:50 +0200
Subject: [PATCH] extensions: TCPOPTSTRIP: Do not print empty options
No point in printing anything if none of the bits are set.
Fixes: aef4c1e727563 ("libxt_TCPOPTSTRIP")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit dba32a76aacf84181a9bd3ba1e301e59ab49d370)
---
extensions/libxt_TCPOPTSTRIP.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/extensions/libxt_TCPOPTSTRIP.c b/extensions/libxt_TCPOPTSTRIP.c
index 6ea3489224602..ff873f98b3aaa 100644
--- a/extensions/libxt_TCPOPTSTRIP.c
+++ b/extensions/libxt_TCPOPTSTRIP.c
@@ -142,6 +142,13 @@ tcpoptstrip_print_list(const struct xt_tcpoptstrip_target_info *info,
}
}
+static bool tcpoptstrip_empty(const struct xt_tcpoptstrip_target_info *info)
+{
+ static const struct xt_tcpoptstrip_target_info empty = {};
+
+ return memcmp(info, &empty, sizeof(empty)) == 0;
+}
+
static void
tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
@@ -149,6 +156,9 @@ tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target,
const struct xt_tcpoptstrip_target_info *info =
(const void *)target->data;
+ if (tcpoptstrip_empty(info))
+ return;
+
printf(" TCPOPTSTRIP options ");
tcpoptstrip_print_list(info, numeric);
}
@@ -159,6 +169,9 @@ tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target)
const struct xt_tcpoptstrip_target_info *info =
(const void *)target->data;
+ if (tcpoptstrip_empty(info))
+ return;
+
printf(" --strip-options ");
tcpoptstrip_print_list(info, true);
}
--
2.40.0

@ -0,0 +1,29 @@
From f180adb86f7004c959cea29eee855a1bc489dcc9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 30 Sep 2022 18:06:10 +0200
Subject: [PATCH] tests: IDLETIMER.t: Fix syntax, support for restore input
Expected output was wrong in the last OK test, probably defeating rule
search check. Also use a different label, otherwise the kernel will
reject the second idletimer with same label but different type if both
rules are added at once.
Fixes: 85b9ec8615428 ("extensions: IDLETIMER: Add alarm timer option")
(cherry picked from commit de043bbf2b78cad83a639e27c75263aa478e8cc4)
---
extensions/libxt_IDLETIMER.t | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/libxt_IDLETIMER.t b/extensions/libxt_IDLETIMER.t
index e8f306d2462c7..3345d5bef9e38 100644
--- a/extensions/libxt_IDLETIMER.t
+++ b/extensions/libxt_IDLETIMER.t
@@ -2,4 +2,4 @@
-j IDLETIMER --timeout;;FAIL
-j IDLETIMER --timeout 42;;FAIL
-j IDLETIMER --timeout 42 --label foo;=;OK
--j IDLETIMER --timeout 42 --label foo --alarm;;OK
+-j IDLETIMER --timeout 42 --label bar --alarm;=;OK
--
2.40.0

@ -0,0 +1,29 @@
From 8b8249ce6128e0b9f909535e63629c10920af4ec Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 5 Oct 2022 20:29:36 +0200
Subject: [PATCH] tests: libebt_stp.t: Drop duplicate whitespace
Code was fixed but the testcase adjustment slipped through.
Fixes: 262dff31a998e ("extensions: libebt_stp: Eliminate duplicate space in output")
(cherry picked from commit dafb31980c4469fd28964b9703d3c77433cc7d21)
---
extensions/libebt_stp.t | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/libebt_stp.t b/extensions/libebt_stp.t
index 0c6b77b91454b..17d6c1c0978e3 100644
--- a/extensions/libebt_stp.t
+++ b/extensions/libebt_stp.t
@@ -1,7 +1,7 @@
:INPUT,FORWARD,OUTPUT
--stp-type 1;=;OK
--stp-flags 0x1;--stp-flags topology-change -j CONTINUE;OK
---stp-root-prio 1 -j ACCEPT;=;OK
+--stp-root-prio 1 -j ACCEPT;=;OK
--stp-root-addr 0d:ea:d0:0b:ee:f0;=;OK
--stp-root-cost 1;=;OK
--stp-sender-prio 1;=;OK
--
2.40.0

@ -0,0 +1,45 @@
From 3bf8687623a0a7b15ce9621f0da6f3361d5753df Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 6 Oct 2022 02:08:10 +0200
Subject: [PATCH] tests: shell: Fix expected output for ip6tables dst match
Forgot to update the shell testsuites when fixing for duplicate
whitespace in output.
Fixes: 11e06cbb3a877 ("extensions: libip6t_dst: Fix output for empty options")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit d89cc773618ddbdedd1ae967a8e686adbaf501f6)
Conflicts:
iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
-> Adjusted to missing commit 68e09d49ef26c
("tests: shell: Fix testcases for changed ip6tables opts output").
---
.../tests/shell/testcases/ip6tables/0002-verbose-output_0 | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0 b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
index 7624cbab655ad..65f755b627bb0 100755
--- a/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
+++ b/iptables/tests/shell/testcases/ip6tables/0002-verbose-output_0
@@ -12,7 +12,7 @@ VOUT2='ACCEPT all opt in eth2 out eth3 feed:babe::4 -> feed:babe::5'
RULE3='-p icmpv6 -m icmp6 --icmpv6-type no-route'
VOUT3=' ipv6-icmp opt in * out * ::/0 -> ::/0 ipv6-icmptype 1 code 0'
RULE4='-m dst --dst-len 42 -m rt --rt-type 23'
-VOUT4=' all opt in * out * ::/0 -> ::/0 dst length:42 rt type:23'
+VOUT4=' all opt in * out * ::/0 -> ::/0 dst length:42 rt type:23'
RULE5='-m frag --fragid 1337 -j LOG'
VOUT5='LOG all opt in * out * ::/0 -> ::/0 frag id:1337 LOG flags 0 level 4'
@@ -36,7 +36,7 @@ Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
0 0 ACCEPT all eth2 eth3 feed:babe::1 feed:babe::2
0 0 ACCEPT all eth2 eth3 feed:babe::4 feed:babe::5
0 0 ipv6-icmp * * ::/0 ::/0 ipv6-icmptype 1 code 0
- 0 0 all * * ::/0 ::/0 dst length:42 rt type:23
+ 0 0 all * * ::/0 ::/0 dst length:42 rt type:23
0 0 LOG all * * ::/0 ::/0 frag id:1337 LOG flags 0 level 4
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
--
2.40.0

@ -0,0 +1,67 @@
From a6c758229e79375efcbf4b30a68cd8c24b48e88f Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 7 Oct 2022 18:29:07 +0200
Subject: [PATCH] libiptc: Fix for segfault when renaming a chain
This is an odd bug: If the number of chains is right and one renames the
last one in the list, libiptc dereferences a NULL pointer. Add fix and
test case for it.
Fixes: 64ff47cde38e4 ("libiptc: fix chain rename bug in libiptc")
Reported-by: Julien Castets <castets.j@gmail.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 97bf4e68fc0794adba3243fd96f40f4568e7216f)
---
.../testcases/chain/0006rename-segfault_0 | 19 +++++++++++++++++++
libiptc/libiptc.c | 9 +++++++++
2 files changed, 28 insertions(+)
create mode 100755 iptables/tests/shell/testcases/chain/0006rename-segfault_0
diff --git a/iptables/tests/shell/testcases/chain/0006rename-segfault_0 b/iptables/tests/shell/testcases/chain/0006rename-segfault_0
new file mode 100755
index 0000000000000..c10a8006b56b4
--- /dev/null
+++ b/iptables/tests/shell/testcases/chain/0006rename-segfault_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# Cover for a bug in libiptc:
+# - the chain 'node-98-tmp' is the last in the list sorted by name
+# - there are 81 chains in total, so three chain index buckets
+# - the last index bucket contains only the 'node-98-tmp' chain
+# => rename temporarily removes it from the bucket, leaving a NULL bucket
+# behind which is dereferenced later when inserting the chain again with new
+# name again
+
+(
+ echo "*filter"
+ for chain in node-1 node-10 node-101 node-102 node-104 node-107 node-11 node-12 node-13 node-14 node-15 node-16 node-17 node-18 node-19 node-2 node-20 node-21 node-22 node-23 node-25 node-26 node-27 node-28 node-29 node-3 node-30 node-31 node-32 node-33 node-34 node-36 node-37 node-39 node-4 node-40 node-41 node-42 node-43 node-44 node-45 node-46 node-47 node-48 node-49 node-5 node-50 node-51 node-53 node-54 node-55 node-56 node-57 node-58 node-59 node-6 node-60 node-61 node-62 node-63 node-64 node-65 node-66 node-68 node-69 node-7 node-70 node-71 node-74 node-75 node-76 node-8 node-80 node-81 node-86 node-89 node-9 node-92 node-93 node-95 node-98-tmp; do
+ echo ":$chain - [0:0]"
+ done
+ echo "COMMIT"
+) | $XT_MULTI iptables-restore
+$XT_MULTI iptables -E node-98-tmp node-98
+exit $?
diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c
index 5888201525213..56bb75e5c3bef 100644
--- a/libiptc/libiptc.c
+++ b/libiptc/libiptc.c
@@ -606,6 +606,15 @@ static int iptcc_chain_index_delete_chain(struct chain_head *c, struct xtc_handl
if (index_ptr == &c->list) { /* Chain used as index ptr */
+ /* If this is the last chain in the list, its index bucket just
+ * became empty. Adjust the size to avoid a NULL-pointer deref
+ * later.
+ */
+ if (next == &h->chains) {
+ h->chain_index_sz--;
+ return 0;
+ }
+
/* See if its possible to avoid a rebuild, by shifting
* to next pointer. Its possible if the next pointer
* is located in the same index bucket.
--
2.40.0

@ -0,0 +1,57 @@
From 6f275ecd5b0654a865d8230c1955baeeed4dae5d Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Fri, 11 Mar 2022 18:28:49 +0100
Subject: [PATCH] extensions: libebt_mark: Fix xlate test case
The false suffix effectively disabled this test file, but it also has
problems: Apart from brmark_xlate() printing 'meta mark' instead of just
'mark', target is printed in the wrong position (like with any other
target-possessing extension.
Fixes: e67c08880961f ("ebtables-translate: add initial test cases")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit bc5f9d05dbf7d0a6c5256c63c492273c93ad3434)
---
extensions/libebt_mark.txlate | 11 +++++++++++
extensions/libebt_mark.xlate | 11 -----------
2 files changed, 11 insertions(+), 11 deletions(-)
create mode 100644 extensions/libebt_mark.txlate
delete mode 100644 extensions/libebt_mark.xlate
diff --git a/extensions/libebt_mark.txlate b/extensions/libebt_mark.txlate
new file mode 100644
index 0000000000000..7529302d9a444
--- /dev/null
+++ b/extensions/libebt_mark.txlate
@@ -0,0 +1,11 @@
+ebtables-translate -A INPUT --mark-set 42
+nft add rule bridge filter INPUT meta mark set 0x2a accept counter
+
+ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN
+nft add rule bridge filter INPUT meta mark set meta mark or 0x2a return counter
+
+ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT
+nft add rule bridge filter INPUT meta mark set meta mark and 0x2a accept counter
+
+ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP
+nft add rule bridge filter INPUT meta mark set meta mark xor 0x2a drop counter
diff --git a/extensions/libebt_mark.xlate b/extensions/libebt_mark.xlate
deleted file mode 100644
index e0982a1e8ebd7..0000000000000
--- a/extensions/libebt_mark.xlate
+++ /dev/null
@@ -1,11 +0,0 @@
-ebtables-translate -A INPUT --mark-set 42
-nft add rule bridge filter INPUT mark set 0x2a counter
-
-ebtables-translate -A INPUT --mark-or 42 --mark-target RETURN
-nft add rule bridge filter INPUT mark set mark or 0x2a counter return
-
-ebtables-translate -A INPUT --mark-and 42 --mark-target ACCEPT
-nft add rule bridge filter INPUT mark set mark and 0x2a counter accept
-
-ebtables-translate -A INPUT --mark-xor 42 --mark-target DROP
-nft add rule bridge filter INPUT mark set mark xor 0x2a counter drop
--
2.40.0

@ -0,0 +1,30 @@
From fd19d22db18ac084f45d739416df1f81a4e31c82 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 16 Nov 2022 13:03:05 +0100
Subject: [PATCH] extensions: libebt_redirect: Fix xlate return code
The callback is supposed to return 1 on success, not 0.
Fixes: 24ce7465056ae ("ebtables-compat: add redirect match extension")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 8543b6f2f4a3a15a5ece7dd1b320b477ce36a8d5)
---
extensions/libebt_redirect.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/libebt_redirect.c b/extensions/libebt_redirect.c
index 6e653997ee99e..4d4c7a02cea89 100644
--- a/extensions/libebt_redirect.c
+++ b/extensions/libebt_redirect.c
@@ -86,7 +86,7 @@ static int brredir_xlate(struct xt_xlate *xl,
xt_xlate_add(xl, "meta set pkttype host");
if (red->target != EBT_ACCEPT)
xt_xlate_add(xl, " %s ", brredir_verdict(red->target));
- return 0;
+ return 1;
}
static struct xtables_target brredirect_target = {
--
2.40.0

@ -0,0 +1,39 @@
From 64788807be19d744bb9c57943e74fe6775a8c05f Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Wed, 16 Nov 2022 13:09:16 +0100
Subject: [PATCH] extensions: libipt_ttl: Sanitize xlate callback
Catch unexpected values in info->mode, also fix indenting.
Fixes: 1b320a1a1dc1f ("extensions: libipt_ttl: Add translation to nft")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 800bed28b2b7bbd931166c7426640ae619f03342)
---
extensions/libipt_ttl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/extensions/libipt_ttl.c b/extensions/libipt_ttl.c
index 6bdd219618091..86ba554ef92a8 100644
--- a/extensions/libipt_ttl.c
+++ b/extensions/libipt_ttl.c
@@ -106,7 +106,7 @@ static int ttl_xlate(struct xt_xlate *xl,
const struct ipt_ttl_info *info =
(struct ipt_ttl_info *) params->match->data;
- switch (info->mode) {
+ switch (info->mode) {
case IPT_TTL_EQ:
xt_xlate_add(xl, "ip ttl");
break;
@@ -121,7 +121,7 @@ static int ttl_xlate(struct xt_xlate *xl,
break;
default:
/* Should not happen. */
- break;
+ return 0;
}
xt_xlate_add(xl, " %u", info->ttl);
--
2.40.0

@ -0,0 +1,88 @@
From f6763e2336fb4eed696fc715375e3ea5a6855b20 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 17 Nov 2022 15:30:11 +0100
Subject: [PATCH] extensions: CONNMARK: Fix xlate callback
Bail out if nfmask != ctmask with XT_CONNMARK_SAVE and
XT_CONNMARK_RESTORE. Looks like this needs a similar implementation to
the one for XT_CONNMARK_SET.
Fix shift mark translation: xt_connmark_shift_ops does not contain
useful strings for nftables. Also add needed braces around the term
being shifted.
Fixes: db7b4e0de960c ("extensions: libxt_CONNMARK: Support bit-shifting for --restore,set and save-mark")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit e6747f6b1098b2bc7dfd482f287b3f90b351f164)
---
extensions/libxt_CONNMARK.c | 15 ++++++++++-----
extensions/libxt_CONNMARK.txlate | 3 +++
2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/extensions/libxt_CONNMARK.c b/extensions/libxt_CONNMARK.c
index 21e1091386294..a6568c99b6c4d 100644
--- a/extensions/libxt_CONNMARK.c
+++ b/extensions/libxt_CONNMARK.c
@@ -595,11 +595,11 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl,
{
const struct xt_connmark_tginfo2 *info =
(const void *)params->target->data;
- const char *shift_op = xt_connmark_shift_ops[info->shift_dir];
+ const char *braces = info->shift_bits ? "( " : "";
switch (info->mode) {
case XT_CONNMARK_SET:
- xt_xlate_add(xl, "ct mark set ");
+ xt_xlate_add(xl, "ct mark set %s", braces);
if (info->ctmask == 0xFFFFFFFFU)
xt_xlate_add(xl, "0x%x ", info->ctmark);
else if (info->ctmark == 0)
@@ -615,26 +615,31 @@ static int connmark_tg_xlate_v2(struct xt_xlate *xl,
info->ctmark, ~info->ctmask);
break;
case XT_CONNMARK_SAVE:
- xt_xlate_add(xl, "ct mark set mark");
+ xt_xlate_add(xl, "ct mark set %smark", braces);
if (!(info->nfmask == UINT32_MAX &&
info->ctmask == UINT32_MAX)) {
if (info->nfmask == info->ctmask)
xt_xlate_add(xl, " and 0x%x", info->nfmask);
+ else
+ return 0;
}
break;
case XT_CONNMARK_RESTORE:
- xt_xlate_add(xl, "meta mark set ct mark");
+ xt_xlate_add(xl, "meta mark set %sct mark", braces);
if (!(info->nfmask == UINT32_MAX &&
info->ctmask == UINT32_MAX)) {
if (info->nfmask == info->ctmask)
xt_xlate_add(xl, " and 0x%x", info->nfmask);
+ else
+ return 0;
}
break;
}
if (info->mode <= XT_CONNMARK_RESTORE &&
info->shift_bits != 0) {
- xt_xlate_add(xl, " %s %u", shift_op, info->shift_bits);
+ xt_xlate_add(xl, " ) %s %u",
+ info->shift_dir ? ">>" : "<<", info->shift_bits);
}
return 1;
diff --git a/extensions/libxt_CONNMARK.txlate b/extensions/libxt_CONNMARK.txlate
index ce40ae5ea65e0..99627c2b05d45 100644
--- a/extensions/libxt_CONNMARK.txlate
+++ b/extensions/libxt_CONNMARK.txlate
@@ -18,3 +18,6 @@ nft add rule ip mangle PREROUTING counter ct mark set mark
iptables-translate -t mangle -A PREROUTING -j CONNMARK --restore-mark
nft add rule ip mangle PREROUTING counter meta mark set ct mark
+
+iptables-translate -t mangle -A PREROUTING -j CONNMARK --set-mark 0x23/0x42 --right-shift-mark 5
+nft add rule ip mangle PREROUTING counter ct mark set ( ct mark xor 0x23 and 0xffffff9c ) >> 5
--
2.40.0

@ -0,0 +1,31 @@
From ce7198e207384f91d510b50e64305de3e05c2c61 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 17 Nov 2022 16:01:11 +0100
Subject: [PATCH] extensions: MARK: Sanitize MARK_xlate()
Since markinfo->mode might contain unexpected values, add a default case
returning zero.
Fixes: afefc7a134ca0 ("extensions: libxt_MARK: Add translation for revision 1 to nft")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit c4fc6440a6f39606e38744bfc827852bb68829f4)
---
extensions/libxt_MARK.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c
index 1536563d0f4c7..100f6a38996ac 100644
--- a/extensions/libxt_MARK.c
+++ b/extensions/libxt_MARK.c
@@ -366,6 +366,8 @@ static int MARK_xlate(struct xt_xlate *xl,
case XT_MARK_OR:
xt_xlate_add(xl, "mark or 0x%x ", (uint32_t)markinfo->mark);
break;
+ default:
+ return 0;
}
return 1;
--
2.40.0

@ -0,0 +1,29 @@
From 6069123a02f5ff736e8d06adc5d5f3f11173febf Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 17 Nov 2022 16:06:46 +0100
Subject: [PATCH] extensions: TCPMSS: Use xlate callback for IPv6, too
Data structures are identical and the translation is layer3-agnostic.
Fixes: bebce197adb42 ("iptables: iptables-compat translation for TCPMSS")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit e05d9af176cb2a62c1bd24fa1d82b12a8ad00221)
---
extensions/libxt_TCPMSS.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/extensions/libxt_TCPMSS.c b/extensions/libxt_TCPMSS.c
index 0d9b200ebc72f..251a5532a838b 100644
--- a/extensions/libxt_TCPMSS.c
+++ b/extensions/libxt_TCPMSS.c
@@ -131,6 +131,7 @@ static struct xtables_target tcpmss_tg_reg[] = {
.x6_parse = TCPMSS_parse,
.x6_fcheck = TCPMSS_check,
.x6_options = TCPMSS6_opts,
+ .xlate = TCPMSS_xlate,
},
};
--
2.40.0

@ -0,0 +1,95 @@
From 383c33a62877379b44ec58032cc707a43b662481 Mon Sep 17 00:00:00 2001
From: Phil Sutter <phil@nwl.cc>
Date: Thu, 17 Nov 2022 16:10:14 +0100
Subject: [PATCH] extensions: TOS: Fix v1 xlate callback
Translation entirely ignored tos_mask field.
Fixes: b669e18489709 ("extensions: libxt_TOS: Add translation to nft")
Signed-off-by: Phil Sutter <phil@nwl.cc>
(cherry picked from commit 161fb8ad126d8f330c8f59a4a1b5885d26477664)
---
extensions/libxt_TOS.c | 33 +++++++++++++++++++++++----------
extensions/libxt_TOS.txlate | 9 ++++++---
2 files changed, 29 insertions(+), 13 deletions(-)
diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c
index b66fa329f4150..4fc849bd2468b 100644
--- a/extensions/libxt_TOS.c
+++ b/extensions/libxt_TOS.c
@@ -183,28 +183,41 @@ static void tos_tg_save(const void *ip, const struct xt_entry_target *target)
printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask);
}
+static int __tos_xlate(struct xt_xlate *xl, const char *ip,
+ uint8_t tos, uint8_t tosmask)
+{
+ xt_xlate_add(xl, "%s dscp set ", ip);
+ if ((tosmask & 0x3f) == 0x3f)
+ xt_xlate_add(xl, "0x%02x", tos >> 2);
+ else if (!tos)
+ xt_xlate_add(xl, "%s dscp and 0x%02x",
+ ip, (uint8_t)~tosmask >> 2);
+ else if (tos == tosmask)
+ xt_xlate_add(xl, "%s dscp or 0x%02x", ip, tos >> 2);
+ else if (!tosmask)
+ xt_xlate_add(xl, "%s dscp xor 0x%02x", ip, tos >> 2);
+ else
+ xt_xlate_add(xl, "%s dscp and 0x%02x xor 0x%02x",
+ ip, (uint8_t)~tosmask >> 2, tos >> 2);
+ return 1;
+}
+
static int tos_xlate(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
const struct ipt_tos_target_info *info =
(struct ipt_tos_target_info *) params->target->data;
- uint8_t dscp = info->tos >> 2;
-
- xt_xlate_add(xl, "ip dscp set 0x%02x", dscp);
- return 1;
+ return __tos_xlate(xl, "ip", info->tos, UINT8_MAX);
}
static int tos_xlate6(struct xt_xlate *xl,
const struct xt_xlate_tg_params *params)
{
- const struct ipt_tos_target_info *info =
- (struct ipt_tos_target_info *) params->target->data;
- uint8_t dscp = info->tos >> 2;
+ const struct xt_tos_target_info *info =
+ (struct xt_tos_target_info *)params->target->data;
- xt_xlate_add(xl, "ip6 dscp set 0x%02x", dscp);
-
- return 1;
+ return __tos_xlate(xl, "ip6", info->tos_value, info->tos_mask);
}
static struct xtables_target tos_tg_reg[] = {
diff --git a/extensions/libxt_TOS.txlate b/extensions/libxt_TOS.txlate
index 0952310edc4ac..9c12674299359 100644
--- a/extensions/libxt_TOS.txlate
+++ b/extensions/libxt_TOS.txlate
@@ -14,10 +14,13 @@ ip6tables-translate -A INPUT -j TOS --set-tos Normal-Service
nft add rule ip6 filter INPUT counter ip6 dscp set 0x00
ip6tables-translate -A INPUT -j TOS --and-tos 0x12
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x00
+nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x04
ip6tables-translate -A INPUT -j TOS --or-tos 0x12
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x04
+nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp or 0x04
ip6tables-translate -A INPUT -j TOS --xor-tos 0x12
-nft add rule ip6 filter INPUT counter ip6 dscp set 0x04
+nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp xor 0x04
+
+ip6tables-translate -A INPUT -j TOS --set-tos 0x12/0x34
+nft add rule ip6 filter INPUT counter ip6 dscp set ip6 dscp and 0x32 xor 0x04
--
2.40.0

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save