diff options
author | Florian Westphal <fw@strlen.de> | 2020-02-24 01:03:23 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2020-02-24 10:58:04 +0100 |
commit | 99bd13bbe8b53556e333c572a53dde1bc0265b0d (patch) | |
tree | 8b21ef93cc27f4c3ff725764cc136989ac653fe8 /src/evaluate.c | |
parent | 222441d31dc4d75e9168948b3547a0babe8d865d (diff) |
src: allow nat maps containing both ip(6) address and port
nft will now be able to handle
map destinations {
type ipv4_addr . inet_service : ipv4_addr . inet_service
}
chain f {
dnat to ip daddr . tcp dport map @destinations
}
Something like this won't work though:
meta l4proto tcp dnat ip6 to numgen inc mod 4 map { 0 : dead::f001 . 8080, ..
as we lack the type info to properly dissect "dead::f001" as an ipv6
address.
For the named map case, this info is available in the map
definition, but for the anon case we'd need to resort to guesswork.
Support is added by peeking into the map definition when evaluating
a nat statement with a map.
Right now, when a map is provided as address, we will only check that
the mapped-to data type matches the expected size (of an ipv4 or ipv6
address).
After this patch, if the mapped-to type is a concatenation, it will
take a peek at the individual concat expressions. If its a combination
of address and service, nft will translate this so that the kernel nat
expression looks at the returned register that would store the
inet_service part of the octet soup returned from the lookup expression.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/evaluate.c')
-rw-r--r-- | src/evaluate.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index ce1e65f4..0afd0403 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2849,6 +2849,52 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, return err; } +static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt) +{ + struct expr *one, *two, *data, *tmp; + const struct datatype *dtype; + int err; + + dtype = get_addr_dtype(stmt->nat.family); + + expr_set_context(&ctx->ectx, dtype, dtype->size); + if (expr_evaluate(ctx, &stmt->nat.addr)) + return -1; + + data = stmt->nat.addr->mappings->set->data; + if (expr_ops(data)->type != EXPR_CONCAT) + return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size, + BYTEORDER_BIG_ENDIAN, + &stmt->nat.addr); + + one = list_first_entry(&data->expressions, struct expr, list); + two = list_entry(one->list.next, struct expr, list); + + if (one == two || !list_is_last(&two->list, &data->expressions)) + return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size, + BYTEORDER_BIG_ENDIAN, + &stmt->nat.addr); + + tmp = one; + err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size, + BYTEORDER_BIG_ENDIAN, + &tmp); + if (err < 0) + return err; + if (tmp != one) + BUG("Internal error: Unexpected alteration of l3 expression"); + + tmp = two; + err = nat_evaluate_transport(ctx, stmt, &tmp); + if (err < 0) + return err; + if (tmp != two) + BUG("Internal error: Unexpected alteration of l4 expression"); + + stmt->nat.ipportmap = true; + return err; +} + static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) { int err; @@ -2862,6 +2908,16 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) if (err < 0) return err; + if (stmt->nat.proto == NULL && + expr_ops(stmt->nat.addr)->type == EXPR_MAP) { + err = stmt_evaluate_nat_map(ctx, stmt); + if (err < 0) + return err; + + stmt->flags |= STMT_F_TERMINAL; + return 0; + } + err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family, &stmt->nat.addr); if (err < 0) |