]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: make interval sets work with string datatypes
authorFlorian Westphal <fw@strlen.de>
Sat, 9 Apr 2022 13:58:28 +0000 (15:58 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 13 Apr 2022 11:43:35 +0000 (13:43 +0200)
Allows to interface names in interval sets:

table inet filter {
        set s {
                type ifname
                flags interval
                elements = { eth*, foo }
        }

Concatenations are not yet supported, also, listing is broken,
those strings will not be printed back because the values will remain
in big-endian order.  Followup patch will extend segtree to translate
this back to host byte order.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/expression.c
src/segtree.c

index deb649e1847bb935735cf0a681c5a2c1fb663c0e..5d879b5359906a6eeccbc135ad3a22b0809e93e2 100644 (file)
@@ -1442,7 +1442,11 @@ void range_expr_value_low(mpz_t rop, const struct expr *expr)
 {
        switch (expr->etype) {
        case EXPR_VALUE:
-               return mpz_set(rop, expr->value);
+               mpz_set(rop, expr->value);
+               if (expr->byteorder == BYTEORDER_HOST_ENDIAN &&
+                   expr_basetype(expr)->type == TYPE_STRING)
+                       mpz_switch_byteorder(rop, expr->len / BITS_PER_BYTE);
+               return;
        case EXPR_PREFIX:
                return range_expr_value_low(rop, expr->prefix);
        case EXPR_RANGE:
@@ -1462,7 +1466,7 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
 
        switch (expr->etype) {
        case EXPR_VALUE:
-               return mpz_set(rop, expr->value);
+               return range_expr_value_low(rop, expr);
        case EXPR_PREFIX:
                range_expr_value_low(rop, expr->prefix);
                assert(expr->len >= expr->prefix_len);
index 188cafedce459aab1047dd95c7b382dccd8ee78a..b4e76bf530d661db85430346480fa2a1bb5ba0b2 100644 (file)
@@ -70,12 +70,30 @@ struct elementary_interval {
        struct expr                     *expr;
 };
 
+static enum byteorder get_key_byteorder(const struct expr *e)
+{
+       enum datatypes basetype = expr_basetype(e)->type;
+
+       switch (basetype) {
+       case TYPE_INTEGER:
+               /* For ranges, integers MUST be in BYTEORDER_BIG_ENDIAN.
+                * If the LHS (lookup key, e.g. 'meta mark', is host endian,
+                * a byteorder expression is injected to convert the register
+                * content before lookup.
+                */
+               return BYTEORDER_BIG_ENDIAN;
+       case TYPE_STRING:
+               return BYTEORDER_HOST_ENDIAN;
+       default:
+               break;
+       }
+
+       return BYTEORDER_INVALID;
+}
+
 static void seg_tree_init(struct seg_tree *tree, const struct set *set,
                          struct expr *init, unsigned int debug_mask)
 {
-       struct expr *first;
-
-       first = list_entry(init->expressions.next, struct expr, list);
        tree->root      = RB_ROOT;
        tree->keytype   = set->key->dtype;
        tree->keylen    = set->key->len;
@@ -85,7 +103,8 @@ static void seg_tree_init(struct seg_tree *tree, const struct set *set,
                tree->datatype  = set->data->dtype;
                tree->datalen   = set->data->len;
        }
-       tree->byteorder = first->byteorder;
+
+       tree->byteorder = get_key_byteorder(set->key);
        tree->debug_mask = debug_mask;
 }
 
@@ -608,6 +627,9 @@ static void set_insert_interval(struct expr *set, struct seg_tree *tree,
        expr = constant_expr_alloc(&internal_location, tree->keytype,
                                   tree->byteorder, tree->keylen, NULL);
        mpz_set(expr->value, ei->left);
+       if (tree->byteorder == BYTEORDER_HOST_ENDIAN)
+               mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
        expr = set_elem_expr_alloc(&internal_location, expr);
 
        if (ei->expr != NULL) {