* [nft PATCH v2] src: add redirect support
@ 2014-10-16 10:41 Arturo Borrero Gonzalez
2014-10-30 16:25 ` Pablo Neira Ayuso
0 siblings, 1 reply; 11+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-10-16 10:41 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
This patch adds redirect support for nft.
The syntax is:
% nft add rule nat prerouting redirect [port|nat_flags]
Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
v2: some cosmetic changes requested by Pablo.
include/statement.h | 10 +++++++++
src/evaluate.c | 40 +++++++++++++++++++++++++++++++++++
src/netlink_delinearize.c | 52 +++++++++++++++++++++++++++++++++++++++++++++
src/netlink_linearize.c | 49 ++++++++++++++++++++++++++++++++++++++++++
src/parser.y | 23 ++++++++++++++++++--
src/scanner.l | 1 +
src/statement.c | 29 +++++++++++++++++++++++++
7 files changed, 202 insertions(+), 2 deletions(-)
diff --git a/include/statement.h b/include/statement.h
index 35c1b7a..d143121 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -79,6 +79,13 @@ struct masq_stmt {
extern struct stmt *masq_stmt_alloc(const struct location *loc);
+struct redir_stmt {
+ struct expr *proto;
+ uint32_t flags;
+};
+
+extern struct stmt *redir_stmt_alloc(const struct location *loc);
+
struct queue_stmt {
struct expr *queue;
uint16_t flags;
@@ -110,6 +117,7 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
* @STMT_REJECT: REJECT statement
* @STMT_NAT: NAT statement
* @STMT_MASQ: masquerade statement
+ * @STMT_REDIR: redirect statement
* @STMT_QUEUE: QUEUE statement
* @STMT_CT: conntrack statement
*/
@@ -124,6 +132,7 @@ enum stmt_types {
STMT_REJECT,
STMT_NAT,
STMT_MASQ,
+ STMT_REDIR,
STMT_QUEUE,
STMT_CT,
};
@@ -172,6 +181,7 @@ struct stmt {
struct reject_stmt reject;
struct nat_stmt nat;
struct masq_stmt masq;
+ struct redir_stmt redir;
struct queue_stmt queue;
struct ct_stmt ct;
};
diff --git a/src/evaluate.c b/src/evaluate.c
index 108248a..d98d7a9 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1375,6 +1375,44 @@ out:
return 0;
}
+static int stmt_evaluate_redir(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ int err;
+ struct proto_ctx *pctx = &ctx->pctx;
+
+ if (!pctx)
+ goto out;
+
+ switch (pctx->family) {
+ case AF_INET:
+ expr_set_context(&ctx->ectx, &ipaddr_type,
+ 4 * BITS_PER_BYTE);
+ break;
+ case AF_INET6:
+ expr_set_context(&ctx->ectx, &ip6addr_type,
+ 16 * BITS_PER_BYTE);
+ break;
+ default:
+ return stmt_error(ctx, stmt, "ip and ip6 support only");
+ }
+
+ if (stmt->redir.proto != NULL) {
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL)
+ return stmt_binary_error(ctx, stmt->redir.proto, stmt,
+ "missing transport protocol match");
+
+ expr_set_context(&ctx->ectx, &inet_service_type,
+ 2 * BITS_PER_BYTE);
+ err = expr_evaluate(ctx, &stmt->redir.proto);
+ if (err < 0)
+ return err;
+ }
+
+out:
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+}
+
static int stmt_evaluate_ct(struct eval_ctx *ctx, struct stmt *stmt)
{
expr_set_context(&ctx->ectx, stmt->ct.tmpl->dtype,
@@ -1437,6 +1475,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
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_CT:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 38618ee..c34c7f6 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -583,6 +583,52 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
+static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *proto;
+ enum nft_registers reg1, reg2;
+ uint32_t flags;
+
+ stmt = redir_stmt_alloc(loc);
+
+ if (nft_rule_expr_is_set(nle, NFT_EXPR_REDIR_FLAGS)) {
+ flags = nft_rule_expr_get_u32(nle, NFT_EXPR_REDIR_FLAGS);
+ stmt->redir.flags = flags;
+ }
+
+ reg1 = nft_rule_expr_get_u32(nle, NFT_EXPR_REDIR_REG_PROTO_MIN);
+ if (reg1) {
+ proto = netlink_get_register(ctx, loc, reg1);
+ if (proto == NULL)
+ return netlink_error(ctx, loc,
+ "redirect statement has no proto "
+ "expression");
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->redir.proto = proto;
+ }
+
+ reg2 = nft_rule_expr_get_u32(nle, NFT_EXPR_REDIR_REG_PROTO_MAX);
+ if (reg2 && reg2 != reg1) {
+ proto = netlink_get_register(ctx, loc, reg2);
+ if (proto == NULL)
+ return netlink_error(ctx, loc,
+ "redirect statement has no proto "
+ "expression");
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ if (stmt->redir.proto != NULL)
+ proto = range_expr_alloc(loc, stmt->redir.proto,
+ proto);
+ stmt->redir.proto = proto;
+ }
+
+ list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nft_rule_expr *nle)
@@ -630,6 +676,7 @@ static const struct {
{ .name = "reject", .parse = netlink_parse_reject },
{ .name = "nat", .parse = netlink_parse_nat },
{ .name = "masq", .parse = netlink_parse_masq },
+ { .name = "redir", .parse = netlink_parse_redir },
{ .name = "queue", .parse = netlink_parse_queue },
};
@@ -1010,6 +1057,11 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
if (stmt->nat.proto != NULL)
expr_postprocess(&rctx, stmt, &stmt->nat.proto);
break;
+ case STMT_REDIR:
+ if (stmt->redir.proto != NULL)
+ expr_postprocess(&rctx, stmt,
+ &stmt->redir.proto);
+ break;
case STMT_REJECT:
stmt_reject_postprocess(rctx, stmt);
break;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 62155cc..de338cb 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -701,6 +701,53 @@ static void netlink_gen_masq_stmt(struct netlink_linearize_ctx *ctx,
nft_rule_add_expr(ctx->nlr, nle);
}
+static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nft_rule_expr *nle;
+ enum nft_registers pmin_reg, pmax_reg;
+ int registers = 0;
+
+ nle = alloc_nft_expr("redir");
+
+ if (stmt->redir.flags != 0)
+ nft_rule_expr_set_u32(nle, NFT_EXPR_REDIR_FLAGS,
+ stmt->redir.flags);
+
+ if (stmt->redir.proto) {
+ pmin_reg = get_register(ctx);
+ registers++;
+
+ if (stmt->redir.proto->ops->type == EXPR_RANGE) {
+ pmax_reg = get_register(ctx);
+ registers++;
+
+ netlink_gen_expr(ctx, stmt->redir.proto->left,
+ pmin_reg);
+ netlink_gen_expr(ctx, stmt->redir.proto->right,
+ pmax_reg);
+ nft_rule_expr_set_u32(nle,
+ NFT_EXPR_REDIR_REG_PROTO_MIN,
+ pmin_reg);
+ nft_rule_expr_set_u32(nle,
+ NFT_EXPR_REDIR_REG_PROTO_MAX,
+ pmax_reg);
+ } else {
+ netlink_gen_expr(ctx, stmt->redir.proto, pmin_reg);
+ nft_rule_expr_set_u32(nle,
+ NFT_EXPR_REDIR_REG_PROTO_MIN,
+ pmin_reg);
+ }
+ }
+
+ while (registers > 0) {
+ release_register(ctx);
+ registers--;
+ }
+
+ nft_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -767,6 +814,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
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_QUEUE:
return netlink_gen_queue_stmt(ctx, stmt);
case STMT_CT:
diff --git a/src/parser.y b/src/parser.y
index 9e9a839..6209e9e 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -375,6 +375,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token SNAT "snat"
%token DNAT "dnat"
%token MASQUERADE "masquerade"
+%token REDIRECT "redirect"
%token RANDOM "random"
%token RANDOM_FULLY "random-fully"
%token PERSISTENT "persistent"
@@ -440,8 +441,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <val> time_unit
%type <stmt> reject_stmt reject_stmt_alloc
%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
-%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc
-%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc
+%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
+%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
%type <val> nf_nat_flags nf_nat_flag
%type <stmt> queue_stmt queue_stmt_alloc
%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
@@ -1186,6 +1187,7 @@ stmt : verdict_stmt
| queue_stmt
| ct_stmt
| masq_stmt
+ | redir_stmt
;
verdict_stmt : verdict_expr
@@ -1420,6 +1422,23 @@ masq_stmt : masq_stmt_alloc
masq_stmt_alloc : MASQUERADE { $$ = masq_stmt_alloc(&@$); }
;
+redir_stmt : redir_stmt_alloc redir_stmt_arg
+ | redir_stmt_alloc
+ ;
+
+redir_stmt_alloc : REDIRECT { $$ = redir_stmt_alloc(&@$); }
+ ;
+
+redir_stmt_arg : COLON expr
+ {
+ $<stmt>0->redir.proto = $2;
+ }
+ | nf_nat_flags
+ {
+ $<stmt>0->redir.flags = $1;
+ }
+ ;
+
nf_nat_flags : nf_nat_flag
| nf_nat_flags COMMA nf_nat_flag
{
diff --git a/src/scanner.l b/src/scanner.l
index 32e59d9..e36c3b1 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -317,6 +317,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"snat" { return SNAT; }
"dnat" { return DNAT; }
"masquerade" { return MASQUERADE; }
+"redirect" { return REDIRECT; }
"random" { return RANDOM; }
"random-fully" { return RANDOM_FULLY; }
"persistent" { return PERSISTENT; }
diff --git a/src/statement.c b/src/statement.c
index 0ae616a..2587d27 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -348,3 +348,32 @@ 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)
+{
+ printf("redirect");
+
+ if (stmt->redir.proto) {
+ printf(" :");
+ expr_print(stmt->redir.proto);
+ }
+
+ print_nf_nat_flags(stmt->redir.flags);
+}
+
+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);
+}
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-10-16 10:41 Arturo Borrero Gonzalez
@ 2014-10-30 16:25 ` Pablo Neira Ayuso
2014-10-30 16:33 ` Pablo Neira Ayuso
2014-11-03 19:42 ` Arturo Borrero Gonzalez
0 siblings, 2 replies; 11+ messages in thread
From: Pablo Neira Ayuso @ 2014-10-30 16:25 UTC (permalink / raw)
To: Arturo Borrero Gonzalez; +Cc: netfilter-devel
On Thu, Oct 16, 2014 at 12:41:19PM +0200, Arturo Borrero Gonzalez wrote:
> This patch adds redirect support for nft.
>
> The syntax is:
>
> % nft add rule nat prerouting redirect [port|nat_flags]
I prefer if you add a couple of valid examples to the patch
description. This won't work as the protocol is not specified.
There's also some minor issues with this patch:
% nft add rule nat prerouting redirect
Memory allocation failure
Please, address and resubmit, thanks Arturo.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-10-30 16:25 ` Pablo Neira Ayuso
@ 2014-10-30 16:33 ` Pablo Neira Ayuso
2014-11-03 19:42 ` Arturo Borrero Gonzalez
1 sibling, 0 replies; 11+ messages in thread
From: Pablo Neira Ayuso @ 2014-10-30 16:33 UTC (permalink / raw)
To: Arturo Borrero Gonzalez; +Cc: netfilter-devel
On Thu, Oct 30, 2014 at 05:25:20PM +0100, Pablo Neira Ayuso wrote:
> On Thu, Oct 16, 2014 at 12:41:19PM +0200, Arturo Borrero Gonzalez wrote:
> > This patch adds redirect support for nft.
> >
> > The syntax is:
> >
> > % nft add rule nat prerouting redirect [port|nat_flags]
>
> I prefer if you add a couple of valid examples to the patch
> description. This won't work as the protocol is not specified.
>
> There's also some minor issues with this patch:
>
> % nft add rule nat prerouting redirect
> Memory allocation failure
>
> Please, address and resubmit, thanks Arturo.
BTW, please integrate the .t test file for the automated regression
testing in the next version of this patch.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-10-30 16:25 ` Pablo Neira Ayuso
2014-10-30 16:33 ` Pablo Neira Ayuso
@ 2014-11-03 19:42 ` Arturo Borrero Gonzalez
2014-11-04 13:37 ` Pablo Neira Ayuso
1 sibling, 1 reply; 11+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-11-03 19:42 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list
On 30 October 2014 17:25, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Thu, Oct 16, 2014 at 12:41:19PM +0200, Arturo Borrero Gonzalez wrote:
>> This patch adds redirect support for nft.
>>
>> The syntax is:
>>
>> % nft add rule nat prerouting redirect [port|nat_flags]
>
> I prefer if you add a couple of valid examples to the patch
> description. This won't work as the protocol is not specified.
>
> There's also some minor issues with this patch:
>
> % nft add rule nat prerouting redirect
> Memory allocation failure
>
> Please, address and resubmit, thanks Arturo.
Hi Pablo,
I've take further look at this patch. I don't see any issue.
As masquerade, I think redirect without protocol should work. I just
tested again the patch with ICMP packets and the redirection simply
works. I used tcpdump for the checks. The rule I used is the same as
in the patch description.
Regarding the memory allocation failure, I'm unable to find the issue.
Do you think is related to this patch? I just added thousands of
redirect rules in both IPv4 and IPv6 with no failures nor leakages
reported by valgrind.
I would request you a bit more info, please.
regards.
--
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* [nft PATCH v2] src: add redirect support
@ 2014-11-03 20:20 Arturo Borrero Gonzalez
0 siblings, 0 replies; 11+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-11-03 20:20 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
This patch adds redirect support for nft.
The syntax is:
% nft add rule nat prerouting redirect [port|nat_flags]
Signed-off-by: Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
---
v2: include regression tests-files
include/statement.h | 10 ++++++++
src/evaluate.c | 40 ++++++++++++++++++++++++++++++
src/netlink_delinearize.c | 52 +++++++++++++++++++++++++++++++++++++++
src/netlink_linearize.c | 49 +++++++++++++++++++++++++++++++++++++
src/parser.y | 23 ++++++++++++++++-
src/scanner.l | 1 +
src/statement.c | 29 ++++++++++++++++++++++
tests/regression/ip/redirect.t | 41 +++++++++++++++++++++++++++++++
tests/regression/ip6/redirect.t | 42 ++++++++++++++++++++++++++++++++
9 files changed, 285 insertions(+), 2 deletions(-)
create mode 100644 tests/regression/ip/redirect.t
create mode 100644 tests/regression/ip6/redirect.t
diff --git a/include/statement.h b/include/statement.h
index 35c1b7a..d143121 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -79,6 +79,13 @@ struct masq_stmt {
extern struct stmt *masq_stmt_alloc(const struct location *loc);
+struct redir_stmt {
+ struct expr *proto;
+ uint32_t flags;
+};
+
+extern struct stmt *redir_stmt_alloc(const struct location *loc);
+
struct queue_stmt {
struct expr *queue;
uint16_t flags;
@@ -110,6 +117,7 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
* @STMT_REJECT: REJECT statement
* @STMT_NAT: NAT statement
* @STMT_MASQ: masquerade statement
+ * @STMT_REDIR: redirect statement
* @STMT_QUEUE: QUEUE statement
* @STMT_CT: conntrack statement
*/
@@ -124,6 +132,7 @@ enum stmt_types {
STMT_REJECT,
STMT_NAT,
STMT_MASQ,
+ STMT_REDIR,
STMT_QUEUE,
STMT_CT,
};
@@ -172,6 +181,7 @@ struct stmt {
struct reject_stmt reject;
struct nat_stmt nat;
struct masq_stmt masq;
+ struct redir_stmt redir;
struct queue_stmt queue;
struct ct_stmt ct;
};
diff --git a/src/evaluate.c b/src/evaluate.c
index b722567..3eeb614 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -1546,6 +1546,44 @@ out:
return 0;
}
+static int stmt_evaluate_redir(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ int err;
+ struct proto_ctx *pctx = &ctx->pctx;
+
+ if (!pctx)
+ goto out;
+
+ switch (pctx->family) {
+ case AF_INET:
+ expr_set_context(&ctx->ectx, &ipaddr_type,
+ 4 * BITS_PER_BYTE);
+ break;
+ case AF_INET6:
+ expr_set_context(&ctx->ectx, &ip6addr_type,
+ 16 * BITS_PER_BYTE);
+ break;
+ default:
+ return stmt_error(ctx, stmt, "ip and ip6 support only");
+ }
+
+ if (stmt->redir.proto != NULL) {
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL)
+ return stmt_binary_error(ctx, stmt->redir.proto, stmt,
+ "missing transport protocol match");
+
+ expr_set_context(&ctx->ectx, &inet_service_type,
+ 2 * BITS_PER_BYTE);
+ err = expr_evaluate(ctx, &stmt->redir.proto);
+ if (err < 0)
+ return err;
+ }
+
+out:
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+}
+
static int stmt_evaluate_ct(struct eval_ctx *ctx, struct stmt *stmt)
{
expr_set_context(&ctx->ectx, stmt->ct.tmpl->dtype,
@@ -1608,6 +1646,8 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
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_CT:
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 8f90cc0..1be409b 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -583,6 +583,52 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
list_add_tail(&stmt->list, &ctx->rule->stmts);
}
+static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nft_rule_expr *nle)
+{
+ struct stmt *stmt;
+ struct expr *proto;
+ enum nft_registers reg1, reg2;
+ uint32_t flags;
+
+ stmt = redir_stmt_alloc(loc);
+
+ if (nft_rule_expr_is_set(nle, NFT_EXPR_REDIR_FLAGS)) {
+ flags = nft_rule_expr_get_u32(nle, NFT_EXPR_REDIR_FLAGS);
+ stmt->redir.flags = flags;
+ }
+
+ reg1 = nft_rule_expr_get_u32(nle, NFT_EXPR_REDIR_REG_PROTO_MIN);
+ if (reg1) {
+ proto = netlink_get_register(ctx, loc, reg1);
+ if (proto == NULL)
+ return netlink_error(ctx, loc,
+ "redirect statement has no proto "
+ "expression");
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ stmt->redir.proto = proto;
+ }
+
+ reg2 = nft_rule_expr_get_u32(nle, NFT_EXPR_REDIR_REG_PROTO_MAX);
+ if (reg2 && reg2 != reg1) {
+ proto = netlink_get_register(ctx, loc, reg2);
+ if (proto == NULL)
+ return netlink_error(ctx, loc,
+ "redirect statement has no proto "
+ "expression");
+
+ expr_set_type(proto, &inet_service_type, BYTEORDER_BIG_ENDIAN);
+ if (stmt->redir.proto != NULL)
+ proto = range_expr_alloc(loc, stmt->redir.proto,
+ proto);
+ stmt->redir.proto = proto;
+ }
+
+ list_add_tail(&stmt->list, &ctx->rule->stmts);
+}
+
static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nft_rule_expr *nle)
@@ -630,6 +676,7 @@ static const struct {
{ .name = "reject", .parse = netlink_parse_reject },
{ .name = "nat", .parse = netlink_parse_nat },
{ .name = "masq", .parse = netlink_parse_masq },
+ { .name = "redir", .parse = netlink_parse_redir },
{ .name = "queue", .parse = netlink_parse_queue },
};
@@ -1014,6 +1061,11 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
if (stmt->nat.proto != NULL)
expr_postprocess(&rctx, stmt, &stmt->nat.proto);
break;
+ case STMT_REDIR:
+ if (stmt->redir.proto != NULL)
+ expr_postprocess(&rctx, stmt,
+ &stmt->redir.proto);
+ break;
case STMT_REJECT:
stmt_reject_postprocess(rctx, stmt);
break;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 62155cc..de338cb 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -701,6 +701,53 @@ static void netlink_gen_masq_stmt(struct netlink_linearize_ctx *ctx,
nft_rule_add_expr(ctx->nlr, nle);
}
+static void netlink_gen_redir_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nft_rule_expr *nle;
+ enum nft_registers pmin_reg, pmax_reg;
+ int registers = 0;
+
+ nle = alloc_nft_expr("redir");
+
+ if (stmt->redir.flags != 0)
+ nft_rule_expr_set_u32(nle, NFT_EXPR_REDIR_FLAGS,
+ stmt->redir.flags);
+
+ if (stmt->redir.proto) {
+ pmin_reg = get_register(ctx);
+ registers++;
+
+ if (stmt->redir.proto->ops->type == EXPR_RANGE) {
+ pmax_reg = get_register(ctx);
+ registers++;
+
+ netlink_gen_expr(ctx, stmt->redir.proto->left,
+ pmin_reg);
+ netlink_gen_expr(ctx, stmt->redir.proto->right,
+ pmax_reg);
+ nft_rule_expr_set_u32(nle,
+ NFT_EXPR_REDIR_REG_PROTO_MIN,
+ pmin_reg);
+ nft_rule_expr_set_u32(nle,
+ NFT_EXPR_REDIR_REG_PROTO_MAX,
+ pmax_reg);
+ } else {
+ netlink_gen_expr(ctx, stmt->redir.proto, pmin_reg);
+ nft_rule_expr_set_u32(nle,
+ NFT_EXPR_REDIR_REG_PROTO_MIN,
+ pmin_reg);
+ }
+ }
+
+ while (registers > 0) {
+ release_register(ctx);
+ registers--;
+ }
+
+ nft_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
@@ -767,6 +814,8 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
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_QUEUE:
return netlink_gen_queue_stmt(ctx, stmt);
case STMT_CT:
diff --git a/src/parser.y b/src/parser.y
index 9e9a839..6209e9e 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -375,6 +375,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%token SNAT "snat"
%token DNAT "dnat"
%token MASQUERADE "masquerade"
+%token REDIRECT "redirect"
%token RANDOM "random"
%token RANDOM_FULLY "random-fully"
%token PERSISTENT "persistent"
@@ -440,8 +441,8 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <val> time_unit
%type <stmt> reject_stmt reject_stmt_alloc
%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
-%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc
-%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc
+%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
+%destructor { stmt_free($$); } nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
%type <val> nf_nat_flags nf_nat_flag
%type <stmt> queue_stmt queue_stmt_alloc
%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
@@ -1186,6 +1187,7 @@ stmt : verdict_stmt
| queue_stmt
| ct_stmt
| masq_stmt
+ | redir_stmt
;
verdict_stmt : verdict_expr
@@ -1420,6 +1422,23 @@ masq_stmt : masq_stmt_alloc
masq_stmt_alloc : MASQUERADE { $$ = masq_stmt_alloc(&@$); }
;
+redir_stmt : redir_stmt_alloc redir_stmt_arg
+ | redir_stmt_alloc
+ ;
+
+redir_stmt_alloc : REDIRECT { $$ = redir_stmt_alloc(&@$); }
+ ;
+
+redir_stmt_arg : COLON expr
+ {
+ $<stmt>0->redir.proto = $2;
+ }
+ | nf_nat_flags
+ {
+ $<stmt>0->redir.flags = $1;
+ }
+ ;
+
nf_nat_flags : nf_nat_flag
| nf_nat_flags COMMA nf_nat_flag
{
diff --git a/src/scanner.l b/src/scanner.l
index 32e59d9..e36c3b1 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -317,6 +317,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"snat" { return SNAT; }
"dnat" { return DNAT; }
"masquerade" { return MASQUERADE; }
+"redirect" { return REDIRECT; }
"random" { return RANDOM; }
"random-fully" { return RANDOM_FULLY; }
"persistent" { return PERSISTENT; }
diff --git a/src/statement.c b/src/statement.c
index 0ae616a..2587d27 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -348,3 +348,32 @@ 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)
+{
+ printf("redirect");
+
+ if (stmt->redir.proto) {
+ printf(" :");
+ expr_print(stmt->redir.proto);
+ }
+
+ print_nf_nat_flags(stmt->redir.flags);
+}
+
+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);
+}
diff --git a/tests/regression/ip/redirect.t b/tests/regression/ip/redirect.t
new file mode 100644
index 0000000..8e0f783
--- /dev/null
+++ b/tests/regression/ip/redirect.t
@@ -0,0 +1,41 @@
+*ip;test-ip4
+:output;type nat hook output priority 0
+
+# without arguments
+udp dport 53 redirect ;ok
+
+# nf_nat flags combination
+udp dport 53 redirect random ;ok
+udp dport 53 redirect random,persistent ;ok
+udp dport 53 redirect random,persistent,random-fully ;ok ;udp dport 53 redirect random,random-fully,persistent
+udp dport 53 redirect random,random-fully ;ok
+udp dport 53 redirect random,random-fully,persistent ;ok
+udp dport 53 redirect persistent ;ok
+udp dport 53 redirect persistent,random ;ok ;udp dport 53 redirect random,persistent
+udp dport 53 redirect persistent,random,random-fully ;ok ;udp dport 53 redirect random,random-fully,persistent
+udp dport 53 redirect persistent,random-fully ;ok ;udp dport 53 redirect random-fully,persistent
+udp dport 53 redirect persistent,random-fully,random;ok ;udp dport 53 redirect random,random-fully,persistent
+
+# port specification
+tcp dport 22 redirect :22 ;ok
+udp dport 1234 redirect :4321 ;ok
+ip daddr 172.16.0.1 udp dport 9998 redirect :6515 ;ok
+tcp dport 39128 redirect :993 ;ok
+redirect :1234 ;nok
+redirect :12341111 ;nok
+
+# invalid arguments
+tcp dport 9128 redirect :993 random ;nok
+tcp dport 9128 redirect :993 random-fully ;nok
+tcp dport 9128 redirect persistent :123 ;nok
+tcp dport 9128 redirect random,persistent :123 ;nok
+
+# redirect is a terminal statement
+tcp dport 22 redirect counter packets 0 bytes 0 accept ;nok
+tcp sport 22 redirect accept ;nok
+ip saddr 10.1.1.1 redirect drop ;nok
+
+# redirect with sets
+tcp dport {1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} redirect ;ok
+ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter packets 0 bytes 0 redirect ;ok ;ip daddr >= 10.0.0.0 ip daddr <= 10.2.3.4 udp dport 53 counter packets 0 bytes 0 redirect
+iifname eth0 ct state new,established tcp dport vmap {22 : drop, 222 : drop } redirect ;ok
diff --git a/tests/regression/ip6/redirect.t b/tests/regression/ip6/redirect.t
new file mode 100644
index 0000000..84ed88f
--- /dev/null
+++ b/tests/regression/ip6/redirect.t
@@ -0,0 +1,42 @@
+*ip6;test-ip6
+:output;type nat hook output priority 0
+
+# with no arguments
+redirect ;ok
+udp dport 954 redirect ;ok
+ip6 saddr fe00::cafe counter packets 0 bytes 0 redirect ;ok
+
+# nf_nat flags combination
+udp dport 53 redirect random ;ok
+udp dport 53 redirect random,persistent ;ok
+udp dport 53 redirect random,persistent,random-fully ;ok ;udp dport 53 redirect random,random-fully,persistent
+udp dport 53 redirect random,random-fully ;ok
+udp dport 53 redirect random,random-fully,persistent ;ok
+udp dport 53 redirect persistent ;ok
+udp dport 53 redirect persistent,random ;ok ;udp dport 53 redirect random,persistent
+udp dport 53 redirect persistent,random,random-fully ;ok ;udp dport 53 redirect random,random-fully,persistent
+udp dport 53 redirect persistent,random-fully ;ok ;udp dport 53 redirect random-fully,persistent
+udp dport 53 redirect persistent,random-fully,random;ok ;udp dport 53 redirect random,random-fully,persistent
+
+# port specification
+udp dport 1234 redirect :1234 ;ok
+ip6 daddr fe00::cafe udp dport 9998 redirect :6515 ;ok
+tcp dport 39128 redirect :993 ;ok
+redirect :1234 ;nok
+redirect :12341111 ;nok
+
+# invalid arguments
+tcp dport 9128 redirect :993 random ;nok
+tcp dport 9128 redirect :993 random-fully ;nok
+tcp dport 9128 redirect persistent :123 ;nok
+tcp dport 9128 redirect random,persistent :123 ;nok
+
+# redirect is a terminal statement
+tcp dport 22 redirect counter packets 0 bytes 0 accept ;nok
+tcp sport 22 redirect accept ;nok
+ip6 saddr ::1 redirect drop ;nok
+
+# redirect with sets
+tcp dport {1,2,3,4,5,6,7,8,101,202,303,1001,2002,3003} redirect ;ok
+ip6 daddr fe00::1-fe00::200 udp dport 53 counter packets 0 bytes 0 redirect ;ok ;ip6 daddr >= fe00::1 ip6 daddr <= fe00::200 udp dport 53 counter packets 0 bytes 0 redirect
+iifname eth0 ct state new,established tcp dport vmap {22 : drop, 222 : drop } redirect ;ok
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-11-03 19:42 ` Arturo Borrero Gonzalez
@ 2014-11-04 13:37 ` Pablo Neira Ayuso
2014-11-04 13:56 ` Arturo Borrero Gonzalez
0 siblings, 1 reply; 11+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-04 13:37 UTC (permalink / raw)
To: Arturo Borrero Gonzalez; +Cc: Netfilter Development Mailing list
On Mon, Nov 03, 2014 at 08:42:13PM +0100, Arturo Borrero Gonzalez wrote:
> On 30 October 2014 17:25, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Thu, Oct 16, 2014 at 12:41:19PM +0200, Arturo Borrero Gonzalez wrote:
> >> This patch adds redirect support for nft.
> >>
> >> The syntax is:
> >>
> >> % nft add rule nat prerouting redirect [port|nat_flags]
> >
> > I prefer if you add a couple of valid examples to the patch
> > description. This won't work as the protocol is not specified.
> >
> > There's also some minor issues with this patch:
> >
> > % nft add rule nat prerouting redirect
> > Memory allocation failure
> >
> > Please, address and resubmit, thanks Arturo.
>
> Hi Pablo,
>
> I've take further look at this patch. I don't see any issue.
>
> As masquerade, I think redirect without protocol should work. I just
> tested again the patch with ICMP packets and the redirection simply
> works. I used tcpdump for the checks. The rule I used is the same as
> in the patch description.
I think this needs to be:
% nft add rule nat prerouting redirect [port] [nat_flags]
And, I think it doesn't make any bad if you extend the description
with some examples as I requested.
Or update the documentation in the same patch including the new
redirect expression.
I'm going to apply this now, but next time please address my requests.
> Regarding the memory allocation failure, I'm unable to find the issue.
My fault, the "memory allocation failure" happens when you use an old
libnftnl with no redirect support, which was the case in my testbed. I
just fixed it here.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-11-04 13:37 ` Pablo Neira Ayuso
@ 2014-11-04 13:56 ` Arturo Borrero Gonzalez
2014-11-04 14:44 ` Pablo Neira Ayuso
0 siblings, 1 reply; 11+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-11-04 13:56 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list
On 4 November 2014 14:37, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>
> I think this needs to be:
>
> % nft add rule nat prerouting redirect [port] [nat_flags]
>
The port and nat_flags arguments are mutually exclusives. That's why I
used the [port|nat_flags] syntax.
--
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-11-04 13:56 ` Arturo Borrero Gonzalez
@ 2014-11-04 14:44 ` Pablo Neira Ayuso
2014-11-04 15:04 ` Arturo Borrero Gonzalez
0 siblings, 1 reply; 11+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-04 14:44 UTC (permalink / raw)
To: Arturo Borrero Gonzalez; +Cc: Netfilter Development Mailing list
On Tue, Nov 04, 2014 at 02:56:58PM +0100, Arturo Borrero Gonzalez wrote:
> On 4 November 2014 14:37, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> >
> > I think this needs to be:
> >
> > % nft add rule nat prerouting redirect [port] [nat_flags]
> >
>
> The port and nat_flags arguments are mutually exclusives. That's why I
> used the [port|nat_flags] syntax.
iptables allows this:
-j REDIRECT --to-ports 8000-8010 --random
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-11-04 14:44 ` Pablo Neira Ayuso
@ 2014-11-04 15:04 ` Arturo Borrero Gonzalez
2014-11-04 16:04 ` Pablo Neira Ayuso
0 siblings, 1 reply; 11+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-11-04 15:04 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list
On 4 November 2014 15:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Tue, Nov 04, 2014 at 02:56:58PM +0100, Arturo Borrero Gonzalez wrote:
>> On 4 November 2014 14:37, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>> >
>> > I think this needs to be:
>> >
>> > % nft add rule nat prerouting redirect [port] [nat_flags]
>> >
>>
>> The port and nat_flags arguments are mutually exclusives. That's why I
>> used the [port|nat_flags] syntax.
>
> iptables allows this:
>
> -j REDIRECT --to-ports 8000-8010 --random
Then, should I change the behaviour of the nft redirect parser?
The code in my patch doesn't allow that.
I think it makes no sense: "redirect to this port; no sorry, redirect
to a random one."
--
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-11-04 15:04 ` Arturo Borrero Gonzalez
@ 2014-11-04 16:04 ` Pablo Neira Ayuso
2014-11-04 16:11 ` Arturo Borrero Gonzalez
0 siblings, 1 reply; 11+ messages in thread
From: Pablo Neira Ayuso @ 2014-11-04 16:04 UTC (permalink / raw)
To: Arturo Borrero Gonzalez; +Cc: Netfilter Development Mailing list
On Tue, Nov 04, 2014 at 04:04:11PM +0100, Arturo Borrero Gonzalez wrote:
> On 4 November 2014 15:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Tue, Nov 04, 2014 at 02:56:58PM +0100, Arturo Borrero Gonzalez wrote:
> >> On 4 November 2014 14:37, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> >> >
> >> > I think this needs to be:
> >> >
> >> > % nft add rule nat prerouting redirect [port] [nat_flags]
> >> >
> >>
> >> The port and nat_flags arguments are mutually exclusives. That's why I
> >> used the [port|nat_flags] syntax.
> >
> > iptables allows this:
> >
> > -j REDIRECT --to-ports 8000-8010 --random
>
> Then, should I change the behaviour of the nft redirect parser?
> The code in my patch doesn't allow that.
Yes, you have to fix this.
> I think it makes no sense: "redirect to this port; no sorry, redirect
> to a random one."
--to-ports reads as "redirect all traffic from ports 8000 to 8010"
--random refers to --to-ports, it reads as "select the port from the
8000-8010 range at random"
If --random is not specified, then the NAT engines selects the destination
port in that range one after another (8000, 8001, 8002, ...) IIRC.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [nft PATCH v2] src: add redirect support
2014-11-04 16:04 ` Pablo Neira Ayuso
@ 2014-11-04 16:11 ` Arturo Borrero Gonzalez
0 siblings, 0 replies; 11+ messages in thread
From: Arturo Borrero Gonzalez @ 2014-11-04 16:11 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development Mailing list
On 4 November 2014 17:04, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Tue, Nov 04, 2014 at 04:04:11PM +0100, Arturo Borrero Gonzalez wrote:
>> On 4 November 2014 15:44, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>> > On Tue, Nov 04, 2014 at 02:56:58PM +0100, Arturo Borrero Gonzalez wrote:
>> >> On 4 November 2014 14:37, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
>> >> >
>> >> > I think this needs to be:
>> >> >
>> >> > % nft add rule nat prerouting redirect [port] [nat_flags]
>> >> >
>> >>
>> >> The port and nat_flags arguments are mutually exclusives. That's why I
>> >> used the [port|nat_flags] syntax.
>> >
>> > iptables allows this:
>> >
>> > -j REDIRECT --to-ports 8000-8010 --random
>>
>> Then, should I change the behaviour of the nft redirect parser?
>> The code in my patch doesn't allow that.
>
> Yes, you have to fix this.
>
>> I think it makes no sense: "redirect to this port; no sorry, redirect
>> to a random one."
>
> --to-ports reads as "redirect all traffic from ports 8000 to 8010"
> --random refers to --to-ports, it reads as "select the port from the
> 8000-8010 range at random"
>
> If --random is not specified, then the NAT engines selects the destination
> port in that range one after another (8000, 8001, 8002, ...) IIRC.
Understood, thanks.
--
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-11-04 16:11 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-11-03 20:20 [nft PATCH v2] src: add redirect support Arturo Borrero Gonzalez
-- strict thread matches above, loose matches on Subject: below --
2014-10-16 10:41 Arturo Borrero Gonzalez
2014-10-30 16:25 ` Pablo Neira Ayuso
2014-10-30 16:33 ` Pablo Neira Ayuso
2014-11-03 19:42 ` Arturo Borrero Gonzalez
2014-11-04 13:37 ` Pablo Neira Ayuso
2014-11-04 13:56 ` Arturo Borrero Gonzalez
2014-11-04 14:44 ` Pablo Neira Ayuso
2014-11-04 15:04 ` Arturo Borrero Gonzalez
2014-11-04 16:04 ` Pablo Neira Ayuso
2014-11-04 16:11 ` Arturo Borrero Gonzalez
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).