From c6127ff0c4480ccefc5c29548409898fb315a2ca Mon Sep 17 00:00:00 2001 From: Jeremy Sowden Date: Mon, 29 Apr 2024 20:27:53 +0100 Subject: evaluate: add support for variables in map expressions 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 Signed-off-by: Pablo Neira Ayuso --- tests/shell/testcases/maps/0024named_objects_1 | 31 +++++ tests/shell/testcases/maps/0024named_objects_2 | 23 ++++ tests/shell/testcases/maps/anonymous_snat_map_1 | 16 +++ tests/shell/testcases/maps/anonymous_snat_map_2 | 23 ++++ .../maps/dumps/0024named_objects_1.json-nft | 147 +++++++++++++++++++++ .../testcases/maps/dumps/0024named_objects_1.nft | 23 ++++ .../maps/dumps/anonymous_snat_map_1.json-nft | 58 ++++++++ .../testcases/maps/dumps/anonymous_snat_map_1.nft | 5 + 8 files changed, 326 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 (limited to 'tests') diff --git a/tests/shell/testcases/maps/0024named_objects_1 b/tests/shell/testcases/maps/0024named_objects_1 new file mode 100755 index 00000000..a861e9e2 --- /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 00000000..584b5100 --- /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 00000000..031de0c1 --- /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 00000000..90e02038 --- /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 00000000..e3fab16d --- /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 00000000..a8e99a3c --- /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 00000000..f4c55706 --- /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 00000000..5009560c --- /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 } + } +} -- cgit v1.2.3