]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: allow to use integer type header fields via typeof set declaration
authorPablo Neira Ayuso <pablo@netfilter.org>
Mon, 28 Mar 2022 15:36:40 +0000 (17:36 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 29 Mar 2022 09:01:45 +0000 (11:01 +0200)
Header fields such as udp length cannot be used in concatenations because
it is using the generic integer_type:

 test.nft:3:10-19: Error: can not use variable sized data types (integer) in concat expressions
                typeof udp length . @th,32,32
                       ^^^^^^^^^^~~~~~~~~~~~~

This patch slightly extends ("src: allow to use typeof of raw expressions in
set declaration") to set on NFTNL_UDATA_SET_KEY_PAYLOAD_LEN in userdata if
TYPE_INTEGER is used.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c
src/payload.c
tests/shell/testcases/maps/dumps/typeof_integer_0.nft [new file with mode: 0644]
tests/shell/testcases/maps/typeof_integer_0 [new file with mode: 0755]

index 61dd4fea10e61a61999f51e00acd3778a75b1f43..6b3b63662411065ddebdd3e900a2f4ab7b01154f 100644 (file)
@@ -3970,7 +3970,7 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
                        return expr_error(ctx->msgs, i,
                                          "specify either ip or ip6 for address matching");
 
-               if (i->etype == EXPR_PAYLOAD && i->payload.is_raw &&
+               if (i->etype == EXPR_PAYLOAD &&
                    i->dtype->type == TYPE_INTEGER) {
                        struct datatype *dtype;
 
index fd6f7011365d9abe6820eff3eb4e8f6ee677d4b5..66418cddb3b5e2d03e3fba85301b287c166aafdd 100644 (file)
@@ -153,9 +153,9 @@ static int payload_expr_build_udata(struct nftnl_udata_buf *udbuf,
                                    expr->payload.base);
                nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET,
                                    expr->payload.offset);
-               nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_LEN,
-                                   expr->len);
        }
+       if (expr->dtype->type == TYPE_INTEGER)
+               nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_LEN, expr->len);
 
        return 0;
 }
@@ -191,7 +191,7 @@ static int payload_parse_udata(const struct nftnl_udata *attr, void *data)
 static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
 {
        const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_PAYLOAD_MAX + 1] = {};
-       unsigned int type, base, offset, len;
+       unsigned int type, base, offset, len = 0;
        const struct proto_desc *desc;
        bool is_raw = false;
        struct expr *expr;
@@ -209,20 +209,23 @@ static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
        desc = find_proto_desc(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_DESC]);
        if (!desc) {
                if (!ud[NFTNL_UDATA_SET_KEY_PAYLOAD_BASE] ||
-                   !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET] ||
-                   !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN])
+                   !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET])
                        return NULL;
 
                base = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_BASE]);
                offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET]);
-               len = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN]);
                is_raw = true;
        }
 
        type = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE]);
+       if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN])
+               len = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN]);
 
        expr = payload_expr_alloc(&internal_location, desc, type);
 
+       if (len)
+               expr->len = len;
+
        if (is_raw) {
                struct datatype *dtype;
 
diff --git a/tests/shell/testcases/maps/dumps/typeof_integer_0.nft b/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
new file mode 100644 (file)
index 0000000..3304155
--- /dev/null
@@ -0,0 +1,20 @@
+table inet t {
+       map m1 {
+               typeof udp length . @ih,32,32 : verdict
+               flags interval
+               elements = { 20-80 . 0x14 : accept,
+                            1-10 . 0xa : drop }
+       }
+
+       map m2 {
+               typeof udp length . @ih,32,32 : verdict
+               elements = { 30 . 0x1e : drop,
+                            20 . 0x24 : accept }
+       }
+
+       chain c {
+               udp length . @ih,32,32 vmap @m1
+               udp length . @ih,32,32 vmap @m2
+               udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+       }
+}
diff --git a/tests/shell/testcases/maps/typeof_integer_0 b/tests/shell/testcases/maps/typeof_integer_0
new file mode 100755 (executable)
index 0000000..d51510a
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+EXPECTED="table inet t {
+       map m1 {
+               typeof udp length . @ih,32,32 : verdict
+               flags interval
+               elements = { 20-80 . 0x14 : accept, 1-10 . 0xa : drop }
+       }
+
+       map m2 {
+               typeof udp length . @ih,32,32 : verdict
+               elements = { 20 . 0x24 : accept, 30 . 0x1e : drop }
+       }
+
+       chain c {
+               udp length . @ih,32,32 vmap @m1
+               udp length . @ih,32,32 vmap @m2
+               udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+       }
+}"
+
+$NFT add element inet t m1 { 90-100 . 40 : drop }
+$NFT delete element inet t m2 { 20 . 20 : accept }
+
+set -e
+$NFT -f - <<< $EXPECTED
+