[PATCH nft 3/3] segtree: postpone bitmask to symbol conversion for interval sets
Pablo Neira Ayuso <[email protected]>
| Newsgroups | gmane.comp.security.firewalls.netfilter.devel |
|---|---|
| Message-ID | <[email protected]> |
netlink_delinearize_setelem() calls bitmask_expr_to_binops() to turn a
bitmask into symbols, ie.
tcp flags { 0x2, 0x12 }
into
tcp flags { syn, syn | ack }
However, this call comes too early for interval set with one single key.
The interval_map_decompose() postprocessing can only deal with value
expressions, otherwise it hits an assertion.
Move this conversion at a later stage of interval_map_decompose() for
interval sets.
Ranges and prefix do not call bitmask_expr_to_binops(), we do not use
symbolic representations for such expressions, instead values are used.
The conversion is still perform for non-interval sets, since there is no
specific function to perform postprocessing for this type of sets.
Add and extend existing tests/shell cases.
Fixes: def2cca8e713 ("set_elem: convert flag value to inclusive-OR binops during delinearize")
Signed-off-by: Pablo Neira Ayuso <[email protected]>
---
src/netlink.c | 6 +-
src/segtree.c | 15 +
.../dumps/vmap_concat_range_binary.json-nft | 154 +++++++++++
.../maps/dumps/vmap_concat_range_binary.nft | 10 +
.../maps/dumps/vmap_range_binary.json-nft | 257 ++++++++++++++++++
.../maps/dumps/vmap_range_binary.nft | 23 ++
.../testcases/maps/vmap_concat_range_binary | 10 +
tests/shell/testcases/maps/vmap_range_binary | 35 +++
8 files changed, 508 insertions(+), 2 deletions(-)
create mode 100644 tests/shell/testcases/maps/dumps/vmap_range_binary.json-nft
create mode 100644 tests/shell/testcases/maps/dumps/vmap_range_binary.nft
create mode 100755 tests/shell/testcases/maps/vmap_range_binary
diff --git a/src/netlink.c b/src/netlink.c
index c305e5619640..8916370604c0 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1440,7 +1440,8 @@ static struct expr *concat_elem_expr(const struct set *set, struct expr *key,
expr->byteorder == BYTEORDER_HOST_ENDIAN))
mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
- if (expr->dtype->basetype != NULL &&
+ if (!(set->flags & NFT_SET_INTERVAL) &&
+ expr->dtype->basetype != NULL &&
expr->dtype->basetype->type == TYPE_BITMASK)
expr = bitmask_expr_to_binops(expr);
@@ -1591,7 +1592,8 @@ key_end:
key->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
- if (key->dtype->basetype != NULL &&
+ if (!(set->flags & NFT_SET_INTERVAL) &&
+ key->dtype->basetype != NULL &&
key->dtype->basetype->type == TYPE_BITMASK)
key = bitmask_expr_to_binops(key);
} else if (flags & NFT_SET_ELEM_CATCHALL) {
diff --git a/src/segtree.c b/src/segtree.c
index 5e178fa3c48d..1dc94688aee1 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -411,6 +411,13 @@ void concat_range_aggregate(struct expr *set)
assert(r1->etype == EXPR_VALUE && r1->etype == EXPR_VALUE);
if (!mpz_cmp(r1->value, r2->value)) {
+ if (r2->dtype->basetype != NULL &&
+ r2->dtype->basetype->type == TYPE_BITMASK) {
+ expr_get(r2);
+ tmp = bitmask_expr_to_binops(r2);
+ list_replace(&r2->list, &tmp->list);
+ expr_free(r2);
+ }
free_r1 = 1;
goto next;
}
@@ -590,6 +597,14 @@ add_interval(struct expr *set, struct expr *low, struct expr *i, bool closed)
if (expr_basetype(low)->type == TYPE_STRING)
mpz_switch_byteorder(key->value,
key->len / BITS_PER_BYTE);
+
+ if (key->dtype->basetype != NULL &&
+ key->dtype->basetype->type == TYPE_BITMASK) {
+ if (low->key->etype == EXPR_MAPPING)
+ low->key->left = bitmask_expr_to_binops(low->key->left);
+ else
+ low->key = bitmask_expr_to_binops(low->key);
+ }
low->key->flags |= EXPR_F_KERNEL;
expr = expr_get(low);
} else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) {
diff --git a/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft
index 8868f2eb180e..de285354d86a 100644
--- a/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft
+++ b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.json-nft
@@ -97,6 +97,65 @@
]
}
},
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": {
+ "typeof": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ }
+ },
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "ack",
+ 90
+ ]
+ },
+ {
+ "concat": [
+ "rst",
+ {
+ "range": [
+ 100,
+ 110
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ },
{
"rule": {
"family": "ip",
@@ -204,6 +263,101 @@
}
]
}
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": "@s"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "ack",
+ 90
+ ]
+ },
+ {
+ "concat": [
+ "rst",
+ {
+ "range": [
+ 100,
+ 110
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
}
]
}
diff --git a/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft
index bc74535b852f..b5d6de32a838 100644
--- a/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft
+++ b/tests/shell/testcases/maps/dumps/vmap_concat_range_binary.nft
@@ -7,8 +7,18 @@ table ip x {
rst . 100-110 : drop }
}
+ set s {
+ typeof tcp flags . tcp dport
+ flags interval
+ elements = { syn | ack . 80,
+ ack . 90,
+ rst . 100-110 }
+ }
+
chain z {
tcp flags . tcp dport vmap @y
tcp flags . tcp dport vmap { syn | ack . 80 : accept, ack . 90 : drop, rst . 100-110 : drop }
+ tcp flags . tcp dport @s
+ tcp flags . tcp dport { syn | ack . 80, ack . 90, rst . 100-110 }
}
}
diff --git a/tests/shell/testcases/maps/dumps/vmap_range_binary.json-nft b/tests/shell/testcases/maps/dumps/vmap_range_binary.json-nft
new file mode 100644
index 000000000000..eba4afb013d8
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_range_binary.json-nft
@@ -0,0 +1,257 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": {
+ "typeof": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ }
+ },
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ "rst",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "ack",
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "range": [
+ "urg",
+ 255
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": {
+ "typeof": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ }
+ },
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ "rst",
+ "ack",
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ {
+ "range": [
+ "urg",
+ 255
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ "data": "@y"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "rst",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "ack",
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "range": [
+ "urg",
+ 255
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ "right": "@s"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "flags"
+ }
+ },
+ "right": {
+ "set": [
+ "rst",
+ "ack",
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ {
+ "range": [
+ "urg",
+ 255
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_range_binary.nft b/tests/shell/testcases/maps/dumps/vmap_range_binary.nft
new file mode 100644
index 000000000000..fbf599c07ff1
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_range_binary.nft
@@ -0,0 +1,23 @@
+table ip x {
+ map y {
+ typeof tcp flags : verdict
+ flags interval
+ elements = { rst : drop,
+ ack : drop,
+ syn | ack : accept,
+ 0x20-0xff : drop }
+ }
+
+ set s {
+ typeof tcp flags
+ flags interval
+ elements = { rst, ack, syn | ack, 0x20-0xff }
+ }
+
+ chain z {
+ tcp flags vmap @y
+ tcp flags vmap { rst : drop, ack : drop, syn | ack : accept, 0x20-0xff : drop }
+ tcp flags @s
+ tcp flags { rst, ack, syn | ack, 0x20-0xff }
+ }
+}
diff --git a/tests/shell/testcases/maps/vmap_concat_range_binary b/tests/shell/testcases/maps/vmap_concat_range_binary
index ad5ef4a9177e..bd0e5ed8d500 100755
--- a/tests/shell/testcases/maps/vmap_concat_range_binary
+++ b/tests/shell/testcases/maps/vmap_concat_range_binary
@@ -13,9 +13,19 @@ RULESET="table ip x {
rst . 100-110 : drop }
}
+ set s {
+ typeof tcp flags . tcp dport
+ flags interval
+ elements = { syn | ack . 80,
+ ack . 90,
+ rst . 100-110 }
+ }
+
chain z {
tcp flags . tcp dport vmap @y
tcp flags . tcp dport vmap { syn | ack . 80 : accept, ack . 90 : drop, rst . 100-110 : drop }
+ tcp flags . tcp dport @s
+ tcp flags . tcp dport { syn | ack . 80, ack . 90, rst . 100-110 }
}
}"
diff --git a/tests/shell/testcases/maps/vmap_range_binary b/tests/shell/testcases/maps/vmap_range_binary
new file mode 100755
index 000000000000..428cec646aca
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_range_binary
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ map y {
+ typeof tcp flags : verdict
+ flags interval
+ elements = { syn | ack : accept,
+ ack : drop,
+ rst : drop,
+ 0x20-0xff : drop,
+ }
+ }
+
+ set s {
+ typeof tcp flags
+ flags interval
+ elements = { syn | ack,
+ ack,
+ rst,
+ 0x20-0xff,
+ }
+ }
+
+
+ chain z {
+ tcp flags vmap @y
+ tcp flags vmap { syn | ack : accept, ack : drop, rst : drop, 0x20-0xff : drop }
+ tcp flags @s
+ tcp flags { syn | ack, ack, rst, 0x20-0xff }
+ }
+}"
+
+$NFT -f - <<< $RULESET
--
2.47.3