From fde8ddfc31bbc4015e8a76b40cc7e27bcd7920ff Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 17 Mar 2018 10:39:27 +0100 Subject: Combine redir and masq statements into nat All these statements are very similar, handling them with the same code is obvious. The only thing required here is a custom extension of enum nft_nat_types which is used in nat_stmt to distinguish between snat and dnat already. Though since enum nft_nat_types is part of kernel uAPI, create a local extended version containing the additional fields. Note that nat statement printing got a bit more complicated to get the number of spaces right for every possible combination of attributes. Note also that there wasn't a case for STMT_MASQ in rule_parse_postprocess(), which seems like a bug. Since STMT_MASQ became just a variant of STMT_NAT, postprocessing will take place for it now anyway. Signed-off-by: Phil Sutter Signed-off-by: Pablo Neira Ayuso --- include/statement.h | 32 ++++------- src/evaluate.c | 40 -------------- src/netlink_delinearize.c | 32 +++++------ src/netlink_linearize.c | 135 +++++++++++++--------------------------------- src/parser_bison.y | 38 ++++++------- src/statement.c | 74 +++++-------------------- 6 files changed, 89 insertions(+), 262 deletions(-) diff --git a/include/statement.h b/include/statement.h index bb4af9d3..fa0b5dfa 100644 --- a/include/statement.h +++ b/include/statement.h @@ -98,28 +98,22 @@ struct reject_stmt { extern struct stmt *reject_stmt_alloc(const struct location *loc); -struct nat_stmt { - enum nft_nat_types type; - struct expr *addr; - struct expr *proto; - uint32_t flags; -}; - -extern struct stmt *nat_stmt_alloc(const struct location *loc); - -struct masq_stmt { - uint32_t flags; - struct expr *proto; +enum nft_nat_etypes { + __NFT_NAT_SNAT = NFT_NAT_SNAT, + __NFT_NAT_DNAT = NFT_NAT_DNAT, + NFT_NAT_MASQ, + NFT_NAT_REDIR, }; -extern struct stmt *masq_stmt_alloc(const struct location *loc); - -struct redir_stmt { +struct nat_stmt { + enum nft_nat_etypes type; + struct expr *addr; struct expr *proto; uint32_t flags; }; -extern struct stmt *redir_stmt_alloc(const struct location *loc); +extern struct stmt *nat_stmt_alloc(const struct location *loc, + enum nft_nat_etypes type); struct queue_stmt { struct expr *queue; @@ -233,8 +227,6 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc); * @STMT_LOG: log statement * @STMT_REJECT: REJECT statement * @STMT_NAT: NAT statement - * @STMT_MASQ: masquerade statement - * @STMT_REDIR: redirect statement * @STMT_QUEUE: QUEUE statement * @STMT_CT: conntrack statement * @STMT_SET: set statement @@ -260,8 +252,6 @@ enum stmt_types { STMT_LOG, STMT_REJECT, STMT_NAT, - STMT_MASQ, - STMT_REDIR, STMT_QUEUE, STMT_CT, STMT_SET, @@ -324,8 +314,6 @@ struct stmt { struct limit_stmt limit; struct reject_stmt reject; struct nat_stmt nat; - struct masq_stmt masq; - struct redir_stmt redir; struct queue_stmt queue; struct quota_stmt quota; struct ct_stmt ct; diff --git a/src/evaluate.c b/src/evaluate.c index 8de5e48d..6ae94b0f 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2465,42 +2465,6 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) return 0; } -static int stmt_evaluate_masq(struct eval_ctx *ctx, struct stmt *stmt) -{ - int err; - - err = nat_evaluate_family(ctx, stmt); - if (err < 0) - return err; - - if (stmt->masq.proto != NULL) { - err = nat_evaluate_transport(ctx, stmt, &stmt->masq.proto); - if (err < 0) - return err; - } - - stmt->flags |= STMT_F_TERMINAL; - return 0; -} - -static int stmt_evaluate_redir(struct eval_ctx *ctx, struct stmt *stmt) -{ - int err; - - err = nat_evaluate_family(ctx, stmt); - if (err < 0) - return err; - - if (stmt->redir.proto != NULL) { - err = nat_evaluate_transport(ctx, stmt, &stmt->redir.proto); - if (err < 0) - return err; - } - - stmt->flags |= STMT_F_TERMINAL; - return 0; -} - static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt) { int err; @@ -2758,10 +2722,6 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt) return stmt_evaluate_reject(ctx, stmt); case STMT_NAT: return stmt_evaluate_nat(ctx, stmt); - case STMT_MASQ: - return stmt_evaluate_masq(ctx, stmt); - case STMT_REDIR: - return stmt_evaluate_redir(ctx, stmt); case STMT_QUEUE: return stmt_evaluate_queue(ctx, stmt); case STMT_DUP: diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index b20047f1..754a307e 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -861,8 +861,8 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx, enum nft_registers reg1, reg2; int family; - stmt = nat_stmt_alloc(loc); - stmt->nat.type = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_TYPE); + stmt = nat_stmt_alloc(loc, + nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_TYPE)); family = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FAMILY); @@ -951,8 +951,8 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, if (nftnl_expr_is_set(nle, NFTNL_EXPR_MASQ_FLAGS)) flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_MASQ_FLAGS); - stmt = masq_stmt_alloc(loc); - stmt->masq.flags = flags; + stmt = nat_stmt_alloc(loc, NFT_NAT_MASQ); + stmt->nat.flags = flags; reg1 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN); if (reg1) { @@ -963,7 +963,7 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, goto out_err; } expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); - stmt->masq.proto = proto; + stmt->nat.proto = proto; } reg2 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MAX); @@ -975,9 +975,9 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx, goto out_err; } expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); - if (stmt->masq.proto != NULL) - proto = range_expr_alloc(loc, stmt->masq.proto, proto); - stmt->masq.proto = proto; + if (stmt->nat.proto != NULL) + proto = range_expr_alloc(loc, stmt->nat.proto, proto); + stmt->nat.proto = proto; } ctx->stmt = stmt; @@ -995,11 +995,11 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, enum nft_registers reg1, reg2; uint32_t flags; - stmt = redir_stmt_alloc(loc); + stmt = nat_stmt_alloc(loc, NFT_NAT_REDIR); if (nftnl_expr_is_set(nle, NFTNL_EXPR_REDIR_FLAGS)) { flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_REDIR_FLAGS); - stmt->redir.flags = flags; + stmt->nat.flags = flags; } reg1 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MIN); @@ -1012,7 +1012,7 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, } expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); - stmt->redir.proto = proto; + stmt->nat.proto = proto; } reg2 = netlink_parse_register(nle, NFTNL_EXPR_REDIR_REG_PROTO_MAX); @@ -1025,10 +1025,10 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx, } expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN); - if (stmt->redir.proto != NULL) - proto = range_expr_alloc(loc, stmt->redir.proto, + if (stmt->nat.proto != NULL) + proto = range_expr_alloc(loc, stmt->nat.proto, proto); - stmt->redir.proto = proto; + stmt->nat.proto = proto; } ctx->stmt = stmt; @@ -2366,10 +2366,6 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r if (stmt->nat.proto != NULL) expr_postprocess(&rctx, &stmt->nat.proto); break; - case STMT_REDIR: - if (stmt->redir.proto != NULL) - expr_postprocess(&rctx, &stmt->redir.proto); - break; case STMT_REJECT: stmt_reject_postprocess(&rctx); break; diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index 12d143b5..1c06fc07 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -946,15 +946,43 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, enum nft_registers pmin_reg, pmax_reg; int registers = 0; int family; + int nftnl_flag_attr; + int nftnl_reg_pmin, nftnl_reg_pmax; - nle = alloc_nft_expr("nat"); - nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_TYPE, stmt->nat.type); + switch (stmt->nat.type) { + case NFT_NAT_SNAT: + case NFT_NAT_DNAT: + 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); - nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_FAMILY, family); + family = nftnl_rule_get_u32(ctx->nlr, NFTNL_RULE_FAMILY); + nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_FAMILY, family); + + nftnl_flag_attr = NFTNL_EXPR_NAT_FLAGS; + nftnl_reg_pmin = NFTNL_EXPR_NAT_REG_PROTO_MIN; + nftnl_reg_pmax = NFTNL_EXPR_NAT_REG_PROTO_MAX; + break; + case NFT_NAT_MASQ: + nle = alloc_nft_expr("masq"); + + nftnl_flag_attr = NFTNL_EXPR_MASQ_FLAGS; + nftnl_reg_pmin = NFTNL_EXPR_MASQ_REG_PROTO_MIN; + nftnl_reg_pmax = NFTNL_EXPR_MASQ_REG_PROTO_MAX; + break; + case NFT_NAT_REDIR: + nle = alloc_nft_expr("redir"); + + nftnl_flag_attr = NFTNL_EXPR_REDIR_FLAGS; + nftnl_reg_pmin = NFTNL_EXPR_REDIR_REG_PROTO_MIN; + nftnl_reg_pmax = NFTNL_EXPR_REDIR_REG_PROTO_MAX; + break; + default: + BUG("unknown nat type %d\n", stmt->nat.type); + break; + } if (stmt->nat.flags != 0) - nftnl_expr_set_u32(nle, NFTNL_EXPR_NAT_FLAGS, stmt->nat.flags); + nftnl_expr_set_u32(nle, nftnl_flag_attr, stmt->nat.flags); if (stmt->nat.addr) { amin_reg = get_register(ctx, NULL); @@ -988,98 +1016,11 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx, netlink_gen_expr(ctx, stmt->nat.proto->left, pmin_reg); netlink_gen_expr(ctx, stmt->nat.proto->right, pmax_reg); - netlink_put_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN, - pmin_reg); - netlink_put_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MAX, - pmax_reg); + netlink_put_register(nle, nftnl_reg_pmin, pmin_reg); + netlink_put_register(nle, nftnl_reg_pmax, pmax_reg); } else { netlink_gen_expr(ctx, stmt->nat.proto, pmin_reg); - netlink_put_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN, - pmin_reg); - } - } - - while (registers > 0) { - release_register(ctx, NULL); - registers--; - } - - nftnl_rule_add_expr(ctx->nlr, nle); -} - -static void netlink_gen_masq_stmt(struct netlink_linearize_ctx *ctx, - const struct stmt *stmt) -{ - enum nft_registers pmin_reg, pmax_reg; - struct nftnl_expr *nle; - int registers = 0; - - nle = alloc_nft_expr("masq"); - if (stmt->masq.flags != 0) - nftnl_expr_set_u32(nle, NFTNL_EXPR_MASQ_FLAGS, - stmt->masq.flags); - if (stmt->masq.proto) { - pmin_reg = get_register(ctx, NULL); - registers++; - - if (stmt->masq.proto->ops->type == EXPR_RANGE) { - pmax_reg = get_register(ctx, NULL); - registers++; - - netlink_gen_expr(ctx, stmt->masq.proto->left, pmin_reg); - netlink_gen_expr(ctx, stmt->masq.proto->right, pmax_reg); - netlink_put_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN, pmin_reg); - netlink_put_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MAX, pmax_reg); - } else { - netlink_gen_expr(ctx, stmt->masq.proto, pmin_reg); - netlink_put_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN, pmin_reg); - } - } - - while (registers > 0) { - release_register(ctx, NULL); - registers--; - } - - nftnl_rule_add_expr(ctx->nlr, nle); -} - -static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx, - const struct stmt *stmt) -{ - struct nftnl_expr *nle; - enum nft_registers pmin_reg, pmax_reg; - int registers = 0; - - nle = alloc_nft_expr("redir"); - - if (stmt->redir.flags != 0) - nftnl_expr_set_u32(nle, NFTNL_EXPR_REDIR_FLAGS, - stmt->redir.flags); - - if (stmt->redir.proto) { - pmin_reg = get_register(ctx, NULL); - registers++; - - if (stmt->redir.proto->ops->type == EXPR_RANGE) { - pmax_reg = get_register(ctx, NULL); - registers++; - - netlink_gen_expr(ctx, stmt->redir.proto->left, - pmin_reg); - netlink_gen_expr(ctx, stmt->redir.proto->right, - pmax_reg); - netlink_put_register(nle, - NFTNL_EXPR_REDIR_REG_PROTO_MIN, - pmin_reg); - netlink_put_register(nle, - NFTNL_EXPR_REDIR_REG_PROTO_MAX, - pmax_reg); - } else { - netlink_gen_expr(ctx, stmt->redir.proto, pmin_reg); - netlink_put_register(nle, - NFTNL_EXPR_REDIR_REG_PROTO_MIN, - pmin_reg); + netlink_put_register(nle, nftnl_reg_pmin, pmin_reg); } } @@ -1310,10 +1251,6 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx, return netlink_gen_reject_stmt(ctx, stmt); case STMT_NAT: return netlink_gen_nat_stmt(ctx, stmt); - case STMT_MASQ: - return netlink_gen_masq_stmt(ctx, stmt); - case STMT_REDIR: - return netlink_gen_redir_stmt(ctx, stmt); case STMT_DUP: return netlink_gen_dup_stmt(ctx, stmt); case STMT_QUEUE: diff --git a/src/parser_bison.y b/src/parser_bison.y index 9c143832..f1617eea 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -2417,16 +2417,8 @@ reject_opts : /* empty */ nat_stmt : nat_stmt_alloc nat_stmt_args ; -nat_stmt_alloc : SNAT - { - $$ = nat_stmt_alloc(&@$); - $$->nat.type = NFT_NAT_SNAT; - } - | DNAT - { - $$ = nat_stmt_alloc(&@$); - $$->nat.type = NFT_NAT_DNAT; - } +nat_stmt_alloc : SNAT { $$ = nat_stmt_alloc(&@$, NFT_NAT_SNAT); } + | DNAT { $$ = nat_stmt_alloc(&@$, NFT_NAT_DNAT); } ; primary_stmt_expr : symbol_expr { $$ = $1; } @@ -2576,21 +2568,21 @@ masq_stmt : masq_stmt_alloc masq_stmt_args | masq_stmt_alloc ; -masq_stmt_alloc : MASQUERADE { $$ = masq_stmt_alloc(&@$); } +masq_stmt_alloc : MASQUERADE { $$ = nat_stmt_alloc(&@$, NFT_NAT_MASQ); } ; masq_stmt_args : TO COLON stmt_expr { - $0->masq.proto = $3; + $0->nat.proto = $3; } | TO COLON stmt_expr nf_nat_flags { - $0->masq.proto = $3; - $0->masq.flags = $4; + $0->nat.proto = $3; + $0->nat.flags = $4; } | nf_nat_flags { - $0->masq.flags = $1; + $0->nat.flags = $1; } ; @@ -2598,30 +2590,30 @@ redir_stmt : redir_stmt_alloc redir_stmt_arg | redir_stmt_alloc ; -redir_stmt_alloc : REDIRECT { $$ = redir_stmt_alloc(&@$); } +redir_stmt_alloc : REDIRECT { $$ = nat_stmt_alloc(&@$, NFT_NAT_REDIR); } ; redir_stmt_arg : TO stmt_expr { - $0->redir.proto = $2; + $0->nat.proto = $2; } | TO COLON stmt_expr { - $0->redir.proto = $3; + $0->nat.proto = $3; } | nf_nat_flags { - $0->redir.flags = $1; + $0->nat.flags = $1; } | TO stmt_expr nf_nat_flags { - $0->redir.proto = $2; - $0->redir.flags = $3; + $0->nat.proto = $2; + $0->nat.flags = $3; } | TO COLON stmt_expr nf_nat_flags { - $0->redir.proto = $3; - $0->redir.flags = $4; + $0->nat.proto = $3; + $0->nat.flags = $4; } ; diff --git a/src/statement.c b/src/statement.c index d495ec44..b8e0b036 100644 --- a/src/statement.c +++ b/src/statement.c @@ -499,10 +499,16 @@ static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) static const char * const nat_types[] = { [NFT_NAT_SNAT] = "snat", [NFT_NAT_DNAT] = "dnat", + [NFT_NAT_MASQ] = "masquerade", + [NFT_NAT_REDIR] = "redirect", }; - nft_print(octx, "%s to ", nat_types[stmt->nat.type]); + nft_print(octx, "%s", nat_types[stmt->nat.type]); + if (stmt->nat.addr || stmt->nat.proto) + nft_print(octx, " to"); + if (stmt->nat.addr) { + nft_print(octx, " "); if (stmt->nat.proto) { if (stmt->nat.addr->ops->type == EXPR_VALUE && stmt->nat.addr->dtype->type == TYPE_IP6ADDR) { @@ -525,6 +531,8 @@ static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx) } if (stmt->nat.proto) { + if (!stmt->nat.addr) + nft_print(octx, " "); nft_print(octx, ":"); expr_print(stmt->nat.proto, octx); } @@ -545,67 +553,13 @@ static const struct stmt_ops nat_stmt_ops = { .destroy = nat_stmt_destroy, }; -struct stmt *nat_stmt_alloc(const struct location *loc) -{ - return stmt_alloc(loc, &nat_stmt_ops); -} - -static void masq_stmt_print(const struct stmt *stmt, struct output_ctx *octx) -{ - nft_print(octx, "masquerade"); - - if (stmt->masq.proto) { - nft_print(octx, " to :"); - expr_print(stmt->masq.proto, octx); - } - - print_nf_nat_flags(stmt->masq.flags, octx); -} - -static void masq_stmt_destroy(struct stmt *stmt) -{ - expr_free(stmt->masq.proto); -} - -static const struct stmt_ops masq_stmt_ops = { - .type = STMT_MASQ, - .name = "masq", - .print = masq_stmt_print, - .destroy = masq_stmt_destroy, -}; - -struct stmt *masq_stmt_alloc(const struct location *loc) -{ - return stmt_alloc(loc, &masq_stmt_ops); -} - -static void redir_stmt_print(const struct stmt *stmt, struct output_ctx *octx) +struct stmt *nat_stmt_alloc(const struct location *loc, + enum nft_nat_etypes type) { - nft_print(octx, "redirect"); - - if (stmt->redir.proto) { - nft_print(octx, " to :"); - expr_print(stmt->redir.proto, octx); - } - - print_nf_nat_flags(stmt->redir.flags, octx); -} + struct stmt *stmt = stmt_alloc(loc, &nat_stmt_ops); -static void redir_stmt_destroy(struct stmt *stmt) -{ - expr_free(stmt->redir.proto); -} - -static const struct stmt_ops redir_stmt_ops = { - .type = STMT_REDIR, - .name = "redir", - .print = redir_stmt_print, - .destroy = redir_stmt_destroy, -}; - -struct stmt *redir_stmt_alloc(const struct location *loc) -{ - return stmt_alloc(loc, &redir_stmt_ops); + stmt->nat.type = type; + return stmt; } static const char * const set_stmt_op_names[] = { -- cgit v1.2.3