diff options
author | Florian Westphal <fw@strlen.de> | 2022-04-09 15:58:29 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2022-04-13 13:43:37 +0200 |
commit | 5e393ea1fc0ad6b59e90103bf83e93b2449d519e (patch) | |
tree | 6f300e461b22905be68d93e5009b140e21a2dd2f /src | |
parent | 2fb4d7ead460ec4fb00bd317d93a5e076f825b39 (diff) |
segtree: add string "range" reversal support
Previous commits allows to use set key as a range, i.e.
key ifname
flags interval
elements = { eth* }
and then have it match on any interface starting with 'eth'.
Listing is broken however, we need to reverse-translate the (128bit)
number back to a string.
'eth*' is stored as interval
00687465 0000000 .. 00697465 0000000, i.e. "eth-eti",
this adds the needed endianess fixups.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/segtree.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/src/segtree.c b/src/segtree.c index b4e76bf5..bed8bbcf 100644 --- a/src/segtree.c +++ b/src/segtree.c @@ -1032,6 +1032,33 @@ static struct expr *interval_to_prefix(struct expr *low, struct expr *i, const m return __expr_to_set_elem(low, prefix); } +static struct expr *interval_to_string(struct expr *low, struct expr *i, const mpz_t range) +{ + unsigned int len = div_round_up(i->len, BITS_PER_BYTE); + unsigned int prefix_len, str_len; + char data[len + 2]; + struct expr *expr; + + prefix_len = expr_value(i)->len - mpz_scan0(range, 0); + + if (prefix_len > i->len || prefix_len % BITS_PER_BYTE) + return interval_to_prefix(low, i, range); + + mpz_export_data(data, expr_value(low)->value, BYTEORDER_BIG_ENDIAN, len); + + str_len = strnlen(data, len); + if (str_len >= len || str_len == 0) + return interval_to_prefix(low, i, range); + + data[str_len] = '*'; + + expr = constant_expr_alloc(&low->location, low->dtype, + BYTEORDER_HOST_ENDIAN, + (str_len + 1) * BITS_PER_BYTE, data); + + return __expr_to_set_elem(low, expr); +} + static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t range) { struct expr *tmp; @@ -1130,16 +1157,24 @@ void interval_map_decompose(struct expr *set) mpz_and(p, expr_value(low)->value, range); - if (!mpz_cmp_ui(range, 0)) + if (!mpz_cmp_ui(range, 0)) { + if (expr_basetype(low)->type == TYPE_STRING) + mpz_switch_byteorder(expr_value(low)->value, low->len / BITS_PER_BYTE); + compound_expr_add(set, expr_get(low)); - else if ((!range_is_prefix(range) || - !(i->dtype->flags & DTYPE_F_PREFIX)) || - mpz_cmp_ui(p, 0)) { - struct expr *expr = interval_to_range(low, i, range); + } else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) { + struct expr *expr; + + if (i->dtype->flags & DTYPE_F_PREFIX) + expr = interval_to_prefix(low, i, range); + else if (expr_basetype(i)->type == TYPE_STRING) + expr = interval_to_string(low, i, range); + else + expr = interval_to_range(low, i, range); compound_expr_add(set, expr); } else { - struct expr *expr = interval_to_prefix(low, i, range); + struct expr *expr = interval_to_range(low, i, range); compound_expr_add(set, expr); } |