All of lore.kernel.org
 help / color / mirror / Atom feed
* [nf-next:nf_tables-experiments PATCH 0/4] NAT expression and IPv6 NAT support
@ 2012-11-15  9:15 Tomasz Bursztyka
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 1/4] nf_tables: Change NFTA_NAT_ attributes to better semantic significance Tomasz Bursztyka
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15  9:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Tomasz Bursztyka

Hi,

Here 4 patches to set up NAT expression and related IPvx chains.
It's an adaptation of existing code (splitting nft_chain_ipv4_nat.c and taking code from ip6tables_nat.c),
that's why I kept former Copyrights even in the new modules created.

In nft_nat.c, I used memcpy() on ipv6 data, let me know if there is a better way (though I guess gcc optimizes it).

Please review,

Tomasz Bursztyka (4):
  nf_tables: Change NFTA_NAT_ attributes to better semantic
    significance
  nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain
  nf_tables: Add support for IPv6 NAT expression
  nf_tables: Add support for IPv6 NAT chain

 include/linux/netfilter/nf_tables.h     |  10 +-
 net/ipv4/netfilter/Kconfig              |   1 +
 net/ipv4/netfilter/nft_chain_nat_ipv4.c | 158 +-------------------
 net/ipv6/netfilter/Kconfig              |   5 +
 net/ipv6/netfilter/Makefile             |   2 +
 net/ipv6/netfilter/nft_chain_nat_ipv6.c | 213 +++++++++++++++++++++++++++
 net/netfilter/Kconfig                   |   5 +
 net/netfilter/Makefile                  |   1 +
 net/netfilter/nft_nat.c                 | 248 ++++++++++++++++++++++++++++++++
 9 files changed, 486 insertions(+), 157 deletions(-)
 create mode 100644 net/ipv6/netfilter/nft_chain_nat_ipv6.c
 create mode 100644 net/netfilter/nft_nat.c

-- 
1.8.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [nf-next:nf_tables-experiments PATCH 1/4] nf_tables: Change NFTA_NAT_ attributes to better semantic significance
  2012-11-15  9:15 [nf-next:nf_tables-experiments PATCH 0/4] NAT expression and IPv6 NAT support Tomasz Bursztyka
