@@ -86,6 +86,7 @@ extern struct stmt *nat_stmt_alloc(const struct location *loc);
struct masq_stmt {
uint32_t flags;
+ struct expr *proto;
};
extern struct stmt *masq_stmt_alloc(const struct location *loc);
@@ -1849,6 +1849,12 @@ static int stmt_evaluate_masq(struct eval_ctx *ctx, struct stmt *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;
}
@@ -726,16 +726,41 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
+ enum nft_registers reg1, reg2;
+ struct expr *proto;
struct stmt *stmt;
- uint32_t flags;
+ uint32_t flags = 0;
- flags = 0;
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;
+ reg1 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MIN);
+ if (reg1) {
+ proto = netlink_get_register(ctx, loc, reg1);
+ if (proto == NULL)
+ return netlink_error(ctx, loc,
+ "MASQUERADE statement"
+ "has no proto expression");
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->masq.proto = proto;
+ }
+
+ reg2 = netlink_parse_register(nle, NFTNL_EXPR_MASQ_REG_PROTO_MAX);
+ if (reg2 && reg2 != reg1) {
+ proto = netlink_get_register(ctx, loc, reg2);
+ if (proto == NULL)
+ return netlink_error(ctx, loc,
+ "MASQUERADE statement"
+ "has no proto expression");
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ if (stmt->masq.proto != NULL)
+ proto = range_expr_alloc(loc, stmt->nat.proto, proto);
+ stmt->nat.proto = proto;
+ }
+
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
@@ -884,12 +884,36 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
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);
}
@@ -1644,17 +1644,28 @@ nat_stmt_args : stmt_expr
}
;
-masq_stmt : masq_stmt_alloc
- | masq_stmt_alloc nf_nat_flags
- {
- $$ = $1;
- $$->masq.flags = $2;
- }
+masq_stmt : masq_stmt_alloc masq_stmt_args
+ | masq_stmt_alloc
;
masq_stmt_alloc : MASQUERADE { $$ = masq_stmt_alloc(&@$); }
;
+masq_stmt_args : TO COLON stmt_expr
+ {
+ $<stmt>0->masq.proto = $3;
+ }
+ | TO COLON stmt_expr nf_nat_flags
+ {
+ $<stmt>0->masq.proto = $3;
+ $<stmt>0->masq.flags = $4;
+ }
+ | nf_nat_flags
+ {
+ $<stmt>0->masq.flags = $1;
+ }
+ ;
+
redir_stmt : redir_stmt_alloc redir_stmt_arg
| redir_stmt_alloc
;
@@ -385,13 +385,24 @@ static void masq_stmt_print(const struct stmt *stmt)
{
printf("masquerade");
+ if (stmt->masq.proto) {
+ printf(":");
+ expr_print(stmt->masq.proto);
+ }
+
print_nf_nat_flags(stmt->masq.flags);
}
+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)