diff options
-rw-r--r-- | src/evaluate.c | 45 | ||||
-rwxr-xr-x | tests/shell/testcases/sets/0047nat_0 | 14 |
2 files changed, 54 insertions, 5 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index 98f3e926..d24f8b66 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -3524,16 +3524,48 @@ static int stmt_evaluate_l3proto(struct eval_ctx *ctx, return 0; } +static void expr_family_infer(struct proto_ctx *pctx, const struct expr *expr, + uint8_t *family) +{ + struct expr *i; + + if (expr->etype == EXPR_MAP) { + switch (expr->map->etype) { + case EXPR_CONCAT: + list_for_each_entry(i, &expr->map->expressions, list) { + if (i->etype == EXPR_PAYLOAD) { + if (i->payload.desc == &proto_ip) + *family = NFPROTO_IPV4; + else if (i->payload.desc == &proto_ip6) + *family = NFPROTO_IPV6; + } + } + break; + case EXPR_PAYLOAD: + if (expr->map->payload.desc == &proto_ip) + *family = NFPROTO_IPV4; + else if (expr->map->payload.desc == &proto_ip6) + *family = NFPROTO_IPV6; + break; + default: + break; + } + } +} + static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, - uint8_t family, - struct expr **addr) + uint8_t *family, struct expr **addr) { struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct datatype *dtype; int err; if (pctx->family == NFPROTO_INET) { - dtype = get_addr_dtype(family); + if (*family == NFPROTO_INET || + *family == NFPROTO_UNSPEC) + expr_family_infer(pctx, *addr, family); + + dtype = get_addr_dtype(*family); if (dtype->size == 0) { return stmt_error(ctx, stmt, "specify `%s ip' or '%s ip6' in %s table to disambiguate", @@ -3556,6 +3588,9 @@ static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt) const struct datatype *dtype; int addr_type, err; + if (stmt->nat.family == NFPROTO_INET) + expr_family_infer(pctx, stmt->nat.addr, &stmt->nat.family); + switch (stmt->nat.family) { case NFPROTO_IPV4: addr_type = TYPE_IPADDR; @@ -3682,7 +3717,7 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) return 0; } - err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family, + err = stmt_evaluate_addr(ctx, stmt, &stmt->nat.family, &stmt->nat.addr); if (err < 0) return err; @@ -3733,7 +3768,7 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt) if (stmt->tproxy.addr->etype == EXPR_RANGE) return stmt_error(ctx, stmt, "Address ranges are not supported for tproxy."); - err = stmt_evaluate_addr(ctx, stmt, stmt->tproxy.family, + err = stmt_evaluate_addr(ctx, stmt, &stmt->tproxy.family, &stmt->tproxy.addr); if (err < 0) diff --git a/tests/shell/testcases/sets/0047nat_0 b/tests/shell/testcases/sets/0047nat_0 index cb1d4d68..d19f5b69 100755 --- a/tests/shell/testcases/sets/0047nat_0 +++ b/tests/shell/testcases/sets/0047nat_0 @@ -18,3 +18,17 @@ EXPECTED="table ip x { set -e $NFT -f - <<< $EXPECTED $NFT add element x y { 10.141.12.0/24 : 192.168.5.10-192.168.5.20 } + +EXPECTED="table inet x { + chain x { + type nat hook prerouting priority dstnat; policy accept; + dnat to ip daddr . tcp dport map { 10.141.10.1 . 22 : 192.168.2.2, 10.141.11.2 . 2222 : 192.168.4.2 } + } + + chain y { + type nat hook postrouting priority srcnat; policy accept; + snat to ip saddr map { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2-192.168.4.3 } + } +}" + +$NFT -f - <<< $EXPECTED |