@ 2012-11-15  9:15 ` Tomasz Bursztyka
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain Tomasz Bursztyka
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15  9:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Tomasz Bursztyka

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
---
 include/linux/netfilter/nf_tables.h     |  8 +++----
 net/ipv4/netfilter/nft_chain_nat_ipv4.c | 42 ++++++++++++++++++++-------------
 2 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 1242e62..f42cc9d 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -395,10 +395,10 @@ enum nft_nat_types {
 enum nft_nat_attributes {
 	NFTA_NAT_UNSPEC,
 	NFTA_NAT_TYPE,
-	NFTA_NAT_ADDR_MIN,
-	NFTA_NAT_ADDR_MAX,
-	NFTA_NAT_PROTO_MIN,
-	NFTA_NAT_PROTO_MAX,
+	NFTA_NAT_REG_ADDR_MIN,
+	NFTA_NAT_REG_ADDR_MAX,
+	NFTA_NAT_REG_PROTO_MIN,
+	NFTA_NAT_REG_PROTO_MAX,
 	__NFTA_NAT_MAX
 };
 #define NFTA_NAT_MAX		(__NFTA_NAT_MAX - 1)
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
index cd28630..95b265b 100644
--- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -61,11 +61,11 @@ static void nft_nat_eval(const struct nft_expr *expr,
 }
 
 static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
-	[NFTA_NAT_ADDR_MIN]	= { .type = NLA_U32 },
-	[NFTA_NAT_ADDR_MAX]	= { .type = NLA_U32 },
-	[NFTA_NAT_PROTO_MIN]	= { .type = NLA_U32 },
-	[NFTA_NAT_PROTO_MAX]	= { .type = NLA_U32 },
-	[NFTA_NAT_TYPE]		= { .type = NLA_U32 },
+	[NFTA_NAT_TYPE]          = { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MIN]  = { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MAX]  = { .type = NLA_U32 },
+	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
+	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
 };
 
 static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
@@ -88,30 +88,34 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 		return -EINVAL;
 	}
 
-	if (tb[NFTA_NAT_ADDR_MIN]) {
-		priv->sreg_addr_min = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MIN]));
+	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
+		priv->sreg_addr_min = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MIN]));
 		err = nft_validate_input_register(priv->sreg_addr_min);
 		if (err < 0)
 			return err;
 	}
 
-	if (tb[NFTA_NAT_ADDR_MAX]) {
-		priv->sreg_addr_max = ntohl(nla_get_be32(tb[NFTA_NAT_ADDR_MAX]));
+	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
+		priv->sreg_addr_max = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MAX]));
 		err = nft_validate_input_register(priv->sreg_addr_max);
 		if (err < 0)
 			return err;
 	} else
 		priv->sreg_addr_max = priv->sreg_addr_min;
 
-	if (tb[NFTA_NAT_PROTO_MIN]) {
-		priv->sreg_proto_min = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MIN]));
+	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
+		priv->sreg_proto_min = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_PROTO_MIN]));
 		err = nft_validate_input_register(priv->sreg_proto_min);
 		if (err < 0)
 			return err;
 	}
 
-	if (tb[NFTA_NAT_PROTO_MAX]) {
-		priv->sreg_proto_max = ntohl(nla_get_be32(tb[NFTA_NAT_PROTO_MAX]));
+	if (tb[NFTA_NAT_REG_PROTO_MAX]) {
+		priv->sreg_proto_max = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_PROTO_MAX]));
 		err = nft_validate_input_register(priv->sreg_proto_max);
 		if (err < 0)
 			return err;
@@ -136,13 +140,17 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
 		break;
 	}
 
-	if (nla_put_be32(skb, NFTA_NAT_ADDR_MIN, htonl(priv->sreg_addr_min)))
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
 		goto nla_put_failure;
-	if (nla_put_be32(skb, NFTA_NAT_ADDR_MAX, htonl(priv->sreg_addr_max)))
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
 		goto nla_put_failure;
-	if (nla_put_be32(skb, NFTA_NAT_PROTO_MIN, htonl(priv->sreg_proto_min)))
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
 		goto nla_put_failure;
-	if (nla_put_be32(skb, NFTA_NAT_PROTO_MAX, htonl(priv->sreg_proto_max)))
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
 		goto nla_put_failure;
 	return 0;
 
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain
  2012-11-15  9:15 [nf-next:nf_tables-experiments PATCH 0/4] NAT expression and IPv6 NAT support Tomasz Bursztyka
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 1/4] nf_tables: Change NFTA_NAT_ attributes to better semantic significance Tomasz Bursztyka
@ 2012-11-15  9:15 ` Tomasz Bursztyka
  2012-11-15 12:26   ` Pablo Neira Ayuso
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression Tomasz Bursztyka
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 4/4] nf_tables: Add support for IPv6 NAT chain Tomasz Bursztyka
  3 siblings, 1 reply; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15  9:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Tomasz Bursztyka

This will permit to generalize NAT expression handling for both IPv4 and IPv6.

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
---
 net/ipv4/netfilter/Kconfig              |   1 +
 net/ipv4/netfilter/nft_chain_nat_ipv4.c | 166 +-------------------------
 net/netfilter/Kconfig                   |   5 +
 net/netfilter/Makefile                  |   1 +
 net/netfilter/nft_nat.c                 | 198 ++++++++++++++++++++++++++++++++
 5 files changed, 210 insertions(+), 161 deletions(-)
 create mode 100644 net/netfilter/nft_nat.c

diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 1aefe95..e0ebf2f 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -63,6 +63,7 @@ config NFT_CHAIN_ROUTE_IPV4
 
 config NFT_CHAIN_NAT_IPV4
 	depends on NF_TABLES_IPV4
+	depends on NFT_NAT
 	tristate "IPv4 nf_tables nat chain support"
 
 config IP_NF_IPTABLES
diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
index 95b265b..f036184 100644
--- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
+++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
  * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
+ * Copyright (c) 2012 Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -14,10 +15,8 @@
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
-#include <linux/netlink.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
-#include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/netfilter/nf_conntrack.h>
 #include <net/netfilter/nf_nat.h>
@@ -26,155 +25,6 @@
 #include <net/netfilter/nf_nat_l3proto.h>
 #include <net/ip.h>
 
-struct nft_nat {
-	enum nft_registers	sreg_addr_min:8;
-	enum nft_registers	sreg_addr_max:8;
-	enum nft_registers	sreg_proto_min:8;
-	enum nft_registers	sreg_proto_max:8;
-	enum nf_nat_manip_type	type;
-};
-
-static void nft_nat_eval(const struct nft_expr *expr,
-			 struct nft_data data[NFT_REG_MAX + 1],
-			 const struct nft_pktinfo *pkt)
-{
-	const struct nft_nat *priv = nft_expr_priv(expr);
-	enum ip_conntrack_info ctinfo;
-	struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
-	struct nf_nat_range range;
-
-	memset(&range, 0, sizeof(range));
-	if (priv->sreg_addr_min) {
-		range.min_addr.ip = data[priv->sreg_addr_min].data[0];
-		range.max_addr.ip = data[priv->sreg_addr_max].data[0];
-		range.flags |= NF_NAT_RANGE_MAP_IPS;
-	}
-
-	if (priv->sreg_proto_min) {
-		range.min_proto.all = data[priv->sreg_proto_min].data[0];
-		range.max_proto.all = data[priv->sreg_proto_max].data[0];
-		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
-	}
-
-	data[NFT_REG_VERDICT].verdict =
-		nf_nat_setup_info(ct, &range, priv->type);
-}
-
-static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
-	[NFTA_NAT_TYPE]          = { .type = NLA_U32 },
-	[NFTA_NAT_REG_ADDR_MIN]  = { .type = NLA_U32 },
-	[NFTA_NAT_REG_ADDR_MAX]  = { .type = NLA_U32 },
-	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
-	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
-};
-
-static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
-			const struct nlattr * const tb[])
-{
-	struct nft_nat *priv = nft_expr_priv(expr);
-	int err;
-
-	if (tb[NFTA_NAT_TYPE] == NULL)
-		return -EINVAL;
-
-	switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
-	case NFT_NAT_SNAT:
-		priv->type = NF_NAT_MANIP_SRC;
-		break;
-	case NFT_NAT_DNAT:
-		priv->type = NF_NAT_MANIP_DST;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
-		priv->sreg_addr_min = ntohl(nla_get_be32(
-						tb[NFTA_NAT_REG_ADDR_MIN]));
-		err = nft_validate_input_register(priv->sreg_addr_min);
-		if (err < 0)
-			return err;
-	}
-
-	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
-		priv->sreg_addr_max = ntohl(nla_get_be32(
-						tb[NFTA_NAT_REG_ADDR_MAX]));
-		err = nft_validate_input_register(priv->sreg_addr_max);
-		if (err < 0)
-			return err;
-	} else
-		priv->sreg_addr_max = priv->sreg_addr_min;
-
-	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
-		priv->sreg_proto_min = ntohl(nla_get_be32(
-						tb[NFTA_NAT_REG_PROTO_MIN]));
-		err = nft_validate_input_register(priv->sreg_proto_min);
-		if (err < 0)
-			return err;
-	}
-
-	if (tb[NFTA_NAT_REG_PROTO_MAX]) {
-		priv->sreg_proto_max = ntohl(nla_get_be32(
-						tb[NFTA_NAT_REG_PROTO_MAX]));
-		err = nft_validate_input_register(priv->sreg_proto_max);
-		if (err < 0)
-			return err;
-	} else
-		priv->sreg_proto_max = priv->sreg_proto_min;
-
-	return 0;
-}
-
-static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
-	const struct nft_nat *priv = nft_expr_priv(expr);
-
-	switch (priv->type) {
-	case NF_NAT_MANIP_SRC:
-		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
-			goto nla_put_failure;
-		break;
-	case NF_NAT_MANIP_DST:
-		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
-			goto nla_put_failure;
-		break;
-	}
-
-	if (nla_put_be32(skb,
-			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
-		goto nla_put_failure;
-	if (nla_put_be32(skb,
-			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
-		goto nla_put_failure;
-	if (nla_put_be32(skb,
-			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
-		goto nla_put_failure;
-	if (nla_put_be32(skb,
-			 NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
-		goto nla_put_failure;
-	return 0;
-
-nla_put_failure:
-	return -1;
-}
-
-static struct nft_expr_type nft_nat_type;
-static const struct nft_expr_ops nft_nat_ops = {
-	.type		= &nft_nat_type,
-	.size		= NFT_EXPR_SIZE(sizeof(struct nft_nat)),
-	.eval		= nft_nat_eval,
-	.init		= nft_nat_init,
-	.dump		= nft_nat_dump,
-};
-
-static struct nft_expr_type nft_nat_type __read_mostly = {
-	.name		= "nat",
-	.ops		= &nft_nat_ops,
-	.policy		= nft_nat_policy,
-	.maxattr	= NFTA_NAT_MAX,
-	.owner		= THIS_MODULE,
-};
-
 /*
  * NAT chains
  */
@@ -331,24 +181,19 @@ static int __init nft_chain_nat_init(void)
 {
 	int err;
 
+#ifdef CONFIG_MODULES
+	request_module("nft_nat");
+#endif
+
 	err = nft_register_chain_type(&nft_chain_nat_ipv4);
 	if (err < 0)
 		return err;
 
-	err = nft_register_expr(&nft_nat_type);
-	if (err < 0)
-		goto err;
-
 	return 0;
-
-err:
-	nft_unregister_chain_type(&nft_chain_nat_ipv4);
-	return err;
 }
 
 static void __exit nft_chain_nat_exit(void)
 {
-	nft_unregister_expr(&nft_nat_type);
 	nft_unregister_chain_type(&nft_chain_nat_ipv4);
 }
 
@@ -358,4 +203,3 @@ module_exit(nft_chain_nat_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
 MODULE_ALIAS_NFT_CHAIN(AF_INET, "nat");
-MODULE_ALIAS_NFT_EXPR("nat");
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 95d2907..9ba8d0e 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -469,6 +469,11 @@ config NFT_LIMIT
        depends on NF_TABLES
        tristate "Netfilter nf_tables limit module"
 
+config NFT_NAT
+       depends on NF_TABLES
+       depends on NF_CONNTRACK
+       tristate "Netfilter nf_tables nat module"
+
 if NETFILTER_XTABLES
 
 comment "Xtables combined modules"
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 62d1a0f..1e9b653 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_NFT_EXTHDR)	+= nft_exthdr.o
 obj-$(CONFIG_NFT_META)		+= nft_meta.o
 obj-$(CONFIG_NFT_CT)		+= nft_ct.o
 obj-$(CONFIG_NFT_LIMIT)		+= nft_limit.o
+obj-$(CONFIG_NFT_NAT)		+= nft_nat.o
 #nf_tables-objs			+= nft_meta_target.o
 obj-$(CONFIG_NFT_RBTREE)	+= nft_rbtree.o
 obj-$(CONFIG_NFT_HASH)		+= nft_hash.o
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
new file mode 100644
index 0000000..ea9854e
--- /dev/null
+++ b/net/netfilter/nft_nat.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
+ * Copyright (c) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_nat.h>
+#include <net/netfilter/nf_nat_core.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_nat_l3proto.h>
+#include <net/ip.h>
+
+struct nft_nat {
+	enum nft_registers      sreg_addr_min:8;
+	enum nft_registers      sreg_addr_max:8;
+	enum nft_registers      sreg_proto_min:8;
+	enum nft_registers      sreg_proto_max:8;
+	enum nf_nat_manip_type  type;
+};
+
+static void nft_nat_eval(const struct nft_expr *expr,
+			 struct nft_data data[NFT_REG_MAX + 1],
+			 const struct nft_pktinfo *pkt)
+{
+	const struct nft_nat *priv = nft_expr_priv(expr);
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
+	struct nf_nat_range range;
+
+	memset(&range, 0, sizeof(range));
+	if (priv->sreg_addr_min) {
+		range.min_addr.ip = data[priv->sreg_addr_min].data[0];
+		range.max_addr.ip = data[priv->sreg_addr_max].data[0];
+		range.flags |= NF_NAT_RANGE_MAP_IPS;
+	}
+
+	if (priv->sreg_proto_min) {
+		range.min_proto.all = data[priv->sreg_proto_min].data[0];
+		range.max_proto.all = data[priv->sreg_proto_max].data[0];
+		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
+	}
+
+	data[NFT_REG_VERDICT].verdict =
+		nf_nat_setup_info(ct, &range, priv->type);
+}
+
+static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
+	[NFTA_NAT_TYPE]		 = { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MIN]	 = { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MAX]	 = { .type = NLA_U32 },
+	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
+	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
+};
+
+static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
+			const struct nlattr * const tb[])
+{
+	struct nft_nat *priv = nft_expr_priv(expr);
+	int err;
+
+	if (tb[NFTA_NAT_TYPE] == NULL)
+		return -EINVAL;
+
+	switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
+	case NFT_NAT_SNAT:
+		priv->type = NF_NAT_MANIP_SRC;
+		break;
+	case NFT_NAT_DNAT:
+		priv->type = NF_NAT_MANIP_DST;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
+		priv->sreg_addr_min = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MIN]));
+		err = nft_validate_input_register(priv->sreg_addr_min);
+		if (err < 0)
+			return err;
+	}
+
+	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
+		priv->sreg_addr_max = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MAX]));
+		err = nft_validate_input_register(priv->sreg_addr_max);
+		if (err < 0)
+			return err;
+	} else
+		priv->sreg_addr_max = priv->sreg_addr_min;
+
+	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
+		priv->sreg_proto_min = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_PROTO_MIN]));
+		err = nft_validate_input_register(priv->sreg_proto_min);
+		if (err < 0)
+			return err;
+	}
+
+	if (tb[NFTA_NAT_REG_PROTO_MAX]) {
+		priv->sreg_proto_max = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_PROTO_MAX]));
+		err = nft_validate_input_register(priv->sreg_proto_max);
+		if (err < 0)
+			return err;
+	} else
+		priv->sreg_proto_max = priv->sreg_proto_min;
+
+	return 0;
+}
+
+static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+	const struct nft_nat *priv = nft_expr_priv(expr);
+
+	switch (priv->type) {
+	case NF_NAT_MANIP_SRC:
+		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
+			goto nla_put_failure;
+		break;
+	case NF_NAT_MANIP_DST:
+		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
+			goto nla_put_failure;
+		break;
+	}
+
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
+		goto nla_put_failure;
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
+		goto nla_put_failure;
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
+		goto nla_put_failure;
+	if (nla_put_be32(skb,
+			 NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
+		goto nla_put_failure;
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static struct nft_expr_type nft_nat_type;
+static const struct nft_expr_ops nft_nat_ops = {
+	.type           = &nft_nat_type,
+	.size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
+	.eval           = nft_nat_eval,
+	.init           = nft_nat_init,
+	.dump           = nft_nat_dump,
+};
+
+static struct nft_expr_type nft_nat_type __read_mostly = {
+	.name           = "nat",
+	.ops            = &nft_nat_ops,
+	.policy         = nft_nat_policy,
+	.maxattr        = NFTA_NAT_MAX,
+	.owner          = THIS_MODULE,
+};
+
+static int __init nft_nat_module_init(void)
+{
+	int err;
+
+	err = nft_register_expr(&nft_nat_type);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static void __exit nft_nat_module_exit(void)
+{
+	nft_unregister_expr(&nft_nat_type);
+}
+
+module_init(nft_nat_module_init);
+module_exit(nft_nat_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
+MODULE_ALIAS_NFT_EXPR("nat");
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression
  2012-11-15  9:15 [nf-next:nf_tables-experiments PATCH 0/4] NAT expression and IPv6 NAT support Tomasz Bursztyka
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 1/4] nf_tables: Change NFTA_NAT_ attributes to better semantic significance Tomasz Bursztyka
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain Tomasz Bursztyka
@ 2012-11-15  9:15 ` Tomasz Bursztyka
  2012-11-15 12:29   ` Pablo Neira Ayuso
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 4/4] nf_tables: Add support for IPv6 NAT chain Tomasz Bursztyka
  3 siblings, 1 reply; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15  9:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Tomasz Bursztyka

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
---
 include/linux/netfilter/nf_tables.h |   6 ++-
 net/netfilter/nft_nat.c             | 100 +++++++++++++++++++++++++++---------
 2 files changed, 79 insertions(+), 27 deletions(-)

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index f42cc9d..7ab2d65 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -395,8 +395,10 @@ enum nft_nat_types {
 enum nft_nat_attributes {
 	NFTA_NAT_UNSPEC,
 	NFTA_NAT_TYPE,
-	NFTA_NAT_REG_ADDR_MIN,
-	NFTA_NAT_REG_ADDR_MAX,
+	NFTA_NAT_REG_ADDR_MIN_V4,
+	NFTA_NAT_REG_ADDR_MAX_V4,
+	NFTA_NAT_REG_ADDR_MIN_V6,
+	NFTA_NAT_REG_ADDR_MAX_V6,
 	NFTA_NAT_REG_PROTO_MIN,
 	NFTA_NAT_REG_PROTO_MAX,
 	__NFTA_NAT_MAX
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
index ea9854e..ca5b0da 100644
--- a/net/netfilter/nft_nat.c
+++ b/net/netfilter/nft_nat.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
+#include <linux/string.h>
 #include <linux/netlink.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
@@ -26,8 +27,10 @@
 #include <net/ip.h>
 
 struct nft_nat {
-	enum nft_registers      sreg_addr_min:8;
-	enum nft_registers      sreg_addr_max:8;
+	enum nft_registers      sreg_addr_min_v4:8;
+	enum nft_registers      sreg_addr_max_v4:8;
+	enum nft_registers      sreg_addr_min_v6:8;
+	enum nft_registers      sreg_addr_max_v6:8;
 	enum nft_registers      sreg_proto_min:8;
 	enum nft_registers      sreg_proto_max:8;
 	enum nf_nat_manip_type  type;
@@ -43,9 +46,15 @@ static void nft_nat_eval(const struct nft_expr *expr,
 	struct nf_nat_range range;
 
 	memset(&range, 0, sizeof(range));
-	if (priv->sreg_addr_min) {
-		range.min_addr.ip = data[priv->sreg_addr_min].data[0];
-		range.max_addr.ip = data[priv->sreg_addr_max].data[0];
+	if (priv->sreg_addr_min_v4) {
+		range.min_addr.ip = data[priv->sreg_addr_min_v4].data[0];
+		range.max_addr.ip = data[priv->sreg_addr_max_v4].data[0];
+		range.flags |= NF_NAT_RANGE_MAP_IPS;
+	} else if (priv->sreg_addr_min_v6) {
+		memcpy(range.min_addr.ip6, data[priv->sreg_addr_min_v4].data,
+		       sizeof(struct nft_data));
+		memcpy(range.max_addr.ip6, data[priv->sreg_addr_max_v6].data,
+		       sizeof(struct nft_data));
 		range.flags |= NF_NAT_RANGE_MAP_IPS;
 	}
 
@@ -60,11 +69,13 @@ static void nft_nat_eval(const struct nft_expr *expr,
 }
 
 static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
-	[NFTA_NAT_TYPE]		 = { .type = NLA_U32 },
-	[NFTA_NAT_REG_ADDR_MIN]	 = { .type = NLA_U32 },
-	[NFTA_NAT_REG_ADDR_MAX]	 = { .type = NLA_U32 },
-	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
-	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
+	[NFTA_NAT_TYPE]			= { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MIN_V4]	= { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MAX_V4]	= { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MIN_V6]	= { .type = NLA_U32 },
+	[NFTA_NAT_REG_ADDR_MAX_V6]	= { .type = NLA_U32 },
+	[NFTA_NAT_REG_PROTO_MIN]	= { .type = NLA_U32 },
+	[NFTA_NAT_REG_PROTO_MAX]	= { .type = NLA_U32 },
 };
 
 static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
@@ -87,22 +98,45 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 		return -EINVAL;
 	}
 
-	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
-		priv->sreg_addr_min = ntohl(nla_get_be32(
-						tb[NFTA_NAT_REG_ADDR_MIN]));
-		err = nft_validate_input_register(priv->sreg_addr_min);
+	if ((tb[NFTA_NAT_REG_ADDR_MIN_V4] && tb[NFTA_NAT_REG_ADDR_MIN_V6]) ||
+	    (tb[NFTA_NAT_REG_ADDR_MIN_V4] && tb[NFTA_NAT_REG_ADDR_MAX_V6]) ||
+	    (tb[NFTA_NAT_REG_ADDR_MAX_V4] && tb[NFTA_NAT_REG_ADDR_MIN_V6]) ||
+	    (tb[NFTA_NAT_REG_ADDR_MAX_V4] && tb[NFTA_NAT_REG_ADDR_MAX_V6]))
+		return -EINVAL;
+
+	if (tb[NFTA_NAT_REG_ADDR_MIN_V4]) {
+		priv->sreg_addr_min_v4 = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MIN_V4]));
+		err = nft_validate_input_register(priv->sreg_addr_min_v4);
+		if (err < 0)
+			return err;
+	}
+
+	if (tb[NFTA_NAT_REG_ADDR_MAX_V4]) {
+		priv->sreg_addr_max_v4 = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MAX_V4]));
+		err = nft_validate_input_register(priv->sreg_addr_max_v4);
+		if (err < 0)
+			return err;
+	} else
+		priv->sreg_addr_max_v4 = priv->sreg_addr_min_v4;
+
+	if (tb[NFTA_NAT_REG_ADDR_MIN_V6]) {
+		priv->sreg_addr_min_v6 = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MIN_V6]));
+		err = nft_validate_input_register(priv->sreg_addr_min_v6);
 		if (err < 0)
 			return err;
 	}
 
-	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
-		priv->sreg_addr_max = ntohl(nla_get_be32(
-						tb[NFTA_NAT_REG_ADDR_MAX]));
-		err = nft_validate_input_register(priv->sreg_addr_max);
+	if (tb[NFTA_NAT_REG_ADDR_MAX_V6]) {
+		priv->sreg_addr_max_v6 = ntohl(nla_get_be32(
+						tb[NFTA_NAT_REG_ADDR_MAX_V6]));
+		err = nft_validate_input_register(priv->sreg_addr_max_v4);
 		if (err < 0)
 			return err;
 	} else
-		priv->sreg_addr_max = priv->sreg_addr_min;
+		priv->sreg_addr_max_v6 = priv->sreg_addr_min_v6;
 
 	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
 		priv->sreg_proto_min = ntohl(nla_get_be32(
@@ -139,12 +173,28 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
 		break;
 	}
 
-	if (nla_put_be32(skb,
-			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
-		goto nla_put_failure;
-	if (nla_put_be32(skb,
-			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
-		goto nla_put_failure;
+	if (priv->sreg_addr_min_v4) {
+		if (nla_put_be32(skb,
+				 NFTA_NAT_REG_ADDR_MIN_V4,
+				 htonl(priv->sreg_addr_min_v4)))
+			goto nla_put_failure;
+		if (nla_put_be32(skb,
+				 NFTA_NAT_REG_ADDR_MAX_V4,
+				 htonl(priv->sreg_addr_max_v4)))
+			goto nla_put_failure;
+	}
+
+	if (priv->sreg_addr_min_v6) {
+		if (nla_put_be32(skb,
+				 NFTA_NAT_REG_ADDR_MIN_V6,
+				 htonl(priv->sreg_addr_min_v6)))
+			goto nla_put_failure;
+		if (nla_put_be32(skb,
+				 NFTA_NAT_REG_ADDR_MAX_V6,
+				 htonl(priv->sreg_addr_max_v6)))
+			goto nla_put_failure;
+	}
+
 	if (nla_put_be32(skb,
 			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
 		goto nla_put_failure;
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [nf-next:nf_tables-experiments PATCH 4/4] nf_tables: Add support for IPv6 NAT chain
  2012-11-15  9:15 [nf-next:nf_tables-experiments PATCH 0/4] NAT expression and IPv6 NAT support Tomasz Bursztyka
                   ` (2 preceding siblings ...)
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression Tomasz Bursztyka
@ 2012-11-15  9:15 ` Tomasz Bursztyka
  3 siblings, 0 replies; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15  9:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Tomasz Bursztyka

Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
---
 net/ipv6/netfilter/Kconfig              |   5 +
 net/ipv6/netfilter/Makefile             |   2 +
 net/ipv6/netfilter/nft_chain_nat_ipv6.c | 213 ++++++++++++++++++++++++++++++++
 3 files changed, 220 insertions(+)
 create mode 100644 net/ipv6/netfilter/nft_chain_nat_ipv6.c

diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 20ab251..0be3357 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -33,6 +33,11 @@ config NFT_CHAIN_ROUTE_IPV6
 	depends on NF_TABLES_IPV6
 	tristate "IPv6 nf_tables route chain support"
 
+config NFT_CHAIN_NAT_IPV6
+	depends on NF_TABLES_IPV6
+	depends on NFT_NAT
+	tristate "IPv6 nf_tables nat chain support"
+
 config IP6_NF_IPTABLES
 	tristate "IP6 tables support (required for filtering)"
 	depends on INET && IPV6
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index cc19b60..07155bd 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -26,6 +26,8 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
 # nf_tables
 obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
+nft_chain_nat_ipv6-y	:= nf_nat_l3proto_ipv6.o nf_nat_proto_icmpv6.o
+obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
 
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
diff --git a/net/ipv6/netfilter/nft_chain_nat_ipv6.c b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
new file mode 100644
index 0000000..633299c
--- /dev/null
+++ b/net/ipv6/netfilter/nft_chain_nat_ipv6.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
+ * Copyright (c) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_nat.h>
+#include <net/netfilter/nf_nat_core.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_nat_l3proto.h>
+#include <net/ipv6.h>
+
+/*
+ * IPv6 NAT chains
+ */
+
+static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
+			      struct sk_buff *skb,
+			      const struct net_device *in,
+			      const struct net_device *out,
+			      int (*okfn)(struct sk_buff *))
+{
+	enum ip_conntrack_info ctinfo;
+	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+	struct nf_conn_nat *nat;
+	enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
+	__be16 frag_off;
+	int hdrlen;
+	u8 nexthdr;
+	unsigned int ret;
+
+	if (ct == NULL || nf_ct_is_untracked(ct))
+		return NF_ACCEPT;
+
+	NF_CT_ASSERT(!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)));
+
+	nat = nfct_nat(ct);
+	if (nat == NULL) {
+		/* Conntrack module was loaded late, can't add extension. */
+		if (nf_ct_is_confirmed(ct))
+			return NF_ACCEPT;
+		nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
+		if (nat == NULL)
+			return NF_ACCEPT;
+	}
+
+	switch (ctinfo) {
+	case IP_CT_RELATED:
+	case IP_CT_RELATED + IP_CT_IS_REPLY:
+		nexthdr = ipv6_hdr(skb)->nexthdr;
+		hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
+					  &nexthdr, &frag_off);
+
+		if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
+			if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
+							   ops->hooknum,
+							   hdrlen))
+				return NF_DROP;
+			else
+				return NF_ACCEPT;
+		}
+		/* Fall through */
+	case IP_CT_NEW:
+		if (nf_nat_initialized(ct, maniptype))
+			break;
+
+		ret = nft_do_chain(ops, skb, in, out, okfn);
+		if (ret != NF_ACCEPT)
+			return ret;
+		if (!nf_nat_initialized(ct, maniptype)) {
+			ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
+			if (ret != NF_ACCEPT)
+				return ret;
+		}
+	default:
+		break;
+	}
+
+	return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
+}
+
+static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops,
+				      struct sk_buff *skb,
+				      const struct net_device *in,
+				      const struct net_device *out,
+				      int (*okfn)(struct sk_buff *))
+{
+	struct in6_addr daddr = ipv6_hdr(skb)->daddr;
+	unsigned int ret;
+
+	ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
+	if (ret != NF_DROP && ret != NF_STOLEN &&
+	    ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
+		skb_dst_drop(skb);
+
+	return ret;
+}
+
+static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops,
+				       struct sk_buff *skb,
+				       const struct net_device *in,
+				       const struct net_device *out,
+				       int (*okfn)(struct sk_buff *))
+{
+	enum ip_conntrack_info ctinfo __maybe_unused;
+	const struct nf_conn *ct __maybe_unused;
+	unsigned int ret;
+
+	ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
+#ifdef CONFIG_XFRM
+	if (ret != NF_DROP && ret != NF_STOLEN &&
+	    !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
+	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
+		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+
+		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
+				      &ct->tuplehash[!dir].tuple.dst.u3) ||
+		    (ct->tuplehash[dir].tuple.src.u.all !=
+		     ct->tuplehash[!dir].tuple.dst.u.all))
+			if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
+				ret = NF_DROP;
+	}
+#endif
+	return ret;
+}
+
+static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops,
+				  struct sk_buff *skb,
+				  const struct net_device *in,
+				  const struct net_device *out,
+				  int (*okfn)(struct sk_buff *))
+{
+	enum ip_conntrack_info ctinfo;
+	const struct nf_conn *ct;
+	unsigned int ret;
+
+	ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
+	if (ret != NF_DROP && ret != NF_STOLEN &&
+	    (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
+		enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+
+		if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
+				      &ct->tuplehash[!dir].tuple.src.u3)) {
+			if (ip6_route_me_harder(skb))
+				ret = NF_DROP;
+		}
+#ifdef CONFIG_XFRM
+		else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
+			 ct->tuplehash[dir].tuple.dst.u.all !=
+			 ct->tuplehash[!dir].tuple.src.u.all)
+			if (nf_xfrm_me_harder(skb, AF_INET6))
+				ret = NF_DROP;
+#endif
+	}
+	return ret;
+}
+
+struct nf_chain_type nft_chain_nat_ipv6 = {
+	.family		= NFPROTO_IPV6,
+	.name		= "nat",
+	.type		= NFT_CHAIN_T_NAT,
+	.hook_mask	= (1 << NF_INET_PRE_ROUTING) |
+			  (1 << NF_INET_POST_ROUTING) |
+			  (1 << NF_INET_LOCAL_OUT) |
+			  (1 << NF_INET_LOCAL_IN),
+	.fn		= {
+		[NF_INET_PRE_ROUTING]	= nf_nat_ipv6_prerouting,
+		[NF_INET_POST_ROUTING]	= nf_nat_ipv6_postrouting,
+		[NF_INET_LOCAL_OUT]	= nf_nat_ipv6_output,
+		[NF_INET_LOCAL_IN]	= nf_nat_ipv6_fn,
+	},
+	.me		= THIS_MODULE,
+};
+
+static int __init nft_chain_nat_ipv6_init(void)
+{
+	int err;
+
+#ifdef CONFIG_MODULES
+	request_module("nft_nat");
+#endif
+
+	err = nft_register_chain_type(&nft_chain_nat_ipv6);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static void __exit nft_chain_nat_ipv6_exit(void)
+{
+	nft_unregister_chain_type(&nft_chain_nat_ipv6);
+}
+
+module_init(nft_chain_nat_ipv6_init);
+module_exit(nft_chain_nat_ipv6_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
+MODULE_ALIAS_NFT_CHAIN(AF_INET6, "nat");
-- 
1.8.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain Tomasz Bursztyka
@ 2012-11-15 12:26   ` Pablo Neira Ayuso
  2012-11-15 12:38     ` Tomasz Bursztyka
  0 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2012-11-15 12:26 UTC (permalink / raw)
  To: Tomasz Bursztyka; +Cc: netfilter-devel

Hi Tomasz,

Thanks for the patchset, one comment, please see below:

On Thu, Nov 15, 2012 at 11:15:50AM +0200, Tomasz Bursztyka wrote:
> This will permit to generalize NAT expression handling for both IPv4 and IPv6.
> 
> Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
> ---
>  net/ipv4/netfilter/Kconfig              |   1 +
>  net/ipv4/netfilter/nft_chain_nat_ipv4.c | 166 +-------------------------
>  net/netfilter/Kconfig                   |   5 +
>  net/netfilter/Makefile                  |   1 +
>  net/netfilter/nft_nat.c                 | 198 ++++++++++++++++++++++++++++++++
>  5 files changed, 210 insertions(+), 161 deletions(-)
>  create mode 100644 net/netfilter/nft_nat.c
> 
> diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
> index 1aefe95..e0ebf2f 100644
> --- a/net/ipv4/netfilter/Kconfig
> +++ b/net/ipv4/netfilter/Kconfig
> @@ -63,6 +63,7 @@ config NFT_CHAIN_ROUTE_IPV4
>  
>  config NFT_CHAIN_NAT_IPV4
>  	depends on NF_TABLES_IPV4
> +	depends on NFT_NAT
>  	tristate "IPv4 nf_tables nat chain support"
>  
>  config IP_NF_IPTABLES
> diff --git a/net/ipv4/netfilter/nft_chain_nat_ipv4.c b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
> index 95b265b..f036184 100644
> --- a/net/ipv4/netfilter/nft_chain_nat_ipv4.c
> +++ b/net/ipv4/netfilter/nft_chain_nat_ipv4.c
> @@ -1,6 +1,7 @@
>  /*
>   * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
>   * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
> + * Copyright (c) 2012 Intel Corporation
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 as
> @@ -14,10 +15,8 @@
>  #include <linux/list.h>
>  #include <linux/skbuff.h>
>  #include <linux/ip.h>
> -#include <linux/netlink.h>
>  #include <linux/netfilter.h>
>  #include <linux/netfilter_ipv4.h>
> -#include <linux/netfilter/nfnetlink.h>
>  #include <linux/netfilter/nf_tables.h>
>  #include <net/netfilter/nf_conntrack.h>
>  #include <net/netfilter/nf_nat.h>
> @@ -26,155 +25,6 @@
>  #include <net/netfilter/nf_nat_l3proto.h>
>  #include <net/ip.h>
>  
> -struct nft_nat {
> -	enum nft_registers	sreg_addr_min:8;
> -	enum nft_registers	sreg_addr_max:8;
> -	enum nft_registers	sreg_proto_min:8;
> -	enum nft_registers	sreg_proto_max:8;
> -	enum nf_nat_manip_type	type;
> -};
> -
> -static void nft_nat_eval(const struct nft_expr *expr,
> -			 struct nft_data data[NFT_REG_MAX + 1],
> -			 const struct nft_pktinfo *pkt)
> -{
> -	const struct nft_nat *priv = nft_expr_priv(expr);
> -	enum ip_conntrack_info ctinfo;
> -	struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
> -	struct nf_nat_range range;
> -
> -	memset(&range, 0, sizeof(range));
> -	if (priv->sreg_addr_min) {
> -		range.min_addr.ip = data[priv->sreg_addr_min].data[0];
> -		range.max_addr.ip = data[priv->sreg_addr_max].data[0];
> -		range.flags |= NF_NAT_RANGE_MAP_IPS;
> -	}
> -
> -	if (priv->sreg_proto_min) {
> -		range.min_proto.all = data[priv->sreg_proto_min].data[0];
> -		range.max_proto.all = data[priv->sreg_proto_max].data[0];
> -		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
> -	}
> -
> -	data[NFT_REG_VERDICT].verdict =
> -		nf_nat_setup_info(ct, &range, priv->type);
> -}
> -
> -static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
> -	[NFTA_NAT_TYPE]          = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_ADDR_MIN]  = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_ADDR_MAX]  = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
> -};
> -
> -static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
> -			const struct nlattr * const tb[])
> -{
> -	struct nft_nat *priv = nft_expr_priv(expr);
> -	int err;
> -
> -	if (tb[NFTA_NAT_TYPE] == NULL)
> -		return -EINVAL;
> -
> -	switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
> -	case NFT_NAT_SNAT:
> -		priv->type = NF_NAT_MANIP_SRC;
> -		break;
> -	case NFT_NAT_DNAT:
> -		priv->type = NF_NAT_MANIP_DST;
> -		break;
> -	default:
> -		return -EINVAL;
> -	}
> -
> -	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
> -		priv->sreg_addr_min = ntohl(nla_get_be32(
> -						tb[NFTA_NAT_REG_ADDR_MIN]));
> -		err = nft_validate_input_register(priv->sreg_addr_min);
> -		if (err < 0)
> -			return err;
> -	}
> -
> -	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
> -		priv->sreg_addr_max = ntohl(nla_get_be32(
> -						tb[NFTA_NAT_REG_ADDR_MAX]));
> -		err = nft_validate_input_register(priv->sreg_addr_max);
> -		if (err < 0)
> -			return err;
> -	} else
> -		priv->sreg_addr_max = priv->sreg_addr_min;
> -
> -	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
> -		priv->sreg_proto_min = ntohl(nla_get_be32(
> -						tb[NFTA_NAT_REG_PROTO_MIN]));
> -		err = nft_validate_input_register(priv->sreg_proto_min);
> -		if (err < 0)
> -			return err;
> -	}
> -
> -	if (tb[NFTA_NAT_REG_PROTO_MAX]) {
> -		priv->sreg_proto_max = ntohl(nla_get_be32(
> -						tb[NFTA_NAT_REG_PROTO_MAX]));
> -		err = nft_validate_input_register(priv->sreg_proto_max);
> -		if (err < 0)
> -			return err;
> -	} else
> -		priv->sreg_proto_max = priv->sreg_proto_min;
> -
> -	return 0;
> -}
> -
> -static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
> -{
> -	const struct nft_nat *priv = nft_expr_priv(expr);
> -
> -	switch (priv->type) {
> -	case NF_NAT_MANIP_SRC:
> -		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
> -			goto nla_put_failure;
> -		break;
> -	case NF_NAT_MANIP_DST:
> -		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
> -			goto nla_put_failure;
> -		break;
> -	}
> -
> -	if (nla_put_be32(skb,
> -			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
> -		goto nla_put_failure;
> -	if (nla_put_be32(skb,
> -			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
> -		goto nla_put_failure;
> -	if (nla_put_be32(skb,
> -			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
> -		goto nla_put_failure;
> -	if (nla_put_be32(skb,
> -			 NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
> -		goto nla_put_failure;
> -	return 0;
> -
> -nla_put_failure:
> -	return -1;
> -}
> -
> -static struct nft_expr_type nft_nat_type;
> -static const struct nft_expr_ops nft_nat_ops = {
> -	.type		= &nft_nat_type,
> -	.size		= NFT_EXPR_SIZE(sizeof(struct nft_nat)),
> -	.eval		= nft_nat_eval,
> -	.init		= nft_nat_init,
> -	.dump		= nft_nat_dump,
> -};
> -
> -static struct nft_expr_type nft_nat_type __read_mostly = {
> -	.name		= "nat",
> -	.ops		= &nft_nat_ops,
> -	.policy		= nft_nat_policy,
> -	.maxattr	= NFTA_NAT_MAX,
> -	.owner		= THIS_MODULE,
> -};
> -
>  /*
>   * NAT chains
>   */
> @@ -331,24 +181,19 @@ static int __init nft_chain_nat_init(void)
>  {
>  	int err;
>  
> +#ifdef CONFIG_MODULES
> +	request_module("nft_nat");
> +#endif

I think this expression is automagically via nft_expr_type_get. The
MODULE_ALIAS_NFT_EXPR macro already helps to achieve that. So I think
we can remove that request_module call.

No need to resend this patchset in case you confirm this comment is
correct, I can delete those lines myself.

> +
>  	err = nft_register_chain_type(&nft_chain_nat_ipv4);
>  	if (err < 0)
>  		return err;
>  
> -	err = nft_register_expr(&nft_nat_type);
> -	if (err < 0)
> -		goto err;
> -
>  	return 0;
> -
> -err:
> -	nft_unregister_chain_type(&nft_chain_nat_ipv4);
> -	return err;
>  }
>  
>  static void __exit nft_chain_nat_exit(void)
>  {
> -	nft_unregister_expr(&nft_nat_type);
>  	nft_unregister_chain_type(&nft_chain_nat_ipv4);
>  }
>  
> @@ -358,4 +203,3 @@ module_exit(nft_chain_nat_exit);
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
>  MODULE_ALIAS_NFT_CHAIN(AF_INET, "nat");
> -MODULE_ALIAS_NFT_EXPR("nat");
> diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
> index 95d2907..9ba8d0e 100644
> --- a/net/netfilter/Kconfig
> +++ b/net/netfilter/Kconfig
> @@ -469,6 +469,11 @@ config NFT_LIMIT
>         depends on NF_TABLES
>         tristate "Netfilter nf_tables limit module"
>  
> +config NFT_NAT
> +       depends on NF_TABLES
> +       depends on NF_CONNTRACK
> +       tristate "Netfilter nf_tables nat module"
> +
>  if NETFILTER_XTABLES
>  
>  comment "Xtables combined modules"
> diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
> index 62d1a0f..1e9b653 100644
> --- a/net/netfilter/Makefile
> +++ b/net/netfilter/Makefile
> @@ -73,6 +73,7 @@ obj-$(CONFIG_NFT_EXTHDR)	+= nft_exthdr.o
>  obj-$(CONFIG_NFT_META)		+= nft_meta.o
>  obj-$(CONFIG_NFT_CT)		+= nft_ct.o
>  obj-$(CONFIG_NFT_LIMIT)		+= nft_limit.o
> +obj-$(CONFIG_NFT_NAT)		+= nft_nat.o
>  #nf_tables-objs			+= nft_meta_target.o
>  obj-$(CONFIG_NFT_RBTREE)	+= nft_rbtree.o
>  obj-$(CONFIG_NFT_HASH)		+= nft_hash.o
> diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
> new file mode 100644
> index 0000000..ea9854e
> --- /dev/null
> +++ b/net/netfilter/nft_nat.c
> @@ -0,0 +1,198 @@
> +/*
> + * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
> + * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
> + * Copyright (c) 2012 Intel Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/skbuff.h>
> +#include <linux/ip.h>
> +#include <linux/netlink.h>
> +#include <linux/netfilter.h>
> +#include <linux/netfilter_ipv4.h>
> +#include <linux/netfilter/nfnetlink.h>
> +#include <linux/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_conntrack.h>
> +#include <net/netfilter/nf_nat.h>
> +#include <net/netfilter/nf_nat_core.h>
> +#include <net/netfilter/nf_tables.h>
> +#include <net/netfilter/nf_nat_l3proto.h>
> +#include <net/ip.h>
> +
> +struct nft_nat {
> +	enum nft_registers      sreg_addr_min:8;
> +	enum nft_registers      sreg_addr_max:8;
> +	enum nft_registers      sreg_proto_min:8;
> +	enum nft_registers      sreg_proto_max:8;
> +	enum nf_nat_manip_type  type;
> +};
> +
> +static void nft_nat_eval(const struct nft_expr *expr,
> +			 struct nft_data data[NFT_REG_MAX + 1],
> +			 const struct nft_pktinfo *pkt)
> +{
> +	const struct nft_nat *priv = nft_expr_priv(expr);
> +	enum ip_conntrack_info ctinfo;
> +	struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
> +	struct nf_nat_range range;
> +
> +	memset(&range, 0, sizeof(range));
> +	if (priv->sreg_addr_min) {
> +		range.min_addr.ip = data[priv->sreg_addr_min].data[0];
> +		range.max_addr.ip = data[priv->sreg_addr_max].data[0];
> +		range.flags |= NF_NAT_RANGE_MAP_IPS;
> +	}
> +
> +	if (priv->sreg_proto_min) {
> +		range.min_proto.all = data[priv->sreg_proto_min].data[0];
> +		range.max_proto.all = data[priv->sreg_proto_max].data[0];
> +		range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
> +	}
> +
> +	data[NFT_REG_VERDICT].verdict =
> +		nf_nat_setup_info(ct, &range, priv->type);
> +}
> +
> +static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
> +	[NFTA_NAT_TYPE]		 = { .type = NLA_U32 },
> +	[NFTA_NAT_REG_ADDR_MIN]	 = { .type = NLA_U32 },
> +	[NFTA_NAT_REG_ADDR_MAX]	 = { .type = NLA_U32 },
> +	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
> +	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
> +};
> +
> +static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
> +			const struct nlattr * const tb[])
> +{
> +	struct nft_nat *priv = nft_expr_priv(expr);
> +	int err;
> +
> +	if (tb[NFTA_NAT_TYPE] == NULL)
> +		return -EINVAL;
> +
> +	switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
> +	case NFT_NAT_SNAT:
> +		priv->type = NF_NAT_MANIP_SRC;
> +		break;
> +	case NFT_NAT_DNAT:
> +		priv->type = NF_NAT_MANIP_DST;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
> +		priv->sreg_addr_min = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_ADDR_MIN]));
> +		err = nft_validate_input_register(priv->sreg_addr_min);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
> +		priv->sreg_addr_max = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_ADDR_MAX]));
> +		err = nft_validate_input_register(priv->sreg_addr_max);
> +		if (err < 0)
> +			return err;
> +	} else
> +		priv->sreg_addr_max = priv->sreg_addr_min;
> +
> +	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
> +		priv->sreg_proto_min = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_PROTO_MIN]));
> +		err = nft_validate_input_register(priv->sreg_proto_min);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	if (tb[NFTA_NAT_REG_PROTO_MAX]) {
> +		priv->sreg_proto_max = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_PROTO_MAX]));
> +		err = nft_validate_input_register(priv->sreg_proto_max);
> +		if (err < 0)
> +			return err;
> +	} else
> +		priv->sreg_proto_max = priv->sreg_proto_min;
> +
> +	return 0;
> +}
> +
> +static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
> +{
> +	const struct nft_nat *priv = nft_expr_priv(expr);
> +
> +	switch (priv->type) {
> +	case NF_NAT_MANIP_SRC:
> +		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
> +			goto nla_put_failure;
> +		break;
> +	case NF_NAT_MANIP_DST:
> +		if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
> +			goto nla_put_failure;
> +		break;
> +	}
> +
> +	if (nla_put_be32(skb,
> +			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
> +		goto nla_put_failure;
> +	if (nla_put_be32(skb,
> +			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
> +		goto nla_put_failure;
> +	if (nla_put_be32(skb,
> +			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
> +		goto nla_put_failure;
> +	if (nla_put_be32(skb,
> +			 NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
> +		goto nla_put_failure;
> +	return 0;
> +
> +nla_put_failure:
> +	return -1;
> +}
> +
> +static struct nft_expr_type nft_nat_type;
> +static const struct nft_expr_ops nft_nat_ops = {
> +	.type           = &nft_nat_type,
> +	.size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
> +	.eval           = nft_nat_eval,
> +	.init           = nft_nat_init,
> +	.dump           = nft_nat_dump,
> +};
> +
> +static struct nft_expr_type nft_nat_type __read_mostly = {
> +	.name           = "nat",
> +	.ops            = &nft_nat_ops,
> +	.policy         = nft_nat_policy,
> +	.maxattr        = NFTA_NAT_MAX,
> +	.owner          = THIS_MODULE,
> +};
> +
> +static int __init nft_nat_module_init(void)
> +{
> +	int err;
> +
> +	err = nft_register_expr(&nft_nat_type);
> +	if (err < 0)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static void __exit nft_nat_module_exit(void)
> +{
> +	nft_unregister_expr(&nft_nat_type);
> +}
> +
> +module_init(nft_nat_module_init);
> +module_exit(nft_nat_module_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
> +MODULE_ALIAS_NFT_EXPR("nat");
> -- 
> 1.8.0
> 
> --
> 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] 10+ messages in thread

* Re: [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression
  2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression Tomasz Bursztyka
@ 2012-11-15 12:29   ` Pablo Neira Ayuso
  2012-11-15 12:44     ` Tomasz Bursztyka
  0 siblings, 1 reply; 10+ messages in thread
From: Pablo Neira Ayuso @ 2012-11-15 12:29 UTC (permalink / raw)
  To: Tomasz Bursztyka; +Cc: netfilter-devel

Hi again Tomasz,

Comment below:

On Thu, Nov 15, 2012 at 11:15:51AM +0200, Tomasz Bursztyka wrote:
> Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
> ---
>  include/linux/netfilter/nf_tables.h |   6 ++-
>  net/netfilter/nft_nat.c             | 100 +++++++++++++++++++++++++++---------
>  2 files changed, 79 insertions(+), 27 deletions(-)
> 
> diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
> index f42cc9d..7ab2d65 100644
> --- a/include/linux/netfilter/nf_tables.h
> +++ b/include/linux/netfilter/nf_tables.h
> @@ -395,8 +395,10 @@ enum nft_nat_types {
>  enum nft_nat_attributes {
>  	NFTA_NAT_UNSPEC,
>  	NFTA_NAT_TYPE,
> -	NFTA_NAT_REG_ADDR_MIN,
> -	NFTA_NAT_REG_ADDR_MAX,
> +	NFTA_NAT_REG_ADDR_MIN_V4,
> +	NFTA_NAT_REG_ADDR_MAX_V4,
> +	NFTA_NAT_REG_ADDR_MIN_V6,
> +	NFTA_NAT_REG_ADDR_MAX_V6,
>  	NFTA_NAT_REG_PROTO_MIN,
>  	NFTA_NAT_REG_PROTO_MAX,
>  	__NFTA_NAT_MAX
> diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
> index ea9854e..ca5b0da 100644
> --- a/net/netfilter/nft_nat.c
> +++ b/net/netfilter/nft_nat.c
> @@ -13,6 +13,7 @@
>  #include <linux/init.h>
>  #include <linux/skbuff.h>
>  #include <linux/ip.h>
> +#include <linux/string.h>
>  #include <linux/netlink.h>
>  #include <linux/netfilter.h>
>  #include <linux/netfilter_ipv4.h>
> @@ -26,8 +27,10 @@
>  #include <net/ip.h>
>  
>  struct nft_nat {
> -	enum nft_registers      sreg_addr_min:8;
> -	enum nft_registers      sreg_addr_max:8;
> +	enum nft_registers      sreg_addr_min_v4:8;
> +	enum nft_registers      sreg_addr_max_v4:8;
> +	enum nft_registers      sreg_addr_min_v6:8;
> +	enum nft_registers      sreg_addr_max_v6:8;

Suggestion: Couldn't we get this patch a bit smaller by adding int
family and the NFTA_NAT_FAMILY attribute?

>  	enum nft_registers      sreg_proto_min:8;
>  	enum nft_registers      sreg_proto_max:8;
>  	enum nf_nat_manip_type  type;
> @@ -43,9 +46,15 @@ static void nft_nat_eval(const struct nft_expr *expr,
>  	struct nf_nat_range range;
>  
>  	memset(&range, 0, sizeof(range));
> -	if (priv->sreg_addr_min) {
> -		range.min_addr.ip = data[priv->sreg_addr_min].data[0];
> -		range.max_addr.ip = data[priv->sreg_addr_max].data[0];
> +	if (priv->sreg_addr_min_v4) {
> +		range.min_addr.ip = data[priv->sreg_addr_min_v4].data[0];
> +		range.max_addr.ip = data[priv->sreg_addr_max_v4].data[0];
> +		range.flags |= NF_NAT_RANGE_MAP_IPS;
> +	} else if (priv->sreg_addr_min_v6) {
> +		memcpy(range.min_addr.ip6, data[priv->sreg_addr_min_v4].data,
> +		       sizeof(struct nft_data));
> +		memcpy(range.max_addr.ip6, data[priv->sreg_addr_max_v6].data,
> +		       sizeof(struct nft_data));
>  		range.flags |= NF_NAT_RANGE_MAP_IPS;
>  	}
>  
> @@ -60,11 +69,13 @@ static void nft_nat_eval(const struct nft_expr *expr,
>  }
>  
>  static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
> -	[NFTA_NAT_TYPE]		 = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_ADDR_MIN]	 = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_ADDR_MAX]	 = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
> -	[NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
> +	[NFTA_NAT_TYPE]			= { .type = NLA_U32 },
> +	[NFTA_NAT_REG_ADDR_MIN_V4]	= { .type = NLA_U32 },
> +	[NFTA_NAT_REG_ADDR_MAX_V4]	= { .type = NLA_U32 },
> +	[NFTA_NAT_REG_ADDR_MIN_V6]	= { .type = NLA_U32 },
> +	[NFTA_NAT_REG_ADDR_MAX_V6]	= { .type = NLA_U32 },
> +	[NFTA_NAT_REG_PROTO_MIN]	= { .type = NLA_U32 },
> +	[NFTA_NAT_REG_PROTO_MAX]	= { .type = NLA_U32 },
>  };
>  
>  static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
> @@ -87,22 +98,45 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
>  		return -EINVAL;
>  	}
>  
> -	if (tb[NFTA_NAT_REG_ADDR_MIN]) {
> -		priv->sreg_addr_min = ntohl(nla_get_be32(
> -						tb[NFTA_NAT_REG_ADDR_MIN]));
> -		err = nft_validate_input_register(priv->sreg_addr_min);
> +	if ((tb[NFTA_NAT_REG_ADDR_MIN_V4] && tb[NFTA_NAT_REG_ADDR_MIN_V6]) ||
> +	    (tb[NFTA_NAT_REG_ADDR_MIN_V4] && tb[NFTA_NAT_REG_ADDR_MAX_V6]) ||
> +	    (tb[NFTA_NAT_REG_ADDR_MAX_V4] && tb[NFTA_NAT_REG_ADDR_MIN_V6]) ||
> +	    (tb[NFTA_NAT_REG_ADDR_MAX_V4] && tb[NFTA_NAT_REG_ADDR_MAX_V6]))
> +		return -EINVAL;
> +
> +	if (tb[NFTA_NAT_REG_ADDR_MIN_V4]) {
> +		priv->sreg_addr_min_v4 = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_ADDR_MIN_V4]));
> +		err = nft_validate_input_register(priv->sreg_addr_min_v4);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	if (tb[NFTA_NAT_REG_ADDR_MAX_V4]) {
> +		priv->sreg_addr_max_v4 = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_ADDR_MAX_V4]));
> +		err = nft_validate_input_register(priv->sreg_addr_max_v4);
> +		if (err < 0)
> +			return err;
> +	} else
> +		priv->sreg_addr_max_v4 = priv->sreg_addr_min_v4;
> +
> +	if (tb[NFTA_NAT_REG_ADDR_MIN_V6]) {
> +		priv->sreg_addr_min_v6 = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_ADDR_MIN_V6]));
> +		err = nft_validate_input_register(priv->sreg_addr_min_v6);
>  		if (err < 0)
>  			return err;
>  	}
>  
> -	if (tb[NFTA_NAT_REG_ADDR_MAX]) {
> -		priv->sreg_addr_max = ntohl(nla_get_be32(
> -						tb[NFTA_NAT_REG_ADDR_MAX]));
> -		err = nft_validate_input_register(priv->sreg_addr_max);
> +	if (tb[NFTA_NAT_REG_ADDR_MAX_V6]) {
> +		priv->sreg_addr_max_v6 = ntohl(nla_get_be32(
> +						tb[NFTA_NAT_REG_ADDR_MAX_V6]));
> +		err = nft_validate_input_register(priv->sreg_addr_max_v4);
>  		if (err < 0)
>  			return err;
>  	} else
> -		priv->sreg_addr_max = priv->sreg_addr_min;
> +		priv->sreg_addr_max_v6 = priv->sreg_addr_min_v6;
>  
>  	if (tb[NFTA_NAT_REG_PROTO_MIN]) {
>  		priv->sreg_proto_min = ntohl(nla_get_be32(
> @@ -139,12 +173,28 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
>  		break;
>  	}
>  
> -	if (nla_put_be32(skb,
> -			 NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
> -		goto nla_put_failure;
> -	if (nla_put_be32(skb,
> -			 NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
> -		goto nla_put_failure;
> +	if (priv->sreg_addr_min_v4) {
> +		if (nla_put_be32(skb,
> +				 NFTA_NAT_REG_ADDR_MIN_V4,
> +				 htonl(priv->sreg_addr_min_v4)))
> +			goto nla_put_failure;
> +		if (nla_put_be32(skb,
> +				 NFTA_NAT_REG_ADDR_MAX_V4,
> +				 htonl(priv->sreg_addr_max_v4)))
> +			goto nla_put_failure;
> +	}
> +
> +	if (priv->sreg_addr_min_v6) {
> +		if (nla_put_be32(skb,
> +				 NFTA_NAT_REG_ADDR_MIN_V6,
> +				 htonl(priv->sreg_addr_min_v6)))
> +			goto nla_put_failure;
> +		if (nla_put_be32(skb,
> +				 NFTA_NAT_REG_ADDR_MAX_V6,
> +				 htonl(priv->sreg_addr_max_v6)))
> +			goto nla_put_failure;
> +	}
> +
>  	if (nla_put_be32(skb,
>  			 NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
>  		goto nla_put_failure;
> -- 
> 1.8.0
> 
> --
> 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] 10+ messages in thread

* Re: [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain
  2012-11-15 12:26   ` Pablo Neira Ayuso
