Skip to contentSkip to conversation

src: add nat persistent and random options

PATCH Applied Arturo Borrero Gonzalez 2 participants 4 messages Oct 3, 2014 – Oct 9, 2014 netfilter

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 src: add nat persistent and random options

This patch adds more configuration options to the nat expression.

The syntax is as follow:
% nft add rule nat postrouting <snat|dnat> <nat_arguments> [flags]

Flags are: random, persistent, random-fully.
Example:

% nft add rule nat postrouting dnat 1.1.1.1 random,persistent

A requirement is to cache some [recent] copies of kernel headers.

---
 .../linux/netfilter/nf_conntrack_tuple_common.h    |   32 ++++++++++++++-
 include/linux/netfilter/nf_nat.h                   |   42 ++++++++++++++++++++
 include/statement.h                                |    1 
 src/netlink_delinearize.c                          |    4 ++
 src/netlink_linearize.c                            |    3 +
 src/parser.y                                       |   21 ++++++++++
 src/scanner.l                                      |    3 +
 src/statement.c                                    |   26 ++++++++++++
 8 files changed, 130 insertions(+), 2 deletions(-)
 create mode 100644 include/linux/netfilter/nf_nat.h
include/linux/netfilter/nf_conntrack_tuple_common.h +30 -2
index 8e145f0..8ab3118 100644
@@ -1,13 +1,41 @@
 #ifndef _NF_CONNTRACK_TUPLE_COMMON_H
 #define _NF_CONNTRACK_TUPLE_COMMON_H
 
-enum ip_conntrack_dir
-{
+#include <linux/types.h>
+
+enum ip_conntrack_dir {
 	IP_CT_DIR_ORIGINAL,
 	IP_CT_DIR_REPLY,
 	IP_CT_DIR_MAX
 };
 
+/* The protocol-specific manipulable parts of the tuple: always in
+ * network order
+ */
+union nf_conntrack_man_proto {
+	/* Add other protocols here. */
+	__be16 all;
+
+	struct {
+		__be16 port;
+	} tcp;
+	struct {
+		__be16 port;
+	} udp;
+	struct {
+		__be16 id;
+	} icmp;
+	struct {
+		__be16 port;
+	} dccp;
+	struct {
+		__be16 port;
+	} sctp;
+	struct {
+		__be16 key;	/* GRE key is 32bit, PPtP only uses 16bit */
+	} gre;
+};
+
 #define CTINFO2DIR(ctinfo) ((ctinfo) >= IP_CT_IS_REPLY ? IP_CT_DIR_REPLY : IP_CT_DIR_ORIGINAL)
 
 #endif /* _NF_CONNTRACK_TUPLE_COMMON_H */
include/linux/netfilter/nf_nat.h new file +42 -0

42 lines not on this page · raw message

include/statement.h +1 -0
index e2f02b8..e04ab7d 100644
@@ -65,6 +65,7 @@ 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);
src/netlink_delinearize.c +4 -0
index 796b632..e2a13d3 100644
@@ -491,6 +491,10 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
 
 	family = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_FAMILY);
 
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_NAT_FLAGS))
+		stmt->nat.flags = nft_rule_expr_get_u32(nle,
+							NFT_EXPR_NAT_FLAGS);
+
 	reg1 = nft_rule_expr_get_u32(nle, NFT_EXPR_NAT_REG_ADDR_MIN);
 	if (reg1) {
 		addr = netlink_get_register(ctx, loc, reg1);
src/netlink_linearize.c +3 -0
index c46b6d4..36b56ff 100644
@@ -631,6 +631,9 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 	family = nft_rule_attr_get_u32(ctx->nlr, NFT_RULE_ATTR_FAMILY);
 	nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_FAMILY, family);
 
