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

login
register
mail settings
Submitter Tomasz Bursztyka
Date Nov. 15, 2012, 9:15 a.m.
Message ID <1352970952-3447-4-git-send-email-tomasz.bursztyka@linux.intel.com>
Download mbox | patch
Permalink /patch/199234/
State Superseded
Headers show

Comments

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(-)
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

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;