From 7f7d5b999ed3f44ee8aec6b4d48051f048f326ab Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 6 Apr 2021 18:34:19 +0200 Subject: evaluate: check if nat statement map specifies a transport header expr Importing the systemd nat table fails: table ip io.systemd.nat { map map_port_ipport { type inet_proto . inet_service : ipv4_addr . inet_service elements = { tcp . 8088 : 192.168.162.117 . 80 } } chain prerouting { type nat hook prerouting priority dstnat + 1; policy accept; fib daddr type local dnat ip addr . port to meta l4proto . th dport map @map_port_ipport } } ruleset:9:48-59: Error: transport protocol mapping is only valid after transport protocol match To resolve this (no transport header base specified), check if the map itself contains a network base protocol expression. This allows nft to import the ruleset. Import still fails with same error if 'inet_service' is removed from the map, as it should. Reported-by: Henning Reich Signed-off-by: Florian Westphal --- src/evaluate.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/evaluate.c b/src/evaluate.c index 85cf9e05..a6bb1792 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2971,12 +2971,48 @@ static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, expr); } +static bool nat_evaluate_addr_has_th_expr(const struct expr *map) +{ + const struct expr *i, *concat; + + if (!map || map->etype != EXPR_MAP) + return false; + + concat = map->map; + if (concat ->etype != EXPR_CONCAT) + return false; + + list_for_each_entry(i, &concat->expressions, list) { + enum proto_bases base; + + if ((i->flags & EXPR_F_PROTOCOL) == 0) + continue; + + switch (i->etype) { + case EXPR_META: + base = i->meta.base; + break; + case EXPR_PAYLOAD: + base = i->payload.base; + break; + default: + return false; + } + + if (base == PROTO_BASE_NETWORK_HDR) + return true; + } + + return false; +} + static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *stmt, struct expr **expr) { struct proto_ctx *pctx = &ctx->pctx; - if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL) + if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL && + !nat_evaluate_addr_has_th_expr(stmt->nat.addr)) return stmt_binary_error(ctx, *expr, stmt, "transport protocol mapping is only " "valid after transport protocol match"); -- cgit v1.2.3