+	if (stmt->nat.flags != 0)
+		nft_rule_expr_set_u32(nle, NFT_EXPR_NAT_FLAGS, stmt->nat.flags);
+
 	if (stmt->nat.addr) {
 		amin_reg = get_register(ctx);
 		registers++;
src/parser.y +21 -0
index 4a8df7b..9fda571 100644
@@ -19,6 +19,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter/nf_tables.h>
 #include <linux/netfilter/nf_conntrack_tuple_common.h>
+#include <linux/netfilter/nf_nat.h>
 #include <libnftnl/common.h>
 #include <libnftnl/set.h>
 
@@ -371,6 +372,9 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %token SNAT			"snat"
 %token DNAT			"dnat"
+%token RANDOM			"random"
+%token RANDOM_FULLY		"random-fully"
+%token PERSISTENT		"persistent"
 
 %token QUEUE			"queue"
 %token QUEUENUM			"num"
@@ -435,6 +439,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %destructor { stmt_free($$); }	reject_stmt
 %type <stmt>			nat_stmt nat_stmt_alloc
 %destructor { stmt_free($$); }	nat_stmt nat_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
 %type <val>			queue_stmt_flags queue_stmt_flag
@@ -1408,6 +1413,22 @@ nat_stmt_args		:	expr
 			{
 				$<stmt>0->nat.proto = $2;
 			}
+			|	nat_stmt_args	nf_nat_flags
+			{
+				$<stmt>0->nat.flags = $2;
+			}
+			;
+
+nf_nat_flags		:	nf_nat_flag
+			|	nf_nat_flags	COMMA	nf_nat_flag
+			{
+				$$ = $1 | $3;
+			}
+			;
+
+nf_nat_flag		:	RANDOM		{ $$ = NF_NAT_RANGE_PROTO_RANDOM; }
+			|	RANDOM_FULLY	{ $$ = NF_NAT_RANGE_PROTO_RANDOM_FULLY; }
+			|	PERSISTENT 	{ $$ = NF_NAT_RANGE_PERSISTENT; }
 			;
 
 queue_stmt		:	queue_stmt_alloc
src/scanner.l +3 -0
index 35c9446..440b0ed 100644
@@ -316,6 +316,9 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 "snat"			{ return SNAT; }
 "dnat"			{ return DNAT; }
+"random"		{ return RANDOM; }
+"random-fully"		{ return RANDOM_FULLY; }
+"persistent"		{ return PERSISTENT; }
 
 "ll"			{ return LL_HDR; }
 "nh"			{ return NETWORK_HDR; }
src/statement.c +26 -0
index 8e4b49e..1b2c31c 100644
@@ -20,6 +20,9 @@
 #include <utils.h>
 #include <list.h>
 
+#include <netinet/in.h>
+#include <linux/netfilter/nf_nat.h>
+
 struct stmt *stmt_alloc(const struct location *loc,
 			const struct stmt_ops *ops)
 {
@@ -240,6 +243,27 @@ struct stmt *reject_stmt_alloc(const struct location *loc)
 	return stmt_alloc(loc, &reject_stmt_ops);
 }
 
+static void print_nf_nat_flags(uint32_t flags)
+{
+	const char *delim = " ";
+
+	if (flags == 0)
+		return;
+
+	if (flags & NF_NAT_RANGE_PROTO_RANDOM) {
+		printf("%srandom", delim);
+		delim = ",";
+	}
+
+	if (flags & NF_NAT_RANGE_PROTO_RANDOM_FULLY) {
+		printf("%srandom-fully", delim);
+		delim = ",";
+	}
+
+	if (flags & NF_NAT_RANGE_PERSISTENT)
+		printf("%spersistent", delim);
+}
+
 static void nat_stmt_print(const struct stmt *stmt)
 {
 	static const char *nat_types[] = {
@@ -254,6 +278,8 @@ static void nat_stmt_print(const struct stmt *stmt)
 		printf(":");
 		expr_print(stmt->nat.proto);
 	}
+
+	print_nf_nat_flags(stmt->nat.flags);
 }
 
 static void nat_stmt_destroy(struct stmt *stmt)
#1 lore raw

PATCH 2/2 src: add masquerade support

This patch adds masquerade support for nft.

The syntax is:

% nft add rule nat postrouting masquerade [flags]

Currently, flags are:
random, random-fully, persistent

Example:
% nft add rule nat postrouting masquerade random,persistent

---
 include/statement.h       |    9 +++++++++
 src/evaluate.c            |   17 +++++++++++++++++
 src/netlink_delinearize.c |   16 ++++++++++++++++
 src/netlink_linearize.c   |   15 +++++++++++++++
 src/parser.y              |   18 ++++++++++++++++--
 src/scanner.l             |    1 +
 src/statement.c           |   18 ++++++++++++++++++
 7 files changed, 92 insertions(+), 2 deletions(-)
include/statement.h +9 -0
index e04ab7d..8728ab6 100644
@@ -70,6 +70,12 @@ struct nat_stmt {
 
 extern struct stmt *nat_stmt_alloc(const struct location *loc);
 
+struct masq_stmt {
+	uint32_t		flags;
+};
+
+extern struct stmt *masq_stmt_alloc(const struct location *loc);
+
 struct queue_stmt {
 	struct expr		*queue;
 	uint16_t		flags;
@@ -100,6 +106,7 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
  * @STMT_LOG:		log statement
  * @STMT_REJECT:	REJECT statement
  * @STMT_NAT:		NAT statement
+ * @STMT_NAT:		masquerade statement
  * @STMT_QUEUE:		QUEUE statement
  * @STMT_CT:		conntrack statement
  */
@@ -113,6 +120,7 @@ enum stmt_types {
 	STMT_LOG,
 	STMT_REJECT,
 	STMT_NAT,
+	STMT_MASQ,
 	STMT_QUEUE,
 	STMT_CT,
 };
@@ -160,6 +168,7 @@ struct stmt {
 		struct limit_stmt	limit;
 		struct reject_stmt	reject;
 		struct nat_stmt		nat;
+		struct masq_stmt	masq;
 		struct queue_stmt	queue;
 		struct ct_stmt		ct;
 	};
src/evaluate.c +17 -0
index 284ee72..0afbe8d 100644
@@ -1171,6 +1171,21 @@ 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)
+{
+	struct proto_ctx *pctx = &ctx->pctx;
+
+	if (pctx && (pctx->family == AF_INET))
+		expr_set_context(&ctx->ectx, &ipaddr_type,
+				4 * BITS_PER_BYTE);
+	else
+		expr_set_context(&ctx->ectx, &ip6addr_type,
+				 16 * BITS_PER_BYTE);
+
+	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,
@@ -1231,6 +1246,8 @@ static 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_QUEUE:
 		return stmt_evaluate_queue(ctx, stmt);
 	case STMT_CT:
src/netlink_delinearize.c +16 -0
index e2a13d3..7785ce4 100644
@@ -558,6 +558,21 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
 	list_add_tail(&stmt->list, &ctx->rule->stmts);
 }
 
+static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
+			       const struct location *loc,
+			       const struct nft_rule_expr *nle)
+{
+	struct stmt *stmt;
+
+	stmt = masq_stmt_alloc(loc);
+
+	if (nft_rule_expr_is_set(nle, NFT_EXPR_MASQ_FLAGS))
+		stmt->masq.flags = nft_rule_expr_get_u32(nle,
+							 NFT_EXPR_MASQ_FLAGS);
+
+	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)
@@ -604,6 +619,7 @@ static const struct {
 	{ .name = "limit",	.parse = netlink_parse_limit },
 	{ .name = "reject",	.parse = netlink_parse_reject },
 	{ .name = "nat",	.parse = netlink_parse_nat },
+	{ .name = "masq",	.parse = netlink_parse_masq },
 	{ .name = "queue",	.parse = netlink_parse_queue },
 };
 
src/netlink_linearize.c +15 -0
index 36b56ff..c5aa0b4 100644
@@ -685,6 +685,19 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
 	nft_rule_add_expr(ctx->nlr, nle);
 }
 
