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@xxxxxxxxxx> tests: shell: add case to test unclosed prefix intervals Signed-off-by: Jeremy Sowden <jeremy@xxxxxxxxxx> --- src/segtree.c | 21 +++++------------ .../sets/0071unclosed_prefix_interval_0 | 23 +++++++++++++++++++ .../dumps/0071unclosed_prefix_interval_0.nft | 19 +++++++++++++++ 3 files changed, 48 insertions(+), 15 deletions(-) create mode 100755 tests/shell/testcases/sets/0071unclosed_prefix_interval_0 create mode 100644 tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft diff --git a/src/segtree.c b/src/segtree.c index d15c39f31f3a..ad3821376dae 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); @@ -619,24 +622,12 @@ void interval_map_decompose(struct expr *set) 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); 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 000000000000..79e3ca7da743 --- /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 000000000000..4eed94c2c884 --- /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 + } +} -- 2.35.1