* [PATCH nft 2/3] netlink: allow typeof keywords with objref maps during listing
2024-02-29 10:41 [PATCH nft 0/3] nftables: add typeof support for objref maps Florian Westphal
2024-02-29 10:41 ` [PATCH nft 1/3] parser: allow typeof in " Florian Westphal
@ 2024-02-29 10:41 ` Florian Westphal
2024-02-29 10:41 ` [PATCH nft 3/3] tests: maps: add a test case for "limit" objref map Florian Westphal
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-02-29 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
Without this,
typeof meta l4proto . ip saddr . tcp sport : limit
... is shown as
type inet_proto . ipv4_addr . inet_service : limit
The "data" element is a value (the object type number).
It doesn't support userinfo data.
There is no reason to add it, the value is the object type
number that the object-reference map stores.
So, if we have an objref map, DO NOT discard the key part,
as we do for normal maps.
For normal maps, we support either typeof notation, i.e.:
typeof meta l4proto . ip saddr . tcp sport : ip saddr
or the data type version:
type inet_proto . ipv4_addr . inet_service : ipv4_addr
... but not a mix, a hyptothetical
typeof meta l4proto . ip saddr . tcp sport : ipv4_addr
... does not work.
If nft finds no udata attached to the data element, for normal
map case, it has to fall back to the "type" form.
But for objref maps this is expected, udata for key but not for data.
Hence, for objref case, keep the typeof part if its valid.
Signed-off-by: Florian Westphal <fw@strlen.de>
---
src/netlink.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/netlink.c b/src/netlink.c
index 3d685b575e64..0088b742d573 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1044,6 +1044,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
}
list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list);
+ set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+
if (datatype) {
uint32_t dlen;
@@ -1056,6 +1058,11 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
typeof_expr_data->len = klen;
set->data = typeof_expr_data;
typeof_expr_data = NULL;
+ } else if (set->flags & NFT_SET_OBJECT) {
+ set->data = constant_expr_alloc(&netlink_location,
+ dtype2,
+ databyteorder, klen,
+ NULL);
} else {
set->data = constant_expr_alloc(&netlink_location,
dtype2,
@@ -1084,7 +1091,6 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
NULL);
}
- set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
set->objtype = objtype;
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH nft 3/3] tests: maps: add a test case for "limit" objref map
2024-02-29 10:41 [PATCH nft 0/3] nftables: add typeof support for objref maps Florian Westphal
2024-02-29 10:41 ` [PATCH nft 1/3] parser: allow typeof in " Florian Westphal
2024-02-29 10:41 ` [PATCH nft 2/3] netlink: allow typeof keywords with objref maps during listing Florian Westphal
@ 2024-02-29 10:41 ` Florian Westphal
2 siblings, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2024-02-29 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: Florian Westphal
check add, delete and removal operations for objref maps.
Also check type vs. typeof declarations and use both
interval and interval+concatenation (rbtree, pipapo).
Signed-off-by: Florian Westphal <fw@strlen.de>
---
.../maps/dumps/named_limits.json-nft | 328 ++++++++++++++++++
.../testcases/maps/dumps/named_limits.nft | 55 +++
tests/shell/testcases/maps/named_limits | 59 ++++
3 files changed, 442 insertions(+)
create mode 100644 tests/shell/testcases/maps/dumps/named_limits.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/named_limits.nft
create mode 100755 tests/shell/testcases/maps/named_limits
diff --git a/tests/shell/testcases/maps/dumps/named_limits.json-nft b/tests/shell/testcases/maps/dumps/named_limits.json-nft
new file mode 100644
index 000000000000..28a92529c8d2
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_limits.json-nft
@@ -0,0 +1,328 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "tarpit-pps",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "burst": 5
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "tarpit-bps",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "rate_unit": "kbytes"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "http-bulk-rl-1m",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "rate_unit": "mbytes"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "http-bulk-rl-10m",
+ "table": "filter",
+ "handle": 0,
+ "rate": 10,
+ "per": "second",
+ "rate_unit": "mbytes"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tarpit4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 10000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tarpit6",
+ "table": "filter",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "size": 10000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "addr4limit",
+ "table": "filter",
+ "type": [
+ "inet_proto",
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "map": "limit",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ ]
+ },
+ "tarpit-bps"
+ ],
+ [
+ {
+ "concat": [
+ "udp",
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ ]
+ },
+ "tarpit-pps"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "127.0.0.1",
+ "127.1.2.3"
+ ]
+ },
+ {
+ "range": [
+ 1,
+ 1024
+ ]
+ }
+ ]
+ },
+ "tarpit-pps"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.255"
+ ]
+ },
+ 80
+ ]
+ },
+ "http-bulk-rl-1m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.255"
+ ]
+ },
+ 443
+ ]
+ },
+ "http-bulk-rl-1m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "prefix": {
+ "addr": "10.0.1.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ ]
+ },
+ "http-bulk-rl-10m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ "10.0.2.1",
+ 22
+ ]
+ },
+ "http-bulk-rl-10m"
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "saddr6limit",
+ "table": "filter",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "map": "limit",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "range": [
+ "dead::beef",
+ "dead::1:aced"
+ ]
+ },
+ "tarpit-pps"
+ ]
+ ]
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "sport"
+ }
+ }
+ ]
+ },
+ "data": "@addr4limit"
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ "data": "@saddr6limit"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/named_limits.nft b/tests/shell/testcases/maps/dumps/named_limits.nft
new file mode 100644
index 000000000000..214df204b770
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_limits.nft
@@ -0,0 +1,55 @@
+table inet filter {
+ limit tarpit-pps {
+ rate 1/second
+ }
+
+ limit tarpit-bps {
+ rate 1 kbytes/second
+ }
+
+ limit http-bulk-rl-1m {
+ rate 1 mbytes/second
+ }
+
+ limit http-bulk-rl-10m {
+ rate 10 mbytes/second
+ }
+
+ set tarpit4 {
+ typeof ip saddr
+ size 10000
+ flags dynamic,timeout
+ timeout 1m
+ }
+
+ set tarpit6 {
+ typeof ip6 saddr
+ size 10000
+ flags dynamic,timeout
+ timeout 1m
+ }
+
+ map addr4limit {
+ typeof meta l4proto . ip saddr . tcp sport : limit
+ flags interval
+ elements = { tcp . 192.168.0.0/16 . 1-65535 : "tarpit-bps",
+ udp . 192.168.0.0/16 . 1-65535 : "tarpit-pps",
+ tcp . 127.0.0.1-127.1.2.3 . 1-1024 : "tarpit-pps",
+ tcp . 10.0.0.1-10.0.0.255 . 80 : "http-bulk-rl-1m",
+ tcp . 10.0.0.1-10.0.0.255 . 443 : "http-bulk-rl-1m",
+ tcp . 10.0.1.0/24 . 1024-65535 : "http-bulk-rl-10m",
+ tcp . 10.0.2.1 . 22 : "http-bulk-rl-10m" }
+ }
+
+ map saddr6limit {
+ typeof ip6 saddr : limit
+ flags interval
+ elements = { dead::beef-dead::1:aced : "tarpit-pps" }
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ limit name meta l4proto . ip saddr . th sport map @addr4limit
+ limit name ip6 saddr map @saddr6limit
+ }
+}
diff --git a/tests/shell/testcases/maps/named_limits b/tests/shell/testcases/maps/named_limits
new file mode 100755
index 000000000000..5604f6caeda6
--- /dev/null
+++ b/tests/shell/testcases/maps/named_limits
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile" || exit 1
+
+add_add_then_create()
+{
+ cmd="$@"
+
+ $NFT "add element inet filter $cmd" || exit 2
+
+ # again, kernel should suppress -EEXIST
+ $NFT "add element inet filter $cmd" || exit 3
+
+ # AGAIN, kernel should report -EEXIST
+ $NFT "create element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 4
+}
+
+add_create_dupe()
+{
+ cmd="$@"
+
+ $NFT "add element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 10
+ $NFT "create element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 11
+}
+
+delete()
+{
+ cmd="$@"
+
+ $NFT "delete element inet filter $cmd" || exit 30
+ $NFT "delete element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 31
+
+ # destroy should NOT report an error
+# $NFT "destroy element inet filter $cmd" || exit 40
+}
+
+add_add_then_create 'saddr6limit { fee1::dead : "tarpit-pps" }'
+add_add_then_create 'saddr6limit { c01a::/64 : "tarpit-bps" }'
+
+# test same with a diffent set type (concat + interval)
+add_add_then_create 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "tarpit-pps" }'
+
+# now test duplicate key with *DIFFERENT* limiter, should fail
+add_create_dupe 'saddr6limit { fee1::dead : "tarpit-bps" }'
+
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 43 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.5 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-bps", tcp . 1.2.3.4 . 42 : "tarpit-pps" }'
+
+# delete keys again
+delete 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 :"tarpit-pps" }'
+
+delete 'saddr6limit { fee1::dead : "tarpit-pps" }'
+delete 'saddr6limit { c01a::/64 : "tarpit-bps" }'
+
+exit 0
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread