]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
Combine redir and masq statements into nat
authorPhil Sutter <phil@nwl.cc>
Sat, 17 Mar 2018 09:39:27 +0000 (10:39 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Sat, 17 Mar 2018 12:23:45 +0000 (13:23 +0100)
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 <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/statement.h
src/evaluate.c
src/netlink_delinearize.c
src/netlink_linearize.c
src/parser_bison.y
src/statement.c

index bb4af9d341228b4aa8c9f9f551ee37a14045fec5..fa0b5dfa4bf5605e84b24fb76140393ec4f61a7b 100644 (file)
@@ -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;
index 8de5e48d728addb254b15a640acc79316bb7f6f1..6ae94b0f56de5109903518a077ac20b161879da4 100644 (file)
@@ -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:
index b20047f14b55e772ac103902edfd46426840b1d4..754a307e99f5291536800e2288ba53dc36553545 100644 (file)
@@ -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;
index 12d143b5acc0d12959130ffa679c20e83c6c9a68..1c06fc07e2fa63625655fb7cd19988e28d8fe403 100644 (file)
@@ -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:
index 9c143832eed6e4b445847c26a6cf55aaf868df60..f1617eeaf1496bf04e57d1259ff2309f34b2e499 100644 (file)
@@ -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
                        {
-                               $<stmt>0->masq.proto = $3;
+                               $<stmt>0->nat.proto = $3;
                        }
                        |       TO      COLON   stmt_expr       nf_nat_flags
                        {
-                               $<stmt>0->masq.proto = $3;
-                               $<stmt>0->masq.flags = $4;
+                               $<stmt>0->nat.proto = $3;
+                               $<stmt>0->nat.flags = $4;
                        }
                        |       nf_nat_flags
                        {
-                               $<stmt>0->masq.flags = $1;
+                               $<stmt>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
                        {
-                               $<stmt>0->redir.proto = $2;
+                               $<stmt>0->nat.proto = $2;
                        }
                        |       TO      COLON   stmt_expr
                        {
-                               $<stmt>0->redir.proto = $3;
+                               $<stmt>0->nat.proto = $3;
                        }
                        |       nf_nat_flags
                        {
-                               $<stmt>0->redir.flags = $1;
+                               $<stmt>0->nat.flags = $1;
                        }
                        |       TO      stmt_expr       nf_nat_flags
                        {
-                               $<stmt>0->redir.proto = $2;
-                               $<stmt>0->redir.flags = $3;
+                               $<stmt>0->nat.proto = $2;
+                               $<stmt>0->nat.flags = $3;
                        }
                        |       TO      COLON   stmt_expr       nf_nat_flags
                        {
-                               $<stmt>0->redir.proto = $3;
-                               $<stmt>0->redir.flags = $4;
+                               $<stmt>0->nat.proto = $3;
+                               $<stmt>0->nat.flags = $4;
                        }
                        ;
 
index d495ec447dfdc07ec33c9801cd459c21e6aa62b8..b8e0b036b9ebd9163f08b1e165f311fe8f171581 100644 (file)
@@ -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[] = {