]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
segtree: add string "range" reversal support
authorFlorian Westphal <fw@strlen.de>
Sat, 9 Apr 2022 13:58:29 +0000 (15:58 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 13 Apr 2022 11:43:37 +0000 (13:43 +0200)
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>
src/segtree.c

index b4e76bf530d661db85430346480fa2a1bb5ba0b2..bed8bbcf0c8e7f60fae2868611fa81461661d229 100644 (file)
@@ -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);
                }