summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Sowden <jeremy@azazel.net>2022-09-18 18:22:12 +0100
committerFlorian Westphal <fw@strlen.de>2022-09-21 13:57:09 +0200
commit7e6be917987c3ab0261bf543eb307cbb2679294f (patch)
tree34d83ccfceb653b19ed762ebdee18cd66fef71fd
parentd899df24826c268c764edb07c3a3ed3f2c90b253 (diff)
segtree: fix decomposition of unclosed intervals containing address prefixes
The code which decomposes unclosed intervals doesn't check for prefixes. This leads to incorrect output for sets which contain these. For example, # nft -f - <<END table ip t { chain c { ip saddr 192.0.0.0/2 drop ip saddr 10.0.0.0/8 drop ip saddr { 192.0.0.0/2, 10.0.0.0/8 } drop } } table ip6 t { chain c { ip6 saddr ff00::/8 drop ip6 saddr fe80::/10 drop ip6 saddr { ff00::/8, fe80::/10 } drop } } END # nft list table ip6 t table ip6 t { chain c { ip6 saddr ff00::/8 drop ip6 saddr fe80::/10 drop ip6 saddr { fe80::/10, ff00::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } drop } } # nft list table ip t table ip t { chain c { ip saddr 192.0.0.0/2 drop ip saddr 10.0.0.0/8 drop ip saddr { 10.0.0.0/8, 192.0.0.0-255.255.255.255 } drop } } Instead of treating the final unclosed interval as a special case, reuse the code which correctly handles closed intervals. Add a shell test-case. Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1018156 Fixes: 86b965bdab8d ("segtree: fix decomposition of unclosed intervals") Signed-off-by: Jeremy Sowden <jeremy@azazel.net> Signed-off-by: Florian Westphal <fw@strlen.de>
-rw-r--r--src/segtree.c24
-rwxr-xr-xtests/shell/testcases/sets/0071unclosed_prefix_interval_023
-rw-r--r--tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft19
3 files changed, 50 insertions, 16 deletions
diff --git a/src/segtree.c b/src/segtree.c
index d15c39f3..0e3d111f 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -158,6 +158,8 @@ static struct expr *expr_value(struct expr *expr)
return expr->left->key;
case EXPR_SET_ELEM:
return expr->key;
+ case EXPR_VALUE:
+ return expr;
default:
BUG("invalid expression type %s\n", expr_name(expr));
}
@@ -503,7 +505,8 @@ add_interval(struct expr *set, struct expr *low, struct expr *i)
mpz_init(p);
mpz_sub(range, expr_value(i)->value, expr_value(low)->value);
- mpz_sub_ui(range, range, 1);
+ if (i->etype != EXPR_VALUE)
+ mpz_sub_ui(range, range, 1);
mpz_and(p, expr_value(low)->value, range);
@@ -618,25 +621,14 @@ void interval_map_decompose(struct expr *set)
mpz_bitmask(i->value, i->len);
if (!mpz_cmp(i->value, expr_value(low)->value)) {
- expr_free(i);
- i = low;
+ compound_expr_add(set, low);
} else {
- i = range_expr_alloc(&low->location,
- expr_clone(expr_value(low)), i);
- i = set_elem_expr_alloc(&low->location, i);
- if (low->etype == EXPR_MAPPING) {
- i = mapping_expr_alloc(&i->location, i,
- expr_clone(low->right));
- interval_expr_copy(i->left, low->left);
- } else {
- interval_expr_copy(i, low);
- }
- i->flags |= EXPR_F_KERNEL;
-
+ add_interval(set, low, i);
expr_free(low);
}
- compound_expr_add(set, i);
+ expr_free(i);
+
out:
if (catchall)
compound_expr_add(set, catchall);
diff --git a/tests/shell/testcases/sets/0071unclosed_prefix_interval_0 b/tests/shell/testcases/sets/0071unclosed_prefix_interval_0
new file mode 100755
index 00000000..79e3ca7d
--- /dev/null
+++ b/tests/shell/testcases/sets/0071unclosed_prefix_interval_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+table inet t {
+ set s1 {
+ type ipv4_addr
+ flags interval
+ elements = { 192.0.0.0/2, 10.0.0.0/8 }
+ }
+ set s2 {
+ type ipv6_addr
+ flags interval
+ elements = { ff00::/8, fe80::/10 }
+ }
+ chain c {
+ ip saddr @s1 accept
+ ip6 daddr @s2 accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft
new file mode 100644
index 00000000..4eed94c2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft
@@ -0,0 +1,19 @@
+table inet t {
+ set s1 {
+ type ipv4_addr
+ flags interval
+ elements = { 10.0.0.0/8, 192.0.0.0/2 }
+ }
+
+ set s2 {
+ type ipv6_addr
+ flags interval
+ elements = { fe80::/10,
+ ff00::/8 }
+ }
+
+ chain c {
+ ip saddr @s1 accept
+ ip6 daddr @s2 accept
+ }
+}