diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/evaluate.c | 124 | ||||
-rw-r--r-- | src/netlink_delinearize.c | 3 | ||||
-rw-r--r-- | src/netlink_linearize.c | 2 | ||||
-rw-r--r-- | src/parser_bison.y | 11 | ||||
-rw-r--r-- | src/statement.c | 12 |
5 files changed, 110 insertions, 42 deletions
diff --git a/src/evaluate.c b/src/evaluate.c index 3a3f2468..3593eb80 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2507,9 +2507,28 @@ static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt) static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt) { + const struct proto_desc *nproto; + switch (ctx->pctx.family) { case NFPROTO_IPV4: case NFPROTO_IPV6: + if (stmt->nat.family == NFPROTO_UNSPEC) + stmt->nat.family = ctx->pctx.family; + return 0; + case NFPROTO_INET: + if (!stmt->nat.addr) + return 0; + + if (stmt->nat.family != NFPROTO_UNSPEC) + return 0; + + nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + + if (nproto == &proto_ip) + stmt->nat.family = NFPROTO_IPV4; + else if (nproto == &proto_ip6) + stmt->nat.family = NFPROTO_IPV6; + return 0; default: return stmt_error(ctx, stmt, @@ -2551,6 +2570,55 @@ static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *stmt, BYTEORDER_BIG_ENDIAN, expr); } +static int stmt_evaluate_l3proto(struct eval_ctx *ctx, + struct stmt *stmt, uint8_t family) +{ + const struct proto_desc *nproto; + + nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + + if ((nproto == &proto_ip && family != NFPROTO_IPV4) || + (nproto == &proto_ip6 && family != NFPROTO_IPV6)) + return stmt_binary_error(ctx, stmt, + &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in tproxy statement", + ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name, + family2str(stmt->tproxy.family)); + return 0; +} + +static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, + uint8_t family, + struct expr **addr) +{ + const struct datatype *dtype; + unsigned int len; + int err; + + if (ctx->pctx.family == NFPROTO_INET) { + switch (family) { + case NFPROTO_IPV4: + dtype = &ipaddr_type; + len = 4 * BITS_PER_BYTE; + break; + case NFPROTO_IPV6: + dtype = &ip6addr_type; + len = 16 * BITS_PER_BYTE; + break; + default: + return stmt_error(ctx, stmt, + "ip or ip6 must be specified with address for inet tables."); + } + + err = stmt_evaluate_arg(ctx, stmt, dtype, len, + BYTEORDER_BIG_ENDIAN, addr); + } else { + err = evaluate_addr(ctx, stmt, addr); + } + + return err; +} + static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) { int err; @@ -2560,7 +2628,12 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) return err; if (stmt->nat.addr != NULL) { - err = evaluate_addr(ctx, stmt, &stmt->nat.addr); + err = stmt_evaluate_l3proto(ctx, stmt, stmt->nat.family); + if (err < 0) + return err; + + err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family, + &stmt->nat.addr); if (err < 0) return err; } @@ -2576,9 +2649,7 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt) { - const struct proto_desc *nproto; - const struct datatype *dtype; - int err, len; + int err; switch (ctx->pctx.family) { case NFPROTO_IPV4: @@ -2600,46 +2671,19 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt) if (!stmt->tproxy.addr && !stmt->tproxy.port) return stmt_error(ctx, stmt, "Either address or port must be specified!"); - nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; - if ((nproto == &proto_ip && stmt->tproxy.family != NFPROTO_IPV4) || - (nproto == &proto_ip6 && stmt->tproxy.family != NFPROTO_IPV6)) - /* this prevents us from rules like - * ip protocol tcp tproxy ip6 to [dead::beef] - */ - return stmt_binary_error(ctx, stmt, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], - "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in tproxy statement", - ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name, - family2str(stmt->tproxy.family)); + err = stmt_evaluate_l3proto(ctx, stmt, stmt->tproxy.family); + if (err < 0) + return err; if (stmt->tproxy.addr != NULL) { if (stmt->tproxy.addr->etype == EXPR_RANGE) return stmt_error(ctx, stmt, "Address ranges are not supported for tproxy."); - if (ctx->pctx.family == NFPROTO_INET) { - switch (stmt->tproxy.family) { - case NFPROTO_IPV4: - dtype = &ipaddr_type; - len = 4 * BITS_PER_BYTE; - break; - case NFPROTO_IPV6: - dtype = &ip6addr_type; - len = 16 * BITS_PER_BYTE; - break; - default: - return stmt_error(ctx, stmt, - "Family must be specified in tproxy statement with address for inet tables."); - } - err = stmt_evaluate_arg(ctx, stmt, dtype, len, - BYTEORDER_BIG_ENDIAN, - &stmt->tproxy.addr); - if (err < 0) - return err; - } - else { - err = evaluate_addr(ctx, stmt, &stmt->tproxy.addr); - if (err < 0) - return err; - } + + err = stmt_evaluate_addr(ctx, stmt, stmt->tproxy.family, + &stmt->tproxy.addr); + + if (err < 0) + return err; } if (stmt->tproxy.port != NULL) { diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 9a2d63df..40ab0256 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -932,6 +932,9 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, family = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FAMILY); + if (ctx->table->handle.family == NFPROTO_INET) + stmt->nat.family = family; + if (nftnl_expr_is_set(nle, NFTNL_EXPR_NAT_FLAGS)) stmt->nat.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FLAGS); diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 8df82d5a..df763544 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -1025,7 +1025,7 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, nle = alloc_nft_expr("nat"); nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_TYPE, stmt->nat.type); - family = nftnl_rule_get_u32(ctx->nlr, NFTNL_RULE_FAMILY); + family = stmt->nat.family; nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_FAMILY, family); nftnl_flag_attr = NFTNL_EXPR_NAT_FLAGS; diff --git a/src/parser_bison.y b/src/parser_bison.y index 0a9679c3..4a2a81cd 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -2816,6 +2816,11 @@ nat_stmt_args : stmt_expr { $<stmt>0->nat.addr = $2; } + | nf_key_proto TO stmt_expr + { + $<stmt>0->nat.family = $1; + $<stmt>0->nat.addr = $3; + } | stmt_expr COLON stmt_expr { $<stmt>0->nat.addr = $1; @@ -2826,6 +2831,12 @@ nat_stmt_args : stmt_expr $<stmt>0->nat.addr = $2; $<stmt>0->nat.proto = $4; } + | nf_key_proto TO stmt_expr COLON stmt_expr + { + $<stmt>0->nat.family = $1; + $<stmt>0->nat.addr = $3; + $<stmt>0->nat.proto = $5; + } | COLON stmt_expr { $<stmt>0->nat.proto = $2; diff --git a/src/statement.c b/src/statement.c index 9b45b3c5..b2370f87 100644 --- a/src/statement.c +++ b/src/statement.c @@ -586,8 +586,18 @@ const char *nat_etype2str(enum nft_nat_etypes type) static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) { nft_print(octx, "%s", nat_etype2str(stmt->nat.type)); - if (stmt->nat.addr || stmt->nat.proto) + if (stmt->nat.addr || stmt->nat.proto) { + switch (stmt->nat.family) { + case NFPROTO_IPV4: + nft_print(octx, " ip"); + break; + case NFPROTO_IPV6: + nft_print(octx, " ip6"); + break; + } + nft_print(octx, " to"); + } if (stmt->nat.addr) { nft_print(octx, " "); |