]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: support for selectors with different byteorder with interval concatenations
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 23 Nov 2022 16:59:21 +0000 (17:59 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 30 Nov 2022 11:50:00 +0000 (12:50 +0100)
Assuming the following interval set with concatenation:

 set test {
typeof ip saddr . meta mark
flags interval
 }

then, the following rule:

 ip saddr . meta mark @test

requires bytecode that swaps the byteorder for the meta mark selector in
case the set contains intervals and concatenations.

 inet x y
   [ meta load nfproto => reg 1 ]
   [ cmp eq reg 1 0x00000002 ]
   [ payload load 4b @ network header + 12 => reg 1 ]
   [ meta load mark => reg 9 ]
   [ byteorder reg 9 = hton(reg 9, 4, 4) ]  <----- this is required !
   [ lookup reg 1 set test dreg 0 ]

This patch updates byteorder_conversion() to add the unary expression
that introduces the byteorder expression.

Moreover, store the meta mark range component of the element tuple in
the set in big endian as it is required for the range comparisons. Undo
the byteorder swap in the netlink delinearize path to listing the meta
mark values accordingly.

Update tests/py to validate that byteorder expression is emitted in the
bytecode. Update tests/shell to validate insertion and listing of a
named map declaration.

A similar commit 806ab081dc9a ("netlink: swap byteorder for
host-endian concat data") already exists in the tree to handle this for
strings with prefix (e.g. eth*).

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c
src/netlink.c
tests/py/inet/meta.t
tests/py/inet/meta.t.payload
tests/shell/testcases/maps/0012map_0
tests/shell/testcases/maps/dumps/0012map_0.nft

index 0bf6a0d1b110c39881b671832f818e55fbb8bdbf..991de1d7e977f6692f0a29f89d611e1eef7f3898 100644 (file)
@@ -148,8 +148,29 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
                return 0;
 
        /* Conversion for EXPR_CONCAT is handled for single composing ranges */
-       if ((*expr)->etype == EXPR_CONCAT)
+       if ((*expr)->etype == EXPR_CONCAT) {
+               struct expr *i, *next, *unary;
+
+               list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+                       if (i->byteorder == BYTEORDER_BIG_ENDIAN)
+                               continue;
+
+                       basetype = expr_basetype(i)->type;
+                       if (basetype == TYPE_STRING)
+                               continue;
+
+                       assert(basetype == TYPE_INTEGER);
+
+                       op = byteorder_conversion_op(i, byteorder);
+                       unary = unary_expr_alloc(&i->location, op, i);
+                       if (expr_evaluate(ctx, &unary) < 0)
+                               return -1;
+
+                       list_replace(&i->list, &unary->list);
+               }
+
                return 0;
+       }
 
        basetype = expr_basetype(*expr)->type;
        switch (basetype) {
index 799cf9b8ebefb08095dee742a18ef34d90012b68..db5e79f235d0e451e2334c3106ef7aad31d58409 100644 (file)
@@ -249,9 +249,20 @@ static int netlink_export_pad(unsigned char *data, const mpz_t v,
 static int netlink_gen_concat_data_expr(int end, const struct expr *i,
                                        unsigned char *data)
 {
+       struct expr *expr;
+
        switch (i->etype) {
        case EXPR_RANGE:
-               i = end ? i->right : i->left;
+               if (end)
+                       expr = i->right;
+               else
+                       expr = i->left;
+
+               if (expr_basetype(expr)->type == TYPE_INTEGER &&
+                   expr->byteorder == BYTEORDER_HOST_ENDIAN)
+                       mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+               i = expr;
                break;
        case EXPR_PREFIX:
                if (end) {
@@ -1109,7 +1120,7 @@ static struct expr *netlink_parse_interval_elem(const struct set *set,
        return range_expr_to_prefix(range);
 }
 
-static struct expr *concat_elem_expr(struct expr *key,
+static struct expr *concat_elem_expr(const struct set *set, struct expr *key,
                                     const struct datatype *dtype,
                                     struct expr *data, int *off)
 {
@@ -1133,7 +1144,9 @@ static struct expr *concat_elem_expr(struct expr *key,
                expr->byteorder = subtype->byteorder;
        }
 
-       if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
+       if (expr_basetype(expr)->type == TYPE_STRING ||
+           (!(set->flags & NFT_SET_INTERVAL) &&
+            expr->byteorder == BYTEORDER_HOST_ENDIAN))
                mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
 
        if (expr->dtype->basetype != NULL &&
@@ -1157,7 +1170,7 @@ static struct expr *netlink_parse_concat_elem_key(const struct set *set,
 
        concat = concat_expr_alloc(&data->location);
        while (off > 0) {
-               expr = concat_elem_expr(n, dtype, data, &off);
+               expr = concat_elem_expr(set, n, dtype, data, &off);
                compound_expr_add(concat, expr);
                if (set->key->etype == EXPR_CONCAT)
                        n = list_next_entry(n, list);
@@ -1180,7 +1193,7 @@ static struct expr *netlink_parse_concat_elem(const struct set *set,
 
        concat = concat_expr_alloc(&data->location);
        while (off > 0) {
-               expr = concat_elem_expr(NULL, dtype, data, &off);
+               expr = concat_elem_expr(set, NULL, dtype, data, &off);
                list_add_tail(&expr->list, &expressions);
        }
 
@@ -1192,7 +1205,7 @@ static struct expr *netlink_parse_concat_elem(const struct set *set,
                while (off > 0) {
                        left = list_first_entry(&expressions, struct expr, list);
 
-                       expr = concat_elem_expr(NULL, dtype, data, &off);
+                       expr = concat_elem_expr(set, NULL, dtype, data, &off);
                        list_del(&left->list);
 
                        range = range_expr_alloc(&data->location, left, expr);
index 423cc5f32cba4a6d7ce604e696a9c51df8ef5565..0d7d5f255c00f0b17d095e1712d577f4b02b775a 100644 (file)
@@ -21,3 +21,5 @@ meta secpath missing;ok;meta ipsec missing
 meta ibrname "br0";fail
 meta obrname "br0";fail
 meta mark set ct mark >> 8;ok
+
+meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 };ok
index fd0545490b78be6bdf4403471aae221095898f1e..2b4e6c2d180ddf89c233303fb3c49c4eb2c49be3 100644 (file)
@@ -97,3 +97,15 @@ inet test-inet input
   [ cmp eq reg 1 0x00000011 ]
   [ payload load 2b @ transport header + 2 => reg 1 ]
   [ cmp eq reg 1 0x00004300 ]
+
+# meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 }
+__set%d test-inet 87 size 1
+__set%d test-inet 0
+       element 0a000000 00005000  - 14000000 00005a00  : 0 [end]       element 00001000 00006400  - 23011000 00007800  : 0 [end]
+ip test-inet input
+  [ meta load l4proto => reg 1 ]
+  [ cmp eq reg 1 0x00000006 ]
+  [ meta load mark => reg 1 ]
+  [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+  [ payload load 2b @ transport header + 2 => reg 9 ]
+  [ lookup reg 1 set __set%d ]
index dd93c482f4413578bae592083e8a33bc3d8f38ca..49e51b755b0fcc7087aeffce93c3c15362109b11 100755 (executable)
@@ -15,3 +15,22 @@ table ip x {
 }"
 
 $NFT -f - <<< "$EXPECTED"
+
+EXPECTED="table ip x {
+       map w {
+               typeof ip saddr . meta mark : verdict
+               flags interval
+               counter
+               elements = {
+                       127.0.0.1-127.0.0.4 . 0x123434-0xb00122 : accept,
+               }
+       }
+
+       chain k {
+               type filter hook input priority filter + 1; policy accept;
+               meta mark set 0x123434
+               ip saddr . meta mark vmap @w
+       }
+}"
+
+$NFT -f - <<< "$EXPECTED"
index e734fc1c70b9383d436c91abb5c95a0139eaebe4..895490cffa8c1be6ad780756b921bd522192d3b0 100644 (file)
@@ -6,7 +6,20 @@ table ip x {
                             "eth1" : drop }
        }
 
+       map w {
+               typeof ip saddr . meta mark : verdict
+               flags interval
+               counter
+               elements = { 127.0.0.1-127.0.0.4 . 0x00123434-0x00b00122 counter packets 0 bytes 0 : accept }
+       }
+
        chain y {
                iifname vmap { "lo" : accept, "eth0" : drop, "eth1" : drop }
        }
+
+       chain k {
+               type filter hook input priority filter + 1; policy accept;
+               meta mark set 0x00123434
+               ip saddr . meta mark vmap @w
+       }
 }