+static void netlink_gen_masq_stmt(struct netlink_linearize_ctx *ctx,
+				  const struct stmt *stmt)
+{
+	struct nft_rule_expr *nle;
+
+	nle = alloc_nft_expr("masq");
+	if (stmt->masq.flags != 0)
+		nft_rule_expr_set_u32(nle, NFT_EXPR_MASQ_FLAGS,
+				      stmt->masq.flags);
+
+	nft_rule_add_expr(ctx->nlr, nle);
+}
+
 static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
 				 const struct stmt *stmt)
 {
@@ -749,6 +762,8 @@ 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_QUEUE:
 		return netlink_gen_queue_stmt(ctx, stmt);
 	case STMT_CT:
src/parser.y +16 -2
index 9fda571..0a698f0 100644
@@ -372,6 +372,7 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 
 %token SNAT			"snat"
 %token DNAT			"dnat"
+%token MASQUERADE		"masquerade"
 %token RANDOM			"random"
 %token RANDOM_FULLY		"random-fully"
 %token PERSISTENT		"persistent"
@@ -437,9 +438,10 @@ static void location_update(struct location *loc, struct location *rhs, int n)
 %type <val>			time_unit
 %type <stmt>			reject_stmt
 %destructor { stmt_free($$); }	reject_stmt
-%type <stmt>			nat_stmt nat_stmt_alloc
-%destructor { stmt_free($$); }	nat_stmt nat_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 <val>			nf_nat_flags nf_nat_flag
+
 %type <stmt>			queue_stmt queue_stmt_alloc
 %destructor { stmt_free($$); }	queue_stmt queue_stmt_alloc
 %type <val>			queue_stmt_flags queue_stmt_flag
@@ -1239,6 +1241,7 @@ stmt			:	verdict_stmt
 			|	nat_stmt
 			|	queue_stmt
 			|	ct_stmt
+			|	masq_stmt
 			;
 
 verdict_stmt		:	verdict_expr
@@ -1419,6 +1422,17 @@ nat_stmt_args		:	expr
 			}
 			;
 
