[nf-next:nf_tables-experiments,3/4] nf_tables: Add support for IPv6 NAT expression

Submitted by Tomasz Bursztyka on Nov. 15, 2012, 9:15 a.m.

Details

Message ID 1352970952-3447-4-git-send-email-tomasz.bursztyka@linux.intel.com
State Superseded
Headers show

Commit Message

Tomasz Bursztyka Nov. 15, 2012, 9:15 a.m.
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(-)

Comments

Pablo Neira Nov. 15, 2012, 12:29 p.m.
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
--
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
Tomasz Bursztyka Nov. 15, 2012, 12:44 p.m.
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
--
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
Pablo Neira Nov. 15, 2012, 12:47 p.m.
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.
--
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

Patch hide | download patch | download mbox

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;