Skip to contentSkip to conversation

src: add redirect support

PATCH Superseded Arturo Borrero Gonzalez 2 participants 10 messages Oct 16, 2014 – Nov 4, 2014 netfilter

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 src: add redirect support

This patch adds redirect support for nft.

The syntax is:

% nft add rule nat prerouting redirect [port|nat_flags]

---
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(-)
include/statement.h +10 -0
index 35c1b7a..d143121 100644
@@ -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;
 	};
src/evaluate.c +40 -0
index 108248a..d98d7a9 100644
@@ -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:
src/netlink_delinearize.c +52 -0

70 lines not on this page · raw message

src/netlink_linearize.c +49 -0

61 lines not on this page · raw message

src/parser.y +21 -2
index 9e9a839..6209e9e 100644
@@ -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
 			{
src/scanner.l +1 -0
index 32e59d9..e36c3b1 100644
@@ -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; }
src/statement.c +29 -0
index 0ae616a..2587d27 100644
@@ -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);
+}
#1 lore raw
Quoted 5 lines · Arturo Borrero Gonzalez

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.

#2 lore raw
Quoted 10 lines · Pablo Neira Ayuso
Quoted 5 lines · Arturo Borrero Gonzalez

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.

Quoted 6 lines

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.

#3 lore raw
In reply to Pablo Neira Ayuso
Quoted 10 lines · Pablo Neira Ayuso
Quoted 5 lines · Arturo Borrero Gonzalez

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.

Quoted 6 lines

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.

Signature · 5 lines
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#4 lore raw
Quoted 18 lines · Arturo Borrero Gonzalez
Quoted 10 lines · Pablo Neira Ayuso
Quoted 5 lines · Arturo Borrero Gonzalez

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.

Quoted 6 lines

There's also some minor issues with this patch:

% nft add rule nat prerouting redirect
Memory allocation failure

Please, address and resubmit, thanks Arturo.

Quoted 8 lines

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.

Quoted 1 line

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.

#5 lore raw
Quoted 5 lines · Pablo Neira Ayuso

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.

Signature · 5 lines
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#6 lore raw
Quoted 9 lines · Arturo Borrero Gonzalez
Quoted 5 lines · Pablo Neira Ayuso

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

#7 lore raw
Quoted 8 lines · Pablo Neira Ayuso
Quoted 7 lines · Arturo Borrero Gonzalez
Quoted 5 lines · Pablo Neira Ayuso

I think this needs to be:

% nft add rule nat prerouting redirect [port] [nat_flags]

Quoted 6 lines
Quoted 2 lines

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."

Signature · 5 lines
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#8 lore raw
Quoted 12 lines · Arturo Borrero Gonzalez
Quoted 11 lines · Pablo Neira Ayuso
Quoted 9 lines · Arturo Borrero Gonzalez
Quoted 5 lines · Pablo Neira Ayuso

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.

Quoted 6 lines
Quoted 3 lines

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.

Quoted 2 lines

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.

#9 lore raw
Quoted 25 lines · Pablo Neira Ayuso
Quoted 12 lines · Arturo Borrero Gonzalez
Quoted 11 lines · Pablo Neira Ayuso
Quoted 9 lines · Arturo Borrero Gonzalez
Quoted 5 lines · Pablo Neira Ayuso

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.

Quoted 6 lines
Quoted 3 lines

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.

Quoted 2 lines

I think it makes no sense: "redirect to this port; no sorry, redirect to a random one."

Quoted 6 lines

--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.

Signature · 5 lines
Arturo Borrero González
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html