@ 2012-11-15 12:38     ` Tomasz Bursztyka
  0 siblings, 0 replies; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15 12:38 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Hi Pablo,

>>   {
>> >  	int err;
>> >  
>> >+#ifdef CONFIG_MODULES
>> >+	request_module("nft_nat");
>> >+#endif
> I think this expression is automagically via nft_expr_type_get. The
> MODULE_ALIAS_NFT_EXPR macro already helps to achieve that. So I think
> we can remove that request_module call.
>
> No need to resend this patchset in case you confirm this comment is
> correct, I can delete those lines myself.

Sure, go ahead.

Tomasz

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression
  2012-11-15 12:29   ` Pablo Neira Ayuso
@ 2012-11-15 12:44     ` Tomasz Bursztyka
  2012-11-15 12:47       ` Pablo Neira Ayuso
  0 siblings, 1 reply; 10+ messages in thread
From: Tomasz Bursztyka @ 2012-11-15 12:44 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Hi Pablo,

>>   #include <linux/netfilter_ipv4.h>
>> >@@ -26,8 +27,10 @@
>> >  #include <net/ip.h>
>> >  
>> >  struct nft_nat {
>> >-	enum nft_registers      sreg_addr_min:8;
>> >-	enum nft_registers      sreg_addr_max:8;
>> >+	enum nft_registers      sreg_addr_min_v4:8;
>> >+	enum nft_registers      sreg_addr_max_v4:8;
>> >+	enum nft_registers      sreg_addr_min_v6:8;
>> >+	enum nft_registers      sreg_addr_max_v6:8;
> Suggestion: Couldn't we get this patch a bit smaller by adding int
> family and the NFTA_NAT_FAMILY attribute?

Why not, at least semantically it could look better indeed, though from 
struct size point of view it won't change anything.
The logic for parsing NFTA would be easier too.

Let's do this.

Tomasz

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression
  2012-11-15 12:44     ` Tomasz Bursztyka
@ 2012-11-15 12:47       ` Pablo Neira Ayuso
  0 siblings, 0 replies; 10+ messages in thread
From: Pablo Neira Ayuso @ 2012-11-15 12:47 UTC (permalink / raw)
  To: Tomasz Bursztyka; +Cc: netfilter-devel

On Thu, Nov 15, 2012 at 02:44:27PM +0200, Tomasz Bursztyka wrote:
> Hi Pablo,
> 
> >>  #include <linux/netfilter_ipv4.h>
> >>>@@ -26,8 +27,10 @@
> >>>  #include <net/ip.h>
> >>>  >  struct nft_nat {
> >>>-	enum nft_registers      sreg_addr_min:8;
> >>>-	enum nft_registers      sreg_addr_max:8;
> >>>+	enum nft_registers      sreg_addr_min_v4:8;
> >>>+	enum nft_registers      sreg_addr_max_v4:8;
> >>>+	enum nft_registers      sreg_addr_min_v6:8;
> >>>+	enum nft_registers      sreg_addr_max_v6:8;
> >Suggestion: Couldn't we get this patch a bit smaller by adding int
> >family and the NFTA_NAT_FAMILY attribute?
> 
> Why not, at least semantically it could look better indeed, though
> from struct size point of view it won't change anything.
> The logic for parsing NFTA would be easier too.
> 
> Let's do this.

Great, thanks a lot.

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-11-15 12:47 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-15  9:15 [nf-next:nf_tables-experiments PATCH 0/4] NAT expression and IPv6 NAT support Tomasz Bursztyka
2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 1/4] nf_tables: Change NFTA_NAT_ attributes to better semantic significance Tomasz Bursztyka
2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 2/4] nf_tables: Split IPv4 NAT into NAT expression and NAT IPv4 chain Tomasz Bursztyka
2012-11-15 12:26   ` Pablo Neira Ayuso
2012-11-15 12:38     ` Tomasz Bursztyka
2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 3/4] nf_tables: Add support for IPv6 NAT expression Tomasz Bursztyka
2012-11-15 12:29   ` Pablo Neira Ayuso
2012-11-15 12:44     ` Tomasz Bursztyka
2012-11-15 12:47       ` Pablo Neira Ayuso
2012-11-15  9:15 ` [nf-next:nf_tables-experiments PATCH 4/4] nf_tables: Add support for IPv6 NAT chain Tomasz Bursztyka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.