]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
evaluate: relax type-checking for integer arguments in mark statements
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 17 Mar 2023 09:16:46 +0000 (10:16 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 28 Mar 2023 08:26:34 +0000 (10:26 +0200)
In order to be able to set ct and meta marks to values derived from
payload expressions, we need to relax the requirement that the type of
the statement argument must match that of the statement key.  Instead,
we require that the base-type of the argument is integer and that the
argument is small enough to fit.

Moreover, swap expression byteorder before to make it compatible with
the statement byteorder, to ensure rulesets are portable.

 # nft --debug=netlink add rule ip t c 'meta mark set ip saddr'
 ip t c
  [ payload load 4b @ network header + 12 => reg 1 ]
  [ byteorder reg 1 = ntoh(reg 1, 4, 4) ] <----------- byteorder swap
  [ meta set mark with reg 1 ]

Based on original work from Jeremy Sowden.

The following patches are required for this to work:

evaluate: get length from statement instead of lhs expression
evaluate: don't eval unary arguments
evaluate: support shifts larger than the width of the left operand
netlink_delinearize: correct type and byte-order of shifts
evaluate: insert byte-order conversions for expressions between 9 and 15 bits

Add one testcase for tests/py.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c
tests/py/ip/meta.t
tests/py/ip/meta.t.json
tests/py/ip/meta.t.payload

index e0263f97dcf889f6f6d3fcc435067b81c2dec7a5..33b1aad72f66327bb77a8d4fb0c2c8278b6534e3 100644 (file)
@@ -2743,13 +2743,22 @@ static int __stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
                                         "expression has type %s with length %d",
                                         dtype->desc, (*expr)->dtype->desc,
                                         (*expr)->len);
-       else if ((*expr)->dtype->type != TYPE_INTEGER &&
-                !datatype_equal((*expr)->dtype, dtype))
+
+       if ((dtype->type == TYPE_MARK &&
+            !datatype_equal(datatype_basetype(dtype), datatype_basetype((*expr)->dtype))) ||
+           (dtype->type != TYPE_MARK &&
+            (*expr)->dtype->type != TYPE_INTEGER &&
+            !datatype_equal((*expr)->dtype, dtype)))
                return stmt_binary_error(ctx, *expr, stmt,              /* verdict vs invalid? */
                                         "datatype mismatch: expected %s, "
                                         "expression has type %s",
                                         dtype->desc, (*expr)->dtype->desc);
 
+       if (dtype->type == TYPE_MARK &&
+           datatype_equal(datatype_basetype(dtype), datatype_basetype((*expr)->dtype)) &&
+           !expr_is_constant(*expr))
+               return byteorder_conversion(ctx, expr, byteorder);
+
        /* we are setting a value, we can't use a set */
        switch ((*expr)->etype) {
        case EXPR_SET:
index 5a05923a1ce135efba48868d43b13c007b9ccfce..85eaf54ce72339031a69aaf9cbfd9b75c71c5e2d 100644 (file)
@@ -15,3 +15,5 @@ meta obrname "br0";fail
 
 meta sdif "lo" accept;ok
 meta sdifname != "vrf1" accept;ok
+
+meta mark set ip dscp;ok
index 3df31ce381fc80e7c7ac520402a3c166ce68d5d5..a93d7e781ce1123121140a2cf26bff8c1434fb45 100644 (file)
         }
     }
 ]
+
+# meta mark set ip dscp
+[
+    {
+        "mangle": {
+            "key": {
+                "meta": {
+                    "key": "mark"
+                }
+            },
+            "value": {
+                "payload": {
+                    "field": "dscp",
+                    "protocol": "ip"
+                }
+            }
+        }
+    }
+]
+
index afde5cc13ac5e0334d20046846342327028109f5..1aa8d003b1d44ab5aeaa5f63b93be8cea33edc1f 100644 (file)
@@ -51,3 +51,11 @@ ip test-ip4 input
   [ cmp eq reg 1 0x00000011 ]
   [ payload load 2b @ transport header + 2 => reg 1 ]
   [ cmp eq reg 1 0x00004300 ]
+
+# meta mark set ip dscp
+ip test-ip4 input
+  [ payload load 1b @ network header + 1 => reg 1 ]
+  [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+  [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+  [ meta set mark with reg 1 ]
+