* [PATCH nft v3 0/2] Support for variables in map expressions
@ 2024-04-29 19:27 Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 1/2] evaluate: handle invalid mapping expressions in stateful object statements gracefully Jeremy Sowden
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Jeremy Sowden @ 2024-04-29 19:27 UTC (permalink / raw)
To: Netfilter Devel
The first patch replaces the current assertion failure for invalid
mapping expression in stateful-object statements with an error message.
This brings it in line with map statements.
It is possible to use a variable to initialize a map, which is then used
in a map statement, but if one tries to use the variable directly, nft
rejects it. The second patch adds support for doing this.
Changes since v2
* Patch 2: error-checking (and test-cases) added for variables that do
not contain maps
Changes since v1
* Patch 1 is new.
* Patch 2 updated to add support for map variables in stateful object
statements.
Jeremy Sowden (2):
evaluate: handle invalid mapping expressions in stateful object
statements gracefully.
evaluate: add support for variables in map expressions
src/evaluate.c | 17 +-
.../shell/testcases/maps/0024named_objects_1 | 31 ++++
.../shell/testcases/maps/0024named_objects_2 | 23 +++
.../shell/testcases/maps/anonymous_snat_map_1 | 16 ++
.../shell/testcases/maps/anonymous_snat_map_2 | 23 +++
.../maps/dumps/0024named_objects_1.json-nft | 147 ++++++++++++++++++
.../maps/dumps/0024named_objects_1.nft | 23 +++
.../maps/dumps/anonymous_snat_map_1.json-nft | 58 +++++++
.../maps/dumps/anonymous_snat_map_1.nft | 5 +
9 files changed, 341 insertions(+), 2 deletions(-)
create mode 100755 tests/shell/testcases/maps/0024named_objects_1
create mode 100755 tests/shell/testcases/maps/0024named_objects_2
create mode 100755 tests/shell/testcases/maps/anonymous_snat_map_1
create mode 100755 tests/shell/testcases/maps/anonymous_snat_map_2
create mode 100644 tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/0024named_objects_1.nft
create mode 100644 tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH nft v3 1/2] evaluate: handle invalid mapping expressions in stateful object statements gracefully.
2024-04-29 19:27 [PATCH nft v3 0/2] Support for variables in map expressions Jeremy Sowden
@ 2024-04-29 19:27 ` Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 2/2] evaluate: add support for variables in map expressions Jeremy Sowden
2024-05-23 16:23 ` [PATCH nft v3 0/2] Support " Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Jeremy Sowden @ 2024-04-29 19:27 UTC (permalink / raw)
To: Netfilter Devel
Currently, they are reported as assertion failures:
BUG: invalid mapping expression variable
nft: src/evaluate.c:4618: stmt_evaluate_objref_map: Assertion `0' failed.
Aborted
Instead, report them more informatively as errors:
/space/azazel/tmp/ruleset.1067161.nft:15:29-38: Error: invalid mapping expression variable
quota name ip saddr map $quota_map
~~~~~~~~ ^^^^^^^^^^
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
---
src/evaluate.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/evaluate.c b/src/evaluate.c
index 1682ba58989e..f28ef2aad8f4 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -4615,8 +4615,9 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
"Expression is not a map with objects");
break;
default:
- BUG("invalid mapping expression %s\n",
- expr_name(map->mappings));
+ return expr_binary_error(ctx->msgs, map->mappings, map->map,
+ "invalid mapping expression %s",
+ expr_name(map->mappings));
}
if (!datatype_compatible(map->mappings->set->key->dtype, map->map->dtype))
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH nft v3 2/2] evaluate: add support for variables in map expressions
2024-04-29 19:27 [PATCH nft v3 0/2] Support for variables in map expressions Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 1/2] evaluate: handle invalid mapping expressions in stateful object statements gracefully Jeremy Sowden
@ 2024-04-29 19:27 ` Jeremy Sowden
2024-05-23 16:23 ` [PATCH nft v3 0/2] Support " Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Jeremy Sowden @ 2024-04-29 19:27 UTC (permalink / raw)
To: Netfilter Devel
It is possible to use a variable to initialize a map, which is then used
in a map statement:
define dst_map = { ::1234 : 5678 }
table ip6 nat {
map dst_map {
typeof ip6 daddr : tcp dport;
elements = $dst_map
}
chain prerouting {
ip6 nexthdr tcp redirect to ip6 daddr map @dst_map
}
}
However, if one tries to use the variable directly in the statement:
define dst_map = { ::1234 : 5678 }
table ip6 nat {
chain prerouting {
ip6 nexthdr tcp redirect to ip6 daddr map $dst_map
}
}
nft rejects it:
/space/azazel/tmp/ruleset.1067161.nft:5:47-54: Error: invalid mapping expression variable
ip6 nexthdr tcp redirect to ip6 daddr map $dst_map
~~~~~~~~~ ^^^^^^^^
It also rejects variables in stateful object statements:
define quota_map = { 192.168.10.123 : "user123", 192.168.10.124 : "user124" }
table ip nat {
quota user123 { over 20 mbytes }
quota user124 { over 20 mbytes }
chain prerouting {
quota name ip saddr map $quota_map
}
}
thus:
/space/azazel/tmp/ruleset.1067161.nft:15:29-38: Error: invalid mapping expression variable
quota name ip saddr map $quota_map
~~~~~~~~ ^^^^^^^^^^
Add support for these uses together with some test-cases.
Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1067161
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
---
src/evaluate.c | 12 ++
.../shell/testcases/maps/0024named_objects_1 | 31 ++++
.../shell/testcases/maps/0024named_objects_2 | 23 +++
.../shell/testcases/maps/anonymous_snat_map_1 | 16 ++
.../shell/testcases/maps/anonymous_snat_map_2 | 23 +++
.../maps/dumps/0024named_objects_1.json-nft | 147 ++++++++++++++++++
.../maps/dumps/0024named_objects_1.nft | 23 +++
.../maps/dumps/anonymous_snat_map_1.json-nft | 58 +++++++
.../maps/dumps/anonymous_snat_map_1.nft | 5 +
9 files changed, 338 insertions(+)
create mode 100755 tests/shell/testcases/maps/0024named_objects_1
create mode 100755 tests/shell/testcases/maps/0024named_objects_2
create mode 100755 tests/shell/testcases/maps/anonymous_snat_map_1
create mode 100755 tests/shell/testcases/maps/anonymous_snat_map_2
create mode 100644 tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/0024named_objects_1.nft
create mode 100644 tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft
diff --git a/src/evaluate.c b/src/evaluate.c
index f28ef2aad8f4..f26bc7f9b0ed 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2061,6 +2061,7 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
mappings->set_flags |= NFT_SET_MAP;
switch (map->mappings->etype) {
+ case EXPR_VARIABLE:
case EXPR_SET:
if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) {
key = expr_clone(ctx->ectx.key);
@@ -2104,6 +2105,11 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
return -1;
+ if (map->mappings->set->init->etype != EXPR_SET) {
+ return expr_error(ctx->msgs, map->mappings->set->init,
+ "Expression is not a map");
+ }
+
if (set_is_interval(map->mappings->set->init->set_flags) &&
!(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
@@ -4576,6 +4582,7 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
mappings->set_flags |= NFT_SET_OBJECT;
switch (map->mappings->etype) {
+ case EXPR_VARIABLE:
case EXPR_SET:
key = constant_expr_alloc(&stmt->location,
ctx->ectx.dtype,
@@ -4595,6 +4602,11 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
return -1;
+ if (map->mappings->set->init->etype != EXPR_SET) {
+ return expr_error(ctx->msgs, map->mappings->set->init,
+ "Expression is not a map");
+ }
+
if (set_is_interval(map->mappings->set->init->set_flags) &&
!(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
diff --git a/tests/shell/testcases/maps/0024named_objects_1 b/tests/shell/testcases/maps/0024named_objects_1
new file mode 100755
index 000000000000..a861e9e2d4a0
--- /dev/null
+++ b/tests/shell/testcases/maps/0024named_objects_1
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# This is the test-case:
+# * creating valid named objects and using map variables in statements
+
+RULESET='
+define counter_map = { 192.168.2.2 : "user123", 1.1.1.1 : "user123", 2.2.2.2 : "user123" }
+define quota_map = { 192.168.2.2 : "user124", 192.168.2.3 : "user124" }
+
+table inet x {
+ counter user123 {
+ packets 12 bytes 1433
+ }
+ counter user321 {
+ packets 12 bytes 1433
+ }
+ quota user123 {
+ over 2000 bytes
+ }
+ quota user124 {
+ over 2000 bytes
+ }
+ chain y {
+ type filter hook input priority 0; policy accept;
+ counter name ip saddr map $counter_map
+ quota name ip saddr map $quota_map drop
+ }
+}'
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/maps/0024named_objects_2 b/tests/shell/testcases/maps/0024named_objects_2
new file mode 100755
index 000000000000..584b5100f650
--- /dev/null
+++ b/tests/shell/testcases/maps/0024named_objects_2
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+#
+# Test some error conditions for using variables to define maps
+#
+
+set -e
+
+for m in "192.168.2.2" "{ 192.168.2.2, 1.1.1.1, 2.2.2.2 }"; do
+
+ RULESET="
+define m = $m"'
+table inet x {
+ chain y {
+ type filter hook input priority 0; policy accept;
+ counter name ip saddr map $m
+ }
+}'
+
+ $NFT -f - <<< "$RULESET" || rc=$?
+ test $rc = 1
+
+done
diff --git a/tests/shell/testcases/maps/anonymous_snat_map_1 b/tests/shell/testcases/maps/anonymous_snat_map_1
new file mode 100755
index 000000000000..031de0c1a83f
--- /dev/null
+++ b/tests/shell/testcases/maps/anonymous_snat_map_1
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# Variable containing anonymous map can be added to a snat rule
+
+set -e
+
+RULESET='
+define m = {1.1.1.1 : 2.2.2.2}
+table nat {
+ chain postrouting {
+ snat ip saddr map $m
+ }
+}
+'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/maps/anonymous_snat_map_2 b/tests/shell/testcases/maps/anonymous_snat_map_2
new file mode 100755
index 000000000000..90e02038093c
--- /dev/null
+++ b/tests/shell/testcases/maps/anonymous_snat_map_2
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+#
+# Test some error conditions for using variables to define maps
+#
+
+set -e
+
+for m in "1.1.1.1" "{1.1.1.1}"; do
+
+ RULESET="
+define m = $m"'
+table nat {
+ chain postrouting {
+ snat ip saddr map $m
+ }
+}
+'
+
+ $NFT -f - <<< "$RULESET" || rc=$?
+ test $rc = 1
+
+done
diff --git a/tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft b/tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft
new file mode 100644
index 000000000000..e3fab16d3337
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0024named_objects_1.json-nft
@@ -0,0 +1,147 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "user123",
+ "table": "x",
+ "handle": 0,
+ "packets": 12,
+ "bytes": 1433
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "user321",
+ "table": "x",
+ "handle": 0,
+ "packets": 12,
+ "bytes": 1433
+ }
+ },
+ {
+ "quota": {
+ "family": "inet",
+ "name": "user123",
+ "table": "x",
+ "handle": 0,
+ "bytes": 2000,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "quota": {
+ "family": "inet",
+ "name": "user124",
+ "table": "x",
+ "handle": 0,
+ "bytes": 2000,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ "user123"
+ ],
+ [
+ "2.2.2.2",
+ "user123"
+ ],
+ [
+ "192.168.2.2",
+ "user123"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "quota": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "192.168.2.2",
+ "user124"
+ ],
+ [
+ "192.168.2.3",
+ "user124"
+ ]
+ ]
+ }
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0024named_objects_1.nft b/tests/shell/testcases/maps/dumps/0024named_objects_1.nft
new file mode 100644
index 000000000000..a8e99a3ca9a2
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0024named_objects_1.nft
@@ -0,0 +1,23 @@
+table inet x {
+ counter user123 {
+ packets 12 bytes 1433
+ }
+
+ counter user321 {
+ packets 12 bytes 1433
+ }
+
+ quota user123 {
+ over 2000 bytes
+ }
+
+ quota user124 {
+ over 2000 bytes
+ }
+
+ chain y {
+ type filter hook input priority filter; policy accept;
+ counter name ip saddr map { 1.1.1.1 : "user123", 2.2.2.2 : "user123", 192.168.2.2 : "user123" }
+ quota name ip saddr map { 192.168.2.2 : "user124", 192.168.2.3 : "user124" } drop
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft
new file mode 100644
index 000000000000..f4c55706787c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.json-nft
@@ -0,0 +1,58 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "nat",
+ "name": "postrouting",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "nat",
+ "chain": "postrouting",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft
new file mode 100644
index 000000000000..5009560c9d69
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anonymous_snat_map_1.nft
@@ -0,0 +1,5 @@
+table ip nat {
+ chain postrouting {
+ snat to ip saddr map { 1.1.1.1 : 2.2.2.2 }
+ }
+}
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH nft v3 0/2] Support for variables in map expressions
2024-04-29 19:27 [PATCH nft v3 0/2] Support for variables in map expressions Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 1/2] evaluate: handle invalid mapping expressions in stateful object statements gracefully Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 2/2] evaluate: add support for variables in map expressions Jeremy Sowden
@ 2024-05-23 16:23 ` Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2024-05-23 16:23 UTC (permalink / raw)
To: Jeremy Sowden; +Cc: Netfilter Devel
On Mon, Apr 29, 2024 at 08:27:51PM +0100, Jeremy Sowden wrote:
> The first patch replaces the current assertion failure for invalid
> mapping expression in stateful-object statements with an error message.
> This brings it in line with map statements.
>
> It is possible to use a variable to initialize a map, which is then used
> in a map statement, but if one tries to use the variable directly, nft
> rejects it. The second patch adds support for doing this.
LGTM, thanks for your patience.
Applied thanks.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-05-23 16:23 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-29 19:27 [PATCH nft v3 0/2] Support for variables in map expressions Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 1/2] evaluate: handle invalid mapping expressions in stateful object statements gracefully Jeremy Sowden
2024-04-29 19:27 ` [PATCH nft v3 2/2] evaluate: add support for variables in map expressions Jeremy Sowden
2024-05-23 16:23 ` [PATCH nft v3 0/2] Support " Pablo Neira Ayuso
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).