+masq_stmt		:	masq_stmt_alloc
+			|	masq_stmt_alloc	nf_nat_flags
+			{
+				$$ = $1;
+				$$->masq.flags = $2;
+			}
+			;
+
+masq_stmt_alloc		:	MASQUERADE 	{ $$ = masq_stmt_alloc(&@$); }
+			;
+
 nf_nat_flags		:	nf_nat_flag
 			|	nf_nat_flags	COMMA	nf_nat_flag
 			{
src/scanner.l +1 -0
index 440b0ed..9c957c0 100644
@@ -316,6 +316,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 
 "snat"			{ return SNAT; }
 "dnat"			{ return DNAT; }
+"masquerade"		{ return MASQUERADE; }
 "random"		{ return RANDOM; }
 "random-fully"		{ return RANDOM_FULLY; }
 "persistent"		{ return PERSISTENT; }
src/statement.c +18 -0
index 1b2c31c..3fa6d66 100644
@@ -299,3 +299,21 @@ 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)
+{
+	printf("masquerade");
+
+	print_nf_nat_flags(stmt->masq.flags);
+}
+
+static const struct stmt_ops masq_stmt_ops = {
+	.type		= STMT_MASQ,
+	.name		= "masq",
+	.print		= masq_stmt_print,
+};
+
+struct stmt *masq_stmt_alloc(const struct location *loc)
+{
+	return stmt_alloc(loc, &masq_stmt_ops);
+}
#2 lore raw

Re: [nft PATCH 2/2] src: add masquerade support

include/statement.h extern struct stmt *ct_stmt_alloc(const struct location *loc, · line 109

Quoted 9 lines · Arturo Borrero Gonzalez
include/statement.h +2 -0
+
 struct queue_stmt {
 	struct expr		*queue;
 	uint16_t		flags;
@@ -100,6 +106,7 @@ extern struct stmt *ct_stmt_alloc(const struct location *loc,
  * @STMT_LOG:		log statement
  * @STMT_REJECT:	REJECT statement
  * @STMT_NAT:		NAT statement
+ * @STMT_NAT:		masquerade statement
       ^
      typo
Quoted 27 lines
include/statement.h +2 -0
  * @STMT_QUEUE:		QUEUE statement
  * @STMT_CT:		conntrack statement
  */
@@ -113,6 +120,7 @@ enum stmt_types {
 	STMT_LOG,
 	STMT_REJECT,
 	STMT_NAT,
+	STMT_MASQ,
 	STMT_QUEUE,
 	STMT_CT,
 };
@@ -160,6 +168,7 @@ struct stmt {
 		struct limit_stmt	limit;
 		struct reject_stmt	reject;
 		struct nat_stmt		nat;
+		struct masq_stmt	masq;
 		struct queue_stmt	queue;
 		struct ct_stmt		ct;
 	};
src/evaluate.c +0 -0
index 284ee72..0afbe8d 100644
@@ -1171,6 +1171,21 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
 	return 0;
 }
 

src/evaluate.c static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) · line 1183

Quoted 10 lines
src/evaluate.c +10 -0
+static int stmt_evaluate_masq(struct eval_ctx *ctx, struct stmt *stmt)
+{
+	struct proto_ctx *pctx = &ctx->pctx;
+
+	if (pctx && (pctx->family == AF_INET))
+		expr_set_context(&ctx->ectx, &ipaddr_type,
+				4 * BITS_PER_BYTE);
+	else
+		expr_set_context(&ctx->ectx, &ip6addr_type,
+				 16 * BITS_PER_BYTE);

Could you use a switch to check pctx->family?

Spot an error for unsupported family, so we don't crash badly if someone tries to use this from a different context.

Quoted 4 lines
src/evaluate.c +4 -0
+	stmt->flags |= STMT_F_TERMINAL;
+	return 0;
+}
+
maintainer Applied
#3 lore raw
In reply to Arturo Borrero Gonzalez
Quoted 11 lines · Arturo Borrero Gonzalez

This patch adds more configuration options to the nat expression.

The syntax is as follow:
% nft add rule nat postrouting <snat|dnat> <nat_arguments> [flags]

Flags are: random, persistent, random-fully.
Example:

% nft add rule nat postrouting dnat 1.1.1.1 random,persistent

A requirement is to cache some [recent] copies of kernel headers.

Applied, thanks Arturo.

Please, send me a follow-up patch to add test for the new regression testing infrastructure and document this in our wiki page.