]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
netlink: dynset: set compound expr dtype based on set key definition
authorFlorian Westphal <fw@strlen.de>
Tue, 28 Sep 2021 19:34:30 +0000 (21:34 +0200)
committerFlorian Westphal <fw@strlen.de>
Wed, 29 Sep 2021 16:31:34 +0000 (18:31 +0200)
"nft add rule ... add @t { ip saddr . 22 ..." will be listed as
'ip saddr . 0x16  [ invalid type]".

This is a display bug, the compound expression created during netlink
deserialization lacks correct datatypes for the value expression.

Avoid this by setting the individual expressions' datatype.
The set key has the needed information, so walk over the types and set
them in the dynset statment.

Also add a test case.

Reported-by: Paulo Ricardo Bruck <paulobruck1@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
src/netlink_delinearize.c
tests/shell/testcases/sets/0045concat_ipv4_service [new file with mode: 0755]
tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft [new file with mode: 0644]

index bd75ad5cbe1e07241b8d5b1b8c23267c9d9d771d..0c2b439eac6fbafded417e89c486b229f01ab974 100644 (file)
@@ -134,6 +134,50 @@ err:
        return NULL;
 }
 
+static struct expr *netlink_parse_concat_key(struct netlink_parse_ctx *ctx,
+                                              const struct location *loc,
+                                              unsigned int reg,
+                                              const struct expr *key)
+{
+       uint32_t type = key->dtype->type;
+       unsigned int n, len = key->len;
+       struct expr *concat, *expr;
+       unsigned int consumed;
+
+       concat = concat_expr_alloc(loc);
+       n = div_round_up(fls(type), TYPE_BITS);
+
+       while (len > 0) {
+               const struct datatype *i;
+
+               expr = netlink_get_register(ctx, loc, reg);
+               if (expr == NULL) {
+                       netlink_error(ctx, loc,
+                                     "Concat expression size mismatch");
+                       goto err;
+               }
+
+               if (n > 0 && concat_subtype_id(type, --n)) {
+                       i = concat_subtype_lookup(type, n);
+
+                       expr_set_type(expr, i, i->byteorder);
+               }
+
+               compound_expr_add(concat, expr);
+
+               consumed = netlink_padded_len(expr->len);
+               assert(consumed > 0);
+               len -= consumed;
+               reg += netlink_register_space(expr->len);
+       }
+
+       return concat;
+
+err:
+       expr_free(concat);
+       return NULL;
+}
+
 static struct expr *netlink_parse_concat_data(struct netlink_parse_ctx *ctx,
                                              const struct location *loc,
                                              unsigned int reg,
@@ -1572,7 +1616,7 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
 
        if (expr->len < set->key->len) {
                expr_free(expr);
-               expr = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
+               expr = netlink_parse_concat_key(ctx, loc, sreg, set->key);
                if (expr == NULL)
                        return;
        }
diff --git a/tests/shell/testcases/sets/0045concat_ipv4_service b/tests/shell/testcases/sets/0045concat_ipv4_service
new file mode 100755 (executable)
index 0000000..5b40f97
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+$NFT -f - <<EOF
+table inet t {
+       set s {
+               type ipv4_addr . inet_service
+               size 65536
+               flags dynamic,timeout
+               elements = { 192.168.7.1 . 22 }
+       }
+
+       chain c {
+               tcp dport 21 add @s { ip saddr . 22 timeout 60s }
+       }
+}
+EOF
diff --git a/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft
new file mode 100644 (file)
index 0000000..e548a17
--- /dev/null
@@ -0,0 +1,12 @@
+table inet t {
+       set s {
+               type ipv4_addr . inet_service
+               size 65536
+               flags dynamic,timeout
+               elements = { 192.168.7.1 . 22 }
+       }
+
+       chain c {
+               tcp dport 21 add @s { ip saddr . 22 timeout 1m }
+       }
+}