]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
optimize: add unsupported statement
authorPablo Neira Ayuso <pablo@netfilter.org>
Fri, 17 Jun 2022 15:49:59 +0000 (17:49 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 23 Jun 2022 17:00:02 +0000 (19:00 +0200)
Do not try to merge rules with unsupported statements. This patch adds a
dummy unsupported statement which is included in the statement
collection and the rule vs statement matrix.

When looking for possible rule mergers, rules using unsupported
statements are discarded, otherwise bogus rule mergers might occur.

Note that __stmt_type_eq() already returns false for unsupported
statements.

Add a test using meta mark statement, which is not yet supported.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
src/optimize.c
tests/shell/testcases/optimizations/dumps/skip_unsupported.nft [new file with mode: 0644]
tests/shell/testcases/optimizations/skip_unsupported [new file with mode: 0755]

index abd0b72f90d373477697243907b68ecb9d03098f..e3d4bc785226640ed2f5215bf8de66061ab2218c 100644 (file)
@@ -301,16 +301,42 @@ static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b
 
 static bool stmt_type_find(struct optimize_ctx *ctx, const struct stmt *stmt)
 {
+       bool unsupported_exists = false;
        uint32_t i;
 
        for (i = 0; i < ctx->num_stmts; i++) {
+               if (ctx->stmt[i]->ops->type == STMT_INVALID)
+                       unsupported_exists = true;
+
                if (__stmt_type_eq(stmt, ctx->stmt[i], false))
                        return true;
        }
 
+       switch (stmt->ops->type) {
+       case STMT_EXPRESSION:
+       case STMT_VERDICT:
+       case STMT_COUNTER:
+       case STMT_NOTRACK:
+       case STMT_LIMIT:
+       case STMT_LOG:
+       case STMT_NAT:
+       case STMT_REJECT:
+               break;
+       default:
+               /* add unsupported statement only once to statement matrix. */
+               if (unsupported_exists)
+                       return true;
+               break;
+       }
+
        return false;
 }
 
+static struct stmt_ops unsupported_stmt_ops = {
+       .type   = STMT_INVALID,
+       .name   = "unsupported",
+};
+
 static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
 {
        struct stmt *stmt, *clone;
@@ -357,8 +383,8 @@ static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
                        clone->reject.family = stmt->reject.family;
                        break;
                default:
-                       xfree(clone);
-                       continue;
+                       clone->ops = &unsupported_stmt_ops;
+                       break;
                }
 
                ctx->stmt[ctx->num_stmts++] = clone;
@@ -369,6 +395,18 @@ static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
        return 0;
 }
 
+static int unsupported_in_stmt_matrix(const struct optimize_ctx *ctx)
+{
+       uint32_t i;
+
+       for (i = 0; i < ctx->num_stmts; i++) {
+               if (ctx->stmt[i]->ops->type == STMT_INVALID)
+                       return i;
+       }
+       /* this should not happen. */
+       return -1;
+}
+
 static int cmd_stmt_find_in_stmt_matrix(struct optimize_ctx *ctx, struct stmt *stmt)
 {
        uint32_t i;
@@ -377,10 +415,14 @@ static int cmd_stmt_find_in_stmt_matrix(struct optimize_ctx *ctx, struct stmt *s
                if (__stmt_type_eq(stmt, ctx->stmt[i], false))
                        return i;
        }
-       /* should not ever happen. */
-       return 0;
+
+       return -1;
 }
 
+static struct stmt unsupported_stmt = {
+       .ops    = &unsupported_stmt_ops,
+};
+
 static void rule_build_stmt_matrix_stmts(struct optimize_ctx *ctx,
                                         struct rule *rule, uint32_t *i)
 {
@@ -389,6 +431,12 @@ static void rule_build_stmt_matrix_stmts(struct optimize_ctx *ctx,
 
        list_for_each_entry(stmt, &rule->stmts, list) {
                k = cmd_stmt_find_in_stmt_matrix(ctx, stmt);
+               if (k < 0) {
+                       k = unsupported_in_stmt_matrix(ctx);
+                       assert(k >= 0);
+                       ctx->stmt_matrix[*i][k] = &unsupported_stmt;
+                       continue;
+               }
                ctx->stmt_matrix[*i][k] = stmt;
        }
        ctx->rule[(*i)++] = rule;
diff --git a/tests/shell/testcases/optimizations/dumps/skip_unsupported.nft b/tests/shell/testcases/optimizations/dumps/skip_unsupported.nft
new file mode 100644 (file)
index 0000000..43b6578
--- /dev/null
@@ -0,0 +1,7 @@
+table inet x {
+       chain y {
+               ip saddr 1.2.3.4 tcp dport 80 meta mark set 0x0000000a accept
+               ip saddr 1.2.3.4 tcp dport 81 meta mark set 0x0000000b accept
+               ip saddr . tcp dport { 1.2.3.5 . 81, 1.2.3.5 . 82 } accept
+       }
+}
diff --git a/tests/shell/testcases/optimizations/skip_unsupported b/tests/shell/testcases/optimizations/skip_unsupported
new file mode 100755 (executable)
index 0000000..9313c30
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet x {
+       chain y {
+               ip saddr 1.2.3.4 tcp dport 80 meta mark set 10 accept
+               ip saddr 1.2.3.4 tcp dport 81 meta mark set 11 accept
+               ip saddr 1.2.3.5 tcp dport 81 accept comment \"test\"
+               ip saddr 1.2.3.5 tcp dport 82 accept
+       }
+}"
+
+$NFT -o -f - <<< $RULESET