import CS nftables-1.0.4-2.el8

This commit is contained in:
eabdullin 2023-09-27 13:44:39 +00:00
parent 53e7e44417
commit c44c7b45ef
122 changed files with 4047 additions and 14516 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/nftables-0.9.3.tar.bz2
SOURCES/nftables-1.0.4.tar.bz2

View File

@ -1 +1 @@
20156858169fde135a0b4c22c4cd9437afcbb733 SOURCES/nftables-0.9.3.tar.bz2
e2e8b324cece1409a311284ff4fe26c3a5554809 SOURCES/nftables-1.0.4.tar.bz2

View File

@ -1,244 +0,0 @@
From 5fac849eac7ecfde4ca6f9c9c406ace030f358f2 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 10 Jan 2020 19:54:16 +0100
Subject: [PATCH] main: enforce options before commands
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1778883
Upstream Status: nftables commit fb9cea50e8b37
commit fb9cea50e8b370b6931e7b53b1a881d3b95b1c91
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Fri Dec 13 11:32:46 2019 +0100
main: enforce options before commands
This patch turns on POSIXLY_CORRECT on the getopt parser to enforce
options before commands. Users get a hint in such a case:
# nft list ruleset -a
Error: syntax error, options must be specified before commands
nft list ruleset -a
^ ~~
This patch recovers 9fc71bc6b602 ("main: Fix for misleading error with
negative chain priority").
Tests have been updated.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/main.c | 46 ++++++++++++++++++-
.../testcases/cache/0001_cache_handling_0 | 2 +-
.../testcases/chains/0016delete_handle_0 | 4 +-
.../testcases/chains/0039negative_priority_0 | 8 ++++
.../testcases/flowtable/0010delete_handle_0 | 2 +-
.../testcases/maps/0008interval_map_delete_0 | 2 +-
tests/shell/testcases/optionals/comments_0 | 2 +-
.../testcases/optionals/comments_handles_0 | 2 +-
.../optionals/delete_object_handles_0 | 4 +-
tests/shell/testcases/optionals/handles_0 | 2 +-
.../shell/testcases/sets/0028delete_handle_0 | 2 +-
11 files changed, 64 insertions(+), 12 deletions(-)
create mode 100755 tests/shell/testcases/chains/0039negative_priority_0
diff --git a/src/main.c b/src/main.c
index fde8b15..74199f9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,7 +46,7 @@ enum opt_vals {
OPT_TERSE = 't',
OPT_INVALID = '?',
};
-#define OPTSTRING "hvcf:iI:jvnsNaeSupypTt"
+#define OPTSTRING "+hvcf:iI:jvnsNaeSupypTt"
static const struct option options[] = {
{
@@ -202,6 +202,47 @@ static const struct {
},
};
+static void nft_options_error(int argc, char * const argv[], int pos)
+{
+ int i;
+
+ fprintf(stderr, "Error: syntax error, options must be specified before commands\n");
+ for (i = 0; i < argc; i++)
+ fprintf(stderr, "%s ", argv[i]);
+ printf("\n%4c%*s\n", '^', pos - 2, "~~");
+}
+
+static bool nft_options_check(int argc, char * const argv[])
+{
+ bool skip = false, nonoption = false;
+ int pos = 0, i;
+
+ for (i = 1; i < argc; i++) {
+ pos += strlen(argv[i - 1]) + 1;
+ if (argv[i][0] == '{') {
+ break;
+ } else if (skip) {
+ skip = false;
+ continue;
+ } else if (argv[i][0] == '-') {
+ if (nonoption) {
+ nft_options_error(argc, argv, pos);
+ return false;
+ } else if (argv[i][1] == 'I' ||
+ argv[i][1] == 'f' ||
+ !strcmp(argv[i], "--includepath") ||
+ !strcmp(argv[i], "--file")) {
+ skip = true;
+ continue;
+ }
+ } else if (argv[i][0] != '-') {
+ nonoption = true;
+ }
+ }
+
+ return true;
+}
+
int main(int argc, char * const *argv)
{
char *buf = NULL, *filename = NULL;
@@ -211,6 +252,9 @@ int main(int argc, char * const *argv)
unsigned int len;
int i, val, rc;
+ if (!nft_options_check(argc, argv))
+ exit(EXIT_FAILURE);
+
nft = nft_ctx_new(NFT_CTX_DEFAULT);
while (1) {
diff --git a/tests/shell/testcases/cache/0001_cache_handling_0 b/tests/shell/testcases/cache/0001_cache_handling_0
index 431aada..0a68440 100755
--- a/tests/shell/testcases/cache/0001_cache_handling_0
+++ b/tests/shell/testcases/cache/0001_cache_handling_0
@@ -20,7 +20,7 @@ TMP=$(mktemp)
echo "$RULESET" >> "$TMP"
$NFT "flush ruleset;include \"$TMP\""
rm -f "$TMP"
-rule_handle=$($NFT list ruleset -a | awk '/saddr/{print $NF}')
+rule_handle=$($NFT -a list ruleset | awk '/saddr/{print $NF}')
$NFT delete rule inet test test handle $rule_handle
$NFT delete set inet test test
$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/chains/0016delete_handle_0 b/tests/shell/testcases/chains/0016delete_handle_0
index 4633d77..8fd1ad8 100755
--- a/tests/shell/testcases/chains/0016delete_handle_0
+++ b/tests/shell/testcases/chains/0016delete_handle_0
@@ -10,8 +10,8 @@ $NFT add chain ip6 test-ip6 x
$NFT add chain ip6 test-ip6 y
$NFT add chain ip6 test-ip6 z
-chain_y_handle=$($NFT list ruleset -a | awk -v n=1 '/chain y/ && !--n {print $NF; exit}');
-chain_z_handle=$($NFT list ruleset -a | awk -v n=2 '/chain z/ && !--n {print $NF; exit}');
+chain_y_handle=$($NFT -a list ruleset | awk -v n=1 '/chain y/ && !--n {print $NF; exit}');
+chain_z_handle=$($NFT -a list ruleset | awk -v n=2 '/chain z/ && !--n {print $NF; exit}');
$NFT delete chain test-ip handle $chain_y_handle
$NFT delete chain ip6 test-ip6 handle $chain_z_handle
diff --git a/tests/shell/testcases/chains/0039negative_priority_0 b/tests/shell/testcases/chains/0039negative_priority_0
new file mode 100755
index 0000000..ba17b8c
--- /dev/null
+++ b/tests/shell/testcases/chains/0039negative_priority_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Test parsing of negative priority values
+
+set -e
+
+$NFT add table t
+$NFT add chain t c { type filter hook input priority -30\; }
diff --git a/tests/shell/testcases/flowtable/0010delete_handle_0 b/tests/shell/testcases/flowtable/0010delete_handle_0
index 303967d..985d4a3 100755
--- a/tests/shell/testcases/flowtable/0010delete_handle_0
+++ b/tests/shell/testcases/flowtable/0010delete_handle_0
@@ -7,7 +7,7 @@ set -e
$NFT add table inet t
$NFT add flowtable inet t f { hook ingress priority filter\; devices = { lo }\; }
-FH=$($NFT list ruleset -a | awk '/flowtable f/ { print $NF }')
+FH=$($NFT -a list ruleset | awk '/flowtable f/ { print $NF }')
$NFT delete flowtable inet t handle $FH
diff --git a/tests/shell/testcases/maps/0008interval_map_delete_0 b/tests/shell/testcases/maps/0008interval_map_delete_0
index a43fd28..7da6eb3 100755
--- a/tests/shell/testcases/maps/0008interval_map_delete_0
+++ b/tests/shell/testcases/maps/0008interval_map_delete_0
@@ -24,7 +24,7 @@ $NFT delete element filter m { 127.0.0.3 }
$NFT add element filter m { 127.0.0.3 : 0x3 }
$NFT add element filter m { 127.0.0.2 : 0x2 }
-GET=$($NFT list ruleset -s)
+GET=$($NFT -s list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
DIFF="$(which diff)"
[ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
diff --git a/tests/shell/testcases/optionals/comments_0 b/tests/shell/testcases/optionals/comments_0
index 29b8506..ab85936 100755
--- a/tests/shell/testcases/optionals/comments_0
+++ b/tests/shell/testcases/optionals/comments_0
@@ -5,4 +5,4 @@
$NFT add table test
$NFT add chain test test
$NFT add rule test test tcp dport 22 counter accept comment test_comment
-$NFT list table test -a | grep 'accept comment \"test_comment\"' >/dev/null
+$NFT -a list table test | grep 'accept comment \"test_comment\"' >/dev/null
diff --git a/tests/shell/testcases/optionals/comments_handles_0 b/tests/shell/testcases/optionals/comments_handles_0
index 30539bf..a01df1d 100755
--- a/tests/shell/testcases/optionals/comments_handles_0
+++ b/tests/shell/testcases/optionals/comments_handles_0
@@ -6,5 +6,5 @@ $NFT add table test
$NFT add chain test test
$NFT add rule test test tcp dport 22 counter accept comment test_comment
set -e
-$NFT list table test -a | grep 'accept comment \"test_comment\" # handle '[[:digit:]]$ >/dev/null
+$NFT -a list table test | grep 'accept comment \"test_comment\" # handle '[[:digit:]]$ >/dev/null
$NFT list table test | grep 'accept comment \"test_comment\"' | grep -v '# handle '[[:digit:]]$ >/dev/null
diff --git a/tests/shell/testcases/optionals/delete_object_handles_0 b/tests/shell/testcases/optionals/delete_object_handles_0
index d5d9654..a2ae422 100755
--- a/tests/shell/testcases/optionals/delete_object_handles_0
+++ b/tests/shell/testcases/optionals/delete_object_handles_0
@@ -10,8 +10,8 @@ $NFT add quota ip6 test-ip6 http-quota over 25 mbytes
$NFT add counter ip6 test-ip6 http-traffic
$NFT add quota ip6 test-ip6 ssh-quota 10 mbytes
-counter_handle=$($NFT list ruleset -a | awk '/https-traffic/{print $NF}')
-quota_handle=$($NFT list ruleset -a | awk '/ssh-quota/{print $NF}')
+counter_handle=$($NFT -a list ruleset | awk '/https-traffic/{print $NF}')
+quota_handle=$($NFT -a list ruleset | awk '/ssh-quota/{print $NF}')
$NFT delete counter test-ip handle $counter_handle
$NFT delete quota ip6 test-ip6 handle $quota_handle
diff --git a/tests/shell/testcases/optionals/handles_0 b/tests/shell/testcases/optionals/handles_0
index 7c6a437..80f3c5b 100755
--- a/tests/shell/testcases/optionals/handles_0
+++ b/tests/shell/testcases/optionals/handles_0
@@ -5,4 +5,4 @@
$NFT add table test
$NFT add chain test test
$NFT add rule test test tcp dport 22 counter accept
-$NFT list table test -a | grep 'accept # handle '[[:digit:]]$ >/dev/null
+$NFT -a list table test | grep 'accept # handle '[[:digit:]]$ >/dev/null
diff --git a/tests/shell/testcases/sets/0028delete_handle_0 b/tests/shell/testcases/sets/0028delete_handle_0
index 4e8b322..5ad17c2 100755
--- a/tests/shell/testcases/sets/0028delete_handle_0
+++ b/tests/shell/testcases/sets/0028delete_handle_0
@@ -7,7 +7,7 @@ $NFT add set test-ip y { type inet_service \; timeout 3h45s \;}
$NFT add set test-ip z { type ipv4_addr\; flags constant , interval\;}
$NFT add set test-ip c {type ipv4_addr \; flags timeout \; elements={192.168.1.1 timeout 10s, 192.168.1.2 timeout 30s} \;}
-set_handle=$($NFT list ruleset -a | awk '/set c/{print $NF}')
+set_handle=$($NFT -a list ruleset | awk '/set c/{print $NF}')
$NFT delete set test-ip handle $set_handle
EXPECTED="table ip test-ip {
--
2.31.1

View File

@ -0,0 +1,97 @@
From c994f1d2a31a2b03557b3eb1c8c2de34b97edce1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 24 Jun 2022 16:02:59 +0200
Subject: [PATCH] tests: shell: runtime set element automerge
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 8fafe4e6b5b30
commit 8fafe4e6b5b30f2539f16403da8d5c5f819e523b
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Mon Jun 13 17:05:22 2022 +0200
tests: shell: runtime set element automerge
Add a test to cover runtime set element automerge.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
tests/shell/testcases/sets/automerge_0 | 64 ++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
create mode 100755 tests/shell/testcases/sets/automerge_0
diff --git a/tests/shell/testcases/sets/automerge_0 b/tests/shell/testcases/sets/automerge_0
new file mode 100755
index 0000000..c9fb609
--- /dev/null
+++ b/tests/shell/testcases/sets/automerge_0
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet x {
+ set y {
+ type inet_service
+ flags interval
+ auto-merge
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+tmpfile=$(mktemp)
+echo -n "add element inet x y { " > $tmpfile
+for ((i=0;i<65535;i+=2))
+do
+ echo -n "$i, " >> $tmpfile
+ if [ $i -eq 65534 ]
+ then
+ echo -n "$i" >> $tmpfile
+ fi
+done
+echo "}" >> $tmpfile
+
+$NFT -f $tmpfile
+
+tmpfile2=$(mktemp)
+for ((i=1;i<65535;i+=2))
+do
+ echo "$i" >> $tmpfile2
+done
+
+tmpfile3=$(mktemp)
+shuf $tmpfile2 > $tmpfile3
+i=0
+cat $tmpfile3 | while read line && [ $i -lt 10 ]
+do
+ $NFT add element inet x y { $line }
+ i=$((i+1))
+done
+
+for ((i=0;i<10;i++))
+do
+ from=$(($RANDOM%65535))
+ to=$(($from+100))
+ $NFT add element inet x y { $from-$to }
+ if [ $? -ne 0 ]
+ then
+ echo "failed to add $from-$to"
+ exit 1
+ fi
+ $NFT get element inet x y { $from-$to }
+ if [ $? -ne 0 ]
+ then
+ echo "failed to get $from-$to"
+ exit 1
+ fi
+done
+
+rm -f $tmpfile
+rm -f $tmpfile2
+rm -f $tmpfile3
--
2.41.0.rc1

View File

@ -1,50 +0,0 @@
From 0c808b1ee29d4a0974f4cc5c0586138730361a41 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 10 Jan 2020 19:54:16 +0100
Subject: [PATCH] main: restore --debug
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1778883
Upstream Status: nftables commit ea5af85371bd1
commit ea5af85371bd18658ea2ffa0a6c9c48e2c64684b
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jan 9 18:16:18 2020 +0100
main: restore --debug
Broken since options are mandatory before commands.
Fixes: fb9cea50e8b3 ("main: enforce options before commands")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/main.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/main.c b/src/main.c
index 74199f9..6ab1b89 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,7 +46,7 @@ enum opt_vals {
OPT_TERSE = 't',
OPT_INVALID = '?',
};
-#define OPTSTRING "+hvcf:iI:jvnsNaeSupypTt"
+#define OPTSTRING "+hvd:cf:iI:jvnsNaeSupypTt"
static const struct option options[] = {
{
@@ -228,8 +228,10 @@ static bool nft_options_check(int argc, char * const argv[])
if (nonoption) {
nft_options_error(argc, argv, pos);
return false;
- } else if (argv[i][1] == 'I' ||
+ } else if (argv[i][1] == 'd' ||
+ argv[i][1] == 'I' ||
argv[i][1] == 'f' ||
+ !strcmp(argv[i], "--debug") ||
!strcmp(argv[i], "--includepath") ||
!strcmp(argv[i], "--file")) {
skip = true;
--
2.31.1

View File

@ -0,0 +1,236 @@
From 33792b491be79cb50d163c4ecc553f1258b82159 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 24 Jun 2022 16:02:59 +0200
Subject: [PATCH] rule: collapse set element commands
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 498a5f0c219d8
commit 498a5f0c219d8a118af4f172f248647d9b077101
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Mon Jun 13 17:22:44 2022 +0200
rule: collapse set element commands
Robots might generate a long list of singleton element commands such as:
add element t s { 1.0.1.0/24 }
...
add element t s { 1.0.2.0/23 }
collapse them into one single command before the evaluation step, ie.
add element t s { 1.0.1.0/24, ..., 1.0.2.0/23 }
this speeds up overlap detection and set element automerge operations in
this worst case scenario.
Since 3da9643fb9ff9 ("intervals: add support to automerge with kernel
elements"), the new interval tracking relies on mergesort. The pattern
above triggers the set sorting for each element.
This patch adds a list to cmd objects that store collapsed commands.
Moreover, expressions also contain a reference to the original command,
to uncollapse the commands after the evaluation step.
These commands are uncollapsed after the evaluation step to ensure error
reporting works as expected (command and netlink message are mapped
1:1).
For the record:
- nftables versions <= 1.0.2 did not perform any kind of overlap
check for the described scenario above (because set cache only contained
elements in the kernel in this case). This is a problem for kernels < 5.7
which rely on userspace to detect overlaps.
- the overlap detection could be skipped for kernels >= 5.7.
- The extended netlink error reporting available for set elements
since 5.19-rc might allow to remove the uncollapse step, in this case,
error reporting does not rely on the netlink sequence to refer to the
command triggering the problem.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/expression.h | 1 +
include/rule.h | 3 ++
src/libnftables.c | 17 ++++++++--
src/rule.c | 75 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 93 insertions(+), 3 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index 2c3818e..53194c9 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -243,6 +243,7 @@ struct expr {
enum expr_types etype:8;
enum ops op:8;
unsigned int len;
+ struct cmd *cmd;
union {
struct {
diff --git a/include/rule.h b/include/rule.h
index e232b97..9081225 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -700,6 +700,7 @@ struct cmd {
enum cmd_obj obj;
struct handle handle;
uint32_t seqnum;
+ struct list_head collapse_list;
union {
void *data;
struct expr *expr;
@@ -728,6 +729,8 @@ extern struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
const struct handle *h, const struct location *loc,
void *data);
extern void nft_cmd_expand(struct cmd *cmd);
+extern bool nft_cmd_collapse(struct list_head *cmds);
+extern void nft_cmd_uncollapse(struct list_head *cmds);
extern struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type,
const struct handle *h,
const struct location *loc, struct obj *obj);
diff --git a/src/libnftables.c b/src/libnftables.c
index 6a22ea0..aac682b 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -501,7 +501,9 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
{
struct nft_cache_filter *filter;
struct cmd *cmd, *next;
+ bool collapsed = false;
unsigned int flags;
+ int err = 0;
filter = nft_cache_filter_init();
flags = nft_cache_evaluate(nft, cmds, filter);
@@ -512,17 +514,26 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
nft_cache_filter_fini(filter);
+ if (nft_cmd_collapse(cmds))
+ collapsed = true;
+
list_for_each_entry_safe(cmd, next, cmds, list) {
struct eval_ctx ectx = {
.nft = nft,
.msgs = msgs,
};
+
if (cmd_evaluate(&ectx, cmd) < 0 &&
- ++nft->state->nerrs == nft->parser_max_errors)
- return -1;
+ ++nft->state->nerrs == nft->parser_max_errors) {
+ err = -1;
+ break;
+ }
}
- if (nft->state->nerrs)
+ if (collapsed)
+ nft_cmd_uncollapse(cmds);
+
+ if (err < 0 || nft->state->nerrs)
return -1;
list_for_each_entry(cmd, cmds, list) {
diff --git a/src/rule.c b/src/rule.c
index 7f61bdc..0526a14 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1279,6 +1279,8 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
cmd->handle = *h;
cmd->location = *loc;
cmd->data = data;
+ init_list_head(&cmd->collapse_list);
+
return cmd;
}
@@ -1379,6 +1381,79 @@ void nft_cmd_expand(struct cmd *cmd)
}
}
+bool nft_cmd_collapse(struct list_head *cmds)
+{
+ struct cmd *cmd, *next, *elems = NULL;
+ struct expr *expr, *enext;
+ bool collapse = false;
+
+ list_for_each_entry_safe(cmd, next, cmds, list) {
+ if (cmd->op != CMD_ADD &&
+ cmd->op != CMD_CREATE) {
+ elems = NULL;
+ continue;
+ }
+
+ if (cmd->obj != CMD_OBJ_ELEMENTS) {
+ elems = NULL;
+ continue;
+ }
+
+ if (!elems) {
+ elems = cmd;
+ continue;
+ }
+
+ if (cmd->op != elems->op) {
+ elems = cmd;
+ continue;
+ }
+
+ if (strcmp(elems->handle.table.name, cmd->handle.table.name) ||
+ strcmp(elems->handle.set.name, cmd->handle.set.name)) {
+ elems = cmd;
+ continue;
+ }
+
+ collapse = true;
+ list_for_each_entry_safe(expr, enext, &cmd->expr->expressions, list) {
+ expr->cmd = cmd;
+ list_move_tail(&expr->list, &elems->expr->expressions);
+ }
+ elems->expr->size += cmd->expr->size;
+ list_move_tail(&cmd->list, &elems->collapse_list);
+ }
+
+ return collapse;
+}
+
+void nft_cmd_uncollapse(struct list_head *cmds)
+{
+ struct cmd *cmd, *cmd_next, *collapse_cmd, *collapse_cmd_next;
+ struct expr *expr, *next;
+
+ list_for_each_entry_safe(cmd, cmd_next, cmds, list) {
+ if (list_empty(&cmd->collapse_list))
+ continue;
+
+ assert(cmd->obj == CMD_OBJ_ELEMENTS);
+
+ list_for_each_entry_safe(expr, next, &cmd->expr->expressions, list) {
+ if (!expr->cmd)
+ continue;
+
+ list_move_tail(&expr->list, &expr->cmd->expr->expressions);
+ cmd->expr->size--;
+ expr->cmd = NULL;
+ }
+
+ list_for_each_entry_safe(collapse_cmd, collapse_cmd_next, &cmd->collapse_list, list) {
+ collapse_cmd->elem.set = set_get(cmd->elem.set);
+ list_add(&collapse_cmd->list, &cmd->list);
+ }
+ }
+}
+
struct markup *markup_alloc(uint32_t format)
{
struct markup *markup;
--
2.41.0.rc1

View File

@ -0,0 +1,84 @@
From af9045e2f2029b6573db32bd15ab861d797b86a6 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 24 Jun 2022 16:02:59 +0200
Subject: [PATCH] intervals: do not report exact overlaps for new elements
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 87ba510fc704f
commit 87ba510fc704f766b5417d3bfc326e8ab9378c2a
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Mon Jun 13 17:22:47 2022 +0200
intervals: do not report exact overlaps for new elements
Two new elements that represent an exact overlap should not trigger an error.
add table t
add set t s { type ipv4_addr; flags interval; }
add element t s { 1.0.1.0/24 }
...
add element t s { 1.0.1.0/24 }
result in a bogus error.
# nft -f set.nft
set.nft:1002:19-28: Error: conflicting intervals specified
add element t s { 1.0.1.0/24 }
^^^^^^^^^^
Fixes: 3da9643fb9ff ("intervals: add support to automerge with kernel elements")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/intervals.c | 3 +--
tests/shell/testcases/sets/exact_overlap_0 | 22 ++++++++++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)
create mode 100755 tests/shell/testcases/sets/exact_overlap_0
diff --git a/src/intervals.c b/src/intervals.c
index bc414d6..89f5c33 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -540,8 +540,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
}
if (mpz_cmp(prev_range.low, range.low) == 0 &&
- mpz_cmp(prev_range.high, range.high) == 0 &&
- (elem->flags & EXPR_F_KERNEL || prev->flags & EXPR_F_KERNEL))
+ mpz_cmp(prev_range.high, range.high) == 0)
goto next;
if (mpz_cmp(prev_range.low, range.low) <= 0 &&
diff --git a/tests/shell/testcases/sets/exact_overlap_0 b/tests/shell/testcases/sets/exact_overlap_0
new file mode 100755
index 0000000..1ce9304
--- /dev/null
+++ b/tests/shell/testcases/sets/exact_overlap_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+RULESET="add table t
+add set t s { type ipv4_addr; flags interval; }
+add element t s { 1.0.1.0/24 }
+add element t s { 1.0.2.0/23 }
+add element t s { 1.0.8.0/21 }
+add element t s { 1.0.32.0/19 }
+add element t s { 1.1.0.0/24 }
+add element t s { 1.1.2.0/23 }
+add element t s { 1.1.4.0/22 }
+add element t s { 1.1.8.0/24 }
+add element t s { 1.1.9.0/24 }
+add element t s { 1.1.10.0/23 }
+add element t s { 1.1.12.0/22 }
+add element t s { 1.1.16.0/20 }
+add element t s { 1.1.32.0/19 }
+add element t s { 1.0.1.0/24 }"
+
+$NFT -f - <<< $RULESET || exit 1
+
+$NFT add element t s { 1.0.1.0/24 }
--
2.41.0.rc1

View File

@ -1,68 +0,0 @@
From 13bd961c3ba83e4189dcffdcf570c5a4391fd5f9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 10 Jan 2020 19:58:29 +0100
Subject: [PATCH] monitor: Do not decompose non-anonymous sets
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1774742
Upstream Status: nftables commit 5d57fa3e99bb9
commit 5d57fa3e99bb9f2044e236d4ddb7d874cfefe1dd
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jan 9 13:34:20 2020 +0100
monitor: Do not decompose non-anonymous sets
They have been decomposed already, trying to do that again causes a
segfault. This is a similar fix as in commit 8ecb885589591 ("src:
restore --echo with anonymous sets").
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/monitor.c | 2 +-
tests/monitor/testcases/set-interval.t | 20 ++++++++++++++++++++
2 files changed, 21 insertions(+), 1 deletion(-)
create mode 100644 tests/monitor/testcases/set-interval.t
diff --git a/src/monitor.c b/src/monitor.c
index ea0393c..0da9858 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -500,7 +500,7 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
static void rule_map_decompose_cb(struct set *s, void *data)
{
- if (s->flags & NFT_SET_INTERVAL)
+ if (s->flags & (NFT_SET_INTERVAL & NFT_SET_ANONYMOUS))
interval_map_decompose(s->init);
}
diff --git a/tests/monitor/testcases/set-interval.t b/tests/monitor/testcases/set-interval.t
new file mode 100644
index 0000000..59930c5
--- /dev/null
+++ b/tests/monitor/testcases/set-interval.t
@@ -0,0 +1,20 @@
+# setup first
+I add table ip t
+I add chain ip t c
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}}
+
+# add set with elements, monitor output expectedly differs
+I add set ip t s { type inet_service; flags interval; elements = { 20, 30-40 }; }
+O add set ip t s { type inet_service; flags interval; }
+O add element ip t s { 20 }
+O add element ip t s { 30-40 }
+J {"add": {"set": {"family": "ip", "name": "s", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [20]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [{"range": [30, 40]}]}}}}
+
+# this would crash nft
+I add rule ip t c tcp dport @s
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": "@s"}}]}}}
--
2.31.1

View File

@ -0,0 +1,55 @@
From cfb1670ece6414c3d2aad5dd7df572b0cc07acd5 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 24 Jun 2022 16:02:59 +0200
Subject: [PATCH] intervals: do not empty cache for maps
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit d434de8b50dcf
commit d434de8b50dcf3f5f4ca027e122a7df9d4e5d8e1
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jun 16 10:53:56 2022 +0200
intervals: do not empty cache for maps
Translate set element to range and sort in maps for the NFT_SET_MAP
case, which does not support for automerge yet.
Fixes: 81e36530fcac ("src: replace interval segment tree overlap and automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/intervals.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/intervals.c b/src/intervals.c
index 89f5c33..e203413 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -216,6 +216,12 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
struct cmd *purge_cmd;
struct handle h = {};
+ if (set->flags & NFT_SET_MAP) {
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+ return 0;
+ }
+
if (existing_set) {
if (existing_set->init) {
list_splice_init(&existing_set->init->expressions,
@@ -229,9 +235,6 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
set_to_range(init);
list_expr_sort(&init->expressions);
- if (set->flags & NFT_SET_MAP)
- return 0;
-
ctx.purge = set_expr_alloc(&internal_location, set);
setelem_automerge(&ctx);
--
2.41.0.rc1

View File

@ -1,80 +0,0 @@
From 2e7cb6c2d46d9b8b91ff4b5d6797b7544c23ba44 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 13 Jan 2020 16:58:57 +0100
Subject: [PATCH] monitor: Fix output for ranges in anonymous sets
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1774742
Upstream Status: nftables commit ddbacd70d061e
commit ddbacd70d061eb1b6808f501969809bfb5d03001
Author: Phil Sutter <phil@nwl.cc>
Date: Mon Jan 13 14:53:24 2020 +0100
monitor: Fix output for ranges in anonymous sets
Previous fix for named interval sets was simply wrong: Instead of
limiting decomposing to anonymous interval sets, it effectively disabled
it entirely.
Since code needs to check for both interval and anonymous bits
separately, introduce set_is_interval() helper to keep the code
readable.
Also extend test case to assert ranges in anonymous sets are correctly
printed by echo or monitor modes. Without this fix, range boundaries are
printed as individual set elements.
Fixes: 5d57fa3e99bb9 ("monitor: Do not decompose non-anonymous sets")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/rule.h | 5 +++++
src/monitor.c | 2 +-
tests/monitor/testcases/set-interval.t | 5 +++++
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/include/rule.h b/include/rule.h
index 0b2eba3..47eb29f 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -363,6 +363,11 @@ static inline bool set_is_meter(uint32_t set_flags)
return set_is_anonymous(set_flags) && (set_flags & NFT_SET_EVAL);
}
+static inline bool set_is_interval(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_INTERVAL;
+}
+
#include <statement.h>
struct counter {
diff --git a/src/monitor.c b/src/monitor.c
index 0da9858..fb803cf 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -500,7 +500,7 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
static void rule_map_decompose_cb(struct set *s, void *data)
{
- if (s->flags & (NFT_SET_INTERVAL & NFT_SET_ANONYMOUS))
+ if (set_is_interval(s->flags) && set_is_anonymous(s->flags))
interval_map_decompose(s->init);
}
diff --git a/tests/monitor/testcases/set-interval.t b/tests/monitor/testcases/set-interval.t
index 59930c5..1fbcfe2 100644
--- a/tests/monitor/testcases/set-interval.t
+++ b/tests/monitor/testcases/set-interval.t
@@ -18,3 +18,8 @@ J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set"
I add rule ip t c tcp dport @s
O -
J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": "@s"}}]}}}
+
+# test anonymous interval sets as well
+I add rule ip t c tcp dport { 20, 30-40 }
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": {"set": [20, {"range": [30, 40]}]}}}]}}}
--
2.31.1

View File

@ -0,0 +1,139 @@
From 5c5128094c75a184e54e82f2ad43c67423184c3e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 24 Jun 2022 16:02:59 +0200
Subject: [PATCH] intervals: Do not sort cached set elements over and over
again
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 59e3a59221fb8
commit 59e3a59221fb81c289a0868a85140dd452fb1c30
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jun 16 10:56:12 2022 +0200
intervals: Do not sort cached set elements over and over again
When adding element(s) to a non-empty set, code merged the two lists and
sorted the result. With many individual 'add element' commands this
causes substantial overhead. Make use of the fact that
existing_set->init is sorted already, sort only the list of new elements
and use list_splice_sorted() to merge the two sorted lists.
Add set_sort_splice() and use it for set element overlap detection and
automerge.
A test case adding ~25k elements in individual commands completes in
about 1/4th of the time with this patch applied.
Joint work with Pablo.
Fixes: 3da9643fb9ff9 ("intervals: add support to automerge with kernel elements")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/expression.h | 1 +
src/intervals.c | 46 +++++++++++++++++++++-----------------------
src/mergesort.c | 2 +-
3 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index 53194c9..cf7319b 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -481,6 +481,7 @@ extern struct expr *compound_expr_alloc(const struct location *loc,
extern void compound_expr_add(struct expr *compound, struct expr *expr);
extern void compound_expr_remove(struct expr *compound, struct expr *expr);
extern void list_expr_sort(struct list_head *head);
+extern void list_splice_sorted(struct list_head *list, struct list_head *head);
extern struct expr *concat_expr_alloc(const struct location *loc);
diff --git a/src/intervals.c b/src/intervals.c
index e203413..dcc06d1 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -118,6 +118,26 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
return false;
}
+static void set_sort_splice(struct expr *init, struct set *set)
+{
+ struct set *existing_set = set->existing_set;
+
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+
+ if (!existing_set)
+ return;
+
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ list_splice_sorted(&existing_set->init->expressions,
+ &init->expressions);
+ init_list_head(&existing_set->init->expressions);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
+}
+
static void setelem_automerge(struct set_automerge_ctx *ctx)
{
struct expr *i, *next, *prev = NULL;
@@ -222,18 +242,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
return 0;
}
- if (existing_set) {
- if (existing_set->init) {
- list_splice_init(&existing_set->init->expressions,
- &init->expressions);
- } else {
- existing_set->init = set_expr_alloc(&internal_location,
- set);
- }
- }
-
- set_to_range(init);
- list_expr_sort(&init->expressions);
+ set_sort_splice(init, set);
ctx.purge = set_expr_alloc(&internal_location, set);
@@ -591,18 +600,7 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
struct expr *i, *n, *clone;
int err;
- if (existing_set) {
- if (existing_set->init) {
- list_splice_init(&existing_set->init->expressions,
- &init->expressions);
- } else {
- existing_set->init = set_expr_alloc(&internal_location,
- set);
- }
- }
-
- set_to_range(init);
- list_expr_sort(&init->expressions);
+ set_sort_splice(init, set);
err = setelem_overlap(msgs, set, init);
diff --git a/src/mergesort.c b/src/mergesort.c
index 8e6aac5..dca7142 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -70,7 +70,7 @@ static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
return ret;
}
-static void list_splice_sorted(struct list_head *list, struct list_head *head)
+void list_splice_sorted(struct list_head *list, struct list_head *head)
{
struct list_head *h = head->next;
struct list_head *l = list->next;
--
2.41.0.rc1

View File

@ -1,51 +0,0 @@
From ca4d1604b18abf7189ecfd5e06cb74abc3694076 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 16 Jan 2020 18:40:52 +0100
Subject: [PATCH] xfrm: spi is big-endian
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1790963
Upstream Status: nftables commit 488356b895024
commit 488356b895024d0944b20feb1f930558726e0877
Author: Florian Westphal <fw@strlen.de>
Date: Tue Jan 14 13:37:28 2020 +0100
xfrm: spi is big-endian
the kernel stores spi in a __be32, so fix up the byteorder annotation.
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/xfrm.c | 2 +-
tests/py/inet/ipsec.t.payload | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/xfrm.c b/src/xfrm.c
index 4dd53c3..336e8c9 100644
--- a/src/xfrm.c
+++ b/src/xfrm.c
@@ -39,7 +39,7 @@ const struct xfrm_template xfrm_templates[] = {
[NFT_XFRM_KEY_DADDR_IP6] = XFRM_TEMPLATE_BE("daddr", &ip6addr_type, 16 * BITS_PER_BYTE),
[NFT_XFRM_KEY_SADDR_IP6] = XFRM_TEMPLATE_BE("saddr", &ip6addr_type, 16 * BITS_PER_BYTE),
[NFT_XFRM_KEY_REQID] = XFRM_TEMPLATE_HE("reqid", &integer_type, 4 * BITS_PER_BYTE),
- [NFT_XFRM_KEY_SPI] = XFRM_TEMPLATE_HE("spi", &integer_type, 4 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_SPI] = XFRM_TEMPLATE_BE("spi", &integer_type, 4 * BITS_PER_BYTE),
};
static void xfrm_expr_print(const struct expr *expr, struct output_ctx *octx)
diff --git a/tests/py/inet/ipsec.t.payload b/tests/py/inet/ipsec.t.payload
index 6049c66..c46a226 100644
--- a/tests/py/inet/ipsec.t.payload
+++ b/tests/py/inet/ipsec.t.payload
@@ -16,7 +16,6 @@ ip ipsec-ip4 ipsec-input
# ipsec out spi 1-561
inet ipsec-inet ipsec-post
[ xfrm load out 0 spi => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 4, 4) ]
[ cmp gte reg 1 0x01000000 ]
[ cmp lte reg 1 0x31020000 ]
--
2.31.1

View File

@ -0,0 +1,44 @@
From a2e5f4f59c0d4a3880a4de5e95adffc553216d2e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:15:02 +0100
Subject: [PATCH] doc: Document limitations of ipsec expression with
xfrm_interface
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 446e76dbde713
commit 446e76dbde713327358f17a8af6ce86b8541c836
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jun 23 17:49:20 2022 +0200
doc: Document limitations of ipsec expression with xfrm_interface
Point at a possible solution to match IPsec info of locally generated
traffic routed to an xfrm-type interface.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
doc/primary-expression.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index f97778b..4d6b087 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -428,6 +428,10 @@ Destination address of the tunnel|
ipv4_addr/ipv6_addr
|=================================
+*Note:* When using xfrm_interface, this expression is not useable in output
+hook as the plain packet does not traverse it with IPsec info attached - use a
+chain in postrouting hook instead.
+
NUMGEN EXPRESSION
~~~~~~~~~~~~~~~~~
--
2.41.0.rc1

View File

@ -1,573 +0,0 @@
From 8537751e48dfacee11d48ad3f050bdacc930284c Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Jan 2020 12:50:23 +0100
Subject: [PATCH] tests: shell: Search diff tool once and for all
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1790793
Upstream Status: nftables commit 68310ba0f9c20
commit 68310ba0f9c2066f7463d66a1a1938b66fb8a4c4
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Jan 14 16:50:35 2020 +0100
tests: shell: Search diff tool once and for all
Instead of calling 'which diff' over and over again, just detect the
tool's presence in run-tests.sh and pass $DIFF to each testcase just
like with nft binary.
Fall back to using 'true' command to avoid the need for any conditional
calling in test cases.
While being at it, unify potential diff calls so that a string
comparison in shell happens irrespective of diff presence.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
tests/shell/run-tests.sh | 7 ++++++-
tests/shell/testcases/flowtable/0010delete_handle_0 | 3 +--
tests/shell/testcases/listing/0003table_0 | 6 ++----
tests/shell/testcases/listing/0004table_0 | 3 +--
tests/shell/testcases/listing/0005ruleset_ip_0 | 3 +--
tests/shell/testcases/listing/0006ruleset_ip6_0 | 3 +--
tests/shell/testcases/listing/0007ruleset_inet_0 | 3 +--
tests/shell/testcases/listing/0008ruleset_arp_0 | 3 +--
tests/shell/testcases/listing/0009ruleset_bridge_0 | 3 +--
tests/shell/testcases/listing/0010sets_0 | 3 +--
tests/shell/testcases/listing/0011sets_0 | 3 +--
tests/shell/testcases/listing/0012sets_0 | 3 +--
tests/shell/testcases/listing/0013objects_0 | 3 +--
tests/shell/testcases/listing/0014objects_0 | 6 ++----
tests/shell/testcases/listing/0015dynamic_0 | 3 +--
tests/shell/testcases/listing/0017objects_0 | 3 +--
tests/shell/testcases/listing/0018data_0 | 3 +--
tests/shell/testcases/listing/0019set_0 | 3 +--
tests/shell/testcases/listing/0020flowtable_0 | 3 +--
.../shell/testcases/maps/0003map_add_many_elements_0 | 3 +--
.../testcases/maps/0004interval_map_create_once_0 | 3 +--
tests/shell/testcases/maps/0008interval_map_delete_0 | 3 +--
tests/shell/testcases/netns/0001nft-f_0 | 3 +--
tests/shell/testcases/netns/0002loosecommands_0 | 3 +--
tests/shell/testcases/netns/0003many_0 | 3 +--
tests/shell/testcases/nft-f/0016redefines_1 | 3 +--
.../testcases/optionals/delete_object_handles_0 | 3 +--
.../testcases/optionals/update_object_handles_0 | 3 +--
.../rule_management/0001addinsertposition_0 | 12 ++++--------
tests/shell/testcases/sets/0028delete_handle_0 | 3 +--
.../testcases/sets/0036add_set_element_expiration_0 | 5 ++++-
tests/shell/testcases/transactions/0003table_0 | 4 +---
tests/shell/testcases/transactions/0040set_0 | 3 +--
33 files changed, 46 insertions(+), 75 deletions(-)
diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh
index 632ccce..29a2c39 100755
--- a/tests/shell/run-tests.sh
+++ b/tests/shell/run-tests.sh
@@ -43,6 +43,11 @@ if [ ! -x "$MODPROBE" ] ; then
msg_error "no modprobe binary found"
fi
+DIFF="$(which diff)"
+if [ ! -x "$DIFF" ] ; then
+ DIFF=true
+fi
+
if [ "$1" == "-v" ] ; then
VERBOSE=y
shift
@@ -96,7 +101,7 @@ do
kernel_cleanup
msg_info "[EXECUTING] $testfile"
- test_output=$(NFT=$NFT ${testfile} 2>&1)
+ test_output=$(NFT=$NFT DIFF=$DIFF ${testfile} 2>&1)
rc_got=$?
echo -en "\033[1A\033[K" # clean the [EXECUTING] foobar line
diff --git a/tests/shell/testcases/flowtable/0010delete_handle_0 b/tests/shell/testcases/flowtable/0010delete_handle_0
index 985d4a3..8dd8d9f 100755
--- a/tests/shell/testcases/flowtable/0010delete_handle_0
+++ b/tests/shell/testcases/flowtable/0010delete_handle_0
@@ -16,7 +16,6 @@ EXPECTED="table inet t {
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0003table_0 b/tests/shell/testcases/listing/0003table_0
index 1b288e4..5060be0 100755
--- a/tests/shell/testcases/listing/0003table_0
+++ b/tests/shell/testcases/listing/0003table_0
@@ -11,15 +11,13 @@ $NFT add table test
GET="$($NFT list table test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
# also this way
GET="$($NFT list table ip test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0004table_0 b/tests/shell/testcases/listing/0004table_0
index 2c7c995..1d69119 100755
--- a/tests/shell/testcases/listing/0004table_0
+++ b/tests/shell/testcases/listing/0004table_0
@@ -12,8 +12,7 @@ $NFT add table test2
GET="$($NFT list table test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0005ruleset_ip_0 b/tests/shell/testcases/listing/0005ruleset_ip_0
index c326680..39c0328 100755
--- a/tests/shell/testcases/listing/0005ruleset_ip_0
+++ b/tests/shell/testcases/listing/0005ruleset_ip_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset ip)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0006ruleset_ip6_0 b/tests/shell/testcases/listing/0006ruleset_ip6_0
index 093d5a5..1b67f50 100755
--- a/tests/shell/testcases/listing/0006ruleset_ip6_0
+++ b/tests/shell/testcases/listing/0006ruleset_ip6_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset ip6)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0007ruleset_inet_0 b/tests/shell/testcases/listing/0007ruleset_inet_0
index b24cc4c..257c7a9 100755
--- a/tests/shell/testcases/listing/0007ruleset_inet_0
+++ b/tests/shell/testcases/listing/0007ruleset_inet_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset inet)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0008ruleset_arp_0 b/tests/shell/testcases/listing/0008ruleset_arp_0
index fff0fee..be42c47 100755
--- a/tests/shell/testcases/listing/0008ruleset_arp_0
+++ b/tests/shell/testcases/listing/0008ruleset_arp_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset arp)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0009ruleset_bridge_0 b/tests/shell/testcases/listing/0009ruleset_bridge_0
index 247ed47..c6a99f5 100755
--- a/tests/shell/testcases/listing/0009ruleset_bridge_0
+++ b/tests/shell/testcases/listing/0009ruleset_bridge_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset bridge)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0010sets_0 b/tests/shell/testcases/listing/0010sets_0
index 855cceb..0f5f2bd 100755
--- a/tests/shell/testcases/listing/0010sets_0
+++ b/tests/shell/testcases/listing/0010sets_0
@@ -57,7 +57,6 @@ $NFT add set inet filter set2 { type icmpv6_type \; }
GET="$($NFT list sets)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0011sets_0 b/tests/shell/testcases/listing/0011sets_0
index aac9eac..b6f12b5 100755
--- a/tests/shell/testcases/listing/0011sets_0
+++ b/tests/shell/testcases/listing/0011sets_0
@@ -38,7 +38,6 @@ $NFT add rule inet filter test tcp dport {80, 443}
GET="$($NFT list sets)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0012sets_0 b/tests/shell/testcases/listing/0012sets_0
index da16d94..6e4c959 100755
--- a/tests/shell/testcases/listing/0012sets_0
+++ b/tests/shell/testcases/listing/0012sets_0
@@ -33,7 +33,6 @@ $NFT add set inet filter set2 { type icmpv6_type \; }
GET="$($NFT list sets inet)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0013objects_0 b/tests/shell/testcases/listing/0013objects_0
index f691579..4d39143 100755
--- a/tests/shell/testcases/listing/0013objects_0
+++ b/tests/shell/testcases/listing/0013objects_0
@@ -42,7 +42,6 @@ $NFT add table test-ip
GET="$($NFT list table test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0014objects_0 b/tests/shell/testcases/listing/0014objects_0
index 20f6840..31d94f8 100755
--- a/tests/shell/testcases/listing/0014objects_0
+++ b/tests/shell/testcases/listing/0014objects_0
@@ -17,15 +17,13 @@ $NFT add table test-ip
GET="$($NFT list quotas)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
GET="$($NFT list quota test https-quota)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0015dynamic_0 b/tests/shell/testcases/listing/0015dynamic_0
index 4ff74e3..65fbe62 100755
--- a/tests/shell/testcases/listing/0015dynamic_0
+++ b/tests/shell/testcases/listing/0015dynamic_0
@@ -16,8 +16,7 @@ $NFT -f - <<< "$EXPECTED"
GET="$($NFT list set ip filter test_set)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0017objects_0 b/tests/shell/testcases/listing/0017objects_0
index 8a586e8..c4e72db 100755
--- a/tests/shell/testcases/listing/0017objects_0
+++ b/tests/shell/testcases/listing/0017objects_0
@@ -13,7 +13,6 @@ $NFT flush map inet filter countermap
GET="$($NFT list map inet filter countermap)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0018data_0 b/tests/shell/testcases/listing/0018data_0
index 544b6bf..4af253d 100755
--- a/tests/shell/testcases/listing/0018data_0
+++ b/tests/shell/testcases/listing/0018data_0
@@ -13,7 +13,6 @@ $NFT flush map inet filter ipmap
GET="$($NFT list map inet filter ipmap)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0019set_0 b/tests/shell/testcases/listing/0019set_0
index 54a8a06..6e8cb4d 100755
--- a/tests/shell/testcases/listing/0019set_0
+++ b/tests/shell/testcases/listing/0019set_0
@@ -13,7 +13,6 @@ $NFT flush set inet filter ipset
GET="$($NFT list set inet filter ipset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0020flowtable_0 b/tests/shell/testcases/listing/0020flowtable_0
index 6f630f1..2f0a98d 100755
--- a/tests/shell/testcases/listing/0020flowtable_0
+++ b/tests/shell/testcases/listing/0020flowtable_0
@@ -15,7 +15,6 @@ $NFT -f - <<< "$EXPECTED"
GET="$($NFT list flowtable inet filter f)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/maps/0003map_add_many_elements_0 b/tests/shell/testcases/maps/0003map_add_many_elements_0
index 047f949..2b254c5 100755
--- a/tests/shell/testcases/maps/0003map_add_many_elements_0
+++ b/tests/shell/testcases/maps/0003map_add_many_elements_0
@@ -61,8 +61,7 @@ EXPECTED="table ip x {
}"
GET=$($NFT list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/maps/0004interval_map_create_once_0 b/tests/shell/testcases/maps/0004interval_map_create_once_0
index 58b399c..3de0c9d 100755
--- a/tests/shell/testcases/maps/0004interval_map_create_once_0
+++ b/tests/shell/testcases/maps/0004interval_map_create_once_0
@@ -60,8 +60,7 @@ EXPECTED="table ip x {
}"
GET=$($NFT list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/maps/0008interval_map_delete_0 b/tests/shell/testcases/maps/0008interval_map_delete_0
index 7da6eb3..39ea312 100755
--- a/tests/shell/testcases/maps/0008interval_map_delete_0
+++ b/tests/shell/testcases/maps/0008interval_map_delete_0
@@ -26,7 +26,6 @@ $NFT add element filter m { 127.0.0.2 : 0x2 }
GET=$($NFT -s list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/netns/0001nft-f_0 b/tests/shell/testcases/netns/0001nft-f_0
index 8194226..a591f2c 100755
--- a/tests/shell/testcases/netns/0001nft-f_0
+++ b/tests/shell/testcases/netns/0001nft-f_0
@@ -93,8 +93,7 @@ fi
KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
$IP netns del $NETNS_NAME
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
exit 1
fi
exit 0
diff --git a/tests/shell/testcases/netns/0002loosecommands_0 b/tests/shell/testcases/netns/0002loosecommands_0
index 465c2e8..231f1fb 100755
--- a/tests/shell/testcases/netns/0002loosecommands_0
+++ b/tests/shell/testcases/netns/0002loosecommands_0
@@ -56,7 +56,6 @@ RULESET="table ip t {
KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
$IP netns del $NETNS_NAME
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
exit 1
fi
diff --git a/tests/shell/testcases/netns/0003many_0 b/tests/shell/testcases/netns/0003many_0
index a5fcb5d..afe9117 100755
--- a/tests/shell/testcases/netns/0003many_0
+++ b/tests/shell/testcases/netns/0003many_0
@@ -97,8 +97,7 @@ function test_netns()
KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
echo "E: ruleset in netns $NETNS_NAME differs from the loaded" >&2
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
$IP netns del $NETNS_NAME
exit 1
fi
diff --git a/tests/shell/testcases/nft-f/0016redefines_1 b/tests/shell/testcases/nft-f/0016redefines_1
index 4c26b37..1f59f6b 100755
--- a/tests/shell/testcases/nft-f/0016redefines_1
+++ b/tests/shell/testcases/nft-f/0016redefines_1
@@ -26,8 +26,7 @@ $NFT -f - <<< "$RULESET"
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/optionals/delete_object_handles_0 b/tests/shell/testcases/optionals/delete_object_handles_0
index a2ae422..9b65e67 100755
--- a/tests/shell/testcases/optionals/delete_object_handles_0
+++ b/tests/shell/testcases/optionals/delete_object_handles_0
@@ -37,7 +37,6 @@ table ip6 test-ip6 {
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/optionals/update_object_handles_0 b/tests/shell/testcases/optionals/update_object_handles_0
index 17c0c86..8b12b8c 100755
--- a/tests/shell/testcases/optionals/update_object_handles_0
+++ b/tests/shell/testcases/optionals/update_object_handles_0
@@ -19,7 +19,6 @@ EXPECTED="table ip test-ip {
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/rule_management/0001addinsertposition_0 b/tests/shell/testcases/rule_management/0001addinsertposition_0
index bb3fda5..237e9e3 100755
--- a/tests/shell/testcases/rule_management/0001addinsertposition_0
+++ b/tests/shell/testcases/rule_management/0001addinsertposition_0
@@ -30,8 +30,7 @@ for arg in "position 2" "handle 2" "index 0"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
@@ -42,8 +41,7 @@ for arg in "position 3" "handle 3" "index 1"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
@@ -62,8 +60,7 @@ for arg in "position 3" "handle 3" "index 1"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
@@ -82,8 +79,7 @@ for arg in "position 2" "handle 2" "index 0"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
diff --git a/tests/shell/testcases/sets/0028delete_handle_0 b/tests/shell/testcases/sets/0028delete_handle_0
index 5ad17c2..c6d1253 100755
--- a/tests/shell/testcases/sets/0028delete_handle_0
+++ b/tests/shell/testcases/sets/0028delete_handle_0
@@ -29,7 +29,6 @@ EXPECTED="table ip test-ip {
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/sets/0036add_set_element_expiration_0 b/tests/shell/testcases/sets/0036add_set_element_expiration_0
index 8dfed6c..51ed0f2 100755
--- a/tests/shell/testcases/sets/0036add_set_element_expiration_0
+++ b/tests/shell/testcases/sets/0036add_set_element_expiration_0
@@ -8,6 +8,9 @@ add element ip x y { 1.1.1.1 timeout 30s expires 15s }"
test_output=$($NFT -e -f - <<< "$RULESET" 2>&1)
-diff -u <(echo "$test_output") <(echo "$RULESET")
+if [ "$test_output" != "$RULESET" ] ; then
+ $DIFF -u <(echo "$test_output") <(echo "$RULESET")
+ exit 1
+fi
$NFT "add chain ip x c; add rule ip x c ip saddr @y"
diff --git a/tests/shell/testcases/transactions/0003table_0 b/tests/shell/testcases/transactions/0003table_0
index 6861eab..91186de 100755
--- a/tests/shell/testcases/transactions/0003table_0
+++ b/tests/shell/testcases/transactions/0003table_0
@@ -14,7 +14,6 @@ fi
KERNEL_RULESET="$($NFT list ruleset)"
if [ "" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
echo "Got a ruleset, but expected empty: "
echo "$KERNEL_RULESET"
exit 1
@@ -42,7 +41,6 @@ $NFT -f - <<< "$RULESETFAIL" && exit 2
KERNEL_RULESET="$($NFT list ruleset)"
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
exit 1
fi
diff --git a/tests/shell/testcases/transactions/0040set_0 b/tests/shell/testcases/transactions/0040set_0
index a404abc..468816b 100755
--- a/tests/shell/testcases/transactions/0040set_0
+++ b/tests/shell/testcases/transactions/0040set_0
@@ -29,8 +29,7 @@ fi
GET="$($NFT list ruleset)"
if [ "$RULESET" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$GET")
+ $DIFF -u <(echo "$RULESET") <(echo "$GET")
exit 1
fi
--
2.31.1

View File

@ -1,85 +0,0 @@
From a44bd9f4b6cf77cb75c5f596908100270893e8d5 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Jan 2020 12:50:23 +0100
Subject: [PATCH] cache: Fix for doubled output after reset command
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1790793
Upstream Status: nftables commit 7def18395d118
commit 7def18395d118e22a009de7e2e8de7f77906580b
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Jan 14 17:25:35 2020 +0100
cache: Fix for doubled output after reset command
Reset command causes a dump of the objects to reset and adds those to
cache. Yet it ignored if the object in question was already there and up
to now CMD_RESET was flagged as NFT_CACHE_FULL.
Tackle this from two angles: First, reduce cache requirements of reset
command to the necessary bits which is table cache. This alone would
suffice if there wasn't interactive mode (and other libnftables users):
A cache containing the objects to reset might be in place already, so
add dumped objects to cache only if they don't exist already.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/cache.c | 4 +++-
src/rule.c | 3 ++-
tests/shell/testcases/sets/0024named_objects_0 | 12 +++++++++++-
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/cache.c b/src/cache.c
index 0c28a28..05f0d68 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -138,8 +138,10 @@ unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
case CMD_GET:
flags = evaluate_cache_get(cmd, flags);
break;
- case CMD_LIST:
case CMD_RESET:
+ flags |= NFT_CACHE_TABLE;
+ break;
+ case CMD_LIST:
case CMD_EXPORT:
case CMD_MONITOR:
flags |= NFT_CACHE_FULL;
diff --git a/src/rule.c b/src/rule.c
index d985d3a..3ca1805 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -2554,7 +2554,8 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
ret = netlink_reset_objs(ctx, cmd, type, dump);
list_for_each_entry_safe(obj, next, &ctx->list, list) {
table = table_lookup(&obj->handle, &ctx->nft->cache);
- list_move(&obj->list, &table->objs);
+ if (!obj_lookup(table, obj->handle.obj.name, obj->type))
+ list_move(&obj->list, &table->objs);
}
if (ret < 0)
return ret;
diff --git a/tests/shell/testcases/sets/0024named_objects_0 b/tests/shell/testcases/sets/0024named_objects_0
index 3bd16f2..21200c3 100755
--- a/tests/shell/testcases/sets/0024named_objects_0
+++ b/tests/shell/testcases/sets/0024named_objects_0
@@ -35,4 +35,14 @@ table inet x {
set -e
$NFT -f - <<< "$RULESET"
-$NFT reset counter inet x user321
+EXPECTED="table inet x {
+ counter user321 {
+ packets 12 bytes 1433
+ }
+}"
+
+GET="$($NFT reset counter inet x user321)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
--
2.31.1

View File

@ -0,0 +1,86 @@
From 23e6c3545b6c416a0eb7d3c7ac97c74215dcc19c Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:18:10 +0100
Subject: [PATCH] tests/py: Add a test for failing ipsec after counter
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit ed2426bccd3ea
commit ed2426bccd3ea954adc8a010bf1736e8ed6a81b9
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jun 23 16:28:42 2022 +0200
tests/py: Add a test for failing ipsec after counter
This is a bug in parser/scanner due to scoping:
| Error: syntax error, unexpected string, expecting saddr or daddr
| add rule ip ipsec-ip4 ipsec-forw counter ipsec out ip daddr 192.168.1.2
| ^^^^^
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
tests/py/inet/ipsec.t | 2 ++
tests/py/inet/ipsec.t.json | 21 +++++++++++++++++++++
tests/py/inet/ipsec.t.payload | 6 ++++++
3 files changed, 29 insertions(+)
diff --git a/tests/py/inet/ipsec.t b/tests/py/inet/ipsec.t
index e924e9b..b18df39 100644
--- a/tests/py/inet/ipsec.t
+++ b/tests/py/inet/ipsec.t
@@ -19,3 +19,5 @@ ipsec in ip6 daddr dead::beef;ok
ipsec out ip6 saddr dead::feed;ok
ipsec in spnum 256 reqid 1;fail
+
+counter ipsec out ip daddr 192.168.1.2;ok
diff --git a/tests/py/inet/ipsec.t.json b/tests/py/inet/ipsec.t.json
index d7d3a03..18a64f3 100644
--- a/tests/py/inet/ipsec.t.json
+++ b/tests/py/inet/ipsec.t.json
@@ -134,3 +134,24 @@
}
}
]
+
+# counter ipsec out ip daddr 192.168.1.2
+[
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "out",
+ "family": "ip",
+ "key": "daddr",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.2"
+ }
+ }
+]
diff --git a/tests/py/inet/ipsec.t.payload b/tests/py/inet/ipsec.t.payload
index c46a226..9648255 100644
--- a/tests/py/inet/ipsec.t.payload
+++ b/tests/py/inet/ipsec.t.payload
@@ -37,3 +37,9 @@ ip ipsec-ip4 ipsec-forw
[ xfrm load out 0 saddr6 => reg 1 ]
[ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xedfe0000 ]
+# counter ipsec out ip daddr 192.168.1.2
+ip ipsec-ip4 ipsec-forw
+ [ counter pkts 0 bytes 0 ]
+ [ xfrm load out 0 daddr4 => reg 1 ]
+ [ cmp eq reg 1 0x0201a8c0 ]
+
--
2.41.0.rc1

View File

@ -1,51 +0,0 @@
From cc70f19e588a0a33ed86c4a059b56a8f5b0c7a82 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 27 Jan 2020 16:11:41 +0100
Subject: [PATCH] netlink: Fix leak in unterminated string deserializer
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1793030
Upstream Status: nftables commit c3f6be3f2dced
commit c3f6be3f2dcedf6d79751c0b975315ebc3184364
Author: Phil Sutter <phil@nwl.cc>
Date: Mon Jan 20 13:52:10 2020 +0100
netlink: Fix leak in unterminated string deserializer
Allocated 'mask' expression is not freed before returning to caller,
although it is used temporarily only.
Fixes: b851ba4731d9f ("src: add interface wildcard matching")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/netlink_delinearize.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 154353b..06a0312 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2030,7 +2030,7 @@ static bool __expr_postprocess_string(struct expr **exprp)
static struct expr *expr_postprocess_string(struct expr *expr)
{
- struct expr *mask;
+ struct expr *mask, *out;
assert(expr_basetype(expr)->type == TYPE_STRING);
if (__expr_postprocess_string(&expr))
@@ -2040,7 +2040,9 @@ static struct expr *expr_postprocess_string(struct expr *expr)
BYTEORDER_HOST_ENDIAN,
expr->len + BITS_PER_BYTE, NULL);
mpz_init_bitmask(mask->value, expr->len);
- return string_wildcard_expr_alloc(&expr->location, mask, expr);
+ out = string_wildcard_expr_alloc(&expr->location, mask, expr);
+ expr_free(mask);
+ return out;
}
static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
--
2.31.1

View File

@ -0,0 +1,38 @@
From d0d4d54136f10c23e279da40aae188b8fdc09293 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:18:10 +0100
Subject: [PATCH] parser: add missing synproxy scope closure
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 994bf5004b365
commit 994bf5004b365904029f0fe8c2de587178583712
Author: Florian Westphal <fw@strlen.de>
Date: Thu Jun 23 18:28:14 2022 +0200
parser: add missing synproxy scope closure
Fixes: 232f2c3287fc ("scanner: synproxy: Move to own scope")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/parser_bison.y | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ca5c488..b548d5b 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -2016,7 +2016,7 @@ map_block_obj_type : COUNTER close_scope_counter { $$ = NFT_OBJECT_COUNTER; }
| QUOTA close_scope_quota { $$ = NFT_OBJECT_QUOTA; }
| LIMIT close_scope_limit { $$ = NFT_OBJECT_LIMIT; }
| SECMARK close_scope_secmark { $$ = NFT_OBJECT_SECMARK; }
- | SYNPROXY { $$ = NFT_OBJECT_SYNPROXY; }
+ | SYNPROXY close_scope_synproxy { $$ = NFT_OBJECT_SYNPROXY; }
;
map_block : /* empty */ { $$ = $<set>-1; }
--
2.41.0.rc1

View File

@ -1,75 +0,0 @@
From 6ecccc872b9cbed921af10e32d1a628eb6a74c01 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 27 Jan 2020 16:11:41 +0100
Subject: [PATCH] netlink: Fix leaks in netlink_parse_cmp()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1793030
Upstream Status: nftables commit e957bd9f10d5e
commit e957bd9f10d5e36671a0b0398e2037fc6201275b
Author: Phil Sutter <phil@nwl.cc>
Date: Mon Jan 20 14:48:26 2020 +0100
netlink: Fix leaks in netlink_parse_cmp()
This fixes several problems at once:
* Err path would leak expr 'right' in two places and 'left' in one.
* Concat case would leak 'right' by overwriting the pointer. Introduce a
temporary variable to hold the new pointer.
Fixes: 6377380bc265f ("netlink_delinearize: handle relational and lookup concat expressions")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/netlink_delinearize.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 06a0312..88dbd5a 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -274,7 +274,7 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
{
struct nft_data_delinearize nld;
enum nft_registers sreg;
- struct expr *expr, *left, *right;
+ struct expr *expr, *left, *right, *tmp;
enum ops op;
sreg = netlink_parse_register(nle, NFTNL_EXPR_CMP_SREG);
@@ -291,19 +291,26 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
if (left->len > right->len &&
expr_basetype(left) != &string_type) {
- return netlink_error(ctx, loc, "Relational expression size mismatch");
+ netlink_error(ctx, loc, "Relational expression size mismatch");
+ goto err_free;
} else if (left->len > 0 && left->len < right->len) {
expr_free(left);
left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
if (left == NULL)
- return;
- right = netlink_parse_concat_data(ctx, loc, sreg, right->len, right);
- if (right == NULL)
- return;
+ goto err_free;
+ tmp = netlink_parse_concat_data(ctx, loc, sreg, right->len, right);
+ if (tmp == NULL)
+ goto err_free;
+ expr_free(right);
+ right = tmp;
}
expr = relational_expr_alloc(loc, op, left, right);
ctx->stmt = expr_stmt_alloc(loc, expr);
+ return;
+err_free:
+ expr_free(left);
+ expr_free(right);
}
static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
--
2.31.1

View File

@ -0,0 +1,144 @@
From 80b1505ca2ef8432375dc524cc6763e7ef795b1a Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:18:10 +0100
Subject: [PATCH] scanner: don't pop active flex scanner scope
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 8623772af0610
commit 8623772af06103ed4ccca3d07e55afbf3d952d6d
Author: Florian Westphal <fw@strlen.de>
Date: Thu Jun 23 19:56:19 2022 +0200
scanner: don't pop active flex scanner scope
Currently we can pop a flex scope that is still active, i.e. the
scanner_pop_start_cond() for the scope has not been done.
Example:
counter ipsec out ip daddr 192.168.1.2 counter name "ipsec_out"
Here, parser fails because 'daddr' is parsed as STRING, not as DADDR token.
Bug is as follows:
COUNTER changes scope to COUNTER. (COUNTER).
Next, IPSEC scope gets pushed, stack is: COUNTER, IPSEC.
Then, the 'COUNTER' scope close happens. Because active scope has changed,
we cannot pop (we would pop the 'ipsec' scope in flex).
The pop operation gets delayed accordingly.
Next, IP gets pushed, stack is: COUNTER, IPSEC, IP, plus the information
that one scope closure/pop was delayed.
Then, the IP scope is closed. Because a pop operation was delayed, we pop again,
which brings us back to COUNTER state.
This is bogus: The pop operation CANNOT be done yet, because the ipsec scope
is still open, but the existing code lacks the information to detect this.
After popping the IP scope, we must remain in IPSEC scope until bison
parser calls scanner_pop_start_cond(, IPSEC).
This adds a counter per flex scope so that we can detect this case.
In above case, after the IP scope gets closed, the "new" (previous)
scope (IPSEC) will be treated as active and its close is attempted again
on the next call to scanner_pop_start_cond().
After this patch, transition in above rule is:
push counter (COUNTER)
push IPSEC (COUNTER, IPSEC)
pop COUNTER (delayed: COUNTER, IPSEC, pending-pop for COUNTER),
push IP (COUNTER, IPSEC, IP, pending-pop for COUNTER)
pop IP (COUNTER, IPSEC, pending-pop for COUNTER)
parse DADDR (we're in IPSEC scope, its valid token)
pop IPSEC (pops all remaining scopes).
We could also resurrect the commit:
"scanner: flags: move to own scope", the test case passes with the
new scope closure logic.
Fixes: bff106c5b277 ("scanner: add support for scope nesting")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/parser.h | 3 +++
src/scanner.l | 11 +++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/parser.h b/include/parser.h
index f32154c..5e5ad28 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -26,6 +26,7 @@ struct parser_state {
unsigned int flex_state_pop;
unsigned int startcond_type;
struct list_head *cmds;
+ unsigned int *startcond_active;
};
enum startcond_type {
@@ -82,6 +83,8 @@ enum startcond_type {
PARSER_SC_STMT_REJECT,
PARSER_SC_STMT_SYNPROXY,
PARSER_SC_STMT_TPROXY,
+
+ __SC_MAX
};
struct mnl_socket;
diff --git a/src/scanner.l b/src/scanner.l
index 2154281..ed7256b 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -1148,6 +1148,8 @@ void *scanner_init(struct parser_state *state)
yylex_init_extra(state, &scanner);
yyset_out(NULL, scanner);
+ state->startcond_active = xzalloc_array(__SC_MAX,
+ sizeof(*state->startcond_active));
return scanner;
}
@@ -1177,6 +1179,8 @@ void scanner_destroy(struct nft_ctx *nft)
struct parser_state *state = yyget_extra(nft->scanner);
input_descriptor_list_destroy(state);
+ xfree(state->startcond_active);
+
yylex_destroy(nft->scanner);
}
@@ -1185,6 +1189,7 @@ static void scanner_push_start_cond(void *scanner, enum startcond_type type)
struct parser_state *state = yyget_extra(scanner);
state->startcond_type = type;
+ state->startcond_active[type]++;
yy_push_state((int)type, scanner);
}
@@ -1193,6 +1198,8 @@ void scanner_pop_start_cond(void *scanner, enum startcond_type t)
{
struct parser_state *state = yyget_extra(scanner);
+ state->startcond_active[t]--;
+
if (state->startcond_type != t) {
state->flex_state_pop++;
return; /* Can't pop just yet! */
@@ -1202,6 +1209,10 @@ void scanner_pop_start_cond(void *scanner, enum startcond_type t)
state->flex_state_pop--;
state->startcond_type = yy_top_state(scanner);
yy_pop_state(scanner);
+
+ t = state->startcond_type;
+ if (state->startcond_active[t])
+ return;
}
state->startcond_type = yy_top_state(scanner);
--
2.41.0.rc1

View File

@ -0,0 +1,67 @@
From babfd73139d19750a7b1f94fdc1b5405f5affe61 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:25:59 +0100
Subject: [PATCH] intervals: fix crash when trying to remove element in empty
set
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 5357cb7b5cb93
commit 5357cb7b5cb93fc9b20d4d95b093d6b9f86b7727
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jun 23 14:20:17 2022 +0200
intervals: fix crash when trying to remove element in empty set
The set deletion routine expects an initialized set, otherwise it crashes.
Fixes: 3e8d934e4f72 ("intervals: support to partial deletion with automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/intervals.c | 6 +++++-
tests/shell/testcases/sets/errors_0 | 14 ++++++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
create mode 100755 tests/shell/testcases/sets/errors_0
diff --git a/src/intervals.c b/src/intervals.c
index dcc06d1..c21b3ee 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -475,7 +475,11 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
if (set->automerge)
automerge_delete(msgs, set, init, debug_mask);
- set_to_range(existing_set->init);
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
list_splice_init(&init->expressions, &del_list);
diff --git a/tests/shell/testcases/sets/errors_0 b/tests/shell/testcases/sets/errors_0
new file mode 100755
index 0000000..2960b69
--- /dev/null
+++ b/tests/shell/testcases/sets/errors_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
+
+delete element ip x y { 2.3.4.5 }"
+
+$NFT -f - <<< $RULESET || exit 0
--
2.41.0.rc1

View File

@ -1,42 +0,0 @@
From 55c537734f476d04c18f67083642b96bbead6219 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 27 Jan 2020 16:11:41 +0100
Subject: [PATCH] netlink: Avoid potential NULL-pointer deref in
netlink_gen_payload_stmt()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1793030
Upstream Status: nftables commit c9ddf0bff363f
commit c9ddf0bff363fc9101b563b592db600bdf4d65c5
Author: Phil Sutter <phil@nwl.cc>
Date: Mon Jan 20 16:32:40 2020 +0100
netlink: Avoid potential NULL-pointer deref in netlink_gen_payload_stmt()
With payload_needs_l4csum_update_pseudohdr() unconditionally
dereferencing passed 'desc' parameter and a previous check for it to be
non-NULL, make sure to call the function only if input is sane.
Fixes: 68de70f2b3fc6 ("netlink_linearize: fix IPv6 layer 4 checksum mangling")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/netlink_linearize.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 498326d..cb1b7fe 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -941,7 +941,7 @@ static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_OFFSET,
csum_off / BITS_PER_BYTE);
}
- if (expr->payload.base == PROTO_BASE_NETWORK_HDR &&
+ if (expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
payload_needs_l4csum_update_pseudohdr(expr, desc))
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
--
2.31.1

View File

@ -0,0 +1,80 @@
From 3ea1e90779e232776e72548e9a768df1771e0f2c Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:25:59 +0100
Subject: [PATCH] intervals: check for EXPR_F_REMOVE in case of element
mismatch
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 6d1ee9267e7e5
commit 6d1ee9267e7e5e429a84d7bb8a8644f9eebddb22
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jun 23 18:41:21 2022 +0200
intervals: check for EXPR_F_REMOVE in case of element mismatch
If auto-merge is disable and element to be deleted finds no exact
matching, then bail out.
Fixes: 3e8d934e4f72 ("intervals: support to partial deletion with automerge")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/intervals.c | 4 ++++
tests/shell/testcases/sets/errors_0 | 20 ++++++++++++++++++--
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/src/intervals.c b/src/intervals.c
index c21b3ee..13009ca 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -421,6 +421,10 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
expr_error(msgs, i, "element does not exist");
err = -1;
goto err;
+ } else if (i->flags & EXPR_F_REMOVE) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
}
prev = NULL;
}
diff --git a/tests/shell/testcases/sets/errors_0 b/tests/shell/testcases/sets/errors_0
index 2960b69..a676ac7 100755
--- a/tests/shell/testcases/sets/errors_0
+++ b/tests/shell/testcases/sets/errors_0
@@ -1,7 +1,5 @@
#!/bin/bash
-set -e
-
RULESET="table ip x {
set y {
type ipv4_addr
@@ -11,4 +9,22 @@ RULESET="table ip x {
delete element ip x y { 2.3.4.5 }"
+$NFT -f - <<< $RULESET
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
+
+add element x y { 1.1.1.1/24 }
+delete element x y { 1.1.1.1/24 }
+add element x y { 1.1.1.1/24 }
+delete element x y { 2.2.2.2/24 }"
+
$NFT -f - <<< $RULESET || exit 0
--
2.41.0.rc1

View File

@ -1,39 +0,0 @@
From 04d0d2e685063d422ce73b67eb01d4803100d379 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:35:27 +0100
Subject: [PATCH] tests: json_echo: Fix for Python3
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1754047
Upstream Status: nftables commit 582f142b1578b
commit 582f142b1578b6036707242bfe874bcefc002ac2
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Feb 6 01:21:30 2020 +0100
tests: json_echo: Fix for Python3
The keys() method returns an object which does not support indexing, so
convert it to a list prior to doing so.
Fixes: a35e3a0cdc63a ("tests: json_echo: convert to py3")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
tests/json_echo/run-test.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/json_echo/run-test.py b/tests/json_echo/run-test.py
index a636d5f..fa7d69a 100755
--- a/tests/json_echo/run-test.py
+++ b/tests/json_echo/run-test.py
@@ -119,7 +119,7 @@ def get_handle(output, search):
else:
data = item
- k = search.keys()[0]
+ k = list(search.keys())[0]
if not k in data:
continue
--
2.31.1

View File

@ -0,0 +1,76 @@
From 477a5632894a8bf6cba1f6e69a3f7d58d220820b Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] netlink_delinearize: allow postprocessing on concatenated
elements
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 0542a431e8dcc
commit 0542a431e8dccfa86fa5b1744f536e61a0b204f3
Author: Florian Westphal <fw@strlen.de>
Date: Tue Jun 14 21:57:58 2022 +0200
netlink_delinearize: allow postprocessing on concatenated elements
Currently there is no case where the individual expressions inside a
mapped concatenation need to be munged.
However, to support proper delinearization for an input like
'rule netdev nt nc set update ether saddr . vlan id timeout 5s @macset'
we need to allow this.
Right now, this gets listed as:
update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s }
because the ethernet protocol is replaced by vlan beforehand,
so we fail to map @ll,48,48 to a vlan protocol.
Likewise, we can't map the vlan info either because we cannot
cope with the 'and' operation properly, nor is it removed.
Prepare for this by deleting and re-adding so that we do not
corrupt the linked list.
After this, the list can be safely changed and a followup patch
can start to delete/reallocate expressions.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/netlink_delinearize.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 068c3bb..2f13990 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2538,16 +2538,21 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
unsigned int type = expr->dtype->type, ntype = 0;
int off = expr->dtype->subtypes;
const struct datatype *dtype;
+ LIST_HEAD(tmp);
+ struct expr *n;
- list_for_each_entry(i, &expr->expressions, list) {
+ list_for_each_entry_safe(i, n, &expr->expressions, list) {
if (type) {
dtype = concat_subtype_lookup(type, --off);
expr_set_type(i, dtype, dtype->byteorder);
}
+ list_del(&i->list);
expr_postprocess(ctx, &i);
+ list_add_tail(&i->list, &tmp);
ntype = concat_subtype_add(ntype, i->dtype->type);
}
+ list_splice(&tmp, &expr->expressions);
datatype_set(expr, concat_type_alloc(ntype));
break;
}
--
2.41.0.rc1

View File

@ -1,68 +0,0 @@
From 0eb301a3f50fb70cb78d955692f3feea1ad8095e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:35:27 +0100
Subject: [PATCH] tests: json_echo: Support testing host binaries
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1754047
Upstream Status: nftables commit 106b1f2b93f82
commit 106b1f2b93f82784c18dd5e312bbf88e6c02a5b8
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Jan 10 11:19:42 2020 +0100
tests: json_echo: Support testing host binaries
Support -H/--host option to use host's libnftables.so.1. Alternatively
users may specify a custom library path via -l/--library option.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
tests/json_echo/run-test.py | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/tests/json_echo/run-test.py b/tests/json_echo/run-test.py
index fa7d69a..36a377a 100755
--- a/tests/json_echo/run-test.py
+++ b/tests/json_echo/run-test.py
@@ -4,6 +4,7 @@ from __future__ import print_function
import sys
import os
import json
+import argparse
TESTS_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(TESTS_PATH, '../../py/'))
@@ -13,12 +14,26 @@ from nftables import Nftables
# Change working directory to repository root
os.chdir(TESTS_PATH + "/../..")
-if not os.path.exists('src/.libs/libnftables.so'):
- print("The nftables library does not exist. "
- "You need to build the project.")
+parser = argparse.ArgumentParser(description='Run JSON echo tests')
+parser.add_argument('-H', '--host', action='store_true',
+ help='Run tests against installed libnftables.so.1')
+parser.add_argument('-l', '--library', default=None,
+ help='Path to libntables.so, overrides --host')
+args = parser.parse_args()
+
+check_lib_path = True
+if args.library is None:
+ if args.host:
+ args.library = 'libnftables.so.1'
+ check_lib_path = False
+ else:
+ args.library = 'src/.libs/libnftables.so.1'
+
+if check_lib_path and not os.path.exists(args.library):
+ print("Library not found at '%s'." % args.library)
sys.exit(1)
-nftables = Nftables(sofile = 'src/.libs/libnftables.so')
+nftables = Nftables(sofile = args.library)
nftables.set_echo_output(True)
# various commands to work with
--
2.31.1

View File

@ -0,0 +1,159 @@
From 120ec5410b0c9f8f84f2bfdf092228cc61899785 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] netlink_delinearize: postprocess binary ands in
concatenations
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 89688c947efc3
commit 89688c947efc36d25c58c85650414fa3a491732e
Author: Florian Westphal <fw@strlen.de>
Date: Tue Jun 14 21:56:48 2022 +0200
netlink_delinearize: postprocess binary ands in concatenations
Input:
update ether saddr . vlan id timeout 5s @macset
ether saddr . vlan id @macset
Before this patch, gets rendered as:
update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s }
@ll,48,48 . @ll,112,16 & 0xfff @macset
After this, listing will show:
update @macset { @ll,48,48 . vlan id timeout 5s }
@ll,48,48 . vlan id @macset
The @ll, ... is due to vlan description replacing the ethernet one,
so payload decode fails to take the concatenation apart (the ethernet
header payload info is matched vs. vlan template).
This will be adjusted by a followup patch.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/netlink.h | 6 ++++++
src/netlink_delinearize.c | 45 ++++++++++++++++++++++++++++++++++-----
2 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/include/netlink.h b/include/netlink.h
index e8e0f68..71c888f 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -42,10 +42,16 @@ struct netlink_parse_ctx {
struct netlink_ctx *nlctx;
};
+
+#define RULE_PP_IN_CONCATENATION (1 << 0)
+
+#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION)
+
struct rule_pp_ctx {
struct proto_ctx pctx;
struct payload_dep_ctx pdctx;
struct stmt *stmt;
+ unsigned int flags;
};
extern const struct input_descriptor indesc_netlink;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 2f13990..cba419d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2259,12 +2259,13 @@ static void binop_adjust(const struct expr *binop, struct expr *right,
}
}
-static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
- struct expr **expr_binop)
+static void __binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr *expr,
+ struct expr *left,
+ struct expr *mask,
+ struct expr **expr_binop)
{
struct expr *binop = *expr_binop;
- struct expr *left = binop->left;
- struct expr *mask = binop->right;
unsigned int shift;
assert(binop->etype == EXPR_BINOP);
@@ -2300,15 +2301,26 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
assert(binop->left == left);
*expr_binop = expr_get(left);
- expr_free(binop);
if (left->etype == EXPR_PAYLOAD)
payload_match_postprocess(ctx, expr, left);
else if (left->etype == EXPR_EXTHDR && right)
expr_set_type(right, left->dtype, left->byteorder);
+
+ expr_free(binop);
}
}
+static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
+ struct expr **expr_binop)
+{
+ struct expr *binop = *expr_binop;
+ struct expr *left = binop->left;
+ struct expr *mask = binop->right;
+
+ __binop_postprocess(ctx, expr, left, mask, expr_binop);
+}
+
static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
{
struct expr *binop = expr->map;
@@ -2541,6 +2553,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
LIST_HEAD(tmp);
struct expr *n;
+ ctx->flags |= RULE_PP_IN_CONCATENATION;
list_for_each_entry_safe(i, n, &expr->expressions, list) {
if (type) {
dtype = concat_subtype_lookup(type, --off);
@@ -2552,6 +2565,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
ntype = concat_subtype_add(ntype, i->dtype->type);
}
+ ctx->flags &= ~RULE_PP_IN_CONCATENATION;
list_splice(&tmp, &expr->expressions);
datatype_set(expr, concat_type_alloc(ntype));
break;
@@ -2568,6 +2582,27 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_set_type(expr->right, &integer_type,
BYTEORDER_HOST_ENDIAN);
break;
+ case OP_AND:
+ expr_set_type(expr->right, expr->left->dtype,
+ expr->left->byteorder);
+
+ /* Do not process OP_AND in ordinary rule context.
+ *
+ * Removal needs to be performed as part of the relational
+ * operation because the RHS constant might need to be adjusted
+ * (shifted).
+ *
+ * This is different in set element context or concatenations:
+ * There is no relational operation (eq, neq and so on), thus
+ * it needs to be processed right away.
+ */
+ if ((ctx->flags & RULE_PP_REMOVE_OP_AND) &&
+ expr->left->etype == EXPR_PAYLOAD &&
+ expr->right->etype == EXPR_VALUE) {
+ __binop_postprocess(ctx, expr, expr->left, expr->right, exprp);
+ return;
+ }
+ break;
default:
expr_set_type(expr->right, expr->left->dtype,
expr->left->byteorder);
--
2.41.0.rc1

View File

@ -1,64 +0,0 @@
From 67f168ebfbeb26a8d7e4f1b9284cc32f13ceff9b Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:35:27 +0100
Subject: [PATCH] tests: monitor: Support running individual test cases
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1754047
Upstream Status: nftables commit eb5034108cdc6
commit eb5034108cdc60341b2d61599077db935b6bbc4f
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Jan 10 11:15:45 2020 +0100
tests: monitor: Support running individual test cases
Recognize testcase paths on command line and limit testing on those
only.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
tests/monitor/run-tests.sh | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
index 0478cf6..efacdaa 100755
--- a/tests/monitor/run-tests.sh
+++ b/tests/monitor/run-tests.sh
@@ -108,6 +108,7 @@ echo_run_test() {
touch $output_file
}
+testcases=""
while [ -n "$1" ]; do
case "$1" in
-d|--debug)
@@ -118,11 +119,15 @@ while [ -n "$1" ]; do
test_json=true
shift
;;
+ testcases/*.t)
+ testcases+=" $1"
+ shift
+ ;;
*)
echo "unknown option '$1'"
;&
-h|--help)
- echo "Usage: $(basename $0) [-j|--json] [-d|--debug]"
+ echo "Usage: $(basename $0) [-j|--json] [-d|--debug] [testcase ...]"
exit 1
;;
esac
@@ -138,7 +143,7 @@ for variant in $variants; do
run_test=${variant}_run_test
output_append=${variant}_output_append
- for testcase in testcases/*.t; do
+ for testcase in ${testcases:-testcases/*.t}; do
echo "$variant: running tests from file $(basename $testcase)"
# files are like this:
#
--
2.31.1

View File

@ -0,0 +1,287 @@
From 5246e288a724e7b9641c94f228096dc1529bb2ea Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] proto: track full stack of seen l2 protocols, not just
cumulative offset
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 0d9daa0407212
commit 0d9daa0407212c8cc89b3ea8aee031ddf0109b08
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 14:32:13 2022 +0200
proto: track full stack of seen l2 protocols, not just cumulative offset
For input, a cumulative size counter of all pushed l2 headers is enough,
because we have the full expression tree available to us.
For delinearization we need to track all seen l2 headers, else we lose
information that we might need at a later time.
Consider:
rule netdev nt nc set update ether saddr . vlan id
during delinearization, the vlan proto_desc replaces the ethernet one,
and by the time we try to split the concatenation apart we will search
the ether saddr offset vs. the templates for proto_vlan.
This replaces the offset with an array that stores the protocol
descriptions seen.
Then, if the payload offset is larger than our description, search the
l2 stack and adjust the offset until we're within the expected offset
boundary.
Reported-by: Eric Garver <eric@garver.life>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/proto.h | 3 +-
src/evaluate.c | 15 +++++++--
src/netlink_delinearize.c | 5 ---
src/payload.c | 67 ++++++++++++++++++++++++++++++++-------
src/proto.c | 2 --
5 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/include/proto.h b/include/proto.h
index a04240a..35e760c 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -193,13 +193,14 @@ struct proto_ctx {
struct {
struct location location;
const struct proto_desc *desc;
- unsigned int offset;
struct {
struct location location;
const struct proto_desc *desc;
} protos[PROTO_CTX_NUM_PROTOS];
unsigned int num_protos;
} protocol[PROTO_BASE_MAX + 1];
+ const struct proto_desc *stacked_ll[PROTO_CTX_NUM_PROTOS];
+ uint8_t stacked_ll_count;
};
extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
diff --git a/src/evaluate.c b/src/evaluate.c
index 82bf131..9246064 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -678,7 +678,13 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0)
return 1;
- payload->payload.offset += ctx->pctx.protocol[base].offset;
+ if (base == PROTO_BASE_LL_HDR) {
+ unsigned int i;
+
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++)
+ payload->payload.offset += ctx->pctx.stacked_ll[i]->length;
+ }
+
rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
return 0;
@@ -727,7 +733,12 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
if (desc == payload->payload.desc) {
const struct proto_hdr_template *tmpl;
- payload->payload.offset += ctx->pctx.protocol[base].offset;
+ if (desc->base == PROTO_BASE_LL_HDR) {
+ unsigned int i;
+
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++)
+ payload->payload.offset += ctx->pctx.stacked_ll[i]->length;
+ }
check_icmp:
if (desc != &proto_icmp && desc != &proto_icmp6)
return 0;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index cba419d..0b5519d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1976,11 +1976,6 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
struct expr *expr,
struct expr *payload)
{
- enum proto_bases base = payload->payload.base;
-
- assert(payload->payload.offset >= ctx->pctx.protocol[base].offset);
- payload->payload.offset -= ctx->pctx.protocol[base].offset;
-
switch (expr->op) {
case OP_EQ:
case OP_NEQ:
diff --git a/src/payload.c b/src/payload.c
index 66418cd..2c0d0ac 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -116,8 +116,13 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
if (desc->base == base->base) {
assert(base->length > 0);
- if (!left->payload.is_raw)
- ctx->protocol[base->base].offset += base->length;
+ if (!left->payload.is_raw) {
+ if (desc->base == PROTO_BASE_LL_HDR &&
+ ctx->stacked_ll_count < PROTO_CTX_NUM_PROTOS) {
+ ctx->stacked_ll[ctx->stacked_ll_count] = base;
+ ctx->stacked_ll_count++;
+ }
+ }
}
proto_ctx_update(ctx, desc->base, loc, desc);
}
@@ -869,6 +874,38 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
}
}
+static const struct proto_desc *get_stacked_desc(const struct proto_ctx *ctx,
+ const struct proto_desc *top,
+ const struct expr *e,
+ unsigned int *skip)
+{
+ unsigned int i, total, payload_offset = e->payload.offset;
+
+ assert(e->etype == EXPR_PAYLOAD);
+
+ if (e->payload.base != PROTO_BASE_LL_HDR ||
+ payload_offset < top->length) {
+ *skip = 0;
+ return top;
+ }
+
+ for (i = 0, total = 0; i < ctx->stacked_ll_count; i++) {
+ const struct proto_desc *stacked;
+
+ stacked = ctx->stacked_ll[i];
+ if (payload_offset < stacked->length) {
+ *skip = total;
+ return stacked;
+ }
+
+ payload_offset -= stacked->length;
+ total += stacked->length;
+ }
+
+ *skip = total;
+ return top;
+}
+
/**
* payload_expr_complete - fill in type information of a raw payload expr
*
@@ -880,9 +917,10 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
*/
void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
{
+ unsigned int payload_offset = expr->payload.offset;
const struct proto_desc *desc;
const struct proto_hdr_template *tmpl;
- unsigned int i;
+ unsigned int i, total;
assert(expr->etype == EXPR_PAYLOAD);
@@ -891,9 +929,12 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
return;
assert(desc->base == expr->payload.base);
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
for (i = 0; i < array_size(desc->templates); i++) {
tmpl = &desc->templates[i];
- if (tmpl->offset != expr->payload.offset ||
+ if (tmpl->offset != payload_offset ||
tmpl->len != expr->len)
continue;
@@ -950,6 +991,7 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
unsigned int payload_len = expr->len;
const struct proto_desc *desc;
unsigned int off, i, len = 0;
+ unsigned int total;
assert(expr->etype == EXPR_PAYLOAD);
@@ -959,10 +1001,8 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
assert(desc->base == expr->payload.base);
- if (ctx->protocol[expr->payload.base].offset) {
- assert(payload_offset >= ctx->protocol[expr->payload.base].offset);
- payload_offset -= ctx->protocol[expr->payload.base].offset;
- }
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
off = round_up(mask->len, BITS_PER_BYTE) - mask_len;
payload_offset += off;
@@ -1009,10 +1049,11 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
void payload_expr_expand(struct list_head *list, struct expr *expr,
const struct proto_ctx *ctx)
{
+ unsigned int payload_offset = expr->payload.offset;
const struct proto_hdr_template *tmpl;
const struct proto_desc *desc;
+ unsigned int i, total;
struct expr *new;
- unsigned int i;
assert(expr->etype == EXPR_PAYLOAD);
@@ -1021,13 +1062,16 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
goto raw;
assert(desc->base == expr->payload.base);
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
for (i = 1; i < array_size(desc->templates); i++) {
tmpl = &desc->templates[i];
if (tmpl->len == 0)
break;
- if (tmpl->offset != expr->payload.offset)
+ if (tmpl->offset != payload_offset)
continue;
if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
@@ -1039,6 +1083,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
list_add_tail(&new->list, list);
expr->len -= tmpl->len;
expr->payload.offset += tmpl->len;
+ payload_offset += tmpl->len;
if (expr->len == 0)
return;
} else if (expr->len > 0) {
@@ -1051,7 +1096,7 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
}
raw:
new = payload_expr_alloc(&expr->location, NULL, 0);
- payload_init_raw(new, expr->payload.base, expr->payload.offset,
+ payload_init_raw(new, expr->payload.base, payload_offset,
expr->len);
list_add_tail(&new->list, list);
}
diff --git a/src/proto.c b/src/proto.c
index a013a00..2663f21 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -160,8 +160,6 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
proto_base_names[i],
ctx->protocol[i].desc ? ctx->protocol[i].desc->name :
"none");
- if (ctx->protocol[i].offset)
- pr_debug(" (offset: %u)", ctx->protocol[i].offset);
if (i == base)
pr_debug(" <-");
pr_debug("\n");
--
2.41.0.rc1

View File

@ -1,40 +0,0 @@
From 18e1b545cbd2d055b16ec3bf5f481d8032dc5dbe Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:35:27 +0100
Subject: [PATCH] tests: monitor: Support testing host's nft binary
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1754047
Upstream Status: nftables commit 15ede6857c8c5
commit 15ede6857c8c578ec6211c8b68424183ba1baf1a
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Feb 5 19:48:53 2020 +0100
tests: monitor: Support testing host's nft binary
Add support for -H/--host flag to use 'nft' tool from $PATH instead of
the local one.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
tests/monitor/run-tests.sh | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
index efacdaa..ffb833a 100755
--- a/tests/monitor/run-tests.sh
+++ b/tests/monitor/run-tests.sh
@@ -119,6 +119,10 @@ while [ -n "$1" ]; do
test_json=true
shift
;;
+ -H|--host)
+ nft=nft
+ shift
+ ;;
testcases/*.t)
testcases+=" $1"
shift
--
2.31.1

View File

@ -0,0 +1,44 @@
From 33df569ad87c851596c02663fb4941bc0783d08c Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] debug: dump the l2 protocol stack
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit dbd5f348c71de
commit dbd5f348c71decf0baa8fb592c576f63fa232f50
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 16:42:23 2022 +0200
debug: dump the l2 protocol stack
Previously we used to print the cumulative size of the headers,
update this to print the tracked l2 stack.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/proto.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/proto.c b/src/proto.c
index 2663f21..c496482 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -154,6 +154,12 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
if (!(debug_mask & NFT_DEBUG_PROTO_CTX))
return;
+ if (base == PROTO_BASE_LL_HDR && ctx->stacked_ll_count) {
+ pr_debug(" saved ll headers:");
+ for (i = 0; i < ctx->stacked_ll_count; i++)
+ pr_debug(" %s", ctx->stacked_ll[i]->name);
+ }
+
pr_debug("update %s protocol context:\n", proto_base_names[base]);
for (i = PROTO_BASE_LL_HDR; i <= PROTO_BASE_MAX; i++) {
pr_debug(" %-20s: %s",
--
2.41.0.rc1

View File

@ -1,76 +0,0 @@
From 74575c409bad2940470f31946c97430043c3195e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:35:27 +0100
Subject: [PATCH] tests: py: Support testing host binaries
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1754047
Upstream Status: nftables commit 5f2746205e50c
commit 5f2746205e50c77295d0f84f8178ee3a1ce15407
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Feb 6 01:36:01 2020 +0100
tests: py: Support testing host binaries
Support -H/--host option to use host's libnftables.so.1. Alternatively
users may specify a custom library path via -l/--library option.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
tests/py/nft-test.py | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/tests/py/nft-test.py b/tests/py/nft-test.py
index 6edca3c..01ee6c9 100755
--- a/tests/py/nft-test.py
+++ b/tests/py/nft-test.py
@@ -1357,10 +1357,16 @@ def main():
dest='force_all_family',
help='keep testing all families on error')
+ parser.add_argument('-H', '--host', action='store_true',
+ help='run tests against installed libnftables.so.1')
+
parser.add_argument('-j', '--enable-json', action='store_true',
dest='enable_json',
help='test JSON functionality as well')
+ parser.add_argument('-l', '--library', default=None,
+ help='path to libntables.so.1, overrides --host')
+
parser.add_argument('-s', '--schema', action='store_true',
dest='enable_schema',
help='verify json input/output against schema')
@@ -1388,9 +1394,17 @@ def main():
# Change working directory to repository root
os.chdir(TESTS_PATH + "/../..")
- if not os.path.exists('src/.libs/libnftables.so'):
- print("The nftables library does not exist. "
- "You need to build the project.")
+ check_lib_path = True
+ if args.library is None:
+ if args.host:
+ args.library = 'libnftables.so.1'
+ check_lib_path = False
+ else:
+ args.library = 'src/.libs/libnftables.so.1'
+
+ if check_lib_path and not os.path.exists(args.library):
+ print("The nftables library at '%s' does not exist. "
+ "You need to build the project." % args.library)
return
if args.enable_schema and not args.enable_json:
@@ -1398,7 +1412,7 @@ def main():
return
global nftables
- nftables = Nftables(sofile = 'src/.libs/libnftables.so')
+ nftables = Nftables(sofile = args.library)
test_files = files_ok = run_total = 0
tests = passed = warnings = errors = 0
--
2.31.1

View File

@ -1,43 +0,0 @@
From d58192a8d2810271d5c6525dc66ba1e1ec3fd2b7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:39:44 +0100
Subject: [PATCH] doc: nft.8: Mention wildcard interface matching
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1763652
Upstream Status: nftables commit 03d45ad330a25
commit 03d45ad330a25323610648bb05f550e0fb9d65b2
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Feb 6 12:24:51 2020 +0100
doc: nft.8: Mention wildcard interface matching
Special meaning of asterisk in interface names wasn't described
anywhere.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
doc/primary-expression.txt | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index 5473d59..a5cab9d 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -36,6 +36,13 @@ add such a rule, it will stop matching if the interface gets renamed and it
will match again in case interface gets deleted and later a new interface
with the same name is created.
+Like with iptables, wildcard matching on interface name prefixes is available for
+*iifname* and *oifname* matches by appending an asterisk (*) character. Note
+however that unlike iptables, nftables does not accept interface names
+consisting of the wildcard character only - users are supposed to just skip
+those always matching expressions. In order to match on literal asterisk
+character, one may escape it using backslash (\).
+
.Meta expression types
[options="header"]
|==================
--
2.31.1

View File

@ -0,0 +1,65 @@
From 1773e6c1975ee4a6b00c24a99bf57b4597af295d Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] tests: add a test case for ether and vlan listing
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit f680055cd4377
commit f680055cd4377f2f531f5f77b3aaa7550988665d
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 19:31:22 2022 +0200
tests: add a test case for ether and vlan listing
before this patch series, test fails dump validation:
- update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
- ether saddr . vlan id @macset
+ update @macset { @ll,48,48 . @ll,112,16 & 0xfff timeout 5s } counter packets 0 bytes 0
+ @ll,48,48 . @ll,112,16 & 0xfff @macset
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
tests/shell/testcases/sets/0070stacked_l2_headers | 6 ++++++
.../sets/dumps/0070stacked_l2_headers.nft | 14 ++++++++++++++
2 files changed, 20 insertions(+)
create mode 100755 tests/shell/testcases/sets/0070stacked_l2_headers
create mode 100644 tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
diff --git a/tests/shell/testcases/sets/0070stacked_l2_headers b/tests/shell/testcases/sets/0070stacked_l2_headers
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/0070stacked_l2_headers
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
new file mode 100644
index 0000000..ef254b9
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
@@ -0,0 +1,14 @@
+table netdev nt {
+ set macset {
+ typeof ether saddr . vlan id
+ size 1024
+ flags dynamic,timeout
+ }
+
+ chain nc {
+ update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
+ ether saddr . vlan id @macset
+ vlan pcp 1
+ ether saddr 0a:0b:0c:0d:0e:0f vlan id 42
+ }
+}
--
2.41.0.rc1

View File

@ -0,0 +1,99 @@
From bba1a2086ec7bcc0cfa8df9e12c6cc1375180011 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:57 +0100
Subject: [PATCH] netlink_delinearize: also postprocess OP_AND in set element
context
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit b1e3ed0335d13
commit b1e3ed0335d13d206a2a2698a1ba189fa396dbf3
Author: Florian Westphal <fw@strlen.de>
Date: Mon Aug 1 13:03:18 2022 +0200
netlink_delinearize: also postprocess OP_AND in set element context
Pablo reports:
add rule netdev nt y update @macset { vlan id timeout 5s }
listing still shows the raw expression:
update @macset { @ll,112,16 & 0xfff timeout 5s }
so also cover the 'set element' case.
Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
include/netlink.h | 4 +++-
src/netlink_delinearize.c | 2 ++
.../sets/dumps/0070stacked_l2_headers.nft | 14 ++++++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/include/netlink.h b/include/netlink.h
index 71c888f..63d07ed 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -44,8 +44,10 @@ struct netlink_parse_ctx {
#define RULE_PP_IN_CONCATENATION (1 << 0)
+#define RULE_PP_IN_SET_ELEM (1 << 1)
-#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION)
+#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION | \
+ RULE_PP_IN_SET_ELEM)
struct rule_pp_ctx {
struct proto_ctx pctx;
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 0b5519d..c6ad84d 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -2660,7 +2660,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_postprocess(ctx, &expr->prefix);
break;
case EXPR_SET_ELEM:
+ ctx->flags |= RULE_PP_IN_SET_ELEM;
expr_postprocess(ctx, &expr->key);
+ ctx->flags &= ~RULE_PP_IN_SET_ELEM;
break;
case EXPR_EXTHDR:
exthdr_dependency_kill(&ctx->pdctx, expr, ctx->pctx.family);
diff --git a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
index ef254b9..0057e9c 100644
--- a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
+++ b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
@@ -1,14 +1,28 @@
table netdev nt {
+ set vlanidset {
+ typeof vlan id
+ size 1024
+ flags dynamic,timeout
+ }
+
set macset {
typeof ether saddr . vlan id
size 1024
flags dynamic,timeout
}
+ set ipset {
+ typeof vlan id . ip saddr
+ size 1024
+ flags dynamic,timeout
+ }
+
chain nc {
update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
ether saddr . vlan id @macset
vlan pcp 1
ether saddr 0a:0b:0c:0d:0e:0f vlan id 42
+ update @vlanidset { vlan id timeout 5s } counter packets 0 bytes 0
+ update @ipset { vlan id . ip saddr timeout 5s } counter packets 0 bytes 0
}
}
--
2.41.0.rc1

View File

@ -1,39 +0,0 @@
From 34ba60c0c2b6057e8b56a77e47899bbeccd88bfd Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 12 Feb 2020 22:39:44 +0100
Subject: [PATCH] scanner: Extend asteriskstring definition
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1763652
Upstream Status: nftables commit 556c5a94b8067
commit 556c5a94b8067f33ef0a42836753dae0736b7524
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Feb 6 12:31:56 2020 +0100
scanner: Extend asteriskstring definition
Accept escaped asterisks also mid-string and as only character.
Especially the latter will help when translating from iptables where
asterisk has no special meaning.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/scanner.l | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/scanner.l b/src/scanner.l
index d32adf4..7daf5c1 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -120,7 +120,7 @@ numberstring ({decstring}|{hexstring})
letter [a-zA-Z]
string ({letter}|[_.])({letter}|{digit}|[/\-_\.])*
quotedstring \"[^"]*\"
-asteriskstring ({string}\*|{string}\\\*)
+asteriskstring ({string}\*|{string}\\\*|\\\*|{string}\\\*{string})
comment #.*$
slash \/
--
2.31.1

View File

@ -0,0 +1,198 @@
From da9367286d4589a3371d547cd8e6dd6d985cc69a Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:58 +0100
Subject: [PATCH] evaluate: search stacked header list for matching payload dep
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 87c3041bfd244
commit 87c3041bfd244aaf39e644d33c0df4fe04079e1c
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 20:02:28 2022 +0200
evaluate: search stacked header list for matching payload dep
"ether saddr 0:1:2:3:4:6 vlan id 2" works, but reverse fails:
"vlan id 2 ether saddr 0:1:2:3:4:6" will give
Error: conflicting protocols specified: vlan vs. ether
After "proto: track full stack of seen l2 protocols, not just cumulative offset",
we have a list of all l2 headers, so search those to see if we had this
proto base in the past before rejecting this.
Reported-by: Eric Garver <eric@garver.life>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/evaluate.c | 21 +++++++---
tests/py/bridge/vlan.t | 3 ++
tests/py/bridge/vlan.t.json | 56 +++++++++++++++++++++++++++
tests/py/bridge/vlan.t.payload | 16 ++++++++
tests/py/bridge/vlan.t.payload.netdev | 20 ++++++++++
5 files changed, 110 insertions(+), 6 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 9246064..d67f915 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -659,13 +659,22 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
struct stmt *nstmt = NULL;
int link, err;
- if (payload->payload.base == PROTO_BASE_LL_HDR &&
- proto_is_dummy(desc)) {
- err = meta_iiftype_gen_dependency(ctx, payload, &nstmt);
- if (err < 0)
- return err;
+ if (payload->payload.base == PROTO_BASE_LL_HDR) {
+ if (proto_is_dummy(desc)) {
+ err = meta_iiftype_gen_dependency(ctx, payload, &nstmt);
+ if (err < 0)
+ return err;
- rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ } else {
+ unsigned int i;
+
+ /* payload desc stored in the L2 header stack? No conflict. */
+ for (i = 0; i < ctx->pctx.stacked_ll_count; i++) {
+ if (ctx->pctx.stacked_ll[i] == payload->payload.desc)
+ return 0;
+ }
+ }
}
assert(base <= PROTO_BASE_MAX);
diff --git a/tests/py/bridge/vlan.t b/tests/py/bridge/vlan.t
index 924ed4e..4920601 100644
--- a/tests/py/bridge/vlan.t
+++ b/tests/py/bridge/vlan.t
@@ -47,3 +47,6 @@ ether type ip vlan id 1 ip saddr 10.0.0.1;fail
# mangling
vlan id 1 vlan id set 2;ok
+
+ether saddr 00:01:02:03:04:05 vlan id 1;ok
+vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
diff --git a/tests/py/bridge/vlan.t.json b/tests/py/bridge/vlan.t.json
index e7640f9..58d4a40 100644
--- a/tests/py/bridge/vlan.t.json
+++ b/tests/py/bridge/vlan.t.json
@@ -761,3 +761,59 @@
}
}
]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:05"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:06"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.payload b/tests/py/bridge/vlan.t.payload
index 6c8d595..713670e 100644
--- a/tests/py/bridge/vlan.t.payload
+++ b/tests/py/bridge/vlan.t.payload
@@ -276,3 +276,19 @@ bridge
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
[ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
diff --git a/tests/py/bridge/vlan.t.payload.netdev b/tests/py/bridge/vlan.t.payload.netdev
index d2c7d74..98a2a2b 100644
--- a/tests/py/bridge/vlan.t.payload.netdev
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -322,3 +322,23 @@ netdev
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
[ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
--
2.41.0.rc1

View File

@ -1,162 +0,0 @@
From 160d84fb761c54a5f757aff907fc197d259196bd Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 17 Feb 2020 15:26:42 +0100
Subject: [PATCH] parser: add a helper for concat expression handling
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1795224
Upstream Status: nftables commit 10f114806ccd9
commit 10f114806ccd9d64f9d72eaa813babb04d719688
Author: Florian Westphal <fw@strlen.de>
Date: Wed Dec 11 14:31:44 2019 +0100
parser: add a helper for concat expression handling
Cull the repeated copy&paste snippets and add/use a helper for this.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/parser_bison.y | 99 ++++++++++++++++++++--------------------------
1 file changed, 43 insertions(+), 56 deletions(-)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 707f467..0fd9b94 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -102,6 +102,25 @@ static void location_update(struct location *loc, struct location *rhs, int n)
}
}
+static struct expr *handle_concat_expr(const struct location *loc,
+ struct expr *expr,
+ struct expr *expr_l, struct expr *expr_r,
+ struct location loc_rhs[3])
+{
+ if (expr->etype != EXPR_CONCAT) {
+ expr = concat_expr_alloc(loc);
+ compound_expr_add(expr, expr_l);
+ } else {
+ location_update(&expr_r->location, loc_rhs, 2);
+
+ expr = expr_l;
+ expr->location = *loc;
+ }
+
+ compound_expr_add(expr, expr_r);
+ return expr;
+}
+
#define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N)
#define symbol_value(loc, str) \
@@ -1878,20 +1897,12 @@ data_type_atom_expr : type_identifier
data_type_expr : data_type_atom_expr
| data_type_expr DOT data_type_atom_expr
{
- if ($1->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
@@ -2992,20 +3003,12 @@ basic_stmt_expr : inclusive_or_stmt_expr
concat_stmt_expr : basic_stmt_expr
| concat_stmt_expr DOT primary_stmt_expr
{
- if ($$->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
@@ -3525,20 +3528,12 @@ basic_expr : inclusive_or_expr
concat_expr : basic_expr
| concat_expr DOT basic_expr
{
- if ($$->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
@@ -3946,20 +3941,12 @@ basic_rhs_expr : inclusive_or_rhs_expr
concat_rhs_expr : basic_rhs_expr
| concat_rhs_expr DOT basic_rhs_expr
{
- if ($$->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
--
2.31.1

View File

@ -1,83 +0,0 @@
From e872d169c189f363ebbdc39105510c1809b58276 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 13 Feb 2020 17:48:18 +0100
Subject: [PATCH] include: resync nf_tables.h cache copy
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1795224
Upstream Status: nftables commit 9b94127950f98
commit 9b94127950f9848bc5a1505ae65ca3045ff68a16
Author: Stefano Brivio <sbrivio@redhat.com>
Date: Thu Jan 30 01:16:55 2020 +0100
include: resync nf_tables.h cache copy
Get this header in sync with nf-next as of merge commit
b3a608222336 (5.6-rc1-ish).
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/nf_tables.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index ed8881a..1a99df3 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -48,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
@@ -299,14 +300,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
*
@@ -368,6 +383,7 @@ 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)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -380,6 +396,7 @@ 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_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
--
2.31.1

View File

@ -0,0 +1,223 @@
From f2988bad7c73e30ea4a80f348f7adf8078e6ef57 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 10:27:58 +0100
Subject: [PATCH] src: allow anon set concatenation with ether and vlan
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit c1c223f1b5818
commit c1c223f1b58188542222ee2d9a4a8cc133d1dc3b
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jul 25 21:34:52 2022 +0200
src: allow anon set concatenation with ether and vlan
vlan id uses integer type (which has a length of 0).
Using it was possible, but listing would assert:
python: mergesort.c:24: concat_expr_msort_value: Assertion `ilen > 0' failed.
There are two reasons for this.
First reason is that the udata/typeof information lacks the 'vlan id'
part, because internally this is 'payload . binop(payload AND mask)'.
binop lacks an udata store. It makes little sense to store it,
'typeof' keyword expects normal match syntax.
So, when storing udata, store the left hand side of the binary
operation, i.e. the load of the 2-byte key.
With that resolved, delinerization could work, but concat_elem_expr()
would splice 12 bits off the elements value, but it should be 16 (on
a byte boundary).
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/expression.c | 17 +++++++++--
src/netlink.c | 10 +++++--
tests/py/bridge/vlan.t | 2 ++
tests/py/bridge/vlan.t.json | 41 +++++++++++++++++++++++++++
tests/py/bridge/vlan.t.payload | 12 ++++++++
tests/py/bridge/vlan.t.payload.netdev | 14 +++++++++
6 files changed, 91 insertions(+), 5 deletions(-)
diff --git a/src/expression.c b/src/expression.c
index deb649e..7390089 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -879,17 +879,30 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX 2
+static struct expr *expr_build_udata_recurse(struct expr *e)
+{
+ switch (e->etype) {
+ case EXPR_BINOP:
+ return e->left;
+ default:
+ break;
+ }
+
+ return e;
+}
+
static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
const struct expr *concat_expr)
{
struct nftnl_udata *nest;
+ struct expr *expr, *tmp;
unsigned int i = 0;
- struct expr *expr;
- list_for_each_entry(expr, &concat_expr->expressions, list) {
+ list_for_each_entry_safe(expr, tmp, &concat_expr->expressions, list) {
struct nftnl_udata *nest_expr;
int err;
+ expr = expr_build_udata_recurse(expr);
if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
return -1;
diff --git a/src/netlink.c b/src/netlink.c
index 89d864e..799cf9b 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1114,17 +1114,21 @@ static struct expr *concat_elem_expr(struct expr *key,
struct expr *data, int *off)
{
const struct datatype *subtype;
+ unsigned int sub_length;
struct expr *expr;
if (key) {
(*off)--;
- expr = constant_expr_splice(data, key->len);
+ sub_length = round_up(key->len, BITS_PER_BYTE);
+
+ expr = constant_expr_splice(data, sub_length);
expr->dtype = datatype_get(key->dtype);
expr->byteorder = key->byteorder;
expr->len = key->len;
} else {
subtype = concat_subtype_lookup(dtype->type, --(*off));
- expr = constant_expr_splice(data, subtype->size);
+ sub_length = round_up(subtype->size, BITS_PER_BYTE);
+ expr = constant_expr_splice(data, sub_length);
expr->dtype = subtype;
expr->byteorder = subtype->byteorder;
}
@@ -1136,7 +1140,7 @@ static struct expr *concat_elem_expr(struct expr *key,
expr->dtype->basetype->type == TYPE_BITMASK)
expr = bitmask_expr_to_binops(expr);
- data->len -= netlink_padding_len(expr->len);
+ data->len -= netlink_padding_len(sub_length);
return expr;
}
diff --git a/tests/py/bridge/vlan.t b/tests/py/bridge/vlan.t
index 4920601..95bdff4 100644
--- a/tests/py/bridge/vlan.t
+++ b/tests/py/bridge/vlan.t
@@ -50,3 +50,5 @@ vlan id 1 vlan id set 2;ok
ether saddr 00:01:02:03:04:05 vlan id 1;ok
vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
+
+ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 };ok
diff --git a/tests/py/bridge/vlan.t.json b/tests/py/bridge/vlan.t.json
index 58d4a40..f77756f 100644
--- a/tests/py/bridge/vlan.t.json
+++ b/tests/py/bridge/vlan.t.json
@@ -817,3 +817,44 @@
}
}
]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 42
+ ]
+ },
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 4095
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.payload b/tests/py/bridge/vlan.t.payload
index 713670e..62e4b89 100644
--- a/tests/py/bridge/vlan.t.payload
+++ b/tests/py/bridge/vlan.t.payload
@@ -292,3 +292,15 @@ bridge test-bridge input
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000200 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-bridge 3 size 2
+__set%d test-bridge 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
diff --git a/tests/py/bridge/vlan.t.payload.netdev b/tests/py/bridge/vlan.t.payload.netdev
index 98a2a2b..1018d4c 100644
--- a/tests/py/bridge/vlan.t.payload.netdev
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -342,3 +342,17 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 14 => reg 1 ]
[ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
--
2.41.0.rc1

View File

@ -0,0 +1,200 @@
From baea5b0f3199d21a8089ab792aee86621f67202c Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 12:45:30 +0100
Subject: [PATCH] evaluate: set eval ctx for add/update statements with integer
constants
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 4cc6b20d31498
commit 4cc6b20d31498d90e90ff574ce8b70276afcee8f
Author: Florian Westphal <fw@strlen.de>
Date: Mon Jan 23 19:03:28 2023 +0100
evaluate: set eval ctx for add/update statements with integer constants
Eric reports that nft asserts when using integer basetype constants with
'typeof' sets. Example:
table netdev t {
set s {
typeof ether saddr . vlan id
flags dynamic,timeout
}
chain c { }
}
loads fine. But adding a rule with add/update statement fails:
nft 'add rule netdev t c set update ether saddr . 0 @s'
nft: netlink_linearize.c:867: netlink_gen_expr: Assertion `dreg < ctx->reg_low' failed.
When the 'ether saddr . 0' concat expression is processed, there is
no set definition available anymore to deduce the required size of the
integer constant.
nft eval step then derives the required length using the data types.
'0' has integer basetype, so the deduced length is 0.
The assertion triggers because serialization step finds that it
needs one more register.
2 are needed to store the ethernet address, another register is
needed for the vlan id.
Update eval step to make the expression context store the set key
information when processing the preceeding set reference, then
let stmt_evaluate_set() preserve the existing context instead of
zeroing it again via stmt_evaluate_arg().
This makes concat expression evaluation compute the total size
needed based on the sets key definition.
Reported-by: Eric Garver <eric@garver.life>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/evaluate.c | 32 +++++++++++++++++--
.../maps/dumps/typeof_maps_concat.nft | 11 +++++++
tests/shell/testcases/maps/typeof_maps_concat | 6 ++++
.../sets/dumps/typeof_sets_concat.nft | 12 +++++++
tests/shell/testcases/sets/typeof_sets_concat | 6 ++++
5 files changed, 65 insertions(+), 2 deletions(-)
create mode 100644 tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
create mode 100755 tests/shell/testcases/maps/typeof_maps_concat
create mode 100644 tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
create mode 100755 tests/shell/testcases/sets/typeof_sets_concat
diff --git a/src/evaluate.c b/src/evaluate.c
index d67f915..7f81411 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1526,6 +1526,14 @@ static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
return ret;
}
+static void expr_evaluate_set_ref(struct eval_ctx *ctx, struct expr *expr)
+{
+ struct set *set = expr->set;
+
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ ctx->ectx.key = set->key;
+}
+
static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *set = *expr, *i, *next;
@@ -2388,6 +2396,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_VARIABLE:
return expr_evaluate_variable(ctx, expr);
case EXPR_SET_REF:
+ expr_evaluate_set_ref(ctx, *expr);
return 0;
case EXPR_VALUE:
return expr_evaluate_value(ctx, expr);
@@ -2550,6 +2559,25 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
}
+/* like stmt_evaluate_arg, but keep existing context created
+ * by previous expr_evaluate().
+ *
+ * This is needed for add/update statements:
+ * ctx->ectx.key has the set key, which may be needed for 'typeof'
+ * sets: the 'add/update' expression might contain integer data types.
+ *
+ * Without the key we cannot derive the element size.
+ */
+static int stmt_evaluate_key(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
{
if (stmt_evaluate_arg(ctx, stmt, &verdict_type, 0, 0, &stmt->expr) < 0)
@@ -3762,7 +3790,7 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
return expr_error(ctx->msgs, stmt->set.set,
"Expression does not refer to a set");
- if (stmt_evaluate_arg(ctx, stmt,
+ if (stmt_evaluate_key(ctx, stmt,
stmt->set.set->set->key->dtype,
stmt->set.set->set->key->len,
stmt->set.set->set->key->byteorder,
@@ -3805,7 +3833,7 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
return expr_error(ctx->msgs, stmt->map.set,
"Expression does not refer to a set");
- if (stmt_evaluate_arg(ctx, stmt,
+ if (stmt_evaluate_key(ctx, stmt,
stmt->map.set->set->key->dtype,
stmt->map.set->set->key->len,
stmt->map.set->set->key->byteorder,
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft b/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
new file mode 100644
index 0000000..1ca98d8
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
@@ -0,0 +1,11 @@
+table netdev t {
+ map m {
+ typeof ether saddr . vlan id : meta mark
+ size 1234
+ flags dynamic,timeout
+ }
+
+ chain c {
+ ether type != 8021q update @m { ether daddr . 123 timeout 1m : 0x0000002a } counter packets 0 bytes 0 return
+ }
+}
diff --git a/tests/shell/testcases/maps/typeof_maps_concat b/tests/shell/testcases/maps/typeof_maps_concat
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_concat
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
new file mode 100644
index 0000000..dbaf7cd
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
@@ -0,0 +1,12 @@
+table netdev t {
+ set s {
+ typeof ether saddr . vlan id
+ size 2048
+ flags dynamic,timeout
+ }
+
+ chain c {
+ ether type != 8021q add @s { ether saddr . 0 timeout 5s } counter packets 0 bytes 0 return
+ ether type != 8021q update @s { ether daddr . 123 timeout 1m } counter packets 0 bytes 0 return
+ }
+}
diff --git a/tests/shell/testcases/sets/typeof_sets_concat b/tests/shell/testcases/sets/typeof_sets_concat
new file mode 100755
index 0000000..07820b7
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_concat
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
--
2.41.0.rc1

View File

@ -1,181 +0,0 @@
From c8a5da2f527c85ab7c392cd293ff37d02a3f93a7 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 13 Feb 2020 17:48:18 +0100
Subject: [PATCH] src: Add support for NFTNL_SET_DESC_CONCAT
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1795224
Upstream Status: nftables commit 6156ba34018dd
Conflicts: Context change in src/mnl.c due to missing commit
6e48df5329eab ("src: add "typeof" build/parse/print support")
commit 6156ba34018dddd59cb6737cfd5a69a0cbc5eaa4
Author: Stefano Brivio <sbrivio@redhat.com>
Date: Thu Jan 30 01:16:56 2020 +0100
src: Add support for NFTNL_SET_DESC_CONCAT
To support arbitrary range concatenations, the kernel needs to know
how long each field in the concatenation is. The new libnftnl
NFTNL_SET_DESC_CONCAT set attribute describes this as an array of
lengths, in bytes, of concatenated fields.
While evaluating concatenated expressions, export the datatype size
into the new field_len array, and hand the data over via libnftnl.
Similarly, when data is passed back from libnftnl, parse it into
the set description.
When set data is cloned, we now need to copy the additional fields
in set_clone(), too.
This change depends on the libnftnl patch with title:
set: Add support for NFTA_SET_DESC_CONCAT attributes
v4: No changes
v3: Rework to use set description data instead of a stand-alone
attribute
v2: No changes
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/expression.h | 2 ++
include/rule.h | 6 +++++-
src/evaluate.c | 14 +++++++++++---
src/mnl.c | 7 +++++++
src/netlink.c | 11 +++++++++++
src/rule.c | 2 +-
6 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index 717b675..ee726aa 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -256,6 +256,8 @@ struct expr {
struct list_head expressions;
unsigned int size;
uint32_t set_flags;
+ uint8_t field_len[NFT_REG32_COUNT];
+ uint8_t field_count;
};
struct {
/* EXPR_SET_REF */
diff --git a/include/rule.h b/include/rule.h
index 47eb29f..c03b0b8 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -290,7 +290,9 @@ extern struct rule *rule_lookup_by_index(const struct chain *chain,
* @rg_cache: cached range element (left)
* @policy: set mechanism policy
* @automerge: merge adjacents and overlapping elements, if possible
- * @desc: set mechanism desc
+ * @desc.size: count of set elements
+ * @desc.field_len: length of single concatenated fields, bytes
+ * @desc.field_count: count of concatenated fields
*/
struct set {
struct list_head list;
@@ -310,6 +312,8 @@ struct set {
bool automerge;
struct {
uint32_t size;
+ uint8_t field_len[NFT_REG32_COUNT];
+ uint8_t field_count;
} desc;
};
diff --git a/src/evaluate.c b/src/evaluate.c
index a865902..58f458d 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1216,6 +1216,8 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
struct expr *i, *next;
list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ unsigned dsize_bytes;
+
if (expr_is_constant(*expr) && dtype && off == 0)
return expr_binary_error(ctx->msgs, i, *expr,
"unexpected concat component, "
@@ -1240,6 +1242,9 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
i->dtype->name);
ntype = concat_subtype_add(ntype, i->dtype->type);
+
+ dsize_bytes = div_round_up(i->dtype->size, BITS_PER_BYTE);
+ (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
}
(*expr)->flags |= flags;
@@ -3321,9 +3326,12 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
"specified in %s definition",
set->key->dtype->name, type);
}
- if (set->flags & NFT_SET_INTERVAL &&
- set->key->etype == EXPR_CONCAT)
- return set_error(ctx, set, "concatenated types not supported in interval sets");
+
+ if (set->flags & NFT_SET_INTERVAL && set->key->etype == EXPR_CONCAT) {
+ memcpy(&set->desc.field_len, &set->key->field_len,
+ sizeof(set->desc.field_len));
+ set->desc.field_count = set->key->field_count;
+ }
if (set_is_datamap(set->flags)) {
if (set->datatype == NULL)
diff --git a/src/mnl.c b/src/mnl.c
index aa5b0b4..221ee05 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -881,6 +881,13 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
set->automerge))
memory_allocation_error();
+ if (set->desc.field_len[0]) {
+ nftnl_set_set_data(nls, NFTNL_SET_DESC_CONCAT,
+ set->desc.field_len,
+ set->desc.field_count *
+ sizeof(set->desc.field_len[0]));
+ }
+
nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf),
nftnl_udata_buf_len(udbuf));
nftnl_udata_buf_free(udbuf);
diff --git a/src/netlink.c b/src/netlink.c
index 486e124..83d863c 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -672,6 +672,17 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE))
set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE);
+ if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) {
+ uint32_t len = NFT_REG32_COUNT;
+ const uint8_t *data;
+
+ data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len);
+ if (data) {
+ memcpy(set->desc.field_len, data, len);
+ set->desc.field_count = len;
+ }
+ }
+
return set;
}
diff --git a/src/rule.c b/src/rule.c
index 3ca1805..4669577 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -337,7 +337,7 @@ struct set *set_clone(const struct set *set)
new_set->objtype = set->objtype;
new_set->policy = set->policy;
new_set->automerge = set->automerge;
- new_set->desc.size = set->desc.size;
+ new_set->desc = set->desc;
return new_set;
}
--
2.31.1

View File

@ -0,0 +1,107 @@
From 6e522a03cfda57267224ecdd653dcfda9c4efe62 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 9 Feb 2023 15:25:37 +0100
Subject: [PATCH] monitor: Sanitize startup race condition
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 545edb7a8ef0a
commit 545edb7a8ef0a8acf991b1b7857fddc24d7b151a
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Sep 28 23:26:42 2022 +0200
monitor: Sanitize startup race condition
During startup, 'nft monitor' first fetches the current ruleset and then
keeps this cache up to date based on received events. This is racey, as
any ruleset changes in between the initial fetch and the socket opening
are not recognized.
This script demonstrates the problem:
| #!/bin/bash
|
| while true; do
| nft flush ruleset
| iptables-nft -A FORWARD
| done &
| maniploop=$!
|
| trap "kill $maniploop; kill \$!; wait" EXIT
|
| while true; do
| nft monitor rules >/dev/null &
| sleep 0.2
| kill $!
| done
If the table add event is missed, the rule add event callback fails to
deserialize the rule and calls abort().
Avoid the inconvenient program exit by returning NULL from
netlink_delinearize_rule() instead of aborting and make callers check
the return value.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/cache.c | 1 +
src/monitor.c | 5 +++++
src/netlink_delinearize.c | 5 ++++-
3 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/cache.c b/src/cache.c
index fd8df88..701aec6 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -490,6 +490,7 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
netlink_dump_rule(nlr, ctx);
rule = netlink_delinearize_rule(ctx, nlr);
+ assert(rule);
list_add_tail(&rule->list, &ctx->list);
return 0;
diff --git a/src/monitor.c b/src/monitor.c
index 7fa92eb..a6b30a1 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -551,6 +551,10 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
nlr = netlink_rule_alloc(nlh);
r = netlink_delinearize_rule(monh->ctx, nlr);
+ if (!r) {
+ fprintf(stderr, "W: Received event for an unknown table.\n");
+ goto out_free_nlr;
+ }
nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
&monh->ctx->nft->cache);
cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
@@ -587,6 +591,7 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
break;
}
rule_free(r);
+out_free_nlr:
nftnl_rule_free(nlr);
return MNL_CB_OK;
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index c6ad84d..1d47c74 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -3194,7 +3194,10 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
pctx->rule = rule_alloc(&netlink_location, &h);
pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
h.table.name, h.family);
- assert(pctx->table != NULL);
+ if (!pctx->table) {
+ errno = ENOENT;
+ return NULL;
+ }
pctx->rule->comment = nftnl_rule_get_comment(nlr);
--
2.41.0.rc1

View File

@ -1,577 +0,0 @@
From 7b1f98e90a32865faca9a97f4348f20c753cd2f3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 14 Feb 2020 14:51:33 +0100
Subject: [PATCH] src: Add support for concatenated set ranges
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1795224
Upstream Status: nftables commit 8ac2f3b2fca38
commit 8ac2f3b2fca38b6533043b0678730c10ba4dc5ef
Author: Stefano Brivio <sbrivio@redhat.com>
Date: Thu Jan 30 01:16:57 2020 +0100
src: Add support for concatenated set ranges
After exporting field lengths via NFTNL_SET_DESC_CONCAT attributes,
we now need to adjust parsing of user input and generation of
netlink key data to complete support for concatenation of set
ranges.
Instead of using separate elements for start and end of a range,
denoting the end element by the NFT_SET_ELEM_INTERVAL_END flag,
as it's currently done for ranges without concatenation, we'll use
the new attribute NFTNL_SET_ELEM_KEY_END as suggested by Pablo. It
behaves in the same way as NFTNL_SET_ELEM_KEY, but it indicates
that the included key represents the upper bound of a range.
For example, "packets with an IPv4 address between 192.0.2.0 and
192.0.2.42, with destination port between 22 and 25", needs to be
expressed as a single element with two keys:
NFTA_SET_ELEM_KEY: 192.0.2.0 . 22
NFTA_SET_ELEM_KEY_END: 192.0.2.42 . 25
To achieve this, we need to:
- adjust the lexer rules to allow multiton expressions as elements
of a concatenation. As wildcards are not allowed (semantics would
be ambiguous), exclude wildcards expressions from the set of
possible multiton expressions, and allow them directly where
needed. Concatenations now admit prefixes and ranges
- generate, for each element in a range concatenation, a second key
attribute, that includes the upper bound for the range
- also expand prefixes and non-ranged values in the concatenation
to ranges: given a set with interval and concatenation support,
the kernel has no way to tell which elements are ranged, so they
all need to be. For example, 192.0.2.0 . 192.0.2.9 : 1024 is
sent as:
NFTA_SET_ELEM_KEY: 192.0.2.0 . 1024
NFTA_SET_ELEM_KEY_END: 192.0.2.9 . 1024
- aggregate ranges when elements received by the kernel represent
concatenated ranges, see concat_range_aggregate()
- perform a few minor adjustments where interval expressions
are already handled: we have intervals in these sets, but
the set specification isn't just an interval, so we can't
just aggregate and deaggregate interval ranges linearly
v4: No changes
v3:
- rework to use a separate key for closing element of range instead of
a separate element with EXPR_F_INTERVAL_END set (Pablo Neira Ayuso)
v2:
- reworked netlink_gen_concat_data(), moved loop body to a new function,
netlink_gen_concat_data_expr() (Phil Sutter)
- dropped repeated pattern in bison file, replaced by a new helper,
compound_expr_alloc_or_add() (Phil Sutter)
- added set_is_nonconcat_range() helper (Phil Sutter)
- in expr_evaluate_set(), we need to set NFT_SET_SUBKEY also on empty
sets where the set in the context already has the flag
- dropped additional 'end' parameter from netlink_gen_data(),
temporarily set EXPR_F_INTERVAL_END on expressions and use that from
netlink_gen_concat_data() to figure out we need to add the 'end'
element (Phil Sutter)
- replace range_mask_len() by a simplified version, as we don't need
to actually store the composing masks of a range (Phil Sutter)
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/expression.h | 1 +
include/rule.h | 5 ++
src/evaluate.c | 5 ++
src/netlink.c | 109 +++++++++++++++++++++++++++++-----------
src/parser_bison.y | 17 +++++--
src/rule.c | 13 ++---
src/segtree.c | 117 +++++++++++++++++++++++++++++++++++++++++++
7 files changed, 229 insertions(+), 38 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index ee726aa..2e41aa0 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -460,6 +460,7 @@ extern int set_to_intervals(struct list_head *msgs, struct set *set,
struct expr *init, bool add,
unsigned int debug_mask, bool merge,
struct output_ctx *octx);
+extern void concat_range_aggregate(struct expr *set);
extern void interval_map_decompose(struct expr *set);
extern struct expr *get_set_intervals(const struct set *set,
diff --git a/include/rule.h b/include/rule.h
index c03b0b8..626973e 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -372,6 +372,11 @@ static inline bool set_is_interval(uint32_t set_flags)
return set_flags & NFT_SET_INTERVAL;
}
+static inline bool set_is_non_concat_range(struct set *s)
+{
+ return (s->flags & NFT_SET_INTERVAL) && s->desc.field_count <= 1;
+}
+
#include <statement.h>
struct counter {
diff --git a/src/evaluate.c b/src/evaluate.c
index 58f458d..0c84816 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -136,6 +136,11 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
if ((*expr)->byteorder == byteorder)
return 0;
+
+ /* Conversion for EXPR_CONCAT is handled for single composing ranges */
+ if ((*expr)->etype == EXPR_CONCAT)
+ return 0;
+
if (expr_basetype(*expr)->type != TYPE_INTEGER)
return expr_error(ctx->msgs, *expr,
"Byteorder mismatch: expected %s, got %s",
diff --git a/src/netlink.c b/src/netlink.c
index 83d863c..e0ba903 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -98,10 +98,11 @@ struct nftnl_expr *alloc_nft_expr(const char *name)
static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
const struct expr *expr)
{
- const struct expr *elem, *key, *data;
+ const struct expr *elem, *data;
struct nftnl_set_elem *nlse;
struct nft_data_linearize nld;
struct nftnl_udata_buf *udbuf = NULL;
+ struct expr *key;
nlse = nftnl_set_elem_alloc();
if (nlse == NULL)
@@ -119,6 +120,16 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
netlink_gen_data(key, &nld);
nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+
+ if (set->set_flags & NFT_SET_INTERVAL && expr->key->field_count > 1) {
+ key->flags |= EXPR_F_INTERVAL_END;
+ netlink_gen_data(key, &nld);
+ key->flags &= ~EXPR_F_INTERVAL_END;
+
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END, &nld.value,
+ nld.len);
+ }
+
if (elem->timeout)
nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT,
elem->timeout);
@@ -186,28 +197,58 @@ void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
data->len = len;
}
+static int netlink_export_pad(unsigned char *data, const mpz_t v,
+ const struct expr *i)
+{
+ mpz_export_data(data, v, i->byteorder,
+ div_round_up(i->len, BITS_PER_BYTE));
+
+ return netlink_padded_len(i->len) / BITS_PER_BYTE;
+}
+
+static int netlink_gen_concat_data_expr(int end, const struct expr *i,
+ unsigned char *data)
+{
+ switch (i->etype) {
+ case EXPR_RANGE:
+ i = end ? i->right : i->left;
+ break;
+ case EXPR_PREFIX:
+ if (end) {
+ int count;
+ mpz_t v;
+
+ mpz_init_bitmask(v, i->len - i->prefix_len);
+ mpz_add(v, i->prefix->value, v);
+ count = netlink_export_pad(data, v, i);
+ mpz_clear(v);
+ return count;
+ }
+ return netlink_export_pad(data, i->prefix->value, i);
+ case EXPR_VALUE:
+ break;
+ default:
+ BUG("invalid expression type '%s' in set", expr_ops(i)->name);
+ }
+
+ return netlink_export_pad(data, i->value, i);
+}
+
static void netlink_gen_concat_data(const struct expr *expr,
struct nft_data_linearize *nld)
{
+ unsigned int len = expr->len / BITS_PER_BYTE, offset = 0;
+ int end = expr->flags & EXPR_F_INTERVAL_END;
+ unsigned char data[len];
const struct expr *i;
- unsigned int len, offset;
-
- len = expr->len / BITS_PER_BYTE;
- if (1) {
- unsigned char data[len];
-
- memset(data, 0, sizeof(data));
- offset = 0;
- list_for_each_entry(i, &expr->expressions, list) {
- assert(i->etype == EXPR_VALUE);
- mpz_export_data(data + offset, i->value, i->byteorder,
- div_round_up(i->len, BITS_PER_BYTE));
- offset += netlink_padded_len(i->len) / BITS_PER_BYTE;
- }
- memcpy(nld->value, data, len);
- nld->len = len;
- }
+ memset(data, 0, len);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += netlink_gen_concat_data_expr(end, i, data + offset);
+
+ memcpy(nld->value, data, len);
+ nld->len = len;
}
static void netlink_gen_constant_data(const struct expr *expr,
@@ -812,6 +853,7 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
+key_end:
key = netlink_alloc_value(&netlink_location, &nld);
datatype_set(key, set->key->dtype);
key->byteorder = set->key->byteorder;
@@ -880,6 +922,15 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
}
out:
compound_expr_add(set->init, expr);
+
+ if (!(flags & NFT_SET_ELEM_INTERVAL_END) &&
+ nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY_END)) {
+ flags |= NFT_SET_ELEM_INTERVAL_END;
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY_END,
+ &nld.len);
+ goto key_end;
+ }
+
return 0;
}
@@ -918,15 +969,16 @@ int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
set->init = set_expr_alloc(&internal_location, set);
nftnl_set_elem_foreach(nls, list_setelem_cb, ctx);
- if (!(set->flags & NFT_SET_INTERVAL))
+ if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
+ concat_range_aggregate(set->init);
+ else if (set->flags & NFT_SET_INTERVAL)
+ interval_map_decompose(set->init);
+ else
list_expr_sort(&ctx->set->init->expressions);
nftnl_set_free(nls);
ctx->set = NULL;
- if (set->flags & NFT_SET_INTERVAL)
- interval_map_decompose(set->init);
-
return 0;
}
@@ -935,6 +987,7 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
struct set *set, struct expr *init)
{
struct nftnl_set *nls, *nls_out = NULL;
+ int err = 0;
nls = nftnl_set_alloc();
if (nls == NULL)
@@ -958,18 +1011,18 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
set->init = set_expr_alloc(loc, set);
nftnl_set_elem_foreach(nls_out, list_setelem_cb, ctx);
- if (!(set->flags & NFT_SET_INTERVAL))
+ if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
+ concat_range_aggregate(set->init);
+ else if (set->flags & NFT_SET_INTERVAL)
+ err = get_set_decompose(table, set);
+ else
list_expr_sort(&ctx->set->init->expressions);
nftnl_set_free(nls);
nftnl_set_free(nls_out);
ctx->set = NULL;
- if (set->flags & NFT_SET_INTERVAL &&
- get_set_decompose(table, set) < 0)
- return -1;
-
- return 0;
+ return err;
}
void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 0fd9b94..ea83f52 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -3551,7 +3551,6 @@ range_rhs_expr : basic_rhs_expr DASH basic_rhs_expr
multiton_rhs_expr : prefix_rhs_expr
| range_rhs_expr
- | wildcard_expr
;
map_expr : concat_expr MAP rhs_expr
@@ -3645,7 +3644,7 @@ set_elem_option : TIMEOUT time_spec
;
set_lhs_expr : concat_rhs_expr
- | multiton_rhs_expr
+ | wildcard_expr
;
set_rhs_expr : concat_rhs_expr
@@ -3898,7 +3897,7 @@ list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr
;
rhs_expr : concat_rhs_expr { $$ = $1; }
- | multiton_rhs_expr { $$ = $1; }
+ | wildcard_expr { $$ = $1; }
| set_expr { $$ = $1; }
| set_ref_symbol_expr { $$ = $1; }
;
@@ -3939,7 +3938,17 @@ basic_rhs_expr : inclusive_or_rhs_expr
;
concat_rhs_expr : basic_rhs_expr
- | concat_rhs_expr DOT basic_rhs_expr
+ | multiton_rhs_expr
+ | concat_rhs_expr DOT multiton_rhs_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ | concat_rhs_expr DOT basic_rhs_expr
{
struct location rhs[] = {
[1] = @2,
diff --git a/src/rule.c b/src/rule.c
index 4669577..e18237b 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -1512,7 +1512,8 @@ static int __do_add_setelems(struct netlink_ctx *ctx, struct set *set,
return -1;
if (set->init != NULL &&
- set->flags & NFT_SET_INTERVAL) {
+ set->flags & NFT_SET_INTERVAL &&
+ set->desc.field_count <= 1) {
interval_map_decompose(expr);
list_splice_tail_init(&expr->expressions, &set->init->expressions);
set->init->size += expr->size;
@@ -1533,7 +1534,7 @@ static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
table = table_lookup(h, &ctx->nft->cache);
set = set_lookup(table, h->set.name);
- if (set->flags & NFT_SET_INTERVAL &&
+ if (set_is_non_concat_range(set) &&
set_to_intervals(ctx->msgs, set, init, true,
ctx->nft->debug_mask, set->automerge,
&ctx->nft->output) < 0)
@@ -1548,7 +1549,7 @@ static int do_add_set(struct netlink_ctx *ctx, const struct cmd *cmd,
struct set *set = cmd->set;
if (set->init != NULL) {
- if (set->flags & NFT_SET_INTERVAL &&
+ if (set_is_non_concat_range(set) &&
set_to_intervals(ctx->msgs, set, set->init, true,
ctx->nft->debug_mask, set->automerge,
&ctx->nft->output) < 0)
@@ -1634,7 +1635,7 @@ static int do_delete_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
table = table_lookup(h, &ctx->nft->cache);
set = set_lookup(table, h->set.name);
- if (set->flags & NFT_SET_INTERVAL &&
+ if (set_is_non_concat_range(set) &&
set_to_intervals(ctx->msgs, set, expr, false,
ctx->nft->debug_mask, set->automerge,
&ctx->nft->output) < 0)
@@ -2488,7 +2489,7 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
set = set_lookup(table, cmd->handle.set.name);
/* Create a list of elements based of what we got from command line. */
- if (set->flags & NFT_SET_INTERVAL)
+ if (set_is_non_concat_range(set))
init = get_set_intervals(set, cmd->expr);
else
init = cmd->expr;
@@ -2501,7 +2502,7 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
if (err >= 0)
__do_list_set(ctx, cmd, table, new_set);
- if (set->flags & NFT_SET_INTERVAL)
+ if (set_is_non_concat_range(set))
expr_free(init);
set_free(new_set);
diff --git a/src/segtree.c b/src/segtree.c
index 7217dbc..e859f84 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -652,6 +652,11 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
set_elem_add(set, new_init, i->key->value,
i->flags, i->byteorder);
break;
+ case EXPR_CONCAT:
+ compound_expr_add(new_init, expr_clone(i));
+ i->flags |= EXPR_F_INTERVAL_END;
+ compound_expr_add(new_init, expr_clone(i));
+ break;
default:
range_expr_value_low(low, i);
set_elem_add(set, new_init, low, 0, i->byteorder);
@@ -823,6 +828,9 @@ static int expr_value_cmp(const void *p1, const void *p2)
struct expr *e2 = *(void * const *)p2;
int ret;
+ if (expr_value(e1)->etype == EXPR_CONCAT)
+ return -1;
+
ret = mpz_cmp(expr_value(e1)->value, expr_value(e2)->value);
if (ret == 0) {
if (e1->flags & EXPR_F_INTERVAL_END)
@@ -834,6 +842,115 @@ static int expr_value_cmp(const void *p1, const void *p2)
return ret;
}
+/* Given start and end elements of a range, check if it can be represented as
+ * a single netmask, and if so, how long, by returning zero or a positive value.
+ */
+static int range_mask_len(const mpz_t start, const mpz_t end, unsigned int len)
+{
+ mpz_t tmp_start, tmp_end;
+ int ret;
+
+ mpz_init_set_ui(tmp_start, mpz_get_ui(start));
+ mpz_init_set_ui(tmp_end, mpz_get_ui(end));
+
+ while (mpz_cmp(tmp_start, tmp_end) <= 0 &&
+ !mpz_tstbit(tmp_start, 0) && mpz_tstbit(tmp_end, 0) &&
+ len--) {
+ mpz_fdiv_q_2exp(tmp_start, tmp_start, 1);
+ mpz_fdiv_q_2exp(tmp_end, tmp_end, 1);
+ }
+
+ ret = !mpz_cmp(tmp_start, tmp_end) ? (int)len : -1;
+
+ mpz_clear(tmp_start);
+ mpz_clear(tmp_end);
+
+ return ret;
+}
+
+/* Given a set with two elements (start and end), transform them into a
+ * concatenation of ranges. That is, from a list of start expressions and a list
+ * of end expressions, form a list of start - end expressions.
+ */
+void concat_range_aggregate(struct expr *set)
+{
+ struct expr *i, *start = NULL, *end, *r1, *r2, *next, *r1_next, *tmp;
+ struct list_head *r2_next;
+ int prefix_len, free_r1;
+ mpz_t range, p;
+
+ list_for_each_entry_safe(i, next, &set->expressions, list) {
+ if (!start) {
+ start = i;
+ continue;
+ }
+ end = i;
+
+ /* Walk over r1 (start expression) and r2 (end) in parallel,
+ * form ranges between corresponding r1 and r2 expressions,
+ * store them by replacing r2 expressions, and free r1
+ * expressions.
+ */
+ r2 = list_first_entry(&expr_value(end)->expressions,
+ struct expr, list);
+ list_for_each_entry_safe(r1, r1_next,
+ &expr_value(start)->expressions,
+ list) {
+ mpz_init(range);
+ mpz_init(p);
+
+ r2_next = r2->list.next;
+ free_r1 = 0;
+
+ if (!mpz_cmp(r1->value, r2->value)) {
+ free_r1 = 1;
+ goto next;
+ }
+
+ mpz_sub(range, r2->value, r1->value);
+ mpz_sub_ui(range, range, 1);
+ mpz_and(p, r1->value, range);
+
+ /* Check if we are forced, or if it's anyway preferable,
+ * to express the range as two points instead of a
+ * netmask.
+ */
+ prefix_len = range_mask_len(r1->value, r2->value,
+ r1->len);
+ if (prefix_len < 0 ||
+ !(r1->dtype->flags & DTYPE_F_PREFIX)) {
+ tmp = range_expr_alloc(&r1->location, r1,
+ r2);
+
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ } else {
+ tmp = prefix_expr_alloc(&r1->location, r1,
+ prefix_len);
+ tmp->len = r2->len;
+
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ expr_free(r2);
+ }
+
+next:
+ mpz_clear(p);
+ mpz_clear(range);
+
+ r2 = list_entry(r2_next, typeof(*r2), list);
+ compound_expr_remove(start, r1);
+
+ if (free_r1)
+ expr_free(r1);
+ }
+
+ compound_expr_remove(set, start);
+ expr_free(start);
+ start = NULL;
+ }
+}
+
void interval_map_decompose(struct expr *set)
{
struct expr **elements, **ranges;
--
2.31.1

View File

@ -0,0 +1,53 @@
From 9126153259c891ef55571f358d1e56b3f2274fc4 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Feb 2023 17:52:16 +0100
Subject: [PATCH] netlink_delinearize: fix decoding of concat data element
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit db59a5c1204c9
commit db59a5c1204c9246a82a115a8761f15809578479
Author: Florian Westphal <fw@strlen.de>
Date: Mon Dec 12 11:04:34 2022 +0100
netlink_delinearize: fix decoding of concat data element
Its possible to use update as follows:
meta l4proto tcp update @pinned { ip saddr . ct original proto-src : ip daddr . ct original proto-dst }
... but when listing, only the first element of the concatenation is
shown.
Check if the element size is too small and parse subsequent registers as
well.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/netlink_delinearize.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 1d47c74..e9e0845 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1659,6 +1659,14 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_SREG_DATA)) {
sreg_data = netlink_parse_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA);
expr_data = netlink_get_register(ctx, loc, sreg_data);
+
+ if (expr_data->len < set->data->len) {
+ expr_free(expr_data);
+ expr_data = netlink_parse_concat_expr(ctx, loc, sreg_data, set->data->len);
+ if (expr_data == NULL)
+ netlink_error(ctx, loc,
+ "Could not parse dynset map data expressions");
+ }
}
if (expr_data != NULL) {
--
2.41.0.rc1

View File

@ -1,119 +0,0 @@
From 68392da523f43b9ae09f824fa68b04b20c9c88f5 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 20 May 2020 11:12:37 +0200
Subject: [PATCH] parser_json: Support ranges in concat expressions
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1805798
Upstream Status: nftables commit 9475ca305a993
commit 9475ca305a993751b05cf26ef8e785a00de98b94
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Mar 6 16:15:48 2020 +0100
parser_json: Support ranges in concat expressions
Duplicate commit 8ac2f3b2fca38's changes to bison parser into JSON
parser by introducing a new context flag signalling we're parsing
concatenated expressions.
Fixes: 8ac2f3b2fca38 ("src: Add support for concatenated set ranges")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Eric Garver <eric@garver.life>
---
src/parser_json.c | 51 +++++++++++++++++++++++++++--------------------
1 file changed, 29 insertions(+), 22 deletions(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index 031930e..c48faa8 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -40,6 +40,7 @@
#define CTX_F_MANGLE (1 << 5)
#define CTX_F_SES (1 << 6) /* set_elem_expr_stmt */
#define CTX_F_MAP (1 << 7) /* LHS of map_expr */
+#define CTX_F_CONCAT (1 << 8) /* inside concat_expr */
struct json_ctx {
struct input_descriptor indesc;
@@ -99,6 +100,7 @@ static struct expr *json_parse_primary_expr(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_set_rhs_expr(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_set_elem_expr_stmt(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root);
static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root);
/* parsing helpers */
@@ -1058,7 +1060,7 @@ static struct expr *json_parse_concat_expr(struct json_ctx *ctx,
}
json_array_foreach(root, index, value) {
- tmp = json_parse_primary_expr(ctx, value);
+ tmp = json_parse_concat_elem_expr(ctx, value);
if (!tmp) {
json_error(ctx, "Parsing expr at index %zd failed.", index);
expr_free(expr);
@@ -1354,28 +1356,28 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
{ "set", json_parse_set_expr, CTX_F_RHS | CTX_F_STMT }, /* allow this as stmt expr because that allows set references */
{ "map", json_parse_map_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS },
/* below three are multiton_rhs_expr */
- { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_STMT },
- { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_STMT },
- { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES },
- { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES },
- { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP },
- { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP },
- { "socket", json_parse_socket_expr, CTX_F_PRIMARY },
- { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "socket", json_parse_socket_expr, CTX_F_PRIMARY | CTX_F_CONCAT },
+ { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
/* below two are hash expr */
- { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
{ "accept", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
{ "drop", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
{ "continue", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
@@ -1500,6 +1502,11 @@ static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root)
return json_parse_flagged_expr(ctx, CTX_F_MAP, root);
}
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_CONCAT, root);
+}
+
static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root)
{
if (json_is_string(root)) {
--
2.31.1

View File

@ -1,51 +0,0 @@
From f7a31d5c3277b29f104fd8ff48df24c8bc790f19 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 24 Jun 2020 18:46:39 +0200
Subject: [PATCH] doc: Document notrack statement
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1841292
Upstream Status: nftables commit f16fbe76f62dc
commit f16fbe76f62dcb9f7395d1837ad2d056463ba55f
Author: Phil Sutter <phil@nwl.cc>
Date: Mon Jun 22 15:07:40 2020 +0200
doc: Document notrack statement
Merely a stub, but better to mention it explicitly instead of having it
appear in synproxy examples and letting users guess as to what it does.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
---
doc/statements.txt | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/doc/statements.txt b/doc/statements.txt
index 3b82436..749533a 100644
--- a/doc/statements.txt
+++ b/doc/statements.txt
@@ -262,6 +262,20 @@ table inet raw {
ct event set new,related,destroy
--------------------------------------
+NOTRACK STATEMENT
+~~~~~~~~~~~~~~~~~
+The notrack statement allows to disable connection tracking for certain
+packets.
+
+[verse]
+*notrack*
+
+Note that for this statement to be effective, it has to be applied to packets
+before a conntrack lookup happens. Therefore, it needs to sit in a chain with
+either prerouting or output hook and a hook priority of -300 or less.
+
+See SYNPROXY STATEMENT for an example usage.
+
META STATEMENT
~~~~~~~~~~~~~~
A meta statement sets the value of a meta expression. The existing meta fields
--
2.31.1

View File

@ -0,0 +1,66 @@
From d6e25e9fb09649963852ba79a249efeb067c6db4 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Feb 2023 17:52:16 +0100
Subject: [PATCH] netlink_linearize: fix timeout with map updates
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 284c038ef4c69
commit 284c038ef4c69d042ef91272d90c143019ecea1f
Author: Florian Westphal <fw@strlen.de>
Date: Mon Dec 12 11:04:35 2022 +0100
netlink_linearize: fix timeout with map updates
Map updates can use timeouts, just like with sets, but the
linearization step did not pass this info to the kernel.
meta l4proto tcp update @pinned { ip saddr . ct original proto-src timeout 90s : ip daddr . tcp dport
Listing this won't show the "timeout 90s" because kernel never saw it to
begin with.
Also update evaluation step to reject a timeout that was set on
the data part: Timeouts are only allowed for the key-value pair
as a whole.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/evaluate.c | 3 +++
src/netlink_linearize.c | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/src/evaluate.c b/src/evaluate.c
index 7f81411..6d0a0f5 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -3858,6 +3858,9 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
if (stmt->map.data->comment != NULL)
return expr_error(ctx->msgs, stmt->map.data,
"Data expression comments are not supported");
+ if (stmt->map.data->timeout > 0)
+ return expr_error(ctx->msgs, stmt->map.data,
+ "Data expression timeouts are not supported");
list_for_each_entry(this, &stmt->map.stmt_list, list) {
if (stmt_evaluate(ctx, this) < 0)
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index c8bbcb7..6de0a96 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -1520,6 +1520,10 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
nft_rule_add_expr(ctx, nle, &stmt->location);
+ if (stmt->map.key->timeout > 0)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
+ stmt->map.key->timeout);
+
list_for_each_entry(this, &stmt->map.stmt_list, list)
num_stmts++;
--
2.41.0.rc1

View File

@ -1,53 +0,0 @@
From 58d8baa70172bb9862276ac5f542248c88d3faf4 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 24 Jun 2020 18:48:14 +0200
Subject: [PATCH] JSON: Improve performance of json_events_cb()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1835300
Upstream Status: nftables commit c96c7da272e33
commit c96c7da272e33a34770c4de4e3e50f7ed264672e
Author: Phil Sutter <phil@nwl.cc>
Date: Wed May 13 16:29:51 2020 +0200
JSON: Improve performance of json_events_cb()
The function tries to insert handles into JSON input for echo option.
Yet there may be nothing to do if the given netlink message doesn't
contain a handle, e.g. if it is an 'add element' command. Calling
seqnum_to_json() is pointless overhead in that case, and if input is
large this overhead is significant. Better wait with that call until
after checking if the message is relevant at all.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Eric Garver <eric@garver.life>
---
src/parser_json.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index c48faa8..ce8e566 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3845,12 +3845,15 @@ static uint64_t handle_from_nlmsg(const struct nlmsghdr *nlh)
}
int json_events_cb(const struct nlmsghdr *nlh, struct netlink_mon_handler *monh)
{
- json_t *tmp, *json = seqnum_to_json(nlh->nlmsg_seq);
uint64_t handle = handle_from_nlmsg(nlh);
+ json_t *tmp, *json;
void *iter;
- /* might be anonymous set, ignore message */
- if (!json || !handle)
+ if (!handle)
+ return MNL_CB_OK;
+
+ json = seqnum_to_json(nlh->nlmsg_seq);
+ if (!json)
return MNL_CB_OK;
tmp = json_object_get(json, "add");
--
2.31.1

View File

@ -0,0 +1,73 @@
From 254a7ef45c890e297d9390a6f20b9132ad17c5d1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Fri, 17 Feb 2023 17:52:16 +0100
Subject: [PATCH] tests: add a test case for map update from packet path with
concat
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit b8e1940aa1907
commit b8e1940aa190773b23b3ee9349beb20c31f42bdb
Author: Florian Westphal <fw@strlen.de>
Date: Mon Dec 12 11:04:36 2022 +0100
tests: add a test case for map update from packet path with concat
add a second test case for map updates, this time with both
a timeout and a data element that consists of a concatenation.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
.../maps/dumps/typeof_maps_concat_update_0.nft | 12 ++++++++++++
.../testcases/maps/typeof_maps_concat_update_0 | 18 ++++++++++++++++++
2 files changed, 30 insertions(+)
create mode 100644 tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft
create mode 100755 tests/shell/testcases/maps/typeof_maps_concat_update_0
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft
new file mode 100644
index 0000000..d91b795
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft
@@ -0,0 +1,12 @@
+table ip foo {
+ map pinned {
+ typeof ip daddr . tcp dport : ip daddr . tcp dport
+ size 65535
+ flags dynamic,timeout
+ timeout 6m
+ }
+
+ chain pr {
+ update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ }
+}
diff --git a/tests/shell/testcases/maps/typeof_maps_concat_update_0 b/tests/shell/testcases/maps/typeof_maps_concat_update_0
new file mode 100755
index 0000000..645ae14
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_concat_update_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# check update statement does print both concatentations (key and data).
+
+EXPECTED="table ip foo {
+ map pinned {
+ typeof ip daddr . tcp dport : ip daddr . tcp dport
+ size 65535
+ flags dynamic,timeout
+ timeout 6m
+ }
+ chain pr {
+ meta l4proto tcp update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
--
2.41.0.rc1

View File

@ -0,0 +1,44 @@
From dbb1bcfbe480866f06977b2648b0a1595091b2b9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:40 +0100
Subject: [PATCH] owner: Fix potential array out of bounds access
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 9967911e3dabb
commit 9967911e3dabb32901617e81e56602af3b37287f
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Wed Dec 21 17:37:46 2022 +0100
owner: Fix potential array out of bounds access
If the link target length exceeds 'sizeof(tmp)' bytes, readlink() will
return 'sizeof(tmp)'. Using this value as index is illegal.
Original update from Phil, for the conntrack-tools tree, which also has
a copy of this function.
Fixes: 6d085b22a8b5 ("table: support for the table owner flag")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/owner.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/owner.c b/src/owner.c
index 2d98a2e..20bed38 100644
--- a/src/owner.c
+++ b/src/owner.c
@@ -66,7 +66,7 @@ static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode)
continue;
rl = readlink(procname, tmp, sizeof(tmp));
- if (rl <= 0 || rl > (ssize_t)sizeof(tmp))
+ if (rl <= 0 || rl >= (ssize_t)sizeof(tmp))
continue;
tmp[rl] = 0;
--
2.41.0.rc1

View File

@ -1,42 +0,0 @@
From ab62f33df5ef33f6eff8d88d9475a01822a2f625 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2020 16:20:22 +0200
Subject: [PATCH] segtree: Fix missing expires value in prefixes
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1832235
Upstream Status: nftables commit 60ba9c22fecc0
commit 60ba9c22fecc0ca9bb2a61f6ad39bceed1aee38f
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Apr 28 20:54:03 2020 +0200
segtree: Fix missing expires value in prefixes
This probable copy'n'paste bug prevented 'expiration' field from being
populated when turning a range into a prefix in
interval_map_decompose(). Consequently, interval sets with timeout did
print expiry value for ranges (such as 10.0.0.1-10.0.0.5) but not
prefixes (10.0.0.0/8, for instance).
Fixes: bb0e6d8a2851b ("segtree: incorrect handling of comments and timeouts with mapping")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/segtree.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/segtree.c b/src/segtree.c
index e859f84..1ba4363 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -1086,7 +1086,7 @@ void interval_map_decompose(struct expr *set)
prefix->comment = xstrdup(low->comment);
if (low->timeout)
prefix->timeout = low->timeout;
- if (low->left->expiration)
+ if (low->expiration)
prefix->expiration = low->expiration;
}
--
2.31.1

View File

@ -0,0 +1,57 @@
From b5fd150a3fbad94381276bedc816d4a6fdecfaf9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:41 +0100
Subject: [PATCH] mnl: dump_nf_hooks() leaks memory in error path
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit ef66f321e49b3
commit ef66f321e49b337c7e678bb90d6acb94f331dfc4
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Jan 11 12:28:15 2023 +0100
mnl: dump_nf_hooks() leaks memory in error path
Have to free the basehook object before returning to caller.
Fixes: 4694f7230195b ("src: add support for base hook dumping")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/mnl.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/mnl.c b/src/mnl.c
index 7dd77be..269d3f1 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -2211,16 +2211,23 @@ static int dump_nf_hooks(const struct nlmsghdr *nlh, void *_data)
struct nlattr *nested[NFNLA_HOOK_INFO_MAX + 1] = {};
uint32_t type;
- if (mnl_attr_parse_nested(tb[NFNLA_HOOK_CHAIN_INFO], dump_nf_chain_info_cb, nested) < 0)
+ if (mnl_attr_parse_nested(tb[NFNLA_HOOK_CHAIN_INFO],
+ dump_nf_chain_info_cb, nested) < 0) {
+ basehook_free(hook);
return -1;
+ }
type = ntohl(mnl_attr_get_u32(nested[NFNLA_HOOK_INFO_TYPE]));
if (type == NFNL_HOOK_TYPE_NFTABLES) {
struct nlattr *info[NFNLA_CHAIN_MAX + 1] = {};
const char *tablename, *chainname;
- if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC], dump_nf_attr_chain_cb, info) < 0)
+ if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC],
+ dump_nf_attr_chain_cb,
+ info) < 0) {
+ basehook_free(hook);
return -1;
+ }
tablename = mnl_attr_get_str(info[NFNLA_CHAIN_TABLE]);
chainname = mnl_attr_get_str(info[NFNLA_CHAIN_NAME]);
--
2.41.0.rc1

View File

@ -1,55 +0,0 @@
From 119fbcbd8c37aac314d6ffa6225ab24ee4b0e31e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2020 16:20:23 +0200
Subject: [PATCH] segtree: Use expr_clone in get_set_interval_*()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1832235
Upstream Status: nftables commit a2eedcc89d2ed
commit a2eedcc89d2ed40411c26d53579300c4f1ccb83d
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Apr 30 13:45:40 2020 +0200
segtree: Use expr_clone in get_set_interval_*()
Both functions perform interval set lookups with either start and end or
only start values as input. Interestingly, in practice they either see
values which are not contained or which match an existing range exactly.
Make use of the above and just return a clone of the matching entry
instead of creating a new one based on input data.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/segtree.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 1ba4363..dc4db6b 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -695,9 +695,7 @@ static struct expr *get_set_interval_find(const struct table *table,
range_expr_value_high(high, i);
if (mpz_cmp(left->key->value, low) >= 0 &&
mpz_cmp(right->key->value, high) <= 0) {
- range = range_expr_alloc(&internal_location,
- expr_clone(left->key),
- expr_clone(right->key));
+ range = expr_clone(i->key);
goto out;
}
break;
@@ -729,9 +727,7 @@ static struct expr *get_set_interval_end(const struct table *table,
case EXPR_RANGE:
range_expr_value_low(low, i);
if (mpz_cmp(low, left->key->value) == 0) {
- range = range_expr_alloc(&internal_location,
- expr_clone(left->key),
- expr_clone(i->key->right));
+ range = expr_clone(i->key);
goto out;
}
break;
--
2.31.1

View File

@ -0,0 +1,41 @@
From f5f1b17763264d88593eba175438818cf6533471 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:41 +0100
Subject: [PATCH] meta: parse_iso_date() returns boolean
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit db6e97bd667bf
commit db6e97bd667bf205cee22049f9d0fd6550cb43a7
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Jan 11 11:26:41 2023 +0100
meta: parse_iso_date() returns boolean
Returning ts if 'ts == (time_t) -1' signals success to caller despite
failure.
Fixes: 4460b839b945a ("meta: fix compiler warning in date_type_parse()")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/meta.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/meta.c b/src/meta.c
index 80ace25..73bd1c4 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -433,7 +433,7 @@ success:
cur_tm = localtime(&ts);
if (ts == (time_t) -1 || cur_tm == NULL)
- return ts;
+ return false;
/* Substract tm_gmtoff to get the current time */
*tstamp = ts - cur_tm->tm_gmtoff;
--
2.41.0.rc1

View File

@ -1,131 +0,0 @@
From 40cdcccf0fc6f4d0d4c2248d4bd9bf3193a922e9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2020 16:20:23 +0200
Subject: [PATCH] segtree: Merge get_set_interval_find() and
get_set_interval_end()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1832235
Upstream Status: nftables commit f21e73d6700b8
commit f21e73d6700b873eb1a295f43bbad9caaca577e2
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Apr 30 13:57:35 2020 +0200
segtree: Merge get_set_interval_find() and get_set_interval_end()
Both functions were very similar already. Under the assumption that they
will always either see a range (or start of) that matches exactly or not
at all, reduce complexity and make get_set_interval_find() accept NULL
(left or) right values. This way it becomes a full replacement for
get_set_interval_end().
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/segtree.c | 63 +++++++++++++--------------------------------------
1 file changed, 16 insertions(+), 47 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index dc4db6b..6e1f696 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -681,63 +681,31 @@ static struct expr *get_set_interval_find(const struct table *table,
{
struct expr *range = NULL;
struct set *set;
- mpz_t low, high;
struct expr *i;
+ mpz_t val;
set = set_lookup(table, set_name);
- mpz_init2(low, set->key->len);
- mpz_init2(high, set->key->len);
+ mpz_init2(val, set->key->len);
list_for_each_entry(i, &set->init->expressions, list) {
switch (i->key->etype) {
case EXPR_RANGE:
- range_expr_value_low(low, i);
- range_expr_value_high(high, i);
- if (mpz_cmp(left->key->value, low) >= 0 &&
- mpz_cmp(right->key->value, high) <= 0) {
- range = expr_clone(i->key);
- goto out;
- }
- break;
- default:
- break;
- }
- }
-out:
- mpz_clear(low);
- mpz_clear(high);
-
- return range;
-}
-
-static struct expr *get_set_interval_end(const struct table *table,
- const char *set_name,
- struct expr *left)
-{
- struct expr *i, *range = NULL;
- struct set *set;
- mpz_t low, high;
+ range_expr_value_low(val, i);
+ if (left && mpz_cmp(left->key->value, val))
+ break;
- set = set_lookup(table, set_name);
- mpz_init2(low, set->key->len);
- mpz_init2(high, set->key->len);
+ range_expr_value_high(val, i);
+ if (right && mpz_cmp(right->key->value, val))
+ break;
- list_for_each_entry(i, &set->init->expressions, list) {
- switch (i->key->etype) {
- case EXPR_RANGE:
- range_expr_value_low(low, i);
- if (mpz_cmp(low, left->key->value) == 0) {
- range = expr_clone(i->key);
- goto out;
- }
- break;
+ range = expr_clone(i->key);
+ goto out;
default:
break;
}
}
out:
- mpz_clear(low);
- mpz_clear(high);
+ mpz_clear(val);
return range;
}
@@ -767,9 +735,9 @@ int get_set_decompose(struct table *table, struct set *set)
left = NULL;
} else {
if (left) {
- range = get_set_interval_end(table,
- set->handle.set.name,
- left);
+ range = get_set_interval_find(table,
+ set->handle.set.name,
+ left, NULL);
if (range)
compound_expr_add(new_init, range);
else
@@ -780,7 +748,8 @@ int get_set_decompose(struct table *table, struct set *set)
}
}
if (left) {
- range = get_set_interval_end(table, set->handle.set.name, left);
+ range = get_set_interval_find(table, set->handle.set.name,
+ left, NULL);
if (range)
compound_expr_add(new_init, range);
else
--
2.31.1

View File

@ -0,0 +1,44 @@
From 3fbbb074303ec3dafd97fcdeaa0a292068c23140 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:41 +0100
Subject: [PATCH] netlink: Fix for potential NULL-pointer deref
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 927d5674e7bf6
commit 927d5674e7bf656428f97c54c9171006e8c3c75e
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Jan 10 22:36:58 2023 +0100
netlink: Fix for potential NULL-pointer deref
If memory allocation fails, calloc() returns NULL which was not checked
for. The code seems to expect zero array size though, so simply
replacing this call by one of the x*calloc() ones won't work. So guard
the call also by a check for 'len'.
Fixes: db0697ce7f602 ("src: support for flowtable listing")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/netlink.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/netlink.c b/src/netlink.c
index 799cf9b..dee1732 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1700,7 +1700,8 @@ netlink_delinearize_flowtable(struct netlink_ctx *ctx,
while (dev_array[len])
len++;
- flowtable->dev_array = calloc(1, len * sizeof(char *));
+ if (len)
+ flowtable->dev_array = xmalloc(len * sizeof(char *));
for (i = 0; i < len; i++)
flowtable->dev_array[i] = xstrdup(dev_array[i]);
--
2.41.0.rc1

View File

@ -1,41 +0,0 @@
From 4337d4eafe66b594b56b43261c8742d6b65d5ee8 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2020 16:20:23 +0200
Subject: [PATCH] tests: 0034get_element_0: do not discard stderr
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1832235
Upstream Status: nftables commit ff29e6c09aed9
commit ff29e6c09aed922a42e0e0551c34dd5d87067512
Author: Florian Westphal <fw@strlen.de>
Date: Sat Feb 22 00:02:25 2020 +0100
tests: 0034get_element_0: do not discard stderr
run_tests.sh alreadty discards stderr by default, but will show it in
case the test script is run directly (passed as argument).
Discarding stderr also in the script prevents one from seeing
BUG() assertions and the like.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
tests/shell/testcases/sets/0034get_element_0 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/shell/testcases/sets/0034get_element_0 b/tests/shell/testcases/sets/0034get_element_0
index c7e7298..e23dbda 100755
--- a/tests/shell/testcases/sets/0034get_element_0
+++ b/tests/shell/testcases/sets/0034get_element_0
@@ -3,7 +3,7 @@
RC=0
check() { # (elems, expected)
- out=$($NFT get element ip t s "{ $1 }" 2>/dev/null)
+ out=$($NFT get element ip t s "{ $1 }")
out=$(grep "elements =" <<< "$out")
out="${out#* \{ }"
out="${out% \}}"
--
2.31.1

View File

@ -0,0 +1,42 @@
From 8bdba078567b879054880ec957a78842c5a18848 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:41 +0100
Subject: [PATCH] optimize: Do not return garbage from stack
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit d4d47e5bdf943
commit d4d47e5bdf943be494aeb5d5a29b8f5212acbddf
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Jan 13 17:09:53 2023 +0100
optimize: Do not return garbage from stack
If input does not contain a single 'add' command (unusual, but
possible), 'ret' value was not initialized by nft_optimize() before
returning its value.
Fixes: fb298877ece27 ("src: add ruleset optimization infrastructure")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/optimize.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/optimize.c b/src/optimize.c
index 3a3049d..6514cbb 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -1017,7 +1017,7 @@ static int cmd_optimize(struct nft_ctx *nft, struct cmd *cmd)
int nft_optimize(struct nft_ctx *nft, struct list_head *cmds)
{
struct cmd *cmd;
- int ret;
+ int ret = 0;
list_for_each_entry(cmd, cmds, list) {
switch (cmd->op) {
--
2.41.0.rc1

View File

@ -1,135 +0,0 @@
From 3a2016f539e46183965bada40946e259c33158d9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 30 Jun 2020 16:20:23 +0200
Subject: [PATCH] segtree: Fix get element command with prefixes
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1832235
Upstream Status: nftables commit 506fb113f7ca4
commit 506fb113f7ca4fbb3d6da09ef6f9dc2b31f54a1f
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Apr 30 14:02:44 2020 +0200
segtree: Fix get element command with prefixes
Code wasn't aware of prefix elements in interval sets. With previous
changes in place, they merely need to be accepted in
get_set_interval_find() - value comparison and expression duplication is
identical to ranges.
Extend sets/0034get_element_0 test to cover prefixes as well. While
being at it, also cover concatenated ranges.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/segtree.c | 1 +
tests/shell/testcases/sets/0034get_element_0 | 62 ++++++++++++++------
2 files changed, 45 insertions(+), 18 deletions(-)
diff --git a/src/segtree.c b/src/segtree.c
index 6e1f696..073c6ec 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -689,6 +689,7 @@ static struct expr *get_set_interval_find(const struct table *table,
list_for_each_entry(i, &set->init->expressions, list) {
switch (i->key->etype) {
+ case EXPR_PREFIX:
case EXPR_RANGE:
range_expr_value_low(val, i);
if (left && mpz_cmp(left->key->value, val))
diff --git a/tests/shell/testcases/sets/0034get_element_0 b/tests/shell/testcases/sets/0034get_element_0
index e23dbda..3343529 100755
--- a/tests/shell/testcases/sets/0034get_element_0
+++ b/tests/shell/testcases/sets/0034get_element_0
@@ -2,43 +2,69 @@
RC=0
-check() { # (elems, expected)
- out=$($NFT get element ip t s "{ $1 }")
+check() { # (set, elems, expected)
+ out=$($NFT get element ip t $1 "{ $2 }")
out=$(grep "elements =" <<< "$out")
out="${out#* \{ }"
out="${out% \}}"
- [[ "$out" == "$2" ]] && return
- echo "ERROR: asked for '$1', expecting '$2' but got '$out'"
+ [[ "$out" == "$3" ]] && return
+ echo "ERROR: asked for '$2' in set $1, expecting '$3' but got '$out'"
((RC++))
}
RULESET="add table ip t
add set ip t s { type inet_service; flags interval; }
add element ip t s { 10, 20-30, 40, 50-60 }
+add set ip t ips { type ipv4_addr; flags interval; }
+add element ip t ips { 10.0.0.1, 10.0.0.5-10.0.0.8 }
+add element ip t ips { 10.0.0.128/25, 10.0.1.0/24, 10.0.2.3-10.0.2.12 }
+add set ip t cs { type ipv4_addr . inet_service; flags interval; }
+add element ip t cs { 10.0.0.1 . 22, 10.1.0.0/16 . 1-1024 }
+add element ip t cs { 10.2.0.1-10.2.0.8 . 1024-65535 }
"
$NFT -f - <<< "$RULESET"
# simple cases, (non-)existing values and ranges
-check 10 10
-check 11 ""
-check 20-30 20-30
-check 15-18 ""
+check s 10 10
+check s 11 ""
+check s 20-30 20-30
+check s 15-18 ""
# multiple single elements, ranges smaller than present
-check "10, 40" "10, 40"
-check "22-24, 26-28" "20-30, 20-30"
-check 21-29 20-30
+check s "10, 40" "10, 40"
+check s "22-24, 26-28" "20-30, 20-30"
+check s 21-29 20-30
# mixed single elements and ranges
-check "10, 20" "10, 20-30"
-check "10, 22" "10, 20-30"
-check "10, 22-24" "10, 20-30"
+check s "10, 20" "10, 20-30"
+check s "10, 22" "10, 20-30"
+check s "10, 22-24" "10, 20-30"
# non-existing ranges matching elements
-check 10-40 ""
-check 10-20 ""
-check 10-25 ""
-check 25-55 ""
+check s 10-40 ""
+check s 10-20 ""
+check s 10-25 ""
+check s 25-55 ""
+
+# playing with IPs, ranges and prefixes
+check ips 10.0.0.1 10.0.0.1
+check ips 10.0.0.2 ""
+check ips 10.0.1.0/24 10.0.1.0/24
+check ips 10.0.1.2/31 10.0.1.0/24
+check ips 10.0.1.0 10.0.1.0/24
+check ips 10.0.1.3 10.0.1.0/24
+check ips 10.0.1.255 10.0.1.0/24
+check ips 10.0.2.3-10.0.2.12 10.0.2.3-10.0.2.12
+check ips 10.0.2.10 10.0.2.3-10.0.2.12
+check ips 10.0.2.12 10.0.2.3-10.0.2.12
+
+# test concatenated ranges, i.e. Pi, Pa and Po
+check cs "10.0.0.1 . 22" "10.0.0.1 . 22"
+check cs "10.0.0.1 . 23" ""
+check cs "10.0.0.2 . 22" ""
+check cs "10.1.0.1 . 42" "10.1.0.0/16 . 1-1024"
+check cs "10.1.1.0/24 . 10-20" "10.1.0.0/16 . 1-1024"
+check cs "10.2.0.3 . 20000" "10.2.0.1-10.2.0.8 . 1024-65535"
exit $RC
--
2.31.1

View File

@ -1,45 +0,0 @@
From 77a93baa622f8aa33fa6182d72b380d980e39574 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Sat, 8 Aug 2020 00:09:06 +0200
Subject: [PATCH] include: Resync nf_tables.h cache copy
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1820684
Upstream Status: nftables commit f1e5a0499c077
commit f1e5a0499c0773f18bc592dd0da0340120daa482
Author: Stefano Brivio <sbrivio@redhat.com>
Date: Mon Apr 13 21:48:02 2020 +0200
include: Resync nf_tables.h cache copy
Get this header in sync with nf.git as of commit ef516e8625dd.
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/nf_tables.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 1a99df3..9b54a86 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -274,6 +274,7 @@ enum nft_rule_compat_attributes {
* @NFT_SET_TIMEOUT: set uses timeouts
* @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
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
@@ -283,6 +284,7 @@ enum nft_set_flags {
NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
NFT_SET_OBJECT = 0x40,
+ NFT_SET_CONCAT = 0x80,
};
/**
--
2.31.1

View File

@ -0,0 +1,51 @@
From 2438c7dafba336236e2e5dc1a6c57b6e157327cf Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:41 +0100
Subject: [PATCH] optimize: Clarify chain_optimize() array allocations
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit b83a0416cdc88
commit b83a0416cdc881c6ac35739cd858e4fe5fb2e04f
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Jan 10 22:13:44 2023 +0100
optimize: Clarify chain_optimize() array allocations
Arguments passed to sizeof() where deemed suspicious by covscan due to
the different type. Consistently specify size of an array 'a' using
'sizeof(*a) * nmemb'.
For the statement arrays in stmt_matrix, even use xzalloc_array() since
the item count is fixed and therefore can't be zero.
Fixes: fb298877ece27 ("src: add ruleset optimization infrastructure")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/optimize.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/optimize.c b/src/optimize.c
index 6514cbb..baa6abc 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -918,10 +918,11 @@ static int chain_optimize(struct nft_ctx *nft, struct list_head *rules)
ctx->num_rules++;
}
- ctx->rule = xzalloc(sizeof(ctx->rule) * ctx->num_rules);
- ctx->stmt_matrix = xzalloc(sizeof(struct stmt *) * ctx->num_rules);
+ ctx->rule = xzalloc(sizeof(*ctx->rule) * ctx->num_rules);
+ ctx->stmt_matrix = xzalloc(sizeof(*ctx->stmt_matrix) * ctx->num_rules);
for (i = 0; i < ctx->num_rules; i++)
- ctx->stmt_matrix[i] = xzalloc(sizeof(struct stmt *) * MAX_STMTS);
+ ctx->stmt_matrix[i] = xzalloc_array(MAX_STMTS,
+ sizeof(**ctx->stmt_matrix));
merge = xzalloc(sizeof(*merge) * ctx->num_rules);
--
2.41.0.rc1

View File

@ -0,0 +1,42 @@
From 21d7fa6f6a40d56c5c23eedd6ddb6a411fb8e62b Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 21 Feb 2023 19:50:41 +0100
Subject: [PATCH] netlink_delinearize: Sanitize concat data element decoding
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit 1344d9e53ba4d
commit 1344d9e53ba4d67cedd13a2c76a970fc7ce65683
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Feb 21 18:36:01 2023 +0100
netlink_delinearize: Sanitize concat data element decoding
The call to netlink_get_register() might return NULL, catch this before
dereferencing the pointer.
Fixes: db59a5c1204c9 ("netlink_delinearize: fix decoding of concat data element")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
src/netlink_delinearize.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index e9e0845..cadb8ec 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1660,7 +1660,7 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
sreg_data = netlink_parse_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA);
expr_data = netlink_get_register(ctx, loc, sreg_data);
- if (expr_data->len < set->data->len) {
+ if (expr_data && expr_data->len < set->data->len) {
expr_free(expr_data);
expr_data = netlink_parse_concat_expr(ctx, loc, sreg_data, set->data->len);
if (expr_data == NULL)
--
2.41.0.rc1

View File

@ -1,72 +0,0 @@
From 5566405cc171c8fa84e0a13ea96b89245a3fb512 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Sat, 8 Aug 2020 00:05:48 +0200
Subject: [PATCH] src: Set NFT_SET_CONCAT flag for sets with concatenated
ranges
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1820684
Upstream Status: nftables commit 09441b5e92cee
commit 09441b5e92ceea60198a35cd657904fa7a10ee54
Author: Stefano Brivio <sbrivio@redhat.com>
Date: Mon Apr 13 21:48:03 2020 +0200
src: Set NFT_SET_CONCAT flag for sets with concatenated ranges
Pablo reports that nft, after commit 8ac2f3b2fca3 ("src: Add support
for concatenated set ranges"), crashes with older kernels (< 5.6)
without support for concatenated set ranges: those sets will be sent
to the kernel, which adds them without notion of the fact that
different concatenated fields are actually included, and nft crashes
while trying to list this kind of malformed concatenation.
Use the NFT_SET_CONCAT flag introduced by kernel commit ef516e8625dd
("netfilter: nf_tables: reintroduce the NFT_SET_CONCAT flag") when
sets including concatenated ranges are sent to the kernel, so that
older kernels (with no knowledge of this flag itself) will refuse set
creation.
Note that, in expr_evaluate_set(), we have to check for the presence
of the flag, also on empty sets that might carry it in context data,
and actually set it in the actual set flags.
Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 0c84816..f66251b 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1360,10 +1360,16 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
set->size += i->size - 1;
set->set_flags |= i->set_flags;
expr_free(i);
- } else if (!expr_is_singleton(i))
+ } else if (!expr_is_singleton(i)) {
set->set_flags |= NFT_SET_INTERVAL;
+ if (i->key->etype == EXPR_CONCAT)
+ set->set_flags |= NFT_SET_CONCAT;
+ }
}
+ if (ctx->set && (ctx->set->flags & NFT_SET_CONCAT))
+ set->set_flags |= NFT_SET_CONCAT;
+
set->set_flags |= NFT_SET_CONSTANT;
datatype_set(set, ctx->ectx.dtype);
@@ -3336,6 +3342,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
memcpy(&set->desc.field_len, &set->key->field_len,
sizeof(set->desc.field_len));
set->desc.field_count = set->key->field_count;
+ set->flags |= NFT_SET_CONCAT;
}
if (set_is_datamap(set->flags)) {
--
2.31.1

View File

@ -1,503 +0,0 @@
From 19da892698f1dce2125a796ad86239711896978f Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:25:20 +0100
Subject: [PATCH] src: store expr, not dtype to track data in sets
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1877022
Upstream Status: nftables commit 343a51702656a
commit 343a51702656a6476e37cfb84609a82155c7fc5e
Author: Florian Westphal <fw@strlen.de>
Date: Tue Jul 16 19:03:55 2019 +0200
src: store expr, not dtype to track data in sets
This will be needed once we add support for the 'typeof' keyword to
handle maps that could e.g. store 'ct helper' "type" values.
Instead of:
set foo {
type ipv4_addr . mark;
this would allow
set foo {
typeof(ip saddr) . typeof(ct mark);
(exact syntax TBD).
This would be needed to allow sets that store variable-sized data types
(string, integer and the like) that can't be used at at the moment.
Adding special data types for everything is problematic due to the
large amount of different types needed.
For anonymous sets, e.g. "string" can be used because the needed size can
be inferred from the statement, e.g. 'osf name { "Windows", "Linux }',
but in case of named sets that won't work because 'type string' lacks the
context needed to derive the size information.
With 'typeof(osf name)' the context is there, but at the moment it won't
help because the expression is discarded instantly and only the data
type is retained.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/datatype.h | 1 -
include/netlink.h | 1 -
include/rule.h | 6 ++---
src/datatype.c | 5 ----
src/evaluate.c | 58 ++++++++++++++++++++++++++++++++--------------
src/expression.c | 2 +-
src/json.c | 4 ++--
src/mnl.c | 6 ++---
src/monitor.c | 2 +-
src/netlink.c | 32 ++++++++++++-------------
src/parser_bison.y | 3 +--
src/parser_json.c | 8 +++++--
src/rule.c | 8 +++----
src/segtree.c | 8 +++++--
14 files changed, 81 insertions(+), 63 deletions(-)
diff --git a/include/datatype.h b/include/datatype.h
index 49b8f60..04b4892 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -293,7 +293,6 @@ concat_subtype_lookup(uint32_t type, unsigned int n)
extern const struct datatype *
set_datatype_alloc(const struct datatype *orig_dtype, unsigned int byteorder);
-extern void set_datatype_destroy(const struct datatype *dtype);
extern void time_print(uint64_t msec, struct output_ctx *octx);
extern struct error_record *time_parse(const struct location *loc,
diff --git a/include/netlink.h b/include/netlink.h
index e694171..88d12ba 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -189,6 +189,5 @@ int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
struct netlink_mon_handler *monh);
enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype);
-const struct datatype *dtype_map_from_kernel(enum nft_data_types type);
#endif /* NFTABLES_NETLINK_H */
diff --git a/include/rule.h b/include/rule.h
index 626973e..3637462 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -283,8 +283,7 @@ extern struct rule *rule_lookup_by_index(const struct chain *chain,
* @gc_int: garbage collection interval
* @timeout: default timeout value
* @key: key expression (data type, length))
- * @datatype: mapping data type
- * @datalen: mapping data len
+ * @data: mapping data expression
* @objtype: mapping object type
* @init: initializer
* @rg_cache: cached range element (left)
@@ -303,8 +302,7 @@ struct set {
uint32_t gc_int;
uint64_t timeout;
struct expr *key;
- const struct datatype *datatype;
- unsigned int datalen;
+ struct expr *data;
uint32_t objtype;
struct expr *init;
struct expr *rg_cache;
diff --git a/src/datatype.c b/src/datatype.c
index b9e167e..189e1b4 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -1190,11 +1190,6 @@ const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
return dtype;
}
-void set_datatype_destroy(const struct datatype *dtype)
-{
- datatype_free(dtype);
-}
-
static struct error_record *time_unit_parse(const struct location *loc,
const char *str, uint64_t *unit)
{
diff --git a/src/evaluate.c b/src/evaluate.c
index f66251b..578dcae 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1383,6 +1383,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
{
struct expr_ctx ectx = ctx->ectx;
struct expr *map = *expr, *mappings;
+ const struct datatype *dtype;
struct expr *key;
expr_set_context(&ctx->ectx, NULL, 0);
@@ -1405,10 +1406,14 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
mappings = implicit_set_declaration(ctx, "__map%d",
key,
mappings);
- mappings->set->datatype =
- datatype_get(set_datatype_alloc(ectx.dtype,
- ectx.byteorder));
- mappings->set->datalen = ectx.len;
+
+ dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
+
+ mappings->set->data = constant_expr_alloc(&netlink_location,
+ dtype, dtype->byteorder,
+ ectx.len, NULL);
+ if (ectx.len && mappings->set->data->len != ectx.len)
+ BUG("%d vs %d\n", mappings->set->data->len, ectx.len);
map->mappings = mappings;
@@ -1444,7 +1449,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
- datatype_set(map, map->mappings->set->datatype);
+ datatype_set(map, map->mappings->set->data->dtype);
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
@@ -1474,7 +1479,12 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
"Key must be a constant");
mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
- expr_set_context(&ctx->ectx, set->datatype, set->datalen);
+ if (set->data) {
+ expr_set_context(&ctx->ectx, set->data->dtype, set->data->len);
+ } else {
+ assert((set->flags & NFT_SET_MAP) == 0);
+ }
+
if (expr_evaluate(ctx, &mapping->right) < 0)
return -1;
if (!expr_is_constant(mapping->right))
@@ -2119,7 +2129,7 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
(*expr)->len);
else if ((*expr)->dtype->type != TYPE_INTEGER &&
!datatype_equal((*expr)->dtype, dtype))
- return stmt_binary_error(ctx, *expr, stmt,
+ return stmt_binary_error(ctx, *expr, stmt, /* verdict vs invalid? */
"datatype mismatch: expected %s, "
"expression has type %s",
dtype->desc, (*expr)->dtype->desc);
@@ -3113,9 +3123,9 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
"Key expression comments are not supported");
if (stmt_evaluate_arg(ctx, stmt,
- stmt->map.set->set->datatype,
- stmt->map.set->set->datalen,
- stmt->map.set->set->datatype->byteorder,
+ stmt->map.set->set->data->dtype,
+ stmt->map.set->set->data->len,
+ stmt->map.set->set->data->byteorder,
&stmt->map.data->key) < 0)
return -1;
if (expr_is_constant(stmt->map.data))
@@ -3161,8 +3171,12 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
mappings = implicit_set_declaration(ctx, "__objmap%d",
key, mappings);
- mappings->set->datatype = &string_type;
- mappings->set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
+
+ mappings->set->data = constant_expr_alloc(&netlink_location,
+ &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+ NULL);
mappings->set->objtype = stmt->objref.type;
map->mappings = mappings;
@@ -3197,7 +3211,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
- datatype_set(map, map->mappings->set->datatype);
+ datatype_set(map, map->mappings->set->data->dtype);
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
@@ -3346,17 +3360,25 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
}
if (set_is_datamap(set->flags)) {
- if (set->datatype == NULL)
+ if (set->data == NULL)
return set_error(ctx, set, "map definition does not "
"specify mapping data type");
- set->datalen = set->datatype->size;
- if (set->datalen == 0 && set->datatype->type != TYPE_VERDICT)
+ if (set->data->len == 0 && set->data->dtype->type != TYPE_VERDICT)
return set_error(ctx, set, "unqualified mapping data "
"type specified in map definition");
} else if (set_is_objmap(set->flags)) {
- set->datatype = &string_type;
- set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
+ if (set->data) {
+ assert(set->data->etype == EXPR_VALUE);
+ assert(set->data->dtype == &string_type);
+ }
+
+ assert(set->data == NULL);
+ set->data = constant_expr_alloc(&netlink_location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+ NULL);
+
}
ctx->set = set;
diff --git a/src/expression.c b/src/expression.c
index 5070b10..6fa2f1d 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -1010,7 +1010,7 @@ static void map_expr_print(const struct expr *expr, struct output_ctx *octx)
{
expr_print(expr->map, octx);
if (expr->mappings->etype == EXPR_SET_REF &&
- expr->mappings->set->datatype->type == TYPE_VERDICT)
+ expr->mappings->set->data->dtype->type == TYPE_VERDICT)
nft_print(octx, " vmap ");
else
nft_print(octx, " map ");
diff --git a/src/json.c b/src/json.c
index 3498e24..1906e7d 100644
--- a/src/json.c
+++ b/src/json.c
@@ -82,7 +82,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
if (set_is_datamap(set->flags)) {
type = "map";
- datatype_ext = set->datatype->name;
+ datatype_ext = set->data->dtype->name;
} else if (set_is_objmap(set->flags)) {
type = "map";
datatype_ext = obj_type_name(set->objtype);
@@ -645,7 +645,7 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
const char *type = "map";
if (expr->mappings->etype == EXPR_SET_REF &&
- expr->mappings->set->datatype->type == TYPE_VERDICT)
+ expr->mappings->set->data->dtype->type == TYPE_VERDICT)
type = "vmap";
return json_pack("{s:{s:o, s:o}}", type,
diff --git a/src/mnl.c b/src/mnl.c
index 221ee05..23341e6 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -839,9 +839,9 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
div_round_up(set->key->len, BITS_PER_BYTE));
if (set_is_datamap(set->flags)) {
nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
- dtype_map_to_kernel(set->datatype));
+ dtype_map_to_kernel(set->data->dtype));
nftnl_set_set_u32(nls, NFTNL_SET_DATA_LEN,
- set->datalen / BITS_PER_BYTE);
+ set->data->len / BITS_PER_BYTE);
}
if (set_is_objmap(set->flags))
nftnl_set_set_u32(nls, NFTNL_SET_OBJ_TYPE, set->objtype);
@@ -873,7 +873,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
if (set_is_datamap(set->flags) &&
!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATABYTEORDER,
- set->datatype->byteorder))
+ set->data->byteorder))
memory_allocation_error();
if (set->automerge &&
diff --git a/src/monitor.c b/src/monitor.c
index fb803cf..7927b6f 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -401,7 +401,7 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
*/
dummyset = set_alloc(monh->loc);
dummyset->key = expr_clone(set->key);
- dummyset->datatype = set->datatype;
+ dummyset->data = set->data;
dummyset->flags = set->flags;
dummyset->init = set_expr_alloc(monh->loc, set);
diff --git a/src/netlink.c b/src/netlink.c
index e0ba903..64e51e5 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -575,7 +575,7 @@ enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
}
}
-const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
+static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
{
switch (type) {
case NFT_DATA_VERDICT:
@@ -622,10 +622,10 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
const struct nftnl_set *nls)
{
const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
- uint32_t flags, key, data, data_len, objtype = 0;
enum byteorder keybyteorder = BYTEORDER_INVALID;
enum byteorder databyteorder = BYTEORDER_INVALID;
- const struct datatype *keytype, *datatype;
+ const struct datatype *keytype, *datatype = NULL;
+ uint32_t flags, key, objtype = 0;
bool automerge = false;
const char *udata;
struct set *set;
@@ -659,6 +659,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
if (set_is_datamap(flags)) {
+ uint32_t data;
+
data = nftnl_set_get_u32(nls, NFTNL_SET_DATA_TYPE);
datatype = dtype_map_from_kernel(data);
if (datatype == NULL) {
@@ -667,8 +669,7 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
data);
return NULL;
}
- } else
- datatype = NULL;
+ }
if (set_is_objmap(flags)) {
objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE);
@@ -691,16 +692,13 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->objtype = objtype;
+ set->data = NULL;
if (datatype)
- set->datatype = datatype_get(set_datatype_alloc(datatype,
- databyteorder));
- else
- set->datatype = NULL;
-
- if (nftnl_set_is_set(nls, NFTNL_SET_DATA_LEN)) {
- data_len = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN);
- set->datalen = data_len * BITS_PER_BYTE;
- }
+ set->data = constant_expr_alloc(&netlink_location,
+ set_datatype_alloc(datatype, databyteorder),
+ databyteorder,
+ nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE,
+ NULL);
if (nftnl_set_is_set(nls, NFTNL_SET_TIMEOUT))
set->timeout = nftnl_set_get_u64(nls, NFTNL_SET_TIMEOUT);
@@ -897,10 +895,10 @@ key_end:
goto out;
data = netlink_alloc_data(&netlink_location, &nld,
- set->datatype->type == TYPE_VERDICT ?
+ set->data->dtype->type == TYPE_VERDICT ?
NFT_REG_VERDICT : NFT_REG_1);
- datatype_set(data, set->datatype);
- data->byteorder = set->datatype->byteorder;
+ datatype_set(data, set->data->dtype);
+ data->byteorder = set->data->byteorder;
if (data->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ea83f52..4cca31b 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -1749,9 +1749,8 @@ map_block : /* empty */ { $$ = $<set>-1; }
stmt_separator
{
$1->key = $3;
- $1->datatype = $5->dtype;
+ $1->data = $5;
- expr_free($5);
$1->flags |= NFT_SET_MAP;
$$ = $1;
}
diff --git a/src/parser_json.c b/src/parser_json.c
index ce8e566..ddc694f 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -2833,11 +2833,15 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
}
if (!json_unpack(root, "{s:s}", "map", &dtype_ext)) {
+ const struct datatype *dtype;
+
set->objtype = string_to_nft_object(dtype_ext);
if (set->objtype) {
set->flags |= NFT_SET_OBJECT;
- } else if (datatype_lookup_byname(dtype_ext)) {
- set->datatype = datatype_lookup_byname(dtype_ext);
+ } else if ((dtype = datatype_lookup_byname(dtype_ext))) {
+ set->data = constant_expr_alloc(&netlink_location,
+ dtype, dtype->byteorder,
+ dtype->size, NULL);
set->flags |= NFT_SET_MAP;
} else {
json_error(ctx, "Invalid map type '%s'.", dtype_ext);
diff --git a/src/rule.c b/src/rule.c
index e18237b..f7d888b 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -332,8 +332,8 @@ struct set *set_clone(const struct set *set)
new_set->gc_int = set->gc_int;
new_set->timeout = set->timeout;
new_set->key = expr_clone(set->key);
- new_set->datatype = datatype_get(set->datatype);
- new_set->datalen = set->datalen;
+ if (set->data)
+ new_set->data = expr_clone(set->data);
new_set->objtype = set->objtype;
new_set->policy = set->policy;
new_set->automerge = set->automerge;
@@ -356,7 +356,7 @@ void set_free(struct set *set)
expr_free(set->init);
handle_free(&set->handle);
expr_free(set->key);
- set_datatype_destroy(set->datatype);
+ expr_free(set->data);
xfree(set);
}
@@ -469,7 +469,7 @@ static void set_print_declaration(const struct set *set,
nft_print(octx, "%s%stype %s",
opts->tab, opts->tab, set->key->dtype->name);
if (set_is_datamap(set->flags))
- nft_print(octx, " : %s", set->datatype->name);
+ nft_print(octx, " : %s", set->data->dtype->name);
else if (set_is_objmap(set->flags))
nft_print(octx, " : %s", obj_type_name(set->objtype));
diff --git a/src/segtree.c b/src/segtree.c
index 073c6ec..d6e3ce2 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -79,8 +79,12 @@ static void seg_tree_init(struct seg_tree *tree, const struct set *set,
tree->root = RB_ROOT;
tree->keytype = set->key->dtype;
tree->keylen = set->key->len;
- tree->datatype = set->datatype;
- tree->datalen = set->datalen;
+ tree->datatype = NULL;
+ tree->datalen = 0;
+ if (set->data) {
+ tree->datatype = set->data->dtype;
+ tree->datalen = set->data->len;
+ }
tree->byteorder = first->byteorder;
tree->debug_mask = debug_mask;
}
--
2.31.1

View File

@ -0,0 +1,54 @@
From a2446688362b6b81bd0fa0dc22cb5cc2fa3378c1 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Thu, 20 Jul 2023 15:55:05 +0200
Subject: [PATCH] tests: monitor: Summarize failures per test case
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2211076
Upstream Status: nftables commit c2b28dcebd058
commit c2b28dcebd058b978692b8e1899e79b96c025396
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jul 20 12:08:45 2023 +0200
tests: monitor: Summarize failures per test case
Explicitly print when tests from a file fail in addition to the diff +
"output differs" message.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <psutter@redhat.com>
---
tests/monitor/run-tests.sh | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
index b5ca47d..f1ac790 100755
--- a/tests/monitor/run-tests.sh
+++ b/tests/monitor/run-tests.sh
@@ -161,7 +161,10 @@ for variant in $variants; do
output_append=${variant}_output_append
for testcase in ${testcases:-testcases/*.t}; do
- echo "$variant: running tests from file $(basename $testcase)"
+ filename=$(basename $testcase)
+ echo "$variant: running tests from file $filename"
+ rc_start=$rc
+
# files are like this:
#
# I add table ip t
@@ -199,6 +202,10 @@ for variant in $variants; do
$run_test
let "rc += $?"
}
+
+ let "rc_diff = rc - rc_start"
+ [[ $rc_diff -ne 0 ]] && \
+ echo "$variant: $rc_diff tests from file $filename failed"
done
done
exit $rc
--
2.41.0

View File

@ -1,120 +0,0 @@
From 785823a1f607a7bcd32d4cb42655422c223fcad5 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:25:20 +0100
Subject: [PATCH] evaluate: Perform set evaluation on implicitly declared
(anonymous) sets
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1877022
Upstream Status: nftables commit 7aa08d45031ec
commit 7aa08d45031ec7ce5dadb4979471d626367c09cd
Author: Stefano Brivio <sbrivio@redhat.com>
Date: Wed May 27 22:51:21 2020 +0200
evaluate: Perform set evaluation on implicitly declared (anonymous) sets
If a set is implicitly declared, set_evaluate() is not called as a
result of cmd_evaluate_add(), because we're adding in fact something
else (e.g. a rule). Expression-wise, evaluation still happens as the
implicit set expression is eventually found in the tree and handled
by expr_evaluate_set(), but context-wise evaluation (set_evaluate())
is skipped, and this might be relevant instead.
This is visible in the reported case of an anonymous set including
concatenated ranges:
# nft add rule t c ip saddr . tcp dport { 192.0.2.1 . 20-30 } accept
BUG: invalid range expression type concat
nft: expression.c:1160: range_expr_value_low: Assertion `0' failed.
Aborted
because we reach do_add_set() without properly evaluated flags and
set description, and eventually end up in expr_to_intervals(), which
can't handle that expression.
Explicitly call set_evaluate() as we add anonymous sets into the
context, and instruct the same function to:
- skip expression-wise set evaluation if the set is anonymous, as
that happens later anyway as part of the general tree evaluation
- skip the insertion in the set cache, as it makes no sense to have
sets that shouldn't be referenced there
For object maps, the allocation of the expression for set->data is
already handled by set_evaluate(), so we can now drop that from
stmt_evaluate_objref_map().
v2:
- skip insertion of set in cache (Pablo Neira Ayuso)
- drop double allocation of expression (and leak of the first
one) for object maps (Pablo Neira Ayuso)
Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
Reported-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 578dcae..fc45cef 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -75,6 +75,7 @@ static void key_fix_dtype_byteorder(struct expr *key)
datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
}
+static int set_evaluate(struct eval_ctx *ctx, struct set *set);
static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
const char *name,
struct expr *key,
@@ -105,6 +106,8 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
list_add_tail(&cmd->list, &ctx->cmd->list);
}
+ set_evaluate(ctx, set);
+
return set_ref_expr_alloc(&expr->location, set);
}
@@ -3171,12 +3174,6 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
mappings = implicit_set_declaration(ctx, "__objmap%d",
key, mappings);
-
- mappings->set->data = constant_expr_alloc(&netlink_location,
- &string_type,
- BYTEORDER_HOST_ENDIAN,
- NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
- NULL);
mappings->set->objtype = stmt->objref.type;
map->mappings = mappings;
@@ -3381,6 +3378,13 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
}
+ /* Default timeout value implies timeout support */
+ if (set->timeout)
+ set->flags |= NFT_SET_TIMEOUT;
+
+ if (set_is_anonymous(set->flags))
+ return 0;
+
ctx->set = set;
if (set->init != NULL) {
expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
@@ -3392,10 +3396,6 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
if (set_lookup(table, set->handle.set.name) == NULL)
set_add_hash(set_get(set), table);
- /* Default timeout value implies timeout support */
- if (set->timeout)
- set->flags |= NFT_SET_TIMEOUT;
-
return 0;
}
--
2.31.1

View File

@ -1,167 +0,0 @@
From 3193f74613b16a42d7784452ebf4d53ccd33b887 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 12 Jan 2021 10:34:35 +0100
Subject: [PATCH] evaluate: missing datatype definition in
implicit_set_declaration()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1877022
Upstream Status: nftables commit 54eb1e16cc478
commit 54eb1e16cc4787906fe8206858f0ea0bfb9c1209
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Sun Jun 7 15:23:21 2020 +0200
evaluate: missing datatype definition in implicit_set_declaration()
set->data from implicit_set_declaration(), otherwise, set_evaluation()
bails out with:
# nft -f /etc/nftables/inet-filter.nft
/etc/nftables/inet-filter.nft:8:32-54: Error: map definition does not specify
mapping data type
tcp dport vmap { 22 : jump ssh_input }
^^^^^^^^^^^^^^^^^^^^^^^
/etc/nftables/inet-filter.nft:13:26-52: Error: map definition does not specify
mapping data type
iif vmap { "eth0" : jump wan_input }
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Add a test to cover this case.
Fixes: 7aa08d45031e ("evaluate: Perform set evaluation on implicitly declared (anonymous) sets")
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=208093
Reviewed-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/evaluate.c | 22 +++++++++++----------
tests/shell/testcases/maps/0009vmap_0 | 19 ++++++++++++++++++
tests/shell/testcases/maps/dumps/0009vmap_0 | 13 ++++++++++++
3 files changed, 44 insertions(+), 10 deletions(-)
create mode 100755 tests/shell/testcases/maps/0009vmap_0
create mode 100644 tests/shell/testcases/maps/dumps/0009vmap_0
diff --git a/src/evaluate.c b/src/evaluate.c
index fc45cef..a966ed4 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -79,6 +79,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set);
static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
const char *name,
struct expr *key,
+ struct expr *data,
struct expr *expr)
{
struct cmd *cmd;
@@ -92,6 +93,7 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
set->flags = NFT_SET_ANONYMOUS | expr->set_flags;
set->handle.set.name = xstrdup(name);
set->key = key;
+ set->data = data;
set->init = expr;
set->automerge = set->flags & NFT_SET_INTERVAL;
@@ -1387,7 +1389,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
struct expr_ctx ectx = ctx->ectx;
struct expr *map = *expr, *mappings;
const struct datatype *dtype;
- struct expr *key;
+ struct expr *key, *data;
expr_set_context(&ctx->ectx, NULL, 0);
if (expr_evaluate(ctx, &map->map) < 0)
@@ -1406,15 +1408,14 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
ctx->ectx.byteorder,
ctx->ectx.len, NULL);
+ dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
+ data = constant_expr_alloc(&netlink_location, dtype,
+ dtype->byteorder, ectx.len, NULL);
+
mappings = implicit_set_declaration(ctx, "__map%d",
- key,
+ key, data,
mappings);
- dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
-
- mappings->set->data = constant_expr_alloc(&netlink_location,
- dtype, dtype->byteorder,
- ectx.len, NULL);
if (ectx.len && mappings->set->data->len != ectx.len)
BUG("%d vs %d\n", mappings->set->data->len, ectx.len);
@@ -1857,7 +1858,8 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
case EXPR_SET:
right = rel->right =
implicit_set_declaration(ctx, "__set%d",
- expr_get(left), right);
+ expr_get(left), NULL,
+ right);
/* fall through */
case EXPR_SET_REF:
/* Data for range lookups needs to be in big endian order */
@@ -2335,7 +2337,7 @@ static int stmt_evaluate_meter(struct eval_ctx *ctx, struct stmt *stmt)
set->set_flags |= NFT_SET_TIMEOUT;
setref = implicit_set_declaration(ctx, stmt->meter.name,
- expr_get(key), set);
+ expr_get(key), NULL, set);
setref->set->desc.size = stmt->meter.size;
stmt->meter.set = setref;
@@ -3173,7 +3175,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
ctx->ectx.len, NULL);
mappings = implicit_set_declaration(ctx, "__objmap%d",
- key, mappings);
+ key, NULL, mappings);
mappings->set->objtype = stmt->objref.type;
map->mappings = mappings;
diff --git a/tests/shell/testcases/maps/0009vmap_0 b/tests/shell/testcases/maps/0009vmap_0
new file mode 100755
index 0000000..7627c81
--- /dev/null
+++ b/tests/shell/testcases/maps/0009vmap_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table inet filter {
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap { 22 : jump ssh_input }
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority -300; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/dumps/0009vmap_0 b/tests/shell/testcases/maps/dumps/0009vmap_0
new file mode 100644
index 0000000..540a8af
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0009vmap_0
@@ -0,0 +1,13 @@
+table inet filter {
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap { 22 : jump ssh_input }
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority -300; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}
--
2.31.1

View File

@ -1,88 +0,0 @@
From 9d67918643e7d17c433e82eb6cdb039cb103c50f Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:26:24 +0100
Subject: [PATCH] mergesort: unbreak listing with binops
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1891790
Upstream Status: nftables commit 3926a3369bb5a
commit 3926a3369bb5ada5c0706dadcbcf938517822a35
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Aug 20 01:05:04 2020 +0200
mergesort: unbreak listing with binops
tcp flags == {syn, syn|ack}
tcp flags & (fin|syn|rst|psh|ack|urg) == {ack, psh|ack, fin, fin|psh|ack}
results in:
BUG: Unknown expression binop
nft: mergesort.c:47: expr_msort_cmp: Assertion `0' failed.
Aborted (core dumped)
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/mergesort.c | 2 ++
tests/py/inet/tcp.t | 2 ++
tests/py/inet/tcp.t.payload | 21 +++++++++++++++++++++
3 files changed, 25 insertions(+)
diff --git a/src/mergesort.c b/src/mergesort.c
index 649b780..02094b4 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -43,6 +43,8 @@ static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
return concat_expr_msort_cmp(e1, e2);
case EXPR_MAPPING:
return expr_msort_cmp(e1->left, e2->left);
+ case EXPR_BINOP:
+ return expr_msort_cmp(e1->left, e2->left);
default:
BUG("Unknown expression %s\n", expr_name(e1));
}
diff --git a/tests/py/inet/tcp.t b/tests/py/inet/tcp.t
index e0a83e2..29f06f5 100644
--- a/tests/py/inet/tcp.t
+++ b/tests/py/inet/tcp.t
@@ -79,6 +79,8 @@ tcp flags != cwr;ok
tcp flags == syn;ok
tcp flags & (syn|fin) == (syn|fin);ok;tcp flags & (fin | syn) == fin | syn
tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr;ok;tcp flags == 0xff
+tcp flags { syn, syn | ack };ok
+tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack };ok
tcp window 22222;ok
tcp window 22;ok
diff --git a/tests/py/inet/tcp.t.payload b/tests/py/inet/tcp.t.payload
index 55f1bc2..076e562 100644
--- a/tests/py/inet/tcp.t.payload
+++ b/tests/py/inet/tcp.t.payload
@@ -680,3 +680,24 @@ inet test-inet input
[ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000080 ]
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000001 : 0 [end] element 00000010 : 0 [end] element 00000018 : 0 [end] element 00000019 : 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = (reg=1 & 0x0000003f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# tcp flags { syn, syn | ack }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000002 : 0 [end] element 00000012 : 0 [end]
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
--
2.31.1

View File

@ -1,134 +0,0 @@
From 876a1202351264f6d3b105258f10bde693870bd4 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:27:16 +0100
Subject: [PATCH] proto: add sctp crc32 checksum fixup
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1895804
Upstream Status: nftables commit 09a3b2ba0c822
commit 09a3b2ba0c8228d1c6bf0f030cae97addb397351
Author: Florian Westphal <fw@strlen.de>
Date: Tue Oct 6 23:16:32 2020 +0200
proto: add sctp crc32 checksum fixup
Stateless SCTP header mangling doesn't work reliably.
This tells the kernel to update the checksum field using
the sctp crc32 algorithm.
Note that this needs additional kernel support to work.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/linux/netfilter/nf_tables.h | 2 ++
include/proto.h | 1 +
src/netlink_linearize.c | 2 +-
src/proto.c | 8 ++++++++
4 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 9b54a86..1328b8e 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -707,10 +707,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 {
diff --git a/include/proto.h b/include/proto.h
index fab48c1..436cbe3 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -78,6 +78,7 @@ struct proto_hdr_template {
struct proto_desc {
const char *name;
enum proto_bases base;
+ enum nft_payload_csum_types checksum_type;
unsigned int checksum_key;
unsigned int protocol_key;
unsigned int length;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index cb1b7fe..606d97a 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -937,7 +937,7 @@ static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
expr->len / BITS_PER_BYTE);
if (csum_off) {
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_TYPE,
- NFT_PAYLOAD_CSUM_INET);
+ desc->checksum_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_OFFSET,
csum_off / BITS_PER_BYTE);
}
diff --git a/src/proto.c b/src/proto.c
index 40ce590..8360abf 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -345,6 +345,7 @@ const struct proto_desc proto_icmp = {
.name = "icmp",
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = ICMPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[ICMPHDR_TYPE] = ICMPHDR_TYPE("type", &icmp_type_type, type),
[ICMPHDR_CODE] = ICMPHDR_TYPE("code", &icmp_code_type, code),
@@ -397,6 +398,7 @@ const struct proto_desc proto_igmp = {
.name = "igmp",
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = IGMPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[IGMPHDR_TYPE] = IGMPHDR_TYPE("type", &igmp_type_type, igmp_type),
[IGMPHDR_MRT] = IGMPHDR_FIELD("mrt", igmp_code),
@@ -417,6 +419,7 @@ const struct proto_desc proto_udp = {
.name = "udp",
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = UDPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
[UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest),
@@ -474,6 +477,7 @@ const struct proto_desc proto_tcp = {
.name = "tcp",
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = TCPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[TCPHDR_SPORT] = INET_SERVICE("sport", struct tcphdr, source),
[TCPHDR_DPORT] = INET_SERVICE("dport", struct tcphdr, dest),
@@ -553,6 +557,8 @@ const struct proto_desc proto_dccp = {
const struct proto_desc proto_sctp = {
.name = "sctp",
.base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = SCTPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_SCTP,
.templates = {
[SCTPHDR_SPORT] = INET_SERVICE("sport", struct sctphdr, source),
[SCTPHDR_DPORT] = INET_SERVICE("dport", struct sctphdr, dest),
@@ -650,6 +656,7 @@ const struct proto_desc proto_ip = {
.name = "ip",
.base = PROTO_BASE_NETWORK_HDR,
.checksum_key = IPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.protocols = {
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
@@ -746,6 +753,7 @@ const struct proto_desc proto_icmp6 = {
.name = "icmpv6",
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = ICMP6HDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[ICMP6HDR_TYPE] = ICMP6HDR_TYPE("type", &icmp6_type_type, icmp6_type),
[ICMP6HDR_CODE] = ICMP6HDR_TYPE("code", &icmpv6_code_type, icmp6_code),
--
2.31.1

View File

@ -1,233 +0,0 @@
From 70dc225b23708c6ac96e2895488f3c6dea9e201d Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:28:27 +0100
Subject: [PATCH] proto: Fix ARP header field ordering
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1896334
Upstream Status: nftables commit f751753f92ea7
commit f751753f92ea76f582f7d5d1fef8b4d5677ba589
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Nov 10 13:07:49 2020 +0100
proto: Fix ARP header field ordering
In ARP header, destination ether address sits between source IP and
destination IP addresses. Enum arp_hdr_fields had this wrong, which
in turn caused wrong ordering of entries in proto_arp->templates. When
expanding a combined payload expression, code assumes that template
entries are ordered by header offset, therefore the destination ether
address match was printed as raw if an earlier field was matched as
well:
| arp saddr ip 192.168.1.1 arp daddr ether 3e:d1:3f:d6:12:0b
was printed as:
| arp saddr ip 192.168.1.1 @nh,144,48 69068440080907
Note: Although strictly not necessary, reorder fields in
proto_arp->templates as well to match their actual ordering, just to
avoid confusion.
Fixes: 4b0f2a712b579 ("src: support for arp sender and target ethernet and IPv4 addresses")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
include/proto.h | 2 +-
src/proto.c | 2 +-
tests/py/arp/arp.t | 3 ++
tests/py/arp/arp.t.json | 56 +++++++++++++++++++++++++++++++
tests/py/arp/arp.t.json.output | 28 ++++++++++++++++
tests/py/arp/arp.t.payload | 10 ++++++
tests/py/arp/arp.t.payload.netdev | 14 ++++++++
7 files changed, 113 insertions(+), 2 deletions(-)
diff --git a/include/proto.h b/include/proto.h
index 436cbe3..5a50059 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -184,8 +184,8 @@ enum arp_hdr_fields {
ARPHDR_PLN,
ARPHDR_OP,
ARPHDR_SADDR_ETHER,
- ARPHDR_DADDR_ETHER,
ARPHDR_SADDR_IP,
+ ARPHDR_DADDR_ETHER,
ARPHDR_DADDR_IP,
};
diff --git a/src/proto.c b/src/proto.c
index 8360abf..49c8c92 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -908,8 +908,8 @@ const struct proto_desc proto_arp = {
[ARPHDR_PLN] = ARPHDR_FIELD("plen", plen),
[ARPHDR_OP] = ARPHDR_TYPE("operation", &arpop_type, oper),
[ARPHDR_SADDR_ETHER] = ARPHDR_TYPE("saddr ether", &etheraddr_type, sha),
- [ARPHDR_DADDR_ETHER] = ARPHDR_TYPE("daddr ether", &etheraddr_type, tha),
[ARPHDR_SADDR_IP] = ARPHDR_TYPE("saddr ip", &ipaddr_type, spa),
+ [ARPHDR_DADDR_ETHER] = ARPHDR_TYPE("daddr ether", &etheraddr_type, tha),
[ARPHDR_DADDR_IP] = ARPHDR_TYPE("daddr ip", &ipaddr_type, tpa),
},
.format = {
diff --git a/tests/py/arp/arp.t b/tests/py/arp/arp.t
index 2540c0a..109d01d 100644
--- a/tests/py/arp/arp.t
+++ b/tests/py/arp/arp.t
@@ -61,4 +61,7 @@ arp daddr ip 4.3.2.1;ok
arp saddr ether aa:bb:cc:aa:bb:cc;ok
arp daddr ether aa:bb:cc:aa:bb:cc;ok
+arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee;ok
+arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1;ok;arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+
meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566;ok;iifname "invalid" arp htype 1 arp ptype ip arp hlen 6 arp plen 4 arp daddr ip 192.168.143.16 arp daddr ether set 11:22:33:44:55:66
diff --git a/tests/py/arp/arp.t.json b/tests/py/arp/arp.t.json
index 5f2f6cd..8508c17 100644
--- a/tests/py/arp/arp.t.json
+++ b/tests/py/arp/arp.t.json
@@ -901,6 +901,62 @@
}
]
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ }
+]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ }
+]
+
# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
[
{
diff --git a/tests/py/arp/arp.t.json.output b/tests/py/arp/arp.t.json.output
index b8507bf..afa75b2 100644
--- a/tests/py/arp/arp.t.json.output
+++ b/tests/py/arp/arp.t.json.output
@@ -66,6 +66,34 @@
}
]
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ }
+]
+
# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
[
{
diff --git a/tests/py/arp/arp.t.payload b/tests/py/arp/arp.t.payload
index 52c9932..f819853 100644
--- a/tests/py/arp/arp.t.payload
+++ b/tests/py/arp/arp.t.payload
@@ -307,3 +307,13 @@ arp test-arp input
[ payload load 6b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+arp
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+arp
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
diff --git a/tests/py/arp/arp.t.payload.netdev b/tests/py/arp/arp.t.payload.netdev
index 667691f..f57610c 100644
--- a/tests/py/arp/arp.t.payload.netdev
+++ b/tests/py/arp/arp.t.payload.netdev
@@ -409,3 +409,17 @@ netdev test-netdev ingress
[ payload load 6b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
--
2.31.1

View File

@ -1,108 +0,0 @@
From 26c4f15080663a12006abf8539ebf28bb223e6d9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:29:15 +0100
Subject: [PATCH] json: echo: Speedup seqnum_to_json()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1900565
Upstream Status: nftables commit 389a0e1edc89a
commit 389a0e1edc89a4048a272e569d3349b1d43bc567
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Nov 20 20:01:59 2020 +0100
json: echo: Speedup seqnum_to_json()
Derek Dai reports:
"If there are a lot of command in JSON node, seqnum_to_json() will slow
down application (eg: firewalld) dramatically since it iterate whole
command list every time."
He sent a patch implementing a lookup table, but we can do better: Speed
this up by introducing a hash table to store the struct json_cmd_assoc
objects in, taking their netlink sequence number as key.
Quickly tested restoring a ruleset containing about 19k rules:
| # time ./before/nft -jeaf large_ruleset.json >/dev/null
| 4.85user 0.47system 0:05.48elapsed 97%CPU (0avgtext+0avgdata 69732maxresident)k
| 0inputs+0outputs (15major+16937minor)pagefaults 0swaps
| # time ./after/nft -jeaf large_ruleset.json >/dev/null
| 0.18user 0.44system 0:00.70elapsed 89%CPU (0avgtext+0avgdata 68484maxresident)k
| 0inputs+0outputs (15major+16645minor)pagefaults 0swaps
Bugzilla: https://bugzilla.netfilter.org/show_bug.cgi?id=1479
Reported-by: Derek Dai <daiderek@gmail.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/parser_json.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index ddc694f..107dc38 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3646,42 +3646,50 @@ static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)
}
struct json_cmd_assoc {
- struct json_cmd_assoc *next;
+ struct hlist_node hnode;
const struct cmd *cmd;
json_t *json;
};
-static struct json_cmd_assoc *json_cmd_list = NULL;
+#define CMD_ASSOC_HSIZE 512
+static struct hlist_head json_cmd_assoc_hash[CMD_ASSOC_HSIZE];
static void json_cmd_assoc_free(void)
{
struct json_cmd_assoc *cur;
+ struct hlist_node *pos, *n;
+ int i;
- while (json_cmd_list) {
- cur = json_cmd_list;
- json_cmd_list = cur->next;
- free(cur);
+ for (i = 0; i < CMD_ASSOC_HSIZE; i++) {
+ hlist_for_each_entry_safe(cur, pos, n,
+ &json_cmd_assoc_hash[i], hnode)
+ free(cur);
}
}
static void json_cmd_assoc_add(json_t *json, const struct cmd *cmd)
{
struct json_cmd_assoc *new = xzalloc(sizeof *new);
+ int key = cmd->seqnum % CMD_ASSOC_HSIZE;
- new->next = json_cmd_list;
new->json = json;
new->cmd = cmd;
- json_cmd_list = new;
+
+ hlist_add_head(&new->hnode, &json_cmd_assoc_hash[key]);
}
static json_t *seqnum_to_json(const uint32_t seqnum)
{
- const struct json_cmd_assoc *cur;
+ int key = seqnum % CMD_ASSOC_HSIZE;
+ struct json_cmd_assoc *cur;
+ struct hlist_node *n;
- for (cur = json_cmd_list; cur; cur = cur->next) {
+
+ hlist_for_each_entry(cur, n, &json_cmd_assoc_hash[key], hnode) {
if (cur->cmd->seqnum == seqnum)
return cur->json;
}
+
return NULL;
}
--
2.31.1

View File

@ -1,116 +0,0 @@
From 0dcfa1b0211fa50201d51d0f52869a8e2d93ba76 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 7 Dec 2020 18:29:15 +0100
Subject: [PATCH] json: Fix seqnum_to_json() functionality
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1900565
Upstream Status: nftables commit 299ec575faa6b
commit 299ec575faa6b070940b483dc517ecd883b9f1a4
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Dec 2 23:07:11 2020 +0100
json: Fix seqnum_to_json() functionality
Introduction of json_cmd_assoc_hash missed that by the time the hash
table insert happens, the struct cmd object's 'seqnum' field which is
used as key is not initialized yet. This doesn't happen until
nft_netlink() prepares the batch object which records the lowest seqnum.
Therefore push all json_cmd_assoc objects into a temporary list until
the first lookup happens. At this time, all referenced cmd objects have
their seqnum set and the list entries can be moved into the hash table
for fast lookups.
To expose such problems in the future, make json_events_cb() emit an
error message if the passed message has a handle but no assoc entry is
found for its seqnum.
Fixes: 389a0e1edc89a ("json: echo: Speedup seqnum_to_json()")
Cc: Derek Dai <daiderek@gmail.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/parser_json.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index 107dc38..785f0e7 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3646,6 +3646,7 @@ static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)
}
struct json_cmd_assoc {
+ struct json_cmd_assoc *next;
struct hlist_node hnode;
const struct cmd *cmd;
json_t *json;
@@ -3653,6 +3654,7 @@ struct json_cmd_assoc {
#define CMD_ASSOC_HSIZE 512
static struct hlist_head json_cmd_assoc_hash[CMD_ASSOC_HSIZE];
+static struct json_cmd_assoc *json_cmd_assoc_list;
static void json_cmd_assoc_free(void)
{
@@ -3660,6 +3662,12 @@ static void json_cmd_assoc_free(void)
struct hlist_node *pos, *n;
int i;
+ while (json_cmd_assoc_list) {
+ cur = json_cmd_assoc_list->next;
+ free(json_cmd_assoc_list);
+ json_cmd_assoc_list = cur;
+ }
+
for (i = 0; i < CMD_ASSOC_HSIZE; i++) {
hlist_for_each_entry_safe(cur, pos, n,
&json_cmd_assoc_hash[i], hnode)
@@ -3670,21 +3678,29 @@ static void json_cmd_assoc_free(void)
static void json_cmd_assoc_add(json_t *json, const struct cmd *cmd)
{
struct json_cmd_assoc *new = xzalloc(sizeof *new);
- int key = cmd->seqnum % CMD_ASSOC_HSIZE;
new->json = json;
new->cmd = cmd;
+ new->next = json_cmd_assoc_list;
- hlist_add_head(&new->hnode, &json_cmd_assoc_hash[key]);
+ json_cmd_assoc_list = new;
}
static json_t *seqnum_to_json(const uint32_t seqnum)
{
- int key = seqnum % CMD_ASSOC_HSIZE;
struct json_cmd_assoc *cur;
struct hlist_node *n;
+ int key;
+ while (json_cmd_assoc_list) {
+ cur = json_cmd_assoc_list;
+ json_cmd_assoc_list = cur->next;
+ key = cur->cmd->seqnum % CMD_ASSOC_HSIZE;
+ hlist_add_head(&cur->hnode, &json_cmd_assoc_hash[key]);
+ }
+
+ key = seqnum % CMD_ASSOC_HSIZE;
hlist_for_each_entry(cur, n, &json_cmd_assoc_hash[key], hnode) {
if (cur->cmd->seqnum == seqnum)
return cur->json;
@@ -3865,8 +3881,11 @@ int json_events_cb(const struct nlmsghdr *nlh, struct netlink_mon_handler *monh)
return MNL_CB_OK;
json = seqnum_to_json(nlh->nlmsg_seq);
- if (!json)
+ if (!json) {
+ json_echo_error(monh, "No JSON command found with seqnum %lu\n",
+ nlh->nlmsg_seq);
return MNL_CB_OK;
+ }
tmp = json_object_get(json, "add");
if (!tmp)
--
2.31.1

View File

@ -1,47 +0,0 @@
From b7964157c40066f09411ac52547acb07d1966aee Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 12 Jan 2021 15:49:43 +0100
Subject: [PATCH] json: don't leave dangling pointers on hlist
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1900565
Upstream Status: nftables commit 48917d876d51c
commit 48917d876d51cd6ba5bff07172acef05c9e12474
Author: Florian Westphal <fw@strlen.de>
Date: Mon Dec 14 16:53:29 2020 +0100
json: don't leave dangling pointers on hlist
unshare -n tests/json_echo/run-test.py
[..]
Adding chain c
free(): double free detected in tcache 2
Aborted (core dumped)
The element must be deleted from the hlist prior to freeing it.
Fixes: 389a0e1edc89a ("json: echo: Speedup seqnum_to_json()")
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/parser_json.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index 785f0e7..986f128 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3670,8 +3670,10 @@ static void json_cmd_assoc_free(void)
for (i = 0; i < CMD_ASSOC_HSIZE; i++) {
hlist_for_each_entry_safe(cur, pos, n,
- &json_cmd_assoc_hash[i], hnode)
+ &json_cmd_assoc_hash[i], hnode) {
+ hlist_del(&cur->hnode);
free(cur);
+ }
}
}
--
2.31.1

View File

@ -1,46 +0,0 @@
From 2b4da3af37ac10d96650da1b8642f82a3aa92e30 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Sat, 20 Feb 2021 09:52:59 +0100
Subject: [PATCH] json: init parser state for every new buffer/file
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1930873
Upstream Status: nftables commit 267338ec39234
commit 267338ec392346ef55ed51509e5f8e8354d6c19a
Author: Eric Garver <eric@garver.life>
Date: Fri Feb 19 10:11:26 2021 -0500
json: init parser state for every new buffer/file
Otherwise invalid error states cause subsequent json parsing to fail
when it should not.
Signed-off-by: Eric Garver <eric@garver.life>
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/parser_json.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/parser_json.c b/src/parser_json.c
index 986f128..662bb4b 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -3777,6 +3777,7 @@ int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
};
int ret;
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->json_root = json_loads(buf, 0, NULL);
if (!nft->json_root)
return -EINVAL;
@@ -3805,6 +3806,7 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
json_error_t err;
int ret;
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->json_root = json_load_file(filename, 0, &err);
if (!nft->json_root)
return -EINVAL;
--
2.31.1

View File

@ -1,465 +0,0 @@
From f9dca1704ce66be31eceac4d7317b825269b3d07 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 2 Mar 2021 17:06:06 +0100
Subject: [PATCH] tests: Disable tests known to fail on RHEL8
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919203
Upstream Status: RHEL-only
RHEL8 kernel does not support:
- ct timeout or expectation objects
- synproxy
- flowtables in families other than inet
- meta time
- bridge family-specific meta expressions (e.g. ibrvproto, ibrpvid)
- socket mark
- osf
- delete set elements from packet path
- update stateful objects
- explicitly setting set element expiration (commit 79ebb5bb4e3)
- flushing chains and deleting referenced objects in the same
transaction (upstream commits with 'bogus EBUSY' in subject)
Disable all related tests to make the testsuites pass.
---
tests/monitor/testcases/object.t | 14 +++---
tests/py/any/meta.t | 36 +++++++--------
tests/py/bridge/meta.t | 8 ++--
tests/py/inet/osf.t | 24 +++++-----
tests/py/inet/socket.t | 2 +-
tests/py/inet/synproxy.t | 12 ++---
tests/py/ip/objects.t | 46 +++++++++----------
tests/py/ip6/sets.t | 2 +-
.../flowtable/0002create_flowtable_0 | 8 ++--
.../testcases/flowtable/0003add_after_flush_0 | 8 ++--
.../flowtable/0004delete_after_add_0 | 6 +--
.../testcases/flowtable/0005delete_in_use_1 | 10 ++--
tests/shell/testcases/flowtable/0007prio_0 | 6 +--
tests/shell/testcases/flowtable/0008prio_1 | 4 +-
.../flowtable/0009deleteafterflush_0 | 12 ++---
tests/shell/testcases/listing/0013objects_0 | 2 +
.../testcases/nft-f/0017ct_timeout_obj_0 | 2 +
.../testcases/nft-f/0018ct_expectation_obj_0 | 2 +
....nft => 0017ct_timeout_obj_0.nft.disabled} | 0
.../optionals/update_object_handles_0 | 2 +
.../sets/0036add_set_element_expiration_0 | 2 +
tests/shell/testcases/transactions/0046set_0 | 2 +
22 files changed, 111 insertions(+), 99 deletions(-)
rename tests/shell/testcases/nft-f/dumps/{0017ct_timeout_obj_0.nft => 0017ct_timeout_obj_0.nft.disabled} (100%)
diff --git a/tests/monitor/testcases/object.t b/tests/monitor/testcases/object.t
index 2afe33c..1b30384 100644
--- a/tests/monitor/testcases/object.t
+++ b/tests/monitor/testcases/object.t
@@ -37,10 +37,10 @@ I delete ct helper ip t cth
O -
J {"delete": {"ct helper": {"family": "ip", "name": "cth", "table": "t", "handle": 0, "type": "sip", "protocol": "tcp", "l3proto": "ip"}}}
-I add ct timeout ip t ctt { protocol udp; l3proto ip; policy = { unreplied : 15, replied : 12 }; }
-O -
-J {"add": {"ct timeout": {"family": "ip", "name": "ctt", "table": "t", "handle": 0, "protocol": "udp", "l3proto": "ip", "policy": {"unreplied": 15, "replied": 12}}}}
-
-I delete ct timeout ip t ctt
-O -
-J {"delete": {"ct timeout": {"family": "ip", "name": "ctt", "table": "t", "handle": 0, "protocol": "udp", "l3proto": "ip", "policy": {"unreplied": 15, "replied": 12}}}}
+# I add ct timeout ip t ctt { protocol udp; l3proto ip; policy = { unreplied : 15, replied : 12 }; }
+# O -
+# J {"add": {"ct timeout": {"family": "ip", "name": "ctt", "table": "t", "handle": 0, "protocol": "udp", "l3proto": "ip", "policy": {"unreplied": 15, "replied": 12}}}}
+#
+# I delete ct timeout ip t ctt
+# O -
+# J {"delete": {"ct timeout": {"family": "ip", "name": "ctt", "table": "t", "handle": 0, "protocol": "udp", "l3proto": "ip", "policy": {"unreplied": 15, "replied": 12}}}}
diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t
index 327f973..241b466 100644
--- a/tests/py/any/meta.t
+++ b/tests/py/any/meta.t
@@ -204,21 +204,21 @@ meta iif . meta oif vmap { "lo" . "lo" : drop };ok;iif . oif vmap { "lo" . "lo"
meta random eq 1;ok;meta random 1
meta random gt 1000000;ok;meta random > 1000000
-meta time "1970-05-23 21:07:14" drop;ok
-meta time 12341234 drop;ok;meta time "1970-05-23 22:07:14" drop
-meta time "2019-06-21 17:00:00" drop;ok
-meta time "2019-07-01 00:00:00" drop;ok
-meta time "2019-07-01 00:01:00" drop;ok
-meta time "2019-07-01 00:00:01" drop;ok
-meta day "Saturday" drop;ok
-meta day 6 drop;ok;meta day "Saturday" drop
-meta day "Satturday" drop;fail
-meta hour "17:00" drop;ok
-meta hour "17:00:00" drop;ok;meta hour "17:00" drop
-meta hour "17:00:01" drop;ok
-meta hour "00:00" drop;ok
-meta hour "00:01" drop;ok
-
-meta time "meh";fail
-meta hour "24:00" drop;fail
-meta day 7 drop;fail
+- meta time "1970-05-23 21:07:14" drop;ok
+- meta time 12341234 drop;ok;meta time "1970-05-23 22:07:14" drop
+- meta time "2019-06-21 17:00:00" drop;ok
+- meta time "2019-07-01 00:00:00" drop;ok
+- meta time "2019-07-01 00:01:00" drop;ok
+- meta time "2019-07-01 00:00:01" drop;ok
+- meta day "Saturday" drop;ok
+- meta day 6 drop;ok;meta day "Saturday" drop
+- meta day "Satturday" drop;fail
+- meta hour "17:00" drop;ok
+- meta hour "17:00:00" drop;ok;meta hour "17:00" drop
+- meta hour "17:00:01" drop;ok
+- meta hour "00:00" drop;ok
+- meta hour "00:01" drop;ok
+
+- meta time "meh";fail
+- meta hour "24:00" drop;fail
+- meta day 7 drop;fail
diff --git a/tests/py/bridge/meta.t b/tests/py/bridge/meta.t
index 94525f2..9f55cde 100644
--- a/tests/py/bridge/meta.t
+++ b/tests/py/bridge/meta.t
@@ -2,7 +2,7 @@
*bridge;test-bridge;input
-meta obrname "br0";ok
-meta ibrname "br0";ok
-meta ibrvproto vlan;ok
-meta ibrpvid 100;ok
+- meta obrname "br0";ok
+- meta ibrname "br0";ok
+- meta ibrvproto vlan;ok
+- meta ibrpvid 100;ok
diff --git a/tests/py/inet/osf.t b/tests/py/inet/osf.t
index c828541..5191e72 100644
--- a/tests/py/inet/osf.t
+++ b/tests/py/inet/osf.t
@@ -4,15 +4,15 @@
*ip6;osfip6;osfchain
*inet;osfinet;osfchain
-osf name "Linux";ok
-osf ttl loose name "Linux";ok
-osf ttl skip name "Linux";ok
-osf ttl skip version "Linux:3.0";ok
-osf ttl skip version "morethan:sixteenbytes";fail
-osf ttl nottl name "Linux";fail
-osf name "morethansixteenbytes";fail
-osf name ;fail
-osf name { "Windows", "MacOs" };ok
-osf version { "Windows:XP", "MacOs:Sierra" };ok
-ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 };ok
-ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 };ok
+- osf name "Linux";ok
+- osf ttl loose name "Linux";ok
+- osf ttl skip name "Linux";ok
+- osf ttl skip version "Linux:3.0";ok
+- osf ttl skip version "morethan:sixteenbytes";fail
+- osf ttl nottl name "Linux";fail
+- osf name "morethansixteenbytes";fail
+- osf name ;fail
+- osf name { "Windows", "MacOs" };ok
+- osf version { "Windows:XP", "MacOs:Sierra" };ok
+- ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 };ok
+- ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 };ok
diff --git a/tests/py/inet/socket.t b/tests/py/inet/socket.t
index 91846e8..dbc0554 100644
--- a/tests/py/inet/socket.t
+++ b/tests/py/inet/socket.t
@@ -8,4 +8,4 @@ socket transparent 0;ok
socket transparent 1;ok
socket transparent 2;fail
-socket mark 0x00000005;ok
+- socket mark 0x00000005;ok
diff --git a/tests/py/inet/synproxy.t b/tests/py/inet/synproxy.t
index 55a05e1..9c58239 100644
--- a/tests/py/inet/synproxy.t
+++ b/tests/py/inet/synproxy.t
@@ -4,10 +4,10 @@
*ip6;synproxyip6;synproxychain
*inet;synproxyinet;synproxychain
-synproxy;ok
-synproxy mss 1460 wscale 7;ok
-synproxy mss 1460 wscale 5 timestamp sack-perm;ok
-synproxy timestamp sack-perm;ok
-synproxy timestamp;ok
-synproxy sack-perm;ok
+-synproxy;ok
+-synproxy mss 1460 wscale 7;ok
+-synproxy mss 1460 wscale 5 timestamp sack-perm;ok
+-synproxy timestamp sack-perm;ok
+-synproxy timestamp;ok
+-synproxy sack-perm;ok
diff --git a/tests/py/ip/objects.t b/tests/py/ip/objects.t
index 4fcde7c..06e94f1 100644
--- a/tests/py/ip/objects.t
+++ b/tests/py/ip/objects.t
@@ -33,26 +33,26 @@ ip saddr 192.168.1.3 limit name "lim1";ok
ip saddr 192.168.1.3 limit name "lim3";fail
limit name tcp dport map {443 : "lim1", 80 : "lim2", 22 : "lim1"};ok
-# ct timeout
-%cttime1 type ct timeout { protocol tcp; policy = { established:122 } ;};ok
-%cttime2 type ct timeout { protocol udp; policy = { syn_sent:122 } ;};fail
-%cttime3 type ct timeout { protocol tcp; policy = { established:132, close:16, close_wait:16 } ; l3proto ip ;};ok
-%cttime4 type ct timeout { protocol udp; policy = { replied:14, unreplied:19 } ;};ok
-%cttime5 type ct timeout {protocol tcp; policy = { estalbished:100 } ;};fail
-
-ct timeout set "cttime1";ok
-
-# ct expectation
-%ctexpect1 type ct expectation { protocol tcp; dport 1234; timeout 2m; size 12; };ok
-%ctexpect2 type ct expectation { protocol udp; };fail
-%ctexpect3 type ct expectation { protocol tcp; dport 4321; };fail
-%ctexpect4 type ct expectation { protocol tcp; dport 4321; timeout 2m; };fail
-%ctexpect5 type ct expectation { protocol udp; dport 9876; timeout 2m; size 12; l3proto ip; };ok
-
-ct expectation set "ctexpect1";ok
-
-# synproxy
-%synproxy1 type synproxy mss 1460 wscale 7;ok
-%synproxy2 type synproxy mss 1460 wscale 7 timestamp sack-perm;ok
-
-synproxy name tcp dport map {443 : "synproxy1", 80 : "synproxy2"};ok
+# # ct timeout
+# %cttime1 type ct timeout { protocol tcp; policy = { established:122 } ;};ok
+# %cttime2 type ct timeout { protocol udp; policy = { syn_sent:122 } ;};fail
+# %cttime3 type ct timeout { protocol tcp; policy = { established:132, close:16, close_wait:16 } ; l3proto ip ;};ok
+# %cttime4 type ct timeout { protocol udp; policy = { replied:14, unreplied:19 } ;};ok
+# %cttime5 type ct timeout {protocol tcp; policy = { estalbished:100 } ;};fail
+#
+# ct timeout set "cttime1";ok
+
+# # ct expectation
+# %ctexpect1 type ct expectation { protocol tcp; dport 1234; timeout 2m; size 12; };ok
+# %ctexpect2 type ct expectation { protocol udp; };fail
+# %ctexpect3 type ct expectation { protocol tcp; dport 4321; };fail
+# %ctexpect4 type ct expectation { protocol tcp; dport 4321; timeout 2m; };fail
+# %ctexpect5 type ct expectation { protocol udp; dport 9876; timeout 2m; size 12; l3proto ip; };ok
+#
+# ct expectation set "ctexpect1";ok
+
+# # synproxy
+# %synproxy1 type synproxy mss 1460 wscale 7;ok
+# %synproxy2 type synproxy mss 1460 wscale 7 timestamp sack-perm;ok
+#
+# synproxy name tcp dport map {443 : "synproxy1", 80 : "synproxy2"};ok
diff --git a/tests/py/ip6/sets.t b/tests/py/ip6/sets.t
index add82eb..cc43aca 100644
--- a/tests/py/ip6/sets.t
+++ b/tests/py/ip6/sets.t
@@ -40,4 +40,4 @@ ip6 saddr != @set33 drop;fail
!set5 type ipv6_addr . ipv6_addr;ok
ip6 saddr . ip6 daddr @set5 drop;ok
add @set5 { ip6 saddr . ip6 daddr };ok
-delete @set5 { ip6 saddr . ip6 daddr };ok
+- delete @set5 { ip6 saddr . ip6 daddr };ok
diff --git a/tests/shell/testcases/flowtable/0002create_flowtable_0 b/tests/shell/testcases/flowtable/0002create_flowtable_0
index 4c85c3f..8b80e34 100755
--- a/tests/shell/testcases/flowtable/0002create_flowtable_0
+++ b/tests/shell/testcases/flowtable/0002create_flowtable_0
@@ -1,12 +1,12 @@
#!/bin/bash
set -e
-$NFT add table t
-$NFT add flowtable t f { hook ingress priority 10 \; devices = { lo }\; }
-if $NFT create flowtable t f { hook ingress priority 10 \; devices = { lo }\; } 2>/dev/null ; then
+$NFT add table inet t
+$NFT add flowtable inet t f { hook ingress priority 10 \; devices = { lo }\; }
+if $NFT create flowtable inet t f { hook ingress priority 10 \; devices = { lo }\; } 2>/dev/null ; then
echo "E: flowtable creation not failing on existing set" >&2
exit 1
fi
-$NFT add flowtable t f { hook ingress priority 10 \; devices = { lo }\; }
+$NFT add flowtable inet t f { hook ingress priority 10 \; devices = { lo }\; }
exit 0
diff --git a/tests/shell/testcases/flowtable/0003add_after_flush_0 b/tests/shell/testcases/flowtable/0003add_after_flush_0
index 481c7ed..b4243bc 100755
--- a/tests/shell/testcases/flowtable/0003add_after_flush_0
+++ b/tests/shell/testcases/flowtable/0003add_after_flush_0
@@ -1,8 +1,8 @@
#!/bin/bash
set -e
-$NFT add table x
-$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT add table inet x
+$NFT add flowtable inet x y { hook ingress priority 0\; devices = { lo }\;}
$NFT flush ruleset
-$NFT add table x
-$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT add table inet x
+$NFT add flowtable inet x y { hook ingress priority 0\; devices = { lo }\;}
diff --git a/tests/shell/testcases/flowtable/0004delete_after_add_0 b/tests/shell/testcases/flowtable/0004delete_after_add_0
index 8d9a842..4618595 100755
--- a/tests/shell/testcases/flowtable/0004delete_after_add_0
+++ b/tests/shell/testcases/flowtable/0004delete_after_add_0
@@ -1,6 +1,6 @@
#!/bin/bash
set -e
-$NFT add table x
-$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
-$NFT delete flowtable x y
+$NFT add table inet x
+$NFT add flowtable inet x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT delete flowtable inet x y
diff --git a/tests/shell/testcases/flowtable/0005delete_in_use_1 b/tests/shell/testcases/flowtable/0005delete_in_use_1
index ef52620..eda1fb9 100755
--- a/tests/shell/testcases/flowtable/0005delete_in_use_1
+++ b/tests/shell/testcases/flowtable/0005delete_in_use_1
@@ -1,11 +1,11 @@
#!/bin/bash
set -e
-$NFT add table x
-$NFT add chain x x
-$NFT add flowtable x y { hook ingress priority 0\; devices = { lo }\;}
-$NFT add rule x x flow add @y
+$NFT add table inet x
+$NFT add chain inet x x
+$NFT add flowtable inet x y { hook ingress priority 0\; devices = { lo }\;}
+$NFT add rule inet x x flow add @y
-$NFT delete flowtable x y || exit 0
+$NFT delete flowtable inet x y || exit 0
echo "E: delete flowtable in use"
exit 1
diff --git a/tests/shell/testcases/flowtable/0007prio_0 b/tests/shell/testcases/flowtable/0007prio_0
index 49bbcac..0ea262f 100755
--- a/tests/shell/testcases/flowtable/0007prio_0
+++ b/tests/shell/testcases/flowtable/0007prio_0
@@ -15,10 +15,10 @@ format_offset () {
fi
}
-$NFT add table t
+$NFT add table inet t
for offset in -11 -10 0 10 11
do
- $NFT add flowtable t f "{ hook ingress priority filter `format_offset $offset`; devices = { lo }; }"
- $NFT delete flowtable t f
+ $NFT add flowtable inet t f "{ hook ingress priority filter `format_offset $offset`; devices = { lo }; }"
+ $NFT delete flowtable inet t f
done
diff --git a/tests/shell/testcases/flowtable/0008prio_1 b/tests/shell/testcases/flowtable/0008prio_1
index 48953d7..0d8cdff 100755
--- a/tests/shell/testcases/flowtable/0008prio_1
+++ b/tests/shell/testcases/flowtable/0008prio_1
@@ -1,9 +1,9 @@
#!/bin/bash
-$NFT add table t
+$NFT add table inet t
for prioname in raw mangle dstnar security srcnat out dummy
do
- $NFT add flowtable t f { hook ingress priority $prioname \; devices = { lo }\; }
+ $NFT add flowtable inet t f { hook ingress priority $prioname \; devices = { lo }\; }
if (($? == 0))
then
echo "E: $prioname should not be a valid priority name for flowtables" >&2
diff --git a/tests/shell/testcases/flowtable/0009deleteafterflush_0 b/tests/shell/testcases/flowtable/0009deleteafterflush_0
index 2cda563..061e22e 100755
--- a/tests/shell/testcases/flowtable/0009deleteafterflush_0
+++ b/tests/shell/testcases/flowtable/0009deleteafterflush_0
@@ -1,9 +1,9 @@
#!/bin/bash
set -e
-$NFT add table x
-$NFT add chain x y
-$NFT add flowtable x f { hook ingress priority 0\; devices = { lo }\;}
-$NFT add rule x y flow add @f
-$NFT flush chain x y
-$NFT delete flowtable x f
+$NFT add table inet x
+$NFT add chain inet x y
+$NFT add flowtable inet x f { hook ingress priority 0\; devices = { lo }\;}
+$NFT add rule inet x y flow add @f
+$NFT flush chain inet x y
+$NFT delete flowtable inet x f
diff --git a/tests/shell/testcases/listing/0013objects_0 b/tests/shell/testcases/listing/0013objects_0
index 4d39143..130d02c 100755
--- a/tests/shell/testcases/listing/0013objects_0
+++ b/tests/shell/testcases/listing/0013objects_0
@@ -1,5 +1,7 @@
#!/bin/bash
+exit 0
+
# list table with all objects and chains
EXPECTED="table ip test {
diff --git a/tests/shell/testcases/nft-f/0017ct_timeout_obj_0 b/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
index 4f40779..e0f9e44 100755
--- a/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
+++ b/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
@@ -1,5 +1,7 @@
#!/bin/bash
+exit 0
+
EXPECTED='table ip filter {
ct timeout cttime{
protocol tcp
diff --git a/tests/shell/testcases/nft-f/0018ct_expectation_obj_0 b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
index 4f9872f..f518cf7 100755
--- a/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
+++ b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
@@ -1,5 +1,7 @@
#!/bin/bash
+exit 0
+
EXPECTED='table ip filter {
ct expectation ctexpect{
protocol tcp
diff --git a/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft.disabled
similarity index 100%
rename from tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft
rename to tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft.disabled
diff --git a/tests/shell/testcases/optionals/update_object_handles_0 b/tests/shell/testcases/optionals/update_object_handles_0
index 8b12b8c..e11b4e7 100755
--- a/tests/shell/testcases/optionals/update_object_handles_0
+++ b/tests/shell/testcases/optionals/update_object_handles_0
@@ -1,5 +1,7 @@
#!/bin/bash
+exit 0
+
set -e
$NFT add table test-ip
$NFT add counter test-ip traffic-counter
diff --git a/tests/shell/testcases/sets/0036add_set_element_expiration_0 b/tests/shell/testcases/sets/0036add_set_element_expiration_0
index 51ed0f2..043bb8f 100755
--- a/tests/shell/testcases/sets/0036add_set_element_expiration_0
+++ b/tests/shell/testcases/sets/0036add_set_element_expiration_0
@@ -1,5 +1,7 @@
#!/bin/bash
+exit 0
+
set -e
RULESET="add table ip x
diff --git a/tests/shell/testcases/transactions/0046set_0 b/tests/shell/testcases/transactions/0046set_0
index 172e24d..1b24964 100755
--- a/tests/shell/testcases/transactions/0046set_0
+++ b/tests/shell/testcases/transactions/0046set_0
@@ -1,5 +1,7 @@
#!/bin/bash
+exit 0
+
RULESET='add table ip filter
add chain ip filter group_7933
add map ip filter group_7933 { type ipv4_addr : classid; flags interval; }
--
2.31.1

View File

@ -1,41 +0,0 @@
From 1490609a3d82e494168a390b34094bacc5e83c02 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 18 May 2021 18:06:50 +0200
Subject: [PATCH] monitor: Fix for use after free when printing map elements
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919203
Upstream Status: nftables commit 02174ffad484d
commit 02174ffad484d9711678e5d415c32307efc39857
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Jan 9 17:43:11 2020 +0100
monitor: Fix for use after free when printing map elements
When populating the dummy set, 'data' field must be cloned just like
'key' field.
Fixes: 343a51702656a ("src: store expr, not dtype to track data in sets")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
src/monitor.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/monitor.c b/src/monitor.c
index 7927b6f..142cc92 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -401,7 +401,8 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
*/
dummyset = set_alloc(monh->loc);
dummyset->key = expr_clone(set->key);
- dummyset->data = set->data;
+ if (set->data)
+ dummyset->data = expr_clone(set->data);
dummyset->flags = set->flags;
dummyset->init = set_expr_alloc(monh->loc, set);
--
2.31.1

View File

@ -1,44 +0,0 @@
From 4ee4ed8d54a8b9f0f0a2b195b3b95b892e4e79a3 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 18 May 2021 18:06:50 +0200
Subject: [PATCH] tests: monitor: use correct $nft value in EXIT trap
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919203
Upstream Status: nftables commit 990cbbf75c40b
commit 990cbbf75c40b92e6d6dc66721dfbedf33cacf8f
Author: Štěpán Němec <snemec@redhat.com>
Date: Wed Jan 27 15:02:03 2021 +0100
tests: monitor: use correct $nft value in EXIT trap
With double quotes, $nft was being expanded to the default value even
in presence of the -H option.
Signed-off-by: Štěpán Němec <snemec@redhat.com>
Helped-by: Tomáš Doležal <todoleza@redhat.com>
Acked-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
tests/monitor/run-tests.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
index ffb833a..c1cacb4 100755
--- a/tests/monitor/run-tests.sh
+++ b/tests/monitor/run-tests.sh
@@ -19,7 +19,7 @@ if [ ! -d $testdir ]; then
echo "Failed to create test directory" >&2
exit 1
fi
-trap "rm -rf $testdir; $nft flush ruleset" EXIT
+trap 'rm -rf $testdir; $nft flush ruleset' EXIT
command_file=$(mktemp -p $testdir)
output_file=$(mktemp -p $testdir)
--
2.31.1

View File

@ -1,57 +0,0 @@
From 805fe6f5c9c8f2af78d8e94bd6b5c33724df3c80 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 18 May 2021 18:16:21 +0200
Subject: [PATCH] evaluate: Reject quoted strings containing only wildcard
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1818117
Upstream Status: nftables commit 032c9f745c6da
commit 032c9f745c6daab8c27176a95963b1c32b0a5d12
Author: Phil Sutter <phil@nwl.cc>
Date: Thu Sep 24 17:38:45 2020 +0200
evaluate: Reject quoted strings containing only wildcard
Fix for an assertion fail when trying to match against an all-wildcard
interface name:
| % nft add rule t c iifname '"*"'
| nft: expression.c:402: constant_expr_alloc: Assertion `(((len) + (8) - 1) / (8)) > 0' failed.
| zsh: abort nft add rule t c iifname '"*"'
Fix this by detecting the string in expr_evaluate_string() and returning
an error message:
| % nft add rule t c iifname '"*"'
| Error: All-wildcard strings are not supported
| add rule t c iifname "*"
| ^^^
While being at it, drop the 'datalen >= 1' clause from the following
conditional as together with the added check for 'datalen == 0', all
possible other values have been caught already.
---
src/evaluate.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index a966ed4..0181750 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -321,8 +321,11 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
return 0;
}
- if (datalen >= 1 &&
- data[datalen - 1] == '\\') {
+ if (datalen == 0)
+ return expr_error(ctx->msgs, expr,
+ "All-wildcard strings are not supported");
+
+ if (data[datalen - 1] == '\\') {
char unescaped_str[data_len];
memset(unescaped_str, 0, sizeof(unescaped_str));
--
2.31.1

View File

@ -1,64 +0,0 @@
From 64f34f34acedad6cce70f2dd91c82a814d4ffe34 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 19 May 2021 18:03:43 +0200
Subject: [PATCH] src: Support odd-sized payload matches
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1934926
Upstream Status: nftables commit 8a927c56d83ed
commit 8a927c56d83ed0f78785011bd92a53edc25a0ca0
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Oct 27 17:05:25 2020 +0100
src: Support odd-sized payload matches
When expanding a payload match, don't disregard oversized templates at
the right offset. A more flexible user may extract less bytes from the
packet if only parts of a field are interesting, e.g. only the prefix of
source/destination address. Support that by using the template, but fix
the length. Later when creating a relational expression for it, detect
the unusually small payload expression length and turn the RHS value
into a prefix expression.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/netlink_delinearize.c | 6 ++++++
src/payload.c | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 88dbd5a..8bdee12 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -1577,6 +1577,12 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
tmp = constant_expr_splice(right, left->len);
expr_set_type(tmp, left->dtype, left->byteorder);
+ if (left->payload.tmpl && (left->len < left->payload.tmpl->len)) {
+ mpz_lshift_ui(tmp->value, left->payload.tmpl->len - left->len);
+ tmp->len = left->payload.tmpl->len;
+ tmp = prefix_expr_alloc(&tmp->location, tmp, left->len);
+ }
+
nexpr = relational_expr_alloc(&expr->location, expr->op,
left, tmp);
if (expr->op == OP_EQ)
diff --git a/src/payload.c b/src/payload.c
index 3576400..45280ef 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -746,6 +746,11 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
expr->payload.offset += tmpl->len;
if (expr->len == 0)
return;
+ } else if (expr->len > 0) {
+ new = payload_expr_alloc(&expr->location, desc, i);
+ new->len = expr->len;
+ list_add_tail(&new->list, list);
+ return;
} else
break;
}
--
2.31.1

View File

@ -1,241 +0,0 @@
From 6fb6d8f15a82b3348184f6950a436becb06931cb Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 19 May 2021 18:03:43 +0200
Subject: [PATCH] src: Optimize prefix matches on byte-boundaries
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1934926
Upstream Status: nftables commit 25338cdb6c77a
Conflicts: There is a hidden dependency on commit ee4391d0ac1e7 ("nat:
transform range to prefix expression when possible").
Backport only the single chunk required to keep prefix
parsing intact to avoid having to backport 9599d9d25a6b3
("src: NAT support for intervals in maps") as a dependency
which is clearly oversized for the sake of this purpose.
commit 25338cdb6c77aa2f0977afbbb612571c9d325213
Author: Phil Sutter <phil@nwl.cc>
Date: Tue Oct 27 17:33:15 2020 +0100
src: Optimize prefix matches on byte-boundaries
If a prefix expression's length is on a byte-boundary, it is sufficient
to just reduce the length passed to "cmp" expression. No need for
explicit bitwise modification of data on LHS. The relevant code is
already there, used for string prefix matches. There is one exception
though, namely zero-length prefixes: Kernel doesn't accept zero-length
"cmp" expressions, so keep them in the old code-path for now.
This patch depends upon the previous one to correctly parse odd-sized
payload matches but has to extend support for non-payload LHS as well.
In practice, this is needed for "ct" expressions as they allow matching
against IP address prefixes, too.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/netlink_delinearize.c | 8 ++++++--
src/netlink_linearize.c | 4 +++-
tests/py/ip/ct.t.payload | 4 ----
tests/py/ip/ip.t.payload | 6 ++----
tests/py/ip/ip.t.payload.bridge | 6 ++----
tests/py/ip/ip.t.payload.inet | 6 ++----
tests/py/ip/ip.t.payload.netdev | 6 ++----
tests/py/ip6/ip6.t.payload.inet | 5 ++---
tests/py/ip6/ip6.t.payload.ip6 | 5 ++---
9 files changed, 21 insertions(+), 29 deletions(-)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 8bdee12..157a473 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -291,8 +291,9 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
if (left->len > right->len &&
expr_basetype(left) != &string_type) {
- netlink_error(ctx, loc, "Relational expression size mismatch");
- goto err_free;
+ mpz_lshift_ui(right->value, left->len - right->len);
+ right = prefix_expr_alloc(loc, right, right->len);
+ right->prefix->len = left->len;
} else if (left->len > 0 && left->len < right->len) {
expr_free(left);
left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
@@ -2164,6 +2165,9 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_postprocess(ctx, &expr->left);
expr_postprocess(ctx, &expr->right);
break;
+ case EXPR_PREFIX:
+ expr_postprocess(ctx, &expr->prefix);
+ break;
case EXPR_SET_ELEM:
expr_postprocess(ctx, &expr->key);
break;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 606d97a..25be634 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -501,7 +501,9 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
return netlink_gen_flagcmp(ctx, expr, dreg);
case EXPR_PREFIX:
sreg = get_register(ctx, expr->left);
- if (expr_basetype(expr->left)->type != TYPE_STRING) {
+ if (expr_basetype(expr->left)->type != TYPE_STRING &&
+ (!expr->right->prefix_len ||
+ expr->right->prefix_len % BITS_PER_BYTE)) {
len = div_round_up(expr->right->len, BITS_PER_BYTE);
netlink_gen_expr(ctx, expr->left, sreg);
right = netlink_gen_prefix(ctx, expr, sreg);
diff --git a/tests/py/ip/ct.t.payload b/tests/py/ip/ct.t.payload
index d5faed4..a7e08f9 100644
--- a/tests/py/ip/ct.t.payload
+++ b/tests/py/ip/ct.t.payload
@@ -21,25 +21,21 @@ ip test-ip4 output
# ct original ip saddr 192.168.1.0/24
ip test-ip4 output
[ ct load src_ip => reg 1 , dir original ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct reply ip saddr 192.168.1.0/24
ip test-ip4 output
[ ct load src_ip => reg 1 , dir reply ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct original ip daddr 192.168.1.0/24
ip test-ip4 output
[ ct load dst_ip => reg 1 , dir original ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct reply ip daddr 192.168.1.0/24
ip test-ip4 output
[ ct load dst_ip => reg 1 , dir reply ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct l3proto ipv4
diff --git a/tests/py/ip/ip.t.payload b/tests/py/ip/ip.t.payload
index d627b22..825c0f0 100644
--- a/tests/py/ip/ip.t.payload
+++ b/tests/py/ip/ip.t.payload
@@ -358,14 +358,12 @@ ip test-ip4 input
# ip saddr 192.168.2.0/24
ip test-ip4 input
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
ip test-ip4 input
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
diff --git a/tests/py/ip/ip.t.payload.bridge b/tests/py/ip/ip.t.payload.bridge
index 91a4fde..e958a5b 100644
--- a/tests/py/ip/ip.t.payload.bridge
+++ b/tests/py/ip/ip.t.payload.bridge
@@ -466,16 +466,14 @@ bridge test-bridge input
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
diff --git a/tests/py/ip/ip.t.payload.inet b/tests/py/ip/ip.t.payload.inet
index b9cb28a..6501473 100644
--- a/tests/py/ip/ip.t.payload.inet
+++ b/tests/py/ip/ip.t.payload.inet
@@ -466,16 +466,14 @@ inet test-inet input
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
diff --git a/tests/py/ip/ip.t.payload.netdev b/tests/py/ip/ip.t.payload.netdev
index 588e5ca..58ae358 100644
--- a/tests/py/ip/ip.t.payload.netdev
+++ b/tests/py/ip/ip.t.payload.netdev
@@ -379,16 +379,14 @@ netdev test-netdev ingress
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
index d015c8e..ffc9b9f 100644
--- a/tests/py/ip6/ip6.t.payload.inet
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -604,9 +604,8 @@ inet test-inet input
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
- [ payload load 16b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
- [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ payload load 8b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
# ip6 saddr ::1 ip6 daddr ::2
inet test-inet input
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
index b2e8363..18b8bcb 100644
--- a/tests/py/ip6/ip6.t.payload.ip6
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -452,9 +452,8 @@ ip6 test-ip6 input
# ip6 saddr ::/64
ip6 test-ip6 input
- [ payload load 16b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
- [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ payload load 8b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
# ip6 saddr ::1 ip6 daddr ::2
ip6 test-ip6 input
--
2.31.1

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +0,0 @@
From f87960ecc2ed04c803b27bb6a9c42ecd0ba0bc96 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] parser: merge sack-perm/sack-permitted and maxseg/mss
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 2a9aea6f2dfb6
commit 2a9aea6f2dfb6ee61528809af98860e06b38762b
Author: Florian Westphal <fw@strlen.de>
Date: Mon Nov 2 00:27:04 2020 +0100
parser: merge sack-perm/sack-permitted and maxseg/mss
One was added by the tcp option parsing ocde, the other by synproxy.
So we have:
synproxy ... sack-perm
synproxy ... mss
and
tcp option maxseg
tcp option sack-permitted
This kills the extra tokens on the scanner/parser side,
so sack-perm and sack-permitted can both be used.
Likewise, 'synproxy maxseg' and 'tcp option mss size 42' will work too.
On the output side, the shorter form is now preferred, i.e. sack-perm
and mss.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
doc/payload-expression.txt | 8 ++++----
src/parser_bison.y | 12 +++++-------
src/scanner.l | 8 ++++----
src/tcpopt.c | 2 +-
tests/py/any/tcpopt.t | 4 ++--
tests/py/any/tcpopt.t.json | 8 ++++----
tests/py/any/tcpopt.t.payload | 12 ++++++------
7 files changed, 26 insertions(+), 28 deletions(-)
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index dba42fd..3d7057c 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -525,13 +525,13 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC
*dst* {*nexthdr* | *hdrlength*}
*mh* {*nexthdr* | *hdrlength* | *checksum* | *type*}
*srh* {*flags* | *tag* | *sid* | *seg-left*}
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
+*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
*ip option* { lsrr | ra | rr | ssrr } 'ip_option_field'
The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
[verse]
*exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
+*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
*ip option* { lsrr | ra | rr | ssrr }
.IPv6 extension headers
@@ -568,7 +568,7 @@ kind, length, size
|window|
TCP Window Scaling |
kind, length, count
-|sack-permitted|
+|sack-perm |
TCP SACK permitted |
kind, length
|sack|
@@ -611,7 +611,7 @@ type, length, ptr, addr
.finding TCP options
--------------------
-filter input tcp option sack-permitted kind 1 counter
+filter input tcp option sack-perm kind 1 counter
--------------------
.matching IPv6 exthdr
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 4cca31b..56d26e3 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -221,7 +221,6 @@ int nft_lex(void *, void *, void *);
%token SYNPROXY "synproxy"
%token MSS "mss"
%token WSCALE "wscale"
-%token SACKPERM "sack-perm"
%token HOOK "hook"
%token DEVICE "device"
@@ -385,14 +384,13 @@ int nft_lex(void *, void *, void *);
%token OPTION "option"
%token ECHO "echo"
%token EOL "eol"
-%token MAXSEG "maxseg"
%token NOOP "noop"
%token SACK "sack"
%token SACK0 "sack0"
%token SACK1 "sack1"
%token SACK2 "sack2"
%token SACK3 "sack3"
-%token SACK_PERMITTED "sack-permitted"
+%token SACK_PERM "sack-permitted"
%token TIMESTAMP "timestamp"
%token KIND "kind"
%token COUNT "count"
@@ -2889,7 +2887,7 @@ synproxy_arg : MSS NUM
{
$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
}
- | SACKPERM
+ | SACK_PERM
{
$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
}
@@ -2944,7 +2942,7 @@ synproxy_ts : /* empty */ { $$ = 0; }
;
synproxy_sack : /* empty */ { $$ = 0; }
- | SACKPERM
+ | SACK_PERM
{
$$ = NF_SYNPROXY_OPT_SACK_PERM;
}
@@ -4736,9 +4734,9 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; }
| NOOP { $$ = TCPOPTHDR_NOOP; }
- | MAXSEG { $$ = TCPOPTHDR_MAXSEG; }
+ | MSS { $$ = TCPOPTHDR_MAXSEG; }
| WINDOW { $$ = TCPOPTHDR_WINDOW; }
- | SACK_PERMITTED { $$ = TCPOPTHDR_SACK_PERMITTED; }
+ | SACK_PERM { $$ = TCPOPTHDR_SACK_PERMITTED; }
| SACK { $$ = TCPOPTHDR_SACK0; }
| SACK0 { $$ = TCPOPTHDR_SACK0; }
| SACK1 { $$ = TCPOPTHDR_SACK1; }
diff --git a/src/scanner.l b/src/scanner.l
index 7daf5c1..a369802 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -419,14 +419,16 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"echo" { return ECHO; }
"eol" { return EOL; }
-"maxseg" { return MAXSEG; }
+"maxseg" { return MSS; }
+"mss" { return MSS; }
"noop" { return NOOP; }
"sack" { return SACK; }
"sack0" { return SACK0; }
"sack1" { return SACK1; }
"sack2" { return SACK2; }
"sack3" { return SACK3; }
-"sack-permitted" { return SACK_PERMITTED; }
+"sack-permitted" { return SACK_PERM; }
+"sack-perm" { return SACK_PERM; }
"timestamp" { return TIMESTAMP; }
"time" { return TIME; }
@@ -562,9 +564,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"osf" { return OSF; }
"synproxy" { return SYNPROXY; }
-"mss" { return MSS; }
"wscale" { return WSCALE; }
-"sack-perm" { return SACKPERM; }
"notrack" { return NOTRACK; }
diff --git a/src/tcpopt.c b/src/tcpopt.c
index ec305d9..6dbaa9e 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -55,7 +55,7 @@ static const struct exthdr_desc tcpopt_window = {
};
static const struct exthdr_desc tcpopt_sack_permitted = {
- .name = "sack-permitted",
+ .name = "sack-perm",
.type = TCPOPT_SACK_PERMITTED,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index 08b1dcb..5f21d49 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -12,8 +12,8 @@ tcp option maxseg size 1;ok
tcp option window kind 1;ok
tcp option window length 1;ok
tcp option window count 1;ok
-tcp option sack-permitted kind 1;ok
-tcp option sack-permitted length 1;ok
+tcp option sack-perm kind 1;ok
+tcp option sack-perm length 1;ok
tcp option sack kind 1;ok
tcp option sack length 1;ok
tcp option sack left 1;ok
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index 48eb339..2c6236a 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -126,14 +126,14 @@
}
]
-# tcp option sack-permitted kind 1
+# tcp option sack-perm kind 1
[
{
"match": {
"left": {
"tcp option": {
"field": "kind",
- "name": "sack-permitted"
+ "name": "sack-perm"
}
},
"op": "==",
@@ -142,14 +142,14 @@
}
]
-# tcp option sack-permitted length 1
+# tcp option sack-perm length 1
[
{
"match": {
"left": {
"tcp option": {
"field": "length",
- "name": "sack-permitted"
+ "name": "sack-perm"
}
},
"op": "==",
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index 63751cf..f63076a 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -166,42 +166,42 @@ inet
[ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option sack-permitted kind 1
+# tcp option sack-perm kind 1
ip
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option sack-permitted kind 1
+# tcp option sack-perm kind 1
ip6
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option sack-permitted kind 1
+# tcp option sack-perm kind 1
inet
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option sack-permitted length 1
+# tcp option sack-perm length 1
ip
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option sack-permitted length 1
+# tcp option sack-perm length 1
ip6
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option sack-permitted length 1
+# tcp option sack-perm length 1
inet
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
--
2.31.1

View File

@ -1,387 +0,0 @@
From 0aa694acf7c233f9426e48d0644b29ddec4fb16d Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] tcpopts: clean up parser -> tcpopt.c plumbing
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 41158e0388ac5
commit 41158e0388ac56380fc0ee301f0d43f95ec43fab
Author: Florian Westphal <fw@strlen.de>
Date: Mon Nov 2 14:53:26 2020 +0100
tcpopts: clean up parser -> tcpopt.c plumbing
tcpopt template mapping is asymmetric:
one mapping is to match dumped netlink exthdr expression to the original
tcp option template.
This struct is indexed by the raw, on-write kind/type number.
The other mapping maps parsed options to the tcp option template.
Remove the latter. The parser is changed to translate the textual
option name, e.g. "maxseg" to the on-wire number.
This avoids the second mapping, it will also allow to more easily
support raw option matching in a followup patch.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
doc/payload-expression.txt | 4 +-
include/tcpopt.h | 35 ++++++++-------
src/parser_bison.y | 26 +++++------
src/parser_json.c | 10 ++---
src/scanner.l | 3 +-
src/tcpopt.c | 92 +++++++++++++++-----------------------
6 files changed, 75 insertions(+), 95 deletions(-)
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 3d7057c..27145c3 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -525,13 +525,13 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC
*dst* {*nexthdr* | *hdrlength*}
*mh* {*nexthdr* | *hdrlength* | *checksum* | *type*}
*srh* {*flags* | *tag* | *sid* | *seg-left*}
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
*ip option* { lsrr | ra | rr | ssrr } 'ip_option_field'
The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
[verse]
*exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
*ip option* { lsrr | ra | rr | ssrr }
.IPv6 extension headers
diff --git a/include/tcpopt.h b/include/tcpopt.h
index ffdbcb0..7f3fbb8 100644
--- a/include/tcpopt.h
+++ b/include/tcpopt.h
@@ -6,7 +6,7 @@
#include <statement.h>
extern struct expr *tcpopt_expr_alloc(const struct location *loc,
- uint8_t type, uint8_t field);
+ unsigned int kind, unsigned int field);
extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
unsigned int offset, unsigned int len,
@@ -15,21 +15,22 @@ extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
extern bool tcpopt_find_template(struct expr *expr, const struct expr *mask,
unsigned int *shift);
-enum tcpopt_hdr_types {
- TCPOPTHDR_INVALID,
- TCPOPTHDR_EOL,
- TCPOPTHDR_NOOP,
- TCPOPTHDR_MAXSEG,
- TCPOPTHDR_WINDOW,
- TCPOPTHDR_SACK_PERMITTED,
- TCPOPTHDR_SACK0,
- TCPOPTHDR_SACK1,
- TCPOPTHDR_SACK2,
- TCPOPTHDR_SACK3,
- TCPOPTHDR_TIMESTAMP,
- TCPOPTHDR_ECHO,
- TCPOPTHDR_ECHO_REPLY,
- __TCPOPTHDR_MAX
+/* TCP option numbers used on wire */
+enum tcpopt_kind {
+ TCPOPT_KIND_EOL = 0,
+ TCPOPT_KIND_NOP = 1,
+ TCPOPT_KIND_MAXSEG = 2,
+ TCPOPT_KIND_WINDOW = 3,
+ TCPOPT_KIND_SACK_PERMITTED = 4,
+ TCPOPT_KIND_SACK = 5,
+ TCPOPT_KIND_TIMESTAMP = 8,
+ TCPOPT_KIND_ECHO = 8,
+ __TCPOPT_KIND_MAX,
+
+ /* extra oob info, internal to nft */
+ TCPOPT_KIND_SACK1 = 256,
+ TCPOPT_KIND_SACK2 = 257,
+ TCPOPT_KIND_SACK3 = 258,
};
enum tcpopt_hdr_fields {
@@ -44,6 +45,6 @@ enum tcpopt_hdr_fields {
TCPOPTHDR_FIELD_TSECR,
};
-extern const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX];
+extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX];
#endif /* NFTABLES_TCPOPT_H */
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 56d26e3..8f77766 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -384,7 +384,7 @@ int nft_lex(void *, void *, void *);
%token OPTION "option"
%token ECHO "echo"
%token EOL "eol"
-%token NOOP "noop"
+%token NOP "nop"
%token SACK "sack"
%token SACK0 "sack0"
%token SACK1 "sack1"
@@ -4732,18 +4732,18 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
| URGPTR { $$ = TCPHDR_URGPTR; }
;
-tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; }
- | NOOP { $$ = TCPOPTHDR_NOOP; }
- | MSS { $$ = TCPOPTHDR_MAXSEG; }
- | WINDOW { $$ = TCPOPTHDR_WINDOW; }
- | SACK_PERM { $$ = TCPOPTHDR_SACK_PERMITTED; }
- | SACK { $$ = TCPOPTHDR_SACK0; }
- | SACK0 { $$ = TCPOPTHDR_SACK0; }
- | SACK1 { $$ = TCPOPTHDR_SACK1; }
- | SACK2 { $$ = TCPOPTHDR_SACK2; }
- | SACK3 { $$ = TCPOPTHDR_SACK3; }
- | ECHO { $$ = TCPOPTHDR_ECHO; }
- | TIMESTAMP { $$ = TCPOPTHDR_TIMESTAMP; }
+tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; }
+ | NOP { $$ = TCPOPT_KIND_NOP; }
+ | MSS { $$ = TCPOPT_KIND_MAXSEG; }
+ | WINDOW { $$ = TCPOPT_KIND_WINDOW; }
+ | SACK_PERM { $$ = TCPOPT_KIND_SACK_PERMITTED; }
+ | SACK { $$ = TCPOPT_KIND_SACK; }
+ | SACK0 { $$ = TCPOPT_KIND_SACK; }
+ | SACK1 { $$ = TCPOPT_KIND_SACK1; }
+ | SACK2 { $$ = TCPOPT_KIND_SACK2; }
+ | SACK3 { $$ = TCPOPT_KIND_SACK3; }
+ | ECHO { $$ = TCPOPT_KIND_ECHO; }
+ | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; }
;
tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; }
diff --git a/src/parser_json.c b/src/parser_json.c
index 662bb4b..44b58a0 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -456,9 +456,9 @@ static int json_parse_tcp_option_type(const char *name, int *val)
{
unsigned int i;
- for (i = 0; i < array_size(tcpopthdr_protocols); i++) {
- if (tcpopthdr_protocols[i] &&
- !strcmp(tcpopthdr_protocols[i]->name, name)) {
+ for (i = 0; i < array_size(tcpopt_protocols); i++) {
+ if (tcpopt_protocols[i] &&
+ !strcmp(tcpopt_protocols[i]->name, name)) {
if (val)
*val = i;
return 0;
@@ -467,7 +467,7 @@ static int json_parse_tcp_option_type(const char *name, int *val)
/* special case for sack0 - sack3 */
if (sscanf(name, "sack%u", &i) == 1 && i < 4) {
if (val)
- *val = TCPOPTHDR_SACK0 + i;
+ *val = TCPOPT_KIND_SACK + i;
return 0;
}
return 1;
@@ -476,7 +476,7 @@ static int json_parse_tcp_option_type(const char *name, int *val)
static int json_parse_tcp_option_field(int type, const char *name, int *val)
{
unsigned int i;
- const struct exthdr_desc *desc = tcpopthdr_protocols[type];
+ const struct exthdr_desc *desc = tcpopt_protocols[type];
for (i = 0; i < array_size(desc->templates); i++) {
if (desc->templates[i].token &&
diff --git a/src/scanner.l b/src/scanner.l
index a369802..20b1b2d 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -421,7 +421,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"eol" { return EOL; }
"maxseg" { return MSS; }
"mss" { return MSS; }
-"noop" { return NOOP; }
+"nop" { return NOP; }
+"noop" { return NOP; }
"sack" { return SACK; }
"sack0" { return SACK0; }
"sack1" { return SACK1; }
diff --git a/src/tcpopt.c b/src/tcpopt.c
index 6dbaa9e..8d5bdec 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -20,7 +20,7 @@ static const struct proto_hdr_template tcpopt_unknown_template =
__offset, __len)
static const struct exthdr_desc tcpopt_eol = {
.name = "eol",
- .type = TCPOPT_EOL,
+ .type = TCPOPT_KIND_EOL,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
},
@@ -28,7 +28,7 @@ static const struct exthdr_desc tcpopt_eol = {
static const struct exthdr_desc tcpopt_nop = {
.name = "noop",
- .type = TCPOPT_NOP,
+ .type = TCPOPT_KIND_NOP,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
},
@@ -36,7 +36,7 @@ static const struct exthdr_desc tcpopt_nop = {
static const struct exthdr_desc tcptopt_maxseg = {
.name = "maxseg",
- .type = TCPOPT_MAXSEG,
+ .type = TCPOPT_KIND_MAXSEG,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
[TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
@@ -46,7 +46,7 @@ static const struct exthdr_desc tcptopt_maxseg = {
static const struct exthdr_desc tcpopt_window = {
.name = "window",
- .type = TCPOPT_WINDOW,
+ .type = TCPOPT_KIND_WINDOW,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
[TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
@@ -56,7 +56,7 @@ static const struct exthdr_desc tcpopt_window = {
static const struct exthdr_desc tcpopt_sack_permitted = {
.name = "sack-perm",
- .type = TCPOPT_SACK_PERMITTED,
+ .type = TCPOPT_KIND_SACK_PERMITTED,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
[TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
@@ -65,7 +65,7 @@ static const struct exthdr_desc tcpopt_sack_permitted = {
static const struct exthdr_desc tcpopt_sack = {
.name = "sack",
- .type = TCPOPT_SACK,
+ .type = TCPOPT_KIND_SACK,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
[TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
@@ -76,7 +76,7 @@ static const struct exthdr_desc tcpopt_sack = {
static const struct exthdr_desc tcpopt_timestamp = {
.name = "timestamp",
- .type = TCPOPT_TIMESTAMP,
+ .type = TCPOPT_KIND_TIMESTAMP,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
[TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
@@ -86,19 +86,14 @@ static const struct exthdr_desc tcpopt_timestamp = {
};
#undef PHT
-#define TCPOPT_OBSOLETE ((struct exthdr_desc *)NULL)
-#define TCPOPT_ECHO 6
-#define TCPOPT_ECHO_REPLY 7
-static const struct exthdr_desc *tcpopt_protocols[] = {
- [TCPOPT_EOL] = &tcpopt_eol,
- [TCPOPT_NOP] = &tcpopt_nop,
- [TCPOPT_MAXSEG] = &tcptopt_maxseg,
- [TCPOPT_WINDOW] = &tcpopt_window,
- [TCPOPT_SACK_PERMITTED] = &tcpopt_sack_permitted,
- [TCPOPT_SACK] = &tcpopt_sack,
- [TCPOPT_ECHO] = TCPOPT_OBSOLETE,
- [TCPOPT_ECHO_REPLY] = TCPOPT_OBSOLETE,
- [TCPOPT_TIMESTAMP] = &tcpopt_timestamp,
+const struct exthdr_desc *tcpopt_protocols[] = {
+ [TCPOPT_KIND_EOL] = &tcpopt_eol,
+ [TCPOPT_KIND_NOP] = &tcpopt_nop,
+ [TCPOPT_KIND_MAXSEG] = &tcptopt_maxseg,
+ [TCPOPT_KIND_WINDOW] = &tcpopt_window,
+ [TCPOPT_KIND_SACK_PERMITTED] = &tcpopt_sack_permitted,
+ [TCPOPT_KIND_SACK] = &tcpopt_sack,
+ [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp,
};
static unsigned int calc_offset(const struct exthdr_desc *desc,
@@ -136,51 +131,34 @@ static unsigned int calc_offset_reverse(const struct exthdr_desc *desc,
}
}
-const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX] = {
- [TCPOPTHDR_EOL] = &tcpopt_eol,
- [TCPOPTHDR_NOOP] = &tcpopt_nop,
- [TCPOPTHDR_MAXSEG] = &tcptopt_maxseg,
- [TCPOPTHDR_WINDOW] = &tcpopt_window,
- [TCPOPTHDR_SACK_PERMITTED] = &tcpopt_sack_permitted,
- [TCPOPTHDR_SACK0] = &tcpopt_sack,
- [TCPOPTHDR_SACK1] = &tcpopt_sack,
- [TCPOPTHDR_SACK2] = &tcpopt_sack,
- [TCPOPTHDR_SACK3] = &tcpopt_sack,
- [TCPOPTHDR_ECHO] = TCPOPT_OBSOLETE,
- [TCPOPTHDR_ECHO_REPLY] = TCPOPT_OBSOLETE,
- [TCPOPTHDR_TIMESTAMP] = &tcpopt_timestamp,
-};
-
-static uint8_t tcpopt_optnum[] = {
- [TCPOPTHDR_SACK0] = 0,
- [TCPOPTHDR_SACK1] = 1,
- [TCPOPTHDR_SACK2] = 2,
- [TCPOPTHDR_SACK3] = 3,
-};
-
-static uint8_t tcpopt_find_optnum(uint8_t optnum)
-{
- if (optnum > TCPOPTHDR_SACK3)
- return 0;
-
- return tcpopt_optnum[optnum];
-}
-
-struct expr *tcpopt_expr_alloc(const struct location *loc, uint8_t type,
- uint8_t field)
+struct expr *tcpopt_expr_alloc(const struct location *loc,
+ unsigned int kind,
+ unsigned int field)
{
const struct proto_hdr_template *tmpl;
const struct exthdr_desc *desc;
+ uint8_t optnum = 0;
struct expr *expr;
- uint8_t optnum;
- desc = tcpopthdr_protocols[type];
+ switch (kind) {
+ case TCPOPT_KIND_SACK1:
+ kind = TCPOPT_KIND_SACK;
+ optnum = 1;
+ break;
+ case TCPOPT_KIND_SACK2:
+ kind = TCPOPT_KIND_SACK;
+ optnum = 2;
+ break;
+ case TCPOPT_KIND_SACK3:
+ kind = TCPOPT_KIND_SACK;
+ optnum = 3;
+ }
+
+ desc = tcpopt_protocols[kind];
tmpl = &desc->templates[field];
if (!tmpl)
return NULL;
- optnum = tcpopt_find_optnum(type);
-
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
BYTEORDER_BIG_ENDIAN, tmpl->len);
expr->exthdr.desc = desc;
@@ -206,7 +184,7 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
assert(type < array_size(tcpopt_protocols));
expr->exthdr.desc = tcpopt_protocols[type];
expr->exthdr.flags = flags;
- assert(expr->exthdr.desc != TCPOPT_OBSOLETE);
+ assert(expr->exthdr.desc != NULL);
for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
tmpl = &expr->exthdr.desc->templates[i];
--
2.31.1

View File

@ -1,118 +0,0 @@
From f4476f9428a79c5d6d8fe284f0da91c2d4177e66 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] tcpopt: rename noop to nop
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 8f591eba561ac
commit 8f591eba561aceeef605283c693b659a708d1cd3
Author: Florian Westphal <fw@strlen.de>
Date: Mon Nov 2 14:58:41 2020 +0100
tcpopt: rename noop to nop
'nop' is the tcp padding "option". "noop" is retained for compatibility
on parser side.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
doc/payload-expression.txt | 4 ++--
src/tcpopt.c | 2 +-
tests/py/any/tcpopt.t | 2 +-
tests/py/any/tcpopt.t.json | 4 ++--
tests/py/any/tcpopt.t.payload | 16 +---------------
5 files changed, 7 insertions(+), 21 deletions(-)
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 27145c3..3a07321 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -559,8 +559,8 @@ Segment Routing Header
|eol|
End if option list|
kind
-|noop|
-1 Byte TCP No-op options |
+|nop|
+1 Byte TCP Nop padding option |
kind
|maxseg|
TCP Maximum Segment Size|
diff --git a/src/tcpopt.c b/src/tcpopt.c
index 8d5bdec..17cb580 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -27,7 +27,7 @@ static const struct exthdr_desc tcpopt_eol = {
};
static const struct exthdr_desc tcpopt_nop = {
- .name = "noop",
+ .name = "nop",
.type = TCPOPT_KIND_NOP,
.templates = {
[TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index 5f21d49..1d42de8 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -5,7 +5,7 @@
*inet;test-inet;input
tcp option eol kind 1;ok
-tcp option noop kind 1;ok
+tcp option nop kind 1;ok
tcp option maxseg kind 1;ok
tcp option maxseg length 1;ok
tcp option maxseg size 1;ok
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index 2c6236a..b15e36e 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -14,14 +14,14 @@
}
]
-# tcp option noop kind 1
+# tcp option nop kind 1
[
{
"match": {
"left": {
"tcp option": {
"field": "kind",
- "name": "noop"
+ "name": "nop"
}
},
"op": "==",
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index f63076a..9c480c8 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -19,21 +19,7 @@ inet
[ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option noop kind 1
-ip
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-ip6
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
+# tcp option nop kind 1
inet
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
--
2.31.1

View File

@ -1,538 +0,0 @@
From 9697436145bf374093dc61e3ad857f7122de08ee Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] tcpopt: split tcpopt_hdr_fields into per-option enum
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 2e1f821d713aa
commit 2e1f821d713aa44717b38901ee80cac8e2aa0335
Author: Florian Westphal <fw@strlen.de>
Date: Mon Nov 2 15:22:40 2020 +0100
tcpopt: split tcpopt_hdr_fields into per-option enum
Currently we're limited to ten template fields in exthdr_desc struct.
Using a single enum for all tpc option fields thus won't work
indefinitely (TCPOPTHDR_FIELD_TSECR is 9) when new option templates get
added.
Fortunately we can just use one enum per tcp option to avoid this.
As a side effect this also allows to simplify the sack offset
calculations. Rather than computing that on-the-fly, just add extra
fields to the SACK template.
expr->exthdr.offset now holds the 'raw' value, filled in from the option
template. This would ease implementation of 'raw option matching'
using offset and length to load from the option.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/tcpopt.h | 46 +++++++++++----
src/evaluate.c | 16 ++---
src/exthdr.c | 1 +
src/ipopt.c | 2 +-
src/netlink_delinearize.c | 2 +-
src/netlink_linearize.c | 4 +-
src/parser_bison.y | 18 +++---
src/parser_json.c | 36 ++++++++++--
src/tcpopt.c | 119 ++++++++++++++++----------------------
9 files changed, 139 insertions(+), 105 deletions(-)
diff --git a/include/tcpopt.h b/include/tcpopt.h
index 7f3fbb8..667c8a7 100644
--- a/include/tcpopt.h
+++ b/include/tcpopt.h
@@ -33,16 +33,42 @@ enum tcpopt_kind {
TCPOPT_KIND_SACK3 = 258,
};
-enum tcpopt_hdr_fields {
- TCPOPTHDR_FIELD_INVALID,
- TCPOPTHDR_FIELD_KIND,
- TCPOPTHDR_FIELD_LENGTH,
- TCPOPTHDR_FIELD_SIZE,
- TCPOPTHDR_FIELD_COUNT,
- TCPOPTHDR_FIELD_LEFT,
- TCPOPTHDR_FIELD_RIGHT,
- TCPOPTHDR_FIELD_TSVAL,
- TCPOPTHDR_FIELD_TSECR,
+/* Internal identifiers */
+enum tcpopt_common {
+ TCPOPT_COMMON_KIND,
+ TCPOPT_COMMON_LENGTH,
+};
+
+enum tcpopt_maxseg {
+ TCPOPT_MAXSEG_KIND,
+ TCPOPT_MAXSEG_LENGTH,
+ TCPOPT_MAXSEG_SIZE,
+};
+
+enum tcpopt_timestamp {
+ TCPOPT_TS_KIND,
+ TCPOPT_TS_LENGTH,
+ TCPOPT_TS_TSVAL,
+ TCPOPT_TS_TSECR,
+};
+
+enum tcpopt_windowscale {
+ TCPOPT_WINDOW_KIND,
+ TCPOPT_WINDOW_LENGTH,
+ TCPOPT_WINDOW_COUNT,
+};
+
+enum tcpopt_hdr_field_sack {
+ TCPOPT_SACK_KIND,
+ TCPOPT_SACK_LENGTH,
+ TCPOPT_SACK_LEFT,
+ TCPOPT_SACK_RIGHT,
+ TCPOPT_SACK_LEFT1,
+ TCPOPT_SACK_RIGHT1,
+ TCPOPT_SACK_LEFT2,
+ TCPOPT_SACK_RIGHT2,
+ TCPOPT_SACK_LEFT3,
+ TCPOPT_SACK_RIGHT3,
};
extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX];
diff --git a/src/evaluate.c b/src/evaluate.c
index 0181750..99a66c2 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -474,7 +474,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
&extra_len);
break;
case EXPR_EXTHDR:
- shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset,
+ shift = expr_offset_shift(expr, expr->exthdr.offset,
&extra_len);
break;
default:
@@ -526,18 +526,16 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
if (expr_evaluate_primary(ctx, exprp) < 0)
return -1;
- if (expr->exthdr.tmpl->offset % BITS_PER_BYTE != 0 ||
+ if (expr->exthdr.offset % BITS_PER_BYTE != 0 ||
expr->len % BITS_PER_BYTE != 0)
expr_evaluate_bits(ctx, exprp);
switch (expr->exthdr.op) {
case NFT_EXTHDR_OP_TCPOPT: {
static const unsigned int max_tcpoptlen = (15 * 4 - 20) * BITS_PER_BYTE;
- unsigned int totlen = 0;
+ unsigned int totlen;
- totlen += expr->exthdr.tmpl->offset;
- totlen += expr->exthdr.tmpl->len;
- totlen += expr->exthdr.offset;
+ totlen = expr->exthdr.tmpl->len + expr->exthdr.offset;
if (totlen > max_tcpoptlen)
return expr_error(ctx->msgs, expr,
@@ -547,11 +545,9 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
}
case NFT_EXTHDR_OP_IPV4: {
static const unsigned int max_ipoptlen = 40 * BITS_PER_BYTE;
- unsigned int totlen = 0;
+ unsigned int totlen;
- totlen += expr->exthdr.tmpl->offset;
- totlen += expr->exthdr.tmpl->len;
- totlen += expr->exthdr.offset;
+ totlen = expr->exthdr.offset + expr->exthdr.tmpl->len;
if (totlen > max_ipoptlen)
return expr_error(ctx->msgs, expr,
diff --git a/src/exthdr.c b/src/exthdr.c
index e1ec6f3..c28213f 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -99,6 +99,7 @@ struct expr *exthdr_expr_alloc(const struct location *loc,
BYTEORDER_BIG_ENDIAN, tmpl->len);
expr->exthdr.desc = desc;
expr->exthdr.tmpl = tmpl;
+ expr->exthdr.offset = tmpl->offset;
return expr;
}
diff --git a/src/ipopt.c b/src/ipopt.c
index b3d0279..7ecb8b9 100644
--- a/src/ipopt.c
+++ b/src/ipopt.c
@@ -102,7 +102,7 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
expr->exthdr.desc = desc;
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
- expr->exthdr.offset = calc_offset(desc, tmpl, ptr);
+ expr->exthdr.offset = tmpl->offset + calc_offset(desc, tmpl, ptr);
return expr;
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 157a473..790336a 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -727,8 +727,8 @@ static void netlink_parse_numgen(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
- enum nft_registers dreg;
uint32_t type, until, offset;
+ enum nft_registers dreg;
struct expr *expr;
type = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_TYPE);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 25be634..9d1a064 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -168,7 +168,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
- unsigned int offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+ unsigned int offset = expr->exthdr.offset;
struct nftnl_expr *nle;
nle = alloc_nft_expr("exthdr");
@@ -896,7 +896,7 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
expr = stmt->exthdr.expr;
- offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+ offset = expr->exthdr.offset;
nle = alloc_nft_expr("exthdr");
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 8f77766..114b289 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4715,7 +4715,7 @@ tcp_hdr_expr : TCP tcp_hdr_field
}
| TCP OPTION tcp_hdr_option_type
{
- $$ = tcpopt_expr_alloc(&@$, $3, TCPOPTHDR_FIELD_KIND);
+ $$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND);
$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
}
;
@@ -4746,14 +4746,14 @@ tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; }
| TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; }
;
-tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; }
- | LENGTH { $$ = TCPOPTHDR_FIELD_LENGTH; }
- | SIZE { $$ = TCPOPTHDR_FIELD_SIZE; }
- | COUNT { $$ = TCPOPTHDR_FIELD_COUNT; }
- | LEFT { $$ = TCPOPTHDR_FIELD_LEFT; }
- | RIGHT { $$ = TCPOPTHDR_FIELD_RIGHT; }
- | TSVAL { $$ = TCPOPTHDR_FIELD_TSVAL; }
- | TSECR { $$ = TCPOPTHDR_FIELD_TSECR; }
+tcp_hdr_option_field : KIND { $$ = TCPOPT_COMMON_KIND; }
+ | LENGTH { $$ = TCPOPT_COMMON_LENGTH; }
+ | SIZE { $$ = TCPOPT_MAXSEG_SIZE; }
+ | COUNT { $$ = TCPOPT_WINDOW_COUNT; }
+ | LEFT { $$ = TCPOPT_SACK_LEFT; }
+ | RIGHT { $$ = TCPOPT_SACK_RIGHT; }
+ | TSVAL { $$ = TCPOPT_TS_TSVAL; }
+ | TSECR { $$ = TCPOPT_TS_TSECR; }
;
dccp_hdr_expr : DCCP dccp_hdr_field
diff --git a/src/parser_json.c b/src/parser_json.c
index 44b58a0..ab2375f 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -466,8 +466,10 @@ static int json_parse_tcp_option_type(const char *name, int *val)
}
/* special case for sack0 - sack3 */
if (sscanf(name, "sack%u", &i) == 1 && i < 4) {
- if (val)
- *val = TCPOPT_KIND_SACK + i;
+ if (val && i == 0)
+ *val = TCPOPT_KIND_SACK;
+ else if (val && i > 0)
+ *val = TCPOPT_KIND_SACK1 + i - 1;
return 0;
}
return 1;
@@ -475,12 +477,38 @@ static int json_parse_tcp_option_type(const char *name, int *val)
static int json_parse_tcp_option_field(int type, const char *name, int *val)
{
+ const struct exthdr_desc *desc;
+ unsigned int block = 0;
unsigned int i;
- const struct exthdr_desc *desc = tcpopt_protocols[type];
+
+ switch (type) {
+ case TCPOPT_KIND_SACK1:
+ type = TCPOPT_KIND_SACK;
+ block = 1;
+ break;
+ case TCPOPT_KIND_SACK2:
+ type = TCPOPT_KIND_SACK;
+ block = 2;
+ break;
+ case TCPOPT_KIND_SACK3:
+ type = TCPOPT_KIND_SACK;
+ block = 3;
+ break;
+ }
+
+ if (type < 0 || type >= (int)array_size(tcpopt_protocols))
+ return 1;
+
+ desc = tcpopt_protocols[type];
for (i = 0; i < array_size(desc->templates); i++) {
if (desc->templates[i].token &&
!strcmp(desc->templates[i].token, name)) {
+ if (block) {
+ block--;
+ continue;
+ }
+
if (val)
*val = i;
return 0;
@@ -585,7 +613,7 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
if (json_unpack(root, "{s:s}", "field", &field)) {
expr = tcpopt_expr_alloc(int_loc, descval,
- TCPOPTHDR_FIELD_KIND);
+ TCPOPT_COMMON_KIND);
expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
return expr;
diff --git a/src/tcpopt.c b/src/tcpopt.c
index 17cb580..d1dd13b 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -22,7 +22,7 @@ static const struct exthdr_desc tcpopt_eol = {
.name = "eol",
.type = TCPOPT_KIND_EOL,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
},
};
@@ -30,7 +30,7 @@ static const struct exthdr_desc tcpopt_nop = {
.name = "nop",
.type = TCPOPT_KIND_NOP,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
},
};
@@ -38,9 +38,9 @@ static const struct exthdr_desc tcptopt_maxseg = {
.name = "maxseg",
.type = TCPOPT_KIND_MAXSEG,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_SIZE] = PHT("size", 16, 16),
+ [TCPOPT_MAXSEG_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_MAXSEG_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_MAXSEG_SIZE] = PHT("size", 16, 16),
},
};
@@ -48,9 +48,9 @@ static const struct exthdr_desc tcpopt_window = {
.name = "window",
.type = TCPOPT_KIND_WINDOW,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_COUNT] = PHT("count", 16, 8),
+ [TCPOPT_WINDOW_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_WINDOW_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_WINDOW_COUNT] = PHT("count", 16, 8),
},
};
@@ -58,8 +58,8 @@ static const struct exthdr_desc tcpopt_sack_permitted = {
.name = "sack-perm",
.type = TCPOPT_KIND_SACK_PERMITTED,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
},
};
@@ -67,10 +67,16 @@ static const struct exthdr_desc tcpopt_sack = {
.name = "sack",
.type = TCPOPT_KIND_SACK,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_LEFT] = PHT("left", 16, 32),
- [TCPOPTHDR_FIELD_RIGHT] = PHT("right", 48, 32),
+ [TCPOPT_SACK_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_SACK_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_SACK_LEFT] = PHT("left", 16, 32),
+ [TCPOPT_SACK_RIGHT] = PHT("right", 48, 32),
+ [TCPOPT_SACK_LEFT1] = PHT("left", 80, 32),
+ [TCPOPT_SACK_RIGHT1] = PHT("right", 112, 32),
+ [TCPOPT_SACK_LEFT2] = PHT("left", 144, 32),
+ [TCPOPT_SACK_RIGHT2] = PHT("right", 176, 32),
+ [TCPOPT_SACK_LEFT3] = PHT("left", 208, 32),
+ [TCPOPT_SACK_RIGHT3] = PHT("right", 240, 32),
},
};
@@ -78,12 +84,13 @@ static const struct exthdr_desc tcpopt_timestamp = {
.name = "timestamp",
.type = TCPOPT_KIND_TIMESTAMP,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_TSVAL] = PHT("tsval", 16, 32),
- [TCPOPTHDR_FIELD_TSECR] = PHT("tsecr", 48, 32),
+ [TCPOPT_TS_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_TS_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_TS_TSVAL] = PHT("tsval", 16, 32),
+ [TCPOPT_TS_TSECR] = PHT("tsecr", 48, 32),
},
};
+
#undef PHT
const struct exthdr_desc *tcpopt_protocols[] = {
@@ -96,65 +103,43 @@ const struct exthdr_desc *tcpopt_protocols[] = {
[TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp,
};
-static unsigned int calc_offset(const struct exthdr_desc *desc,
- const struct proto_hdr_template *tmpl,
- unsigned int num)
-{
- if (!desc || tmpl == &tcpopt_unknown_template)
- return 0;
-
- switch (desc->type) {
- case TCPOPT_SACK:
- /* Make sure, offset calculations only apply to left and right
- * fields
- */
- return (tmpl->offset < 16) ? 0 : num * 64;
- default:
- return 0;
- }
-}
-
-
-static unsigned int calc_offset_reverse(const struct exthdr_desc *desc,
- const struct proto_hdr_template *tmpl,
- unsigned int offset)
-{
- if (!desc || tmpl == &tcpopt_unknown_template)
- return offset;
-
- switch (desc->type) {
- case TCPOPT_SACK:
- /* We can safely ignore the first left/right field */
- return offset < 80 ? offset : (offset % 64);
- default:
- return offset;
- }
-}
-
struct expr *tcpopt_expr_alloc(const struct location *loc,
unsigned int kind,
unsigned int field)
{
const struct proto_hdr_template *tmpl;
- const struct exthdr_desc *desc;
- uint8_t optnum = 0;
+ const struct exthdr_desc *desc = NULL;
struct expr *expr;
switch (kind) {
case TCPOPT_KIND_SACK1:
kind = TCPOPT_KIND_SACK;
- optnum = 1;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT1;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT1;
break;
case TCPOPT_KIND_SACK2:
kind = TCPOPT_KIND_SACK;
- optnum = 2;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT2;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT2;
break;
case TCPOPT_KIND_SACK3:
kind = TCPOPT_KIND_SACK;
- optnum = 3;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT3;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT3;
+ break;
}
- desc = tcpopt_protocols[kind];
+ if (kind < array_size(tcpopt_protocols))
+ desc = tcpopt_protocols[kind];
+
+ if (!desc)
+ return NULL;
tmpl = &desc->templates[field];
if (!tmpl)
return NULL;
@@ -164,34 +149,32 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
expr->exthdr.desc = desc;
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
- expr->exthdr.offset = calc_offset(desc, tmpl, optnum);
+ expr->exthdr.offset = tmpl->offset;
return expr;
}
-void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
unsigned int len, uint32_t flags)
{
const struct proto_hdr_template *tmpl;
- unsigned int i, off;
+ unsigned int i;
assert(expr->etype == EXPR_EXTHDR);
expr->len = len;
expr->exthdr.flags = flags;
- expr->exthdr.offset = offset;
+ expr->exthdr.offset = off;
+
+ if (type >= array_size(tcpopt_protocols))
+ return;
- assert(type < array_size(tcpopt_protocols));
expr->exthdr.desc = tcpopt_protocols[type];
expr->exthdr.flags = flags;
assert(expr->exthdr.desc != NULL);
for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
tmpl = &expr->exthdr.desc->templates[i];
- /* We have to reverse calculate the offset for the sack options
- * at this point
- */
- off = calc_offset_reverse(expr->exthdr.desc, tmpl, offset);
if (tmpl->offset != off || tmpl->len != len)
continue;
--
2.31.1

View File

@ -1,336 +0,0 @@
From 8a4b6cbf58e965d67b0337ba1736bd3691a49890 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] tcpopt: allow to check for presence of any tcp option
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 24d8da3083422
commit 24d8da3083422da8336eeed2ee23b2ccf598ba5a
Author: Florian Westphal <fw@strlen.de>
Date: Wed Oct 21 23:54:17 2020 +0200
tcpopt: allow to check for presence of any tcp option
nft currently doesn't allow to check for presence of arbitrary tcp options.
Only known options where nft provides a template can be tested for.
This allows to test for presence of raw protocol values as well.
Example:
tcp option 42 exists
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/expression.h | 3 +-
src/exthdr.c | 12 ++++++++
src/ipopt.c | 1 +
src/netlink_linearize.c | 2 +-
src/parser_bison.y | 7 +++++
src/tcpopt.c | 42 +++++++++++++++++++++++----
tests/py/any/tcpopt.t | 2 ++
tests/py/any/tcpopt.t.payload | 53 +++--------------------------------
8 files changed, 65 insertions(+), 57 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index 2e41aa0..b50183d 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -299,7 +299,8 @@ struct expr {
/* EXPR_EXTHDR */
const struct exthdr_desc *desc;
const struct proto_hdr_template *tmpl;
- unsigned int offset;
+ uint16_t offset;
+ uint8_t raw_type;
enum nft_exthdr_op op;
unsigned int flags;
} exthdr;
diff --git a/src/exthdr.c b/src/exthdr.c
index c28213f..68d5aa5 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -32,6 +32,13 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
*/
unsigned int offset = expr->exthdr.offset / 64;
+ if (expr->exthdr.desc == NULL &&
+ expr->exthdr.offset == 0 &&
+ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) {
+ nft_print(octx, "tcp option %d", expr->exthdr.raw_type);
+ return;
+ }
+
nft_print(octx, "tcp option %s", expr->exthdr.desc->name);
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
return;
@@ -59,6 +66,7 @@ static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2)
return e1->exthdr.desc == e2->exthdr.desc &&
e1->exthdr.tmpl == e2->exthdr.tmpl &&
e1->exthdr.op == e2->exthdr.op &&
+ e1->exthdr.raw_type == e2->exthdr.raw_type &&
e1->exthdr.flags == e2->exthdr.flags;
}
@@ -69,6 +77,7 @@ static void exthdr_expr_clone(struct expr *new, const struct expr *expr)
new->exthdr.offset = expr->exthdr.offset;
new->exthdr.op = expr->exthdr.op;
new->exthdr.flags = expr->exthdr.flags;
+ new->exthdr.raw_type = expr->exthdr.raw_type;
}
const struct expr_ops exthdr_expr_ops = {
@@ -98,6 +107,7 @@ struct expr *exthdr_expr_alloc(const struct location *loc,
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
BYTEORDER_BIG_ENDIAN, tmpl->len);
expr->exthdr.desc = desc;
+ expr->exthdr.raw_type = desc ? desc->type : 0;
expr->exthdr.tmpl = tmpl;
expr->exthdr.offset = tmpl->offset;
return expr;
@@ -176,6 +186,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
unsigned int i;
assert(expr->etype == EXPR_EXTHDR);
+ expr->exthdr.raw_type = type;
+
if (op == NFT_EXTHDR_OP_TCPOPT)
return tcpopt_init_raw(expr, type, offset, len, flags);
if (op == NFT_EXTHDR_OP_IPV4)
diff --git a/src/ipopt.c b/src/ipopt.c
index 7ecb8b9..5f9f908 100644
--- a/src/ipopt.c
+++ b/src/ipopt.c
@@ -103,6 +103,7 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
expr->exthdr.offset = tmpl->offset + calc_offset(desc, tmpl, ptr);
+ expr->exthdr.raw_type = desc->type;
return expr;
}
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 9d1a064..28b0e6a 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -174,7 +174,7 @@ static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("exthdr");
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
- expr->exthdr.desc->type);
+ expr->exthdr.raw_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 114b289..4ea9364 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4744,6 +4744,13 @@ tcp_hdr_option_type : EOL { $$ = TCPOPT_KIND_EOL; }
| SACK3 { $$ = TCPOPT_KIND_SACK3; }
| ECHO { $$ = TCPOPT_KIND_ECHO; }
| TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; }
+ | NUM {
+ if ($1 > 255) {
+ erec_queue(error(&@1, "value too large"), state->msgs);
+ YYERROR;
+ }
+ $$ = $1;
+ }
;
tcp_hdr_option_field : KIND { $$ = TCPOPT_COMMON_KIND; }
diff --git a/src/tcpopt.c b/src/tcpopt.c
index d1dd13b..1cf97a5 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -103,6 +103,19 @@ const struct exthdr_desc *tcpopt_protocols[] = {
[TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp,
};
+/**
+ * tcpopt_expr_alloc - allocate tcp option extension expression
+ *
+ * @loc: location from parser
+ * @kind: raw tcp option value to find in packet
+ * @field: highlevel field to find in the option if @kind is present in packet
+ *
+ * Allocate a new tcp option expression.
+ * @kind is the raw option value to find in the packet.
+ * Exception: SACK may use extra OOB data that is mangled here.
+ *
+ * @field is the optional field to extract from the @type option.
+ */
struct expr *tcpopt_expr_alloc(const struct location *loc,
unsigned int kind,
unsigned int field)
@@ -138,8 +151,22 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
if (kind < array_size(tcpopt_protocols))
desc = tcpopt_protocols[kind];
- if (!desc)
- return NULL;
+ if (!desc) {
+ if (field != TCPOPT_COMMON_KIND || kind > 255)
+ return NULL;
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, &integer_type,
+ BYTEORDER_BIG_ENDIAN, 8);
+
+ desc = tcpopt_protocols[TCPOPT_NOP];
+ tmpl = &desc->templates[field];
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+ expr->exthdr.raw_type = kind;
+ return expr;
+ }
+
tmpl = &desc->templates[field];
if (!tmpl)
return NULL;
@@ -149,6 +176,7 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
expr->exthdr.desc = desc;
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+ expr->exthdr.raw_type = desc->type;
expr->exthdr.offset = tmpl->offset;
return expr;
@@ -165,6 +193,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
expr->len = len;
expr->exthdr.flags = flags;
expr->exthdr.offset = off;
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
if (type >= array_size(tcpopt_protocols))
return;
@@ -178,12 +210,10 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
if (tmpl->offset != off || tmpl->len != len)
continue;
- if (flags & NFT_EXTHDR_F_PRESENT)
- datatype_set(expr, &boolean_type);
- else
+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0)
datatype_set(expr, tmpl->dtype);
+
expr->exthdr.tmpl = tmpl;
- expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
break;
}
}
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index 1d42de8..7b17014 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -30,6 +30,7 @@ tcp option timestamp kind 1;ok
tcp option timestamp length 1;ok
tcp option timestamp tsval 1;ok
tcp option timestamp tsecr 1;ok
+tcp option 255 missing;ok
tcp option foobar;fail
tcp option foo bar;fail
@@ -38,6 +39,7 @@ tcp option eol left 1;fail
tcp option eol left 1;fail
tcp option sack window;fail
tcp option sack window 1;fail
+tcp option 256 exists;fail
tcp option window exists;ok
tcp option window missing;ok
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index 9c480c8..34f8e26 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -509,20 +509,6 @@ inet
[ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
[ cmp eq reg 1 0x01000000 ]
-# tcp option timestamp tsecr 1
-ip
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-ip6
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
# tcp option timestamp tsecr 1
inet
[ meta load l4proto => reg 1 ]
@@ -530,19 +516,12 @@ inet
[ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
[ cmp eq reg 1 0x01000000 ]
-# tcp option window exists
-ip
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window exists
-ip6
+# tcp option 255 missing
+inet
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
+ [ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
# tcp option window exists
inet
@@ -551,20 +530,6 @@ inet
[ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
-# tcp option window missing
-ip
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000000 ]
-
-# tcp option window missing
-ip6
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000000 ]
-
# tcp option window missing
inet
[ meta load l4proto => reg 1 ]
@@ -572,16 +537,6 @@ inet
[ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
[ cmp eq reg 1 0x00000000 ]
-# tcp option maxseg size set 1360
-ip
- [ immediate reg 1 0x00005005 ]
- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
-
-# tcp option maxseg size set 1360
-ip6
- [ immediate reg 1 0x00005005 ]
- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
-
# tcp option maxseg size set 1360
inet
[ immediate reg 1 0x00005005 ]
--
2.31.1

View File

@ -1,137 +0,0 @@
From 267d86b62132a009badd57b2ffcffed6ae682a1e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] tcp: add raw tcp option match support
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 881d8cb21c0b9
commit 881d8cb21c0b9168787b932f41b801593bde2216
Author: Florian Westphal <fw@strlen.de>
Date: Mon Nov 2 20:10:25 2020 +0100
tcp: add raw tcp option match support
tcp option @42,16,4 (@kind,offset,length).
Signed-off-by: Florian Westphal <fw@strlen.de>
---
doc/payload-expression.txt | 6 ++++++
src/exthdr.c | 13 +++++++++----
src/parser_bison.y | 5 +++++
src/tcpopt.c | 2 ++
tests/py/any/tcpopt.t | 2 ++
tests/py/any/tcpopt.t.payload | 7 +++++++
6 files changed, 31 insertions(+), 4 deletions(-)
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 3a07321..b6d2a28 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -591,6 +591,12 @@ TCP Timestamps |
kind, length, tsval, tsecr
|============================
+TCP option matching also supports raw expression syntax to access arbitrary options:
+[verse]
+*tcp option*
+[verse]
+*tcp option* *@*'number'*,*'offset'*,*'length'
+
.IP Options
[options="header"]
|==================
diff --git a/src/exthdr.c b/src/exthdr.c
index 68d5aa5..5c75720 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -32,10 +32,15 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
*/
unsigned int offset = expr->exthdr.offset / 64;
- if (expr->exthdr.desc == NULL &&
- expr->exthdr.offset == 0 &&
- expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) {
- nft_print(octx, "tcp option %d", expr->exthdr.raw_type);
+ if (expr->exthdr.desc == NULL) {
+ if (expr->exthdr.offset == 0 &&
+ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) {
+ nft_print(octx, "tcp option %d", expr->exthdr.raw_type);
+ return;
+ }
+
+ nft_print(octx, "tcp option @%u,%u,%u", expr->exthdr.raw_type,
+ expr->exthdr.offset, expr->len);
return;
}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 4ea9364..5aedc55 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -4718,6 +4718,11 @@ tcp_hdr_expr : TCP tcp_hdr_field
$$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND);
$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
}
+ | TCP OPTION AT tcp_hdr_option_type COMMA NUM COMMA NUM
+ {
+ $$ = tcpopt_expr_alloc(&@$, $4, 0);
+ tcpopt_init_raw($$, $4, $6, $8, 0);
+ }
;
tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
diff --git a/src/tcpopt.c b/src/tcpopt.c
index 1cf97a5..05b5ee6 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -197,6 +197,8 @@ void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
if (flags & NFT_EXTHDR_F_PRESENT)
datatype_set(expr, &boolean_type);
+ else
+ datatype_set(expr, &integer_type);
if (type >= array_size(tcpopt_protocols))
return;
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
index 7b17014..e759ac6 100644
--- a/tests/py/any/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -31,6 +31,7 @@ tcp option timestamp length 1;ok
tcp option timestamp tsval 1;ok
tcp option timestamp tsecr 1;ok
tcp option 255 missing;ok
+tcp option @255,8,8 255;ok
tcp option foobar;fail
tcp option foo bar;fail
@@ -40,6 +41,7 @@ tcp option eol left 1;fail
tcp option sack window;fail
tcp option sack window 1;fail
tcp option 256 exists;fail
+tcp option @255,8,8 256;fail
tcp option window exists;ok
tcp option window missing;ok
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
index 34f8e26..cddba61 100644
--- a/tests/py/any/tcpopt.t.payload
+++ b/tests/py/any/tcpopt.t.payload
@@ -523,6 +523,13 @@ inet
[ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ]
[ cmp eq reg 1 0x00000000 ]
+# tcp option @255,8,8 255
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 255 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
# tcp option window exists
inet
[ meta load l4proto => reg 1 ]
--
2.31.1

View File

@ -1,199 +0,0 @@
From ad566e27398e81ed803c4225179bb8df4718a2e9 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 17:44:08 +0200
Subject: [PATCH] json: tcp: add raw tcp option match support
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit cb21869649208
commit cb21869649208118ed61354e2674858e4ff6c23c
Author: Florian Westphal <fw@strlen.de>
Date: Tue Nov 3 12:04:20 2020 +0100
json: tcp: add raw tcp option match support
To similar change as in previous one, this time for the
jason (de)serialization.
Re-uses the raw payload match syntax, i.e. base,offset,length.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/json.c | 22 ++++++++--------
src/parser_json.c | 52 ++++++++++++++++++++++++++------------
tests/py/any/tcpopt.t.json | 34 +++++++++++++++++++++++++
3 files changed, 82 insertions(+), 26 deletions(-)
diff --git a/src/json.c b/src/json.c
index 1906e7d..b77c6d2 100644
--- a/src/json.c
+++ b/src/json.c
@@ -656,30 +656,32 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
{
const char *desc = expr->exthdr.desc ?
- expr->exthdr.desc->name :
- "unknown-exthdr";
+ expr->exthdr.desc->name : NULL;
const char *field = expr->exthdr.tmpl->token;
json_t *root;
bool is_exists = expr->exthdr.flags & NFT_EXTHDR_F_PRESENT;
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
+ static const char *offstrs[] = { "", "1", "2", "3" };
unsigned int offset = expr->exthdr.offset / 64;
+ const char *offstr = "";
- if (offset) {
- const char *offstrs[] = { "0", "1", "2", "3" };
- const char *offstr = "";
-
+ if (desc) {
if (offset < 4)
offstr = offstrs[offset];
root = json_pack("{s:s+}", "name", desc, offstr);
+
+ if (!is_exists)
+ json_object_set_new(root, "field", json_string(field));
} else {
- root = json_pack("{s:s}", "name", desc);
+ root = json_pack("{s:i, s:i, s:i}",
+ "base", expr->exthdr.raw_type,
+ "offset", expr->exthdr.offset,
+ "len", expr->len);
+ is_exists = false;
}
- if (!is_exists)
- json_object_set_new(root, "field", json_string(field));
-
return json_pack("{s:o}", "tcp option", root);
}
if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
diff --git a/src/parser_json.c b/src/parser_json.c
index ab2375f..fbf7db5 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -500,6 +500,8 @@ static int json_parse_tcp_option_field(int type, const char *name, int *val)
return 1;
desc = tcpopt_protocols[type];
+ if (!desc)
+ return 1;
for (i = 0; i < array_size(desc->templates); i++) {
if (desc->templates[i].token &&
@@ -599,30 +601,48 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
const char *type, json_t *root)
{
+ int fieldval, kind, offset, len;
const char *desc, *field;
- int descval, fieldval;
struct expr *expr;
- if (json_unpack_err(ctx, root, "{s:s}", "name", &desc))
- return NULL;
-
- if (json_parse_tcp_option_type(desc, &descval)) {
- json_error(ctx, "Unknown tcp option name '%s'.", desc);
- return NULL;
- }
+ if (!json_unpack(root, "{s:i, s:i, s:i}",
+ "base", &kind, "offset", &offset, "len", &len)) {
+ uint32_t flag = 0;
- if (json_unpack(root, "{s:s}", "field", &field)) {
- expr = tcpopt_expr_alloc(int_loc, descval,
+ expr = tcpopt_expr_alloc(int_loc, kind,
TCPOPT_COMMON_KIND);
- expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ if (kind < 0 || kind > 255)
+ return NULL;
+
+ if (offset == TCPOPT_COMMON_KIND && len == 8)
+ flag = NFT_EXTHDR_F_PRESENT;
+
+ tcpopt_init_raw(expr, kind, offset, len, flag);
return expr;
+ } else if (!json_unpack(root, "{s:s}", "name", &desc)) {
+ if (json_parse_tcp_option_type(desc, &kind)) {
+ json_error(ctx, "Unknown tcp option name '%s'.", desc);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = tcpopt_expr_alloc(int_loc, kind,
+ TCPOPT_COMMON_KIND);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ return expr;
+ }
+
+ if (json_parse_tcp_option_field(kind, field, &fieldval)) {
+ json_error(ctx, "Unknown tcp option field '%s'.", field);
+ return NULL;
+ }
+
+ return tcpopt_expr_alloc(int_loc, kind, fieldval);
}
- if (json_parse_tcp_option_field(descval, field, &fieldval)) {
- json_error(ctx, "Unknown tcp option field '%s'.", field);
- return NULL;
- }
- return tcpopt_expr_alloc(int_loc, descval, fieldval);
+
+ json_error(ctx, "Invalid tcp option expression properties.");
+ return NULL;
}
static int json_parse_ip_option_type(const char *name, int *val)
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index b15e36e..139e97d 100644
--- a/tests/py/any/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -414,6 +414,40 @@
}
]
+# tcp option 255 missing
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 255,
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# tcp option @255,8,8 255
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 255,
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
+
# tcp option window exists
[
{
--
2.31.1

View File

@ -1,57 +0,0 @@
From 2026f7d056679508f8506fbba7f578aa15af7c05 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 16:32:27 +0200
Subject: [PATCH] json: Simplify non-tcpopt exthdr printing a bit
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit fd81d3ec3ae8b
commit fd81d3ec3ae8b8d1d54a708d63b2dab2c8508c90
Author: Phil Sutter <phil@nwl.cc>
Date: Tue May 4 13:18:11 2021 +0200
json: Simplify non-tcpopt exthdr printing a bit
This was just duplicate code apart from the object's name.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/json.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/src/json.c b/src/json.c
index b77c6d2..a6d0716 100644
--- a/src/json.c
+++ b/src/json.c
@@ -684,21 +684,17 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
return json_pack("{s:o}", "tcp option", root);
}
- if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
- root = json_pack("{s:s}", "name", desc);
- if (!is_exists)
- json_object_set_new(root, "field", json_string(field));
-
- return json_pack("{s:o}", "ip option", root);
- }
-
- root = json_pack("{s:s}",
- "name", desc);
+ root = json_pack("{s:s}", "name", desc);
if (!is_exists)
json_object_set_new(root, "field", json_string(field));
- return json_pack("{s:o}", "exthdr", root);
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_IPV4:
+ return json_pack("{s:o}", "ip option", root);
+ default:
+ return json_pack("{s:o}", "exthdr", root);
+ }
}
json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx)
--
2.31.1

View File

@ -1,175 +0,0 @@
From c724812d9561021fb6a80c817d411d9ba2de5dbd Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 13 Jul 2021 13:54:12 +0200
Subject: [PATCH] scanner: introduce start condition stack
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 5896772fe3c5f
commit 5896772fe3c5f01696188ea04957a825ee601b12
Author: Florian Westphal <fw@strlen.de>
Date: Mon Mar 8 18:18:33 2021 +0100
scanner: introduce start condition stack
Add a small initial chunk of flex start conditionals.
This starts with two low-hanging fruits, numgen and j/symhash.
NUMGEN and HASH start conditions are entered from flex when
the corresponding expression token is encountered.
Flex returns to the INIT condition when the bison parser
has seen a complete numgen/hash statement.
This intentionally uses a stack rather than BEGIN()
to eventually support nested states.
The scanner_pop_start_cond() function argument is not used yet, but
will need to be used later to deal with nesting.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
include/parser.h | 8 ++++++++
src/parser_bison.y | 11 +++++++----
src/scanner.l | 36 +++++++++++++++++++++++++++++-------
3 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/include/parser.h b/include/parser.h
index 949284d..1d293f5 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -28,6 +28,12 @@ struct parser_state {
struct list_head *cmds;
};
+enum startcond_type {
+ PARSER_SC_BEGIN,
+ PARSER_SC_EXPR_HASH,
+ PARSER_SC_EXPR_NUMGEN,
+};
+
struct mnl_socket;
extern void parser_init(struct nft_ctx *nft, struct parser_state *state,
@@ -47,4 +53,6 @@ extern void scanner_push_buffer(void *scanner,
const struct input_descriptor *indesc,
const char *buffer);
+extern void scanner_pop_start_cond(void *scanner, enum startcond_type sc);
+
#endif /* NFTABLES_PARSER_H */
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 5aedc55..9a9447f 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -840,6 +840,9 @@ opt_newline : NEWLINE
| /* empty */
;
+close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); };
+close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); };
+
common_block : INCLUDE QUOTED_STRING stmt_separator
{
if (scanner_include_file(nft, scanner, $2, &@$) < 0) {
@@ -4249,7 +4252,7 @@ numgen_type : INC { $$ = NFT_NG_INCREMENTAL; }
| RANDOM { $$ = NFT_NG_RANDOM; }
;
-numgen_expr : NUMGEN numgen_type MOD NUM offset_opt
+numgen_expr : NUMGEN numgen_type MOD NUM offset_opt close_scope_numgen
{
$$ = numgen_expr_alloc(&@$, $2, $4, $5);
}
@@ -4306,17 +4309,17 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key
}
;
-hash_expr : JHASH expr MOD NUM SEED NUM offset_opt
+hash_expr : JHASH expr MOD NUM SEED NUM offset_opt close_scope_hash
{
$$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS);
$$->hash.expr = $2;
}
- | JHASH expr MOD NUM offset_opt
+ | JHASH expr MOD NUM offset_opt close_scope_hash
{
$$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS);
$$->hash.expr = $2;
}
- | SYMHASH MOD NUM offset_opt
+ | SYMHASH MOD NUM offset_opt close_scope_hash
{
$$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM);
}
diff --git a/src/scanner.l b/src/scanner.l
index 20b1b2d..68fe988 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -98,6 +98,8 @@ static void reset_pos(struct parser_state *state, struct location *loc)
state->indesc->column = 1;
}
+static void scanner_push_start_cond(void *scanner, enum startcond_type type);
+
#define YY_USER_ACTION { \
update_pos(yyget_extra(yyscanner), yylloc, yyleng); \
update_offset(yyget_extra(yyscanner), yylloc, yyleng); \
@@ -193,6 +195,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%option yylineno
%option nodefault
%option warn
+%option stack
+%s SCANSTATE_EXPR_HASH
+%s SCANSTATE_EXPR_NUMGEN
%%
@@ -548,15 +553,21 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"state" { return STATE; }
"status" { return STATUS; }
-"numgen" { return NUMGEN; }
-"inc" { return INC; }
-"mod" { return MOD; }
-"offset" { return OFFSET; }
+"numgen" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; }
+<SCANSTATE_EXPR_NUMGEN>{
+ "inc" { return INC; }
+}
-"jhash" { return JHASH; }
-"symhash" { return SYMHASH; }
-"seed" { return SEED; }
+"jhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; }
+"symhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; }
+<SCANSTATE_EXPR_HASH>{
+ "seed" { return SEED; }
+}
+<SCANSTATE_EXPR_HASH,SCANSTATE_EXPR_NUMGEN>{
+ "mod" { return MOD; }
+ "offset" { return OFFSET; }
+}
"dup" { return DUP; }
"fwd" { return FWD; }
@@ -949,3 +960,14 @@ void scanner_destroy(struct nft_ctx *nft)
input_descriptor_list_destroy(state);
yylex_destroy(nft->scanner);
}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type)
+{
+ yy_push_state((int)type, scanner);
+}
+
+void scanner_pop_start_cond(void *scanner, enum startcond_type t)
+{
+ yy_pop_state(scanner);
+ (void)yy_top_state(scanner); /* suppress gcc warning wrt. unused function */
+}
--
2.31.1

View File

@ -1,96 +0,0 @@
From 595e79b1ccdfa6b11cd6c2b1c8eda0161b58d22a Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Tue, 13 Jul 2021 13:54:12 +0200
Subject: [PATCH] scanner: sctp: Move to own scope
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 0925d7e214825
Conflicts: Context change due to missing other scopes.
commit 0925d7e214825628e7db4a86d5ebbad578ab0777
Author: Phil Sutter <phil@nwl.cc>
Date: Tue May 4 13:06:32 2021 +0200
scanner: sctp: Move to own scope
This isolates only "vtag" token for now.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Reviewed-by: Florian Westphal <fw@strlen.de>
---
include/parser.h | 1 +
src/parser_bison.y | 5 +++--
src/scanner.l | 8 ++++++--
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/include/parser.h b/include/parser.h
index 1d293f5..2e6ef4d 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -30,6 +30,7 @@ struct parser_state {
enum startcond_type {
PARSER_SC_BEGIN,
+ PARSER_SC_SCTP,
PARSER_SC_EXPR_HASH,
PARSER_SC_EXPR_NUMGEN,
};
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 9a9447f..beb5995 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -842,6 +842,7 @@ opt_newline : NEWLINE
close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); };
close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); };
+close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); };
common_block : INCLUDE QUOTED_STRING stmt_separator
{
@@ -4059,7 +4060,7 @@ primary_rhs_expr : symbol_expr { $$ = $1; }
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | SCTP
+ | SCTP close_scope_sctp
{
uint8_t data = IPPROTO_SCTP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
@@ -4782,7 +4783,7 @@ dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; }
| TYPE { $$ = DCCPHDR_TYPE; }
;
-sctp_hdr_expr : SCTP sctp_hdr_field
+sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp
{
$$ = payload_expr_alloc(&@$, &proto_sctp, $2);
}
diff --git a/src/scanner.l b/src/scanner.l
index 68fe988..b79ae55 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -196,6 +196,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%option nodefault
%option warn
%option stack
+%s SCANSTATE_SCTP
%s SCANSTATE_EXPR_HASH
%s SCANSTATE_EXPR_NUMGEN
@@ -488,8 +489,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"dccp" { return DCCP; }
-"sctp" { return SCTP; }
-"vtag" { return VTAG; }
+"sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; }
+
+<SCANSTATE_SCTP>{
+ "vtag" { return VTAG; }
+}
"rt" { return RT; }
"rt0" { return RT0; }
--
2.31.1

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +0,0 @@
From 7ba8ea2cf06230e647b096f40d3006abec45f801 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 16:33:20 +0200
Subject: [PATCH] include: missing sctp_chunk.h in Makefile.am
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1979334
Upstream Status: nftables commit 117ceb4f52711
commit 117ceb4f527119a6d44bf5e23f2ff7a8d116658a
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Tue May 25 14:04:36 2021 +0200
include: missing sctp_chunk.h in Makefile.am
Fix make distcheck.
Fixes: 0e3871cfd9a1 ("exthdr: Implement SCTP Chunk matching")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/Makefile.am | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/Makefile.am b/include/Makefile.am
index 04a4a61..4ee5124 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -30,6 +30,7 @@ noinst_HEADERS = cli.h \
osf.h \
parser.h \
proto.h \
+ sctp_chunk.h \
socket.h \
rule.h \
rt.h \
--
2.31.1

View File

@ -1,71 +0,0 @@
From 5a735f26b0c6617b2851a7399c8ad118e89deba8 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 12 Jul 2021 16:34:38 +0200
Subject: [PATCH] doc: nft.8: Extend monitor description by trace
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1820365
Upstream Status: nftables commit 2acf8b2caea19
commit 2acf8b2caea19d8abd46d475a908f8d6afb33aa0
Author: Phil Sutter <phil@nwl.cc>
Date: Wed May 19 13:12:48 2021 +0200
doc: nft.8: Extend monitor description by trace
Briefly describe 'nft monitor trace' command functionality.
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
doc/nft.txt | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/doc/nft.txt b/doc/nft.txt
index abb9260..9cc35ee 100644
--- a/doc/nft.txt
+++ b/doc/nft.txt
@@ -734,13 +734,26 @@ These are some additional commands included in nft.
MONITOR
~~~~~~~~
The monitor command allows you to listen to Netlink events produced by the
-nf_tables subsystem, related to creation and deletion of objects. When they
+nf_tables subsystem. These are either related to creation and deletion of
+objects or to packets for which *meta nftrace* was enabled. When they
occur, nft will print to stdout the monitored events in either JSON or
native nft format. +
-To filter events related to a concrete object, use one of the keywords 'tables', 'chains', 'sets', 'rules', 'elements', 'ruleset'. +
+[verse]
+____
+*monitor* [*new* | *destroy*] 'MONITOR_OBJECT'
+*monitor* *trace*
+
+'MONITOR_OBJECT' := *tables* | *chains* | *sets* | *rules* | *elements* | *ruleset*
+____
+
+To filter events related to a concrete object, use one of the keywords in
+'MONITOR_OBJECT'.
-To filter events related to a concrete action, use keyword 'new' or 'destroy'.
+To filter events related to a concrete action, use keyword *new* or *destroy*.
+
+The second form of invocation takes no further options and exclusively prints
+events generated for packets with *nftrace* enabled.
Hit ^C to finish the monitor operation.
@@ -764,6 +777,12 @@ Hit ^C to finish the monitor operation.
% nft monitor ruleset
---------------------
+.Trace incoming packets from host 10.0.0.1
+------------------------------------------
+% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1
+% nft monitor trace
+------------------------------------------
+
ERROR REPORTING
---------------
When an error is detected, nft shows the line(s) containing the error, the
--
2.31.1

View File

@ -1,44 +0,0 @@
From e8300966510001e38f2b6530607bac2a93de5c2e Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Mon, 2 Aug 2021 14:35:08 +0200
Subject: [PATCH] tests: shell: Fix bogus testsuite failure with 100Hz
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1919203
Upstream Status: nftables commit c9c5b5f621c37
commit c9c5b5f621c37d17140dac682d211825ef321093
Author: Phil Sutter <phil@nwl.cc>
Date: Mon Jul 26 15:27:32 2021 +0200
tests: shell: Fix bogus testsuite failure with 100Hz
On kernels with CONFIG_HZ=100, clock granularity does not allow tracking
timeouts in single digit ms range. Change sets/0031set_timeout_size_0 to
not expose this detail.
Signed-off-by: Phil Sutter <phil@nwl.cc>
Acked-by: Florian Westphal <fw@strlen.de>
---
tests/shell/testcases/sets/0031set_timeout_size_0 | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/shell/testcases/sets/0031set_timeout_size_0 b/tests/shell/testcases/sets/0031set_timeout_size_0
index 9edd5f6..796640d 100755
--- a/tests/shell/testcases/sets/0031set_timeout_size_0
+++ b/tests/shell/testcases/sets/0031set_timeout_size_0
@@ -3,10 +3,10 @@
RULESET="add table x
add set x y { type ipv4_addr; size 128; timeout 30s; flags dynamic; }
add chain x test
-add rule x test set update ip saddr timeout 1d2h3m4s8ms @y
+add rule x test set update ip saddr timeout 1d2h3m4s10ms @y
add rule x test set update ip daddr timeout 100ms @y"
set -e
$NFT -f - <<< "$RULESET"
-$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s8ms }'
+$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s10ms }'
$NFT list chain x test | grep -q 'update @y { ip daddr timeout 100ms }'
--
2.31.1

View File

@ -1,100 +0,0 @@
From 8cb078a2f9f69259325c10f479c198349ef01ef2 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 6 Oct 2021 17:24:44 +0200
Subject: [PATCH] parser_json: Fix error reporting for invalid syntax
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1994141
Upstream Status: nftables commit 9fe5d1bc18cfa
commit 9fe5d1bc18cfaed2ecf717e3dd9a97ff5b0e183c
Author: Phil Sutter <phil@nwl.cc>
Date: Wed Sep 1 16:41:44 2021 +0200
parser_json: Fix error reporting for invalid syntax
Errors emitted by the JSON parser caused BUG() in erec_print() due to
input descriptor values being bogus.
Due to lack of 'include' support, JSON parser uses a single input
descriptor only and it lived inside the json_ctx object on stack of
nft_parse_json_*() functions.
By the time errors are printed though, that scope is not valid anymore.
Move the static input descriptor object to avoid this.
Fixes: 586ad210368b7 ("libnftables: Implement JSON parser")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/parser_json.c | 18 ++++++++----------
1 file changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index a069a89..ef4d4fb 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -44,7 +44,6 @@
#define CTX_F_CONCAT (1 << 8) /* inside concat_expr */
struct json_ctx {
- struct input_descriptor indesc;
struct nft_ctx *nft;
struct list_head *msgs;
struct list_head *cmds;
@@ -107,11 +106,12 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root);
/* parsing helpers */
const struct location *int_loc = &internal_location;
+static struct input_descriptor json_indesc;
static void json_lib_error(struct json_ctx *ctx, json_error_t *err)
{
struct location loc = {
- .indesc = &ctx->indesc,
+ .indesc = &json_indesc,
.line_offset = err->position - err->column,
.first_line = err->line,
.last_line = err->line,
@@ -3864,16 +3864,15 @@ int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
struct list_head *msgs, struct list_head *cmds)
{
struct json_ctx ctx = {
- .indesc = {
- .type = INDESC_BUFFER,
- .data = buf,
- },
.nft = nft,
.msgs = msgs,
.cmds = cmds,
};
int ret;
+ json_indesc.type = INDESC_BUFFER;
+ json_indesc.data = buf;
+
parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->json_root = json_loads(buf, 0, NULL);
if (!nft->json_root)
@@ -3892,10 +3891,6 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
struct list_head *msgs, struct list_head *cmds)
{
struct json_ctx ctx = {
- .indesc = {
- .type = INDESC_FILE,
- .name = filename,
- },
.nft = nft,
.msgs = msgs,
.cmds = cmds,
@@ -3903,6 +3898,9 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
json_error_t err;
int ret;
+ json_indesc.type = INDESC_FILE;
+ json_indesc.name = filename;
+
parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->json_root = json_load_file(filename, 0, &err);
if (!nft->json_root)
--
2.31.1

View File

@ -1,37 +0,0 @@
From bb4718fa421938c4a501b9a55df68de16a572f23 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 6 Oct 2021 17:32:04 +0200
Subject: [PATCH] parser_bison: Fix for implicit declaration of isalnum
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1999059
Upstream Status: nftables commit 7c3b2a7acbdc7
commit 7c3b2a7acbdc793b822a230ec0c28086c7d0365d
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Jun 11 16:03:32 2021 +0200
parser_bison: Fix for implicit declaration of isalnum
Have to include ctype.h to make it known.
Fixes: e76bb37940181 ("src: allow for variables in the log prefix string")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/parser_bison.y | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 5ab5744..d38ec30 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -10,6 +10,7 @@
%{
+#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <inttypes.h>
--
2.31.1

View File

@ -1,46 +0,0 @@
From 99d51194569f2784261f452ee821c42c3a7a6808 Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 6 Oct 2021 17:32:04 +0200
Subject: [PATCH] parser_json: Fix for memleak in tcp option error path
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1999059
Upstream Status: nftables commit f7b0eef8391ae
commit f7b0eef8391ae7f89a3a82f6eeecaebe199224d7
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Jun 11 16:07:02 2021 +0200
parser_json: Fix for memleak in tcp option error path
If 'kind' value is invalid, the function returned without freeing 'expr'
first. Fix this by performing the check before allocation.
Fixes: cb21869649208 ("json: tcp: add raw tcp option match support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/parser_json.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/parser_json.c b/src/parser_json.c
index ef4d4fb..2250be9 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -610,12 +610,12 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
"base", &kind, "offset", &offset, "len", &len)) {
uint32_t flag = 0;
- expr = tcpopt_expr_alloc(int_loc, kind,
- TCPOPT_COMMON_KIND);
-
if (kind < 0 || kind > 255)
return NULL;
+ expr = tcpopt_expr_alloc(int_loc, kind,
+ TCPOPT_COMMON_KIND);
+
if (offset == TCPOPT_COMMON_KIND && len == 8)
flag = NFT_EXTHDR_F_PRESENT;
--
2.31.1

View File

@ -1,37 +0,0 @@
From 5f30a3447d28381fdf534ff4ed90167455d1283b Mon Sep 17 00:00:00 2001
From: Phil Sutter <psutter@redhat.com>
Date: Wed, 6 Oct 2021 17:32:04 +0200
Subject: [PATCH] json: Drop pointless assignment in exthdr_expr_json()
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1999059
Upstream Status: nftables commit c1616dfd1ce40
commit c1616dfd1ce40bac197924c8947e1c646e915dca
Author: Phil Sutter <phil@nwl.cc>
Date: Fri Jun 11 16:23:22 2021 +0200
json: Drop pointless assignment in exthdr_expr_json()
The updated value of 'is_exists' is no longer read at this point.
Fixes: cb21869649208 ("json: tcp: add raw tcp option match support")
Signed-off-by: Phil Sutter <phil@nwl.cc>
---
src/json.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/json.c b/src/json.c
index dfc9031..ecec51c 100644
--- a/src/json.c
+++ b/src/json.c
@@ -679,7 +679,6 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
"base", expr->exthdr.raw_type,
"offset", expr->exthdr.offset,
"len", expr->len);
- is_exists = false;
}
return json_pack("{s:o}", "tcp option", root);
--
2.31.1

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