]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
src: convert set to list expression
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 8 Jul 2025 22:32:13 +0000 (00:32 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 9 Jul 2025 22:13:04 +0000 (00:13 +0200)
The following definition:

 define xyz = { "dummy0", "dummy1" }

is represented as a set expression to ease integration with sets.

However, this definition can be used in chains and flowtables to specify
the devices, for instance:

  table netdev x {
    chain y {
      type filter hook ingress devices = $xyz priority 0; policy drop;
    }
  }

in this context, $xyz defines a _list_ of devices, not a set.

Transform the set to list expression from the evaluation step for chains
and flowtables.

This patch also handles:

 define xyz = { "dummy0", $abc }

where $abc is also transformed to a list expression in the context of
chains and flowtables.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/evaluate.c
src/mnl.c

index f4f72ee4a4f7c345081d7b64ad955d2698a489e1..fb6c4e06ae32f48b7771b1c4913b0e7c8bc51f9b 100644 (file)
@@ -5393,9 +5393,54 @@ static bool evaluate_expr_variable(struct eval_ctx *ctx, struct expr **exprp)
        return true;
 }
 
-static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
+static struct expr *expr_set_to_list(struct eval_ctx *ctx, struct expr *dev_expr)
 {
        struct expr *expr, *next, *key;
+       struct location loc;
+       LIST_HEAD(tmp);
+
+       list_for_each_entry_safe(expr, next, &dev_expr->expressions, list) {
+               list_del(&expr->list);
+
+               switch (expr->etype) {
+               case EXPR_VARIABLE:
+                       expr_set_context(&ctx->ectx, &ifname_type,
+                                        IFNAMSIZ * BITS_PER_BYTE);
+                       if (!evaluate_expr_variable(ctx, &expr))
+                               return false;
+
+                       if (expr->etype == EXPR_SET) {
+                               expr = expr_set_to_list(ctx, expr);
+                               list_splice_init(&expr->expressions, &tmp);
+                               expr_free(expr);
+                               continue;
+                       }
+                       break;
+               case EXPR_SET_ELEM:
+                       key = expr_clone(expr->key);
+                       expr_free(expr);
+                       expr = key;
+                       break;
+               case EXPR_VALUE:
+                       break;
+               default:
+                       break;
+               }
+
+               list_add(&expr->list, &tmp);
+       }
+
+       loc = dev_expr->location;
+       expr_free(dev_expr);
+       dev_expr = compound_expr_alloc(&loc, EXPR_LIST);
+       list_splice_init(&tmp, &dev_expr->expressions);
+
+       return dev_expr;
+}
+
+static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
+{
+       struct expr *expr, *next;
        LIST_HEAD(tmp);
 
        if ((*dev_expr)->etype == EXPR_VARIABLE) {
@@ -5405,9 +5450,10 @@ static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
                        return false;
        }
 
-       if ((*dev_expr)->etype != EXPR_SET &&
-           (*dev_expr)->etype != EXPR_LIST)
-               return true;
+       if ((*dev_expr)->etype == EXPR_SET)
+               *dev_expr = expr_set_to_list(ctx, *dev_expr);
+
+       assert((*dev_expr)->etype == EXPR_LIST);
 
        list_for_each_entry_safe(expr, next, &(*dev_expr)->expressions, list) {
                list_del(&expr->list);
@@ -5418,11 +5464,13 @@ static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
                                         IFNAMSIZ * BITS_PER_BYTE);
                        if (!evaluate_expr_variable(ctx, &expr))
                                return false;
-                       break;
-               case EXPR_SET_ELEM:
-                       key = expr_clone(expr->key);
-                       expr_free(expr);
-                       expr = key;
+
+                       if (expr->etype == EXPR_SET) {
+                               expr = expr_set_to_list(ctx, expr);
+                               list_splice_init(&expr->expressions, &tmp);
+                               expr_free(expr);
+                               continue;
+                       }
                        break;
                case EXPR_VALUE:
                        break;
index 8a8dc4d6ef1c2a71c963b6b443c627aa28328992..cc20908fd636e750f6c82d0fac371ad276db3920 100644 (file)
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -757,7 +757,6 @@ static struct nft_dev *nft_dev_array(const struct expr *dev_expr, int *num_devs)
        struct expr *expr;
 
        switch (dev_expr->etype) {
-       case EXPR_SET:
        case EXPR_LIST:
                list_for_each_entry(expr, &dev_expr->expressions, list)
                        len++;