Select the merge criteria based on the statements that are used in the candidate rules, instead of using the list of statements in the given chain. Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1657 Fixes: 0a6dbfce6dc3 ("optimize: merge nat rules with same selectors into map") Signed-off-by: Pablo Neira Ayuso <pablo@xxxxxxxxxxxxx> --- src/optimize.c | 22 +++++++++---------- .../optimizations/dumps/merge_nat.nft | 4 ++++ tests/shell/testcases/optimizations/merge_nat | 4 ++++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/optimize.c b/src/optimize.c index 5f6e3a64fdd3..ff4f26278a6d 100644 --- a/src/optimize.c +++ b/src/optimize.c @@ -985,21 +985,21 @@ static void rule_optimize_print(struct output_ctx *octx, fprintf(octx->error_fp, "%s\n", line); } -static enum stmt_types merge_stmt_type(const struct optimize_ctx *ctx) +static enum stmt_types merge_stmt_type(const struct optimize_ctx *ctx, + uint32_t from, uint32_t to) { - uint32_t i; + uint32_t i, j; - for (i = 0; i < ctx->num_stmts; i++) { - switch (ctx->stmt[i]->ops->type) { - case STMT_VERDICT: - case STMT_NAT: - return ctx->stmt[i]->ops->type; - default: - continue; + for (i = from; i <= to; i++) { + for (j = 0; j < ctx->num_stmts; j++) { + if (!ctx->stmt_matrix[i][j]) + continue; + if (ctx->stmt_matrix[i][j]->ops->type == STMT_NAT) + return STMT_NAT; } } - /* actually no verdict, this assumes rules have the same verdict. */ + /* merge by verdict, even if no verdict is specified. */ return STMT_VERDICT; } @@ -1012,7 +1012,7 @@ static void merge_rules(const struct optimize_ctx *ctx, bool same_verdict; uint32_t i; - stmt_type = merge_stmt_type(ctx); + stmt_type = merge_stmt_type(ctx, from, to); switch (stmt_type) { case STMT_VERDICT: diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat.nft b/tests/shell/testcases/optimizations/dumps/merge_nat.nft index 7a6ecb76a934..32423b220ed1 100644 --- a/tests/shell/testcases/optimizations/dumps/merge_nat.nft +++ b/tests/shell/testcases/optimizations/dumps/merge_nat.nft @@ -1,20 +1,24 @@ table ip test1 { chain y { + oif "lo" accept dnat to ip saddr map { 4.4.4.4 : 1.1.1.1, 5.5.5.5 : 2.2.2.2 } } } table ip test2 { chain y { + oif "lo" accept dnat ip to tcp dport map { 80 : 1.1.1.1 . 8001, 81 : 2.2.2.2 . 9001 } } } table ip test3 { chain y { + oif "lo" accept snat to ip saddr . tcp sport map { 1.1.1.1 . 1024-65535 : 3.3.3.3, 2.2.2.2 . 1024-65535 : 4.4.4.4 } } } table ip test4 { chain y { + oif "lo" accept dnat ip to ip daddr . tcp dport map { 1.1.1.1 . 80 : 4.4.4.4 . 8000, 2.2.2.2 . 81 : 3.3.3.3 . 9000 } } } diff --git a/tests/shell/testcases/optimizations/merge_nat b/tests/shell/testcases/optimizations/merge_nat index 290cfcfebe2e..ec9b239c6f48 100755 --- a/tests/shell/testcases/optimizations/merge_nat +++ b/tests/shell/testcases/optimizations/merge_nat @@ -4,6 +4,7 @@ set -e RULESET="table ip test1 { chain y { + oif lo accept ip saddr 4.4.4.4 dnat to 1.1.1.1 ip saddr 5.5.5.5 dnat to 2.2.2.2 } @@ -13,6 +14,7 @@ $NFT -o -f - <<< $RULESET RULESET="table ip test2 { chain y { + oif lo accept tcp dport 80 dnat to 1.1.1.1:8001 tcp dport 81 dnat to 2.2.2.2:9001 } @@ -22,6 +24,7 @@ $NFT -o -f - <<< $RULESET RULESET="table ip test3 { chain y { + oif lo accept ip saddr 1.1.1.1 tcp sport 1024-65535 snat to 3.3.3.3 ip saddr 2.2.2.2 tcp sport 1024-65535 snat to 4.4.4.4 } @@ -31,6 +34,7 @@ $NFT -o -f - <<< $RULESET RULESET="table ip test4 { chain y { + oif lo accept ip daddr 1.1.1.1 tcp dport 80 dnat to 4.4.4.4:8000 ip daddr 2.2.2.2 tcp dport 81 dnat to 3.3.3.3:9000 } -- 2.30.2