All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf-next, v2 1/3] netfilter: xt_TEE: always allocate private area
@ 2015-06-18 18:13 Pablo Neira Ayuso
  2015-06-18 18:13 ` =?y?q?=5BPATCH=20nf-next=2C=20v2=202/3=5D=20netfilter=3A=20move=20generic=20TEE=20code=20from=20xtables=20to=20nf=5Ftee=5Fipv=7B4=2C6=7D=20modules?= Pablo Neira Ayuso
  2015-06-18 18:13 ` [PATCH nf-next, v2 3/3] netfilter: nf_tables: add nft_tee expression Pablo Neira Ayuso
  0 siblings, 2 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-18 18:13 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, arturo.borrero.glez

This simplifies the integration with nf_tables at the cost of consuming little
extra memory per rule, and I don't expect many rules using TEE in a ruleset.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 net/netfilter/xt_TEE.c |   40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)

diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index a747eb4..189ad13 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -53,6 +53,11 @@ static struct net *pick_net(struct sk_buff *skb)
 	return &init_net;
 }
 
+static inline bool tee_has_notifier(const struct xt_tee_tginfo *info)
+{
+	return info->priv->notifier.notifier_call != NULL;
+}
+
 static bool
 tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
 {
@@ -62,7 +67,7 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
 	struct flowi4 fl4;
 
 	memset(&fl4, 0, sizeof(fl4));
-	if (info->priv) {
+	if (tee_has_notifier(info)) {
 		if (info->priv->oif == -1)
 			return false;
 		fl4.flowi4_oif = info->priv->oif;
@@ -144,7 +149,7 @@ tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
 	struct flowi6 fl6;
 
 	memset(&fl6, 0, sizeof(fl6));
-	if (info->priv) {
+	if (tee_has_notifier(info)) {
 		if (info->priv->oif == -1)
 			return false;
 		fl6.flowi6_oif = info->priv->oif;
@@ -235,34 +240,37 @@ static int tee_tg_check(const struct xt_tgchk_param *par)
 		   sizeof(tee_zero_address)) == 0)
 		return -EINVAL;
 
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+
+	priv->tginfo	= info;
+	priv->oif	= -1;
+
 	if (info->oif[0]) {
 		if (info->oif[sizeof(info->oif)-1] != '\0')
-			return -EINVAL;
-
-		priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-		if (priv == NULL)
-			return -ENOMEM;
+			goto err1;
 
-		priv->tginfo  = info;
-		priv->oif     = -1;
 		priv->notifier.notifier_call = tee_netdev_event;
-		info->priv    = priv;
-
 		register_netdevice_notifier(&priv->notifier);
-	} else
-		info->priv = NULL;
+	}
+
+	info->priv	= priv;
 
 	return 0;
+err1:
+	kfree(priv);
+	return -EINVAL;
 }
 
 static void tee_tg_destroy(const struct xt_tgdtor_param *par)
 {
 	struct xt_tee_tginfo *info = par->targinfo;
 
-	if (info->priv) {
+	if (tee_has_notifier(info))
 		unregister_netdevice_notifier(&info->priv->notifier);
-		kfree(info->priv);
-	}
+
+	kfree(info->priv);
 }
 
 static struct xt_target tee_tg_reg[] __read_mostly = {
-- 
1.7.10.4


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

* =?y?q?=5BPATCH=20nf-next=2C=20v2=202/3=5D=20netfilter=3A=20move=20generic=20TEE=20code=20from=20xtables=20to=20nf=5Ftee=5Fipv=7B4=2C6=7D=20modules?=
  2015-06-18 18:13 [PATCH nf-next, v2 1/3] netfilter: xt_TEE: always allocate private area Pablo Neira Ayuso
@ 2015-06-18 18:13 ` Pablo Neira Ayuso
  2015-06-18 18:13 ` [PATCH nf-next, v2 3/3] netfilter: nf_tables: add nft_tee expression Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-18 18:13 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, arturo.borrero.glez

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 23893 bytes --]

This allows us to reuse the existing code from nf_tables. Based on original
work from Arturo Borrero Gonzalez.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
 include/net/netfilter/ipv4/nf_tee_ipv4.h |    9 ++
 include/net/netfilter/ipv6/nf_tee_ipv6.h |    9 ++
 include/net/netfilter/nf_tee.h           |   22 +++
 include/uapi/linux/netfilter/xt_TEE.h    |    2 +-
 net/ipv4/netfilter/Kconfig               |    7 +
 net/ipv4/netfilter/Makefile              |    2 +
 net/ipv4/netfilter/nf_tee_ipv4.c         |  116 +++++++++++++++
 net/ipv6/netfilter/Kconfig               |    7 +
 net/ipv6/netfilter/Makefile              |    2 +
 net/ipv6/netfilter/nf_tee_ipv6.c         |   90 ++++++++++++
 net/netfilter/Kconfig                    |   10 ++
 net/netfilter/Makefile                   |    2 +
 net/netfilter/nf_tee.c                   |   91 ++++++++++++
 net/netfilter/xt_TEE.c                   |  234 ++----------------------------
 14 files changed, 384 insertions(+), 219 deletions(-)
 create mode 100644 include/net/netfilter/ipv4/nf_tee_ipv4.h
 create mode 100644 include/net/netfilter/ipv6/nf_tee_ipv6.h
 create mode 100644 include/net/netfilter/nf_tee.h
 create mode 100644 net/ipv4/netfilter/nf_tee_ipv4.c
 create mode 100644 net/ipv6/netfilter/nf_tee_ipv6.c
 create mode 100644 net/netfilter/nf_tee.c

diff --git a/include/net/netfilter/ipv4/nf_tee_ipv4.h b/include/net/netfilter/ipv4/nf_tee_ipv4.h
new file mode 100644
index 0000000..dc3c9aa
--- /dev/null
+++ b/include/net/netfilter/ipv4/nf_tee_ipv4.h
@@ -0,0 +1,9 @@
+#ifndef _NF_TEE_IPV4_H_
+#define _NF_TEE_IPV4_H_
+
+#include <net/netfilter/nf_tee.h>
+
+unsigned int nf_tee_ipv4(struct sk_buff *skb, const struct nf_tee *tee,
+			 unsigned int hooknum, const struct in_addr *gw);
+
+#endif /* _NF_TEE_IPV4_H_ */
diff --git a/include/net/netfilter/ipv6/nf_tee_ipv6.h b/include/net/netfilter/ipv6/nf_tee_ipv6.h
new file mode 100644
index 0000000..67a8012
--- /dev/null
+++ b/include/net/netfilter/ipv6/nf_tee_ipv6.h
@@ -0,0 +1,9 @@
+#ifndef _NF_TEE_IPV6_H_
+#define _NF_TEE_IPV6_H_
+
+#include <net/netfilter/nf_tee.h>
+
+unsigned int nf_tee_ipv6(struct sk_buff *skb, const struct nf_tee *tee,
+			 unsigned int hooknum, const struct in6_addr *gw);
+
+#endif /* _NF_TEE_IPV6_H_ */
diff --git a/include/net/netfilter/nf_tee.h b/include/net/netfilter/nf_tee.h
new file mode 100644
index 0000000..e1f52bf
--- /dev/null
+++ b/include/net/netfilter/nf_tee.h
@@ -0,0 +1,22 @@
+#ifndef _NF_TEE_H_
+#define _NF_TEE_H_
+
+#include <linux/netfilter.h>
+#include <linux/if.h>
+
+struct nf_tee {
+	char			oifname[IFNAMSIZ];
+	int			oif;
+	struct notifier_block	notifier;
+};
+
+struct net *nf_tee_pick_net(struct sk_buff *skb);
+int nf_tee_init(struct nf_tee *tee, const char *oifname);
+void nf_tee_fini(struct nf_tee *tee);
+
+static inline bool nf_tee_has_notifier(const struct nf_tee *tee)
+{
+	return tee->notifier.notifier_call != NULL;
+}
+
+#endif
diff --git a/include/uapi/linux/netfilter/xt_TEE.h b/include/uapi/linux/netfilter/xt_TEE.h
index 5c21d5c..754e43f 100644
--- a/include/uapi/linux/netfilter/xt_TEE.h
+++ b/include/uapi/linux/netfilter/xt_TEE.h
@@ -6,7 +6,7 @@ struct xt_tee_tginfo {
 	char oif[16];
 
 	/* used internally by the kernel */
-	struct xt_tee_priv *priv __attribute__((aligned(8)));
+	struct nf_tee *priv __attribute__((aligned(8)));
 };
 
 #endif /* _XT_TEE_TARGET_H */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 2199a5d..2153bb2 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -67,6 +67,13 @@ config NF_TABLES_ARP
 
 endif # NF_TABLES
 
+config NF_TEE_IPV4
+	tristate "Netfilter IPv4 packet cloning to alternate destination"
+	select NF_TEE
+	help
+	  This option enables the nf_tee_ipv4 core, which clones an IPv4 packet
+	  to be rerouted to another destination.
+
 config NF_LOG_ARP
 	tristate "ARP packet logging"
 	default m if NETFILTER_ADVANCED=n
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 7fe6c70..6b492de 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -70,3 +70,5 @@ obj-$(CONFIG_IP_NF_ARP_MANGLE) += arpt_mangle.o
 
 # just filtering instance of ARP tables for now
 obj-$(CONFIG_IP_NF_ARPFILTER) += arptable_filter.o
+
+obj-$(CONFIG_NF_TEE_IPV4) += nf_tee_ipv4.o
diff --git a/net/ipv4/netfilter/nf_tee_ipv4.c b/net/ipv4/netfilter/nf_tee_ipv4.c
new file mode 100644
index 0000000..dc65659
--- /dev/null
+++ b/net/ipv4/netfilter/nf_tee_ipv4.c
@@ -0,0 +1,116 @@
+/*
+ * (C) 2007 by Sebastian Claßen
+ * (C) 2007-2010 by Jan Engelhardt
+ *
+ * Extracted from xt_TEE.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 or later, as
+ * published by the Free Software Foundation.
+ */
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/route.h>
+#include <linux/skbuff.h>
+#include <net/checksum.h>
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/netfilter/nf_tee.h>
+#include <net/netfilter/ipv4/nf_tee_ipv4.h>
+
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+#	define WITH_CONNTRACK 1
+#	include <net/netfilter/nf_conntrack.h>
+#endif
+
+static DEFINE_PER_CPU(bool, tee_active);
+
+static bool nf_tee_ipv4_route(struct sk_buff *skb, const struct nf_tee *tee,
+			      const struct in_addr *gw)
+{
+	const struct iphdr *iph = ip_hdr(skb);
+	struct net *net = nf_tee_pick_net(skb);
+	struct rtable *rt;
+	struct flowi4 fl4;
+
+	memset(&fl4, 0, sizeof(fl4));
+	if (nf_tee_has_notifier(tee)) {
+		if (tee->oif == -1)
+			return false;
+
+		fl4.flowi4_oif = tee->oif;
+	}
+	fl4.daddr = gw->s_addr;
+	fl4.flowi4_tos = RT_TOS(iph->tos);
+	fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
+	fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
+	rt = ip_route_output_key(net, &fl4);
+	if (IS_ERR(rt))
+		return false;
+
+	skb_dst_drop(skb);
+	skb_dst_set(skb, &rt->dst);
+	skb->dev      = rt->dst.dev;
+	skb->protocol = htons(ETH_P_IP);
+
+	return true;
+}
+
+unsigned int nf_tee_ipv4(struct sk_buff *skb, const struct nf_tee *tee,
+			 unsigned int hooknum, const struct in_addr *gw)
+{
+	struct iphdr *iph;
+
+	if (__this_cpu_read(tee_active))
+		return XT_CONTINUE;
+	/*
+	 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
+	 * the original skb, which should continue on its way as if nothing has
+	 * happened. The copy should be independently delivered to the TEE
+	 * --gateway.
+	 */
+	skb = pskb_copy(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		return XT_CONTINUE;
+
+#ifdef WITH_CONNTRACK
+	/* Avoid counting cloned packets towards the original connection. */
+	nf_conntrack_put(skb->nfct);
+	skb->nfct     = &nf_ct_untracked_get()->ct_general;
+	skb->nfctinfo = IP_CT_NEW;
+	nf_conntrack_get(skb->nfct);
+#endif
+	/*
+	 * If we are in PREROUTING/INPUT, the checksum must be recalculated
+	 * since the length could have changed as a result of defragmentation.
+	 *
+	 * We also decrease the TTL to mitigate potential TEE loops
+	 * between two hosts.
+	 *
+	 * Set %IP_DF so that the original source is notified of a potentially
+	 * decreased MTU on the clone route. IPv6 does this too.
+	 */
+	iph = ip_hdr(skb);
+	iph->frag_off |= htons(IP_DF);
+	if (hooknum == NF_INET_PRE_ROUTING ||
+	    hooknum == NF_INET_LOCAL_IN)
+		--iph->ttl;
+	ip_send_check(iph);
+
+	if (nf_tee_ipv4_route(skb, tee, gw)) {
+		__this_cpu_write(tee_active, true);
+		ip_local_out(skb);
+		__this_cpu_write(tee_active, false);
+	} else {
+		kfree_skb(skb);
+	}
+	return XT_CONTINUE;
+}
+EXPORT_SYMBOL_GPL(nf_tee_ipv4);
+
+MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
+MODULE_DESCRIPTION("nf_tee_ipv4: Reroute IPv4 packet copy");
+MODULE_LICENSE("GPL");
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index b552cf0..92c37bb 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -59,6 +59,13 @@ config NF_LOG_IPV6
 	default m if NETFILTER_ADVANCED=n
 	select NF_LOG_COMMON
 
+config NF_TEE_IPV6
+	tristate "Netfilter IPv6 packet cloning to alternate destination"
+	select NF_TEE
+	help
+	  This option enables the nf_tee_ipv6 core, which clone an IPv6 packet
+	  to be rerouted to another destination.
+
 config NF_NAT_IPV6
 	tristate "IPv6 NAT"
 	depends on NF_CONNTRACK_IPV6
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index c36e0a5..b3a2946 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -30,6 +30,8 @@ obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o
 # reject
 obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o
 
+obj-$(CONFIG_NF_TEE_IPV6) += nf_tee_ipv6.o
+
 # nf_tables
 obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
 obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
diff --git a/net/ipv6/netfilter/nf_tee_ipv6.c b/net/ipv6/netfilter/nf_tee_ipv6.c
new file mode 100644
index 0000000..35ea63e
--- /dev/null
+++ b/net/ipv6/netfilter/nf_tee_ipv6.c
@@ -0,0 +1,90 @@
+/*
+ * (C) 2007 by Sebastian Claßen
+ * (C) 2007-2010 by Jan Engelhardt
+ *
+ * Extracted from xt_TEE.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 or later, as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/skbuff.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/netfilter/nf_tee.h>
+#include <net/netfilter/ipv6/nf_tee_ipv6.h>
+
+#if IS_ENABLED(CONFIG_NF_CONNTRACK)
+#	define WITH_CONNTRACK 1
+#	include <net/netfilter/nf_conntrack.h>
+#endif
+
+static DEFINE_PER_CPU(bool, tee_active);
+
+static bool nf_tee_ipv6_route(struct sk_buff *skb, const struct nf_tee *tee,
+			      const struct in6_addr *gw)
+{
+	const struct ipv6hdr *iph = ipv6_hdr(skb);
+	struct net *net = nf_tee_pick_net(skb);
+	struct dst_entry *dst;
+	struct flowi6 fl6;
+
+	memset(&fl6, 0, sizeof(fl6));
+	if (nf_tee_has_notifier(tee)) {
+		if (tee->oif == -1)
+			return false;
+		fl6.flowi6_oif = tee->oif;
+	}
+	fl6.daddr = *gw;
+	fl6.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
+			 (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
+	dst = ip6_route_output(net, NULL, &fl6);
+	if (dst->error) {
+		dst_release(dst);
+		return false;
+	}
+	skb_dst_drop(skb);
+	skb_dst_set(skb, dst);
+	skb->dev      = dst->dev;
+	skb->protocol = htons(ETH_P_IPV6);
+
+	return true;
+}
+
+unsigned int nf_tee_ipv6(struct sk_buff *skb, const struct nf_tee *tee,
+			 unsigned int hooknum, const struct in6_addr *gw)
+{
+	if (__this_cpu_read(tee_active))
+		return XT_CONTINUE;
+	skb = pskb_copy(skb, GFP_ATOMIC);
+	if (skb == NULL)
+		return XT_CONTINUE;
+
+#ifdef WITH_CONNTRACK
+	nf_conntrack_put(skb->nfct);
+	skb->nfct     = &nf_ct_untracked_get()->ct_general;
+	skb->nfctinfo = IP_CT_NEW;
+	nf_conntrack_get(skb->nfct);
+#endif
+	if (hooknum == NF_INET_PRE_ROUTING ||
+	    hooknum == NF_INET_LOCAL_IN) {
+		struct ipv6hdr *iph = ipv6_hdr(skb);
+		--iph->hop_limit;
+	}
+	if (nf_tee_ipv6_route(skb, tee, gw)) {
+		__this_cpu_write(tee_active, true);
+		ip6_local_out(skb);
+		__this_cpu_write(tee_active, false);
+	} else {
+		kfree_skb(skb);
+	}
+	return XT_CONTINUE;
+}
+EXPORT_SYMBOL_GPL(nf_tee_ipv6);
+
+MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
+MODULE_DESCRIPTION("nf_tee_ipv6: Reroute IPv6 packet copy");
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 6eae69a..afdba34 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -564,6 +564,14 @@ config NFT_COMPAT
 
 endif # NF_TABLES
 
+config NF_TEE
+	tristate "Netfilter nf_tee module"
+	depends on !NF_CONNTRACK || NF_CONNTRACK
+	help
+	  This module is the core nf_tee engine, which allows you
+	  to copy and redirect packets to another gateway.
+
+
 config NETFILTER_XTABLES
 	tristate "Netfilter Xtables support (required for ip_tables)"
 	default m if NETFILTER_ADVANCED=n
@@ -867,6 +875,8 @@ config NETFILTER_XT_TARGET_TEE
 	depends on NETFILTER_ADVANCED
 	depends on IPV6 || IPV6=n
 	depends on !NF_CONNTRACK || NF_CONNTRACK
+	select NF_TEE_IPV4
+	select NF_TEE_IPV6 if IP6_NF_IPTABLES
 	---help---
 	This option adds a "TEE" target with which a packet can be cloned and
 	this clone be rerouted to another nexthop.
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 70d026d..9be0e4b 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -47,6 +47,8 @@ obj-$(CONFIG_NF_CONNTRACK_TFTP) += nf_conntrack_tftp.o
 nf_nat-y	:= nf_nat_core.o nf_nat_proto_unknown.o nf_nat_proto_common.o \
 		   nf_nat_proto_udp.o nf_nat_proto_tcp.o nf_nat_helper.o
 
+obj-$(CONFIG_NF_TEE) += nf_tee.o
+
 # generic transport layer logging
 obj-$(CONFIG_NF_LOG_COMMON) += nf_log_common.o
 
diff --git a/net/netfilter/nf_tee.c b/net/netfilter/nf_tee.c
new file mode 100644
index 0000000..c677b95
--- /dev/null
+++ b/net/netfilter/nf_tee.c
@@ -0,0 +1,91 @@
+/*
+ * (C) 2007 by Sebastian Claßen <sebastian.classen@freenet.ag>
+ * (C) 2007-2010 by Jan Engelhardt <jengelh@medozas.de>
+ *
+ * Extracted from xt_TEE.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 or later, as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/percpu.h>
+#include <linux/skbuff.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <net/net_namespace.h>
+#include <net/dst.h>
+#include <net/netfilter/nf_tee.h>
+
+struct net *nf_tee_pick_net(struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_NS
+	const struct dst_entry *dst;
+
+	if (skb->dev != NULL)
+		return dev_net(skb->dev);
+	dst = skb_dst(skb);
+	if (dst != NULL && dst->dev != NULL)
+		return dev_net(dst->dev);
+#endif
+	return &init_net;
+}
+EXPORT_SYMBOL_GPL(nf_tee_pick_net);
+
+static int nf_tee_netdev_event(struct notifier_block *this, unsigned long event,
+			       void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct nf_tee *tee;
+
+	tee = container_of(this, struct nf_tee, notifier);
+	switch (event) {
+	case NETDEV_REGISTER:
+		if (!strcmp(dev->name, tee->oifname))
+			tee->oif = dev->ifindex;
+		break;
+	case NETDEV_UNREGISTER:
+		if (dev->ifindex == tee->oif)
+			tee->oif = -1;
+		break;
+	case NETDEV_CHANGENAME:
+		if (!strcmp(dev->name, tee->oifname))
+			tee->oif = dev->ifindex;
+		else if (dev->ifindex == tee->oif)
+			tee->oif = -1;
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+int nf_tee_init(struct nf_tee *tee, const char *oifname)
+{
+	tee->oif = -1;
+
+	if (oifname[0]) {
+		if (oifname[sizeof(tee->oifname) - 1] != '\0')
+			return -EINVAL;
+
+		memcpy(tee->oifname, oifname, sizeof(tee->oifname));
+		tee->notifier.notifier_call = nf_tee_netdev_event;
+		register_netdevice_notifier(&tee->notifier);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nf_tee_init);
+
+void nf_tee_fini(struct nf_tee *tee)
+{
+	if (nf_tee_has_notifier(tee))
+		unregister_netdevice_notifier(&tee->notifier);
+}
+EXPORT_SYMBOL_GPL(nf_tee_fini);
+
+MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
+MODULE_DESCRIPTION("nf_tee: Reroute packet copy");
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 189ad13..9744132 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -10,256 +10,56 @@
  *	modify it under the terms of the GNU General Public License
  *	version 2 or later, as published by the Free Software Foundation.
  */
-#include <linux/ip.h>
 #include <linux/module.h>
-#include <linux/percpu.h>
-#include <linux/route.h>
 #include <linux/skbuff.h>
-#include <linux/notifier.h>
-#include <net/checksum.h>
-#include <net/icmp.h>
-#include <net/ip.h>
-#include <net/ipv6.h>
-#include <net/ip6_route.h>
-#include <net/route.h>
 #include <linux/netfilter/x_tables.h>
+#include <net/netfilter/ipv4/nf_tee_ipv4.h>
+#include <net/netfilter/ipv6/nf_tee_ipv6.h>
 #include <linux/netfilter/xt_TEE.h>
 
-#if IS_ENABLED(CONFIG_NF_CONNTRACK)
-#	define WITH_CONNTRACK 1
-#	include <net/netfilter/nf_conntrack.h>
-#endif
-
-struct xt_tee_priv {
-	struct notifier_block	notifier;
-	struct xt_tee_tginfo	*tginfo;
-	int			oif;
-};
-
-static const union nf_inet_addr tee_zero_address;
-static DEFINE_PER_CPU(bool, tee_active);
-
-static struct net *pick_net(struct sk_buff *skb)
-{
-#ifdef CONFIG_NET_NS
-	const struct dst_entry *dst;
-
-	if (skb->dev != NULL)
-		return dev_net(skb->dev);
-	dst = skb_dst(skb);
-	if (dst != NULL && dst->dev != NULL)
-		return dev_net(dst->dev);
-#endif
-	return &init_net;
-}
-
-static inline bool tee_has_notifier(const struct xt_tee_tginfo *info)
-{
-	return info->priv->notifier.notifier_call != NULL;
-}
-
-static bool
-tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
-{
-	const struct iphdr *iph = ip_hdr(skb);
-	struct net *net = pick_net(skb);
-	struct rtable *rt;
-	struct flowi4 fl4;
-
-	memset(&fl4, 0, sizeof(fl4));
-	if (tee_has_notifier(info)) {
-		if (info->priv->oif == -1)
-			return false;
-		fl4.flowi4_oif = info->priv->oif;
-	}
-	fl4.daddr = info->gw.ip;
-	fl4.flowi4_tos = RT_TOS(iph->tos);
-	fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
-	fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
-	rt = ip_route_output_key(net, &fl4);
-	if (IS_ERR(rt))
-		return false;
-
-	skb_dst_drop(skb);
-	skb_dst_set(skb, &rt->dst);
-	skb->dev      = rt->dst.dev;
-	skb->protocol = htons(ETH_P_IP);
-	return true;
-}
-
 static unsigned int
 tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
 {
 	const struct xt_tee_tginfo *info = par->targinfo;
-	struct iphdr *iph;
-
-	if (__this_cpu_read(tee_active))
-		return XT_CONTINUE;
-	/*
-	 * Copy the skb, and route the copy. Will later return %XT_CONTINUE for
-	 * the original skb, which should continue on its way as if nothing has
-	 * happened. The copy should be independently delivered to the TEE
-	 * --gateway.
-	 */
-	skb = pskb_copy(skb, GFP_ATOMIC);
-	if (skb == NULL)
-		return XT_CONTINUE;
 
-#ifdef WITH_CONNTRACK
-	/* Avoid counting cloned packets towards the original connection. */
-	nf_conntrack_put(skb->nfct);
-	skb->nfct     = &nf_ct_untracked_get()->ct_general;
-	skb->nfctinfo = IP_CT_NEW;
-	nf_conntrack_get(skb->nfct);
-#endif
-	/*
-	 * If we are in PREROUTING/INPUT, the checksum must be recalculated
-	 * since the length could have changed as a result of defragmentation.
-	 *
-	 * We also decrease the TTL to mitigate potential TEE loops
-	 * between two hosts.
-	 *
-	 * Set %IP_DF so that the original source is notified of a potentially
-	 * decreased MTU on the clone route. IPv6 does this too.
-	 */
-	iph = ip_hdr(skb);
-	iph->frag_off |= htons(IP_DF);
-	if (par->hooknum == NF_INET_PRE_ROUTING ||
-	    par->hooknum == NF_INET_LOCAL_IN)
-		--iph->ttl;
-	ip_send_check(iph);
-
-	if (tee_tg_route4(skb, info)) {
-		__this_cpu_write(tee_active, true);
-		ip_local_out(skb);
-		__this_cpu_write(tee_active, false);
-	} else {
-		kfree_skb(skb);
-	}
-	return XT_CONTINUE;
+	return nf_tee_ipv4(skb, info->priv, par->hooknum, &info->gw.in);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
-static bool
-tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
-{
-	const struct ipv6hdr *iph = ipv6_hdr(skb);
-	struct net *net = pick_net(skb);
-	struct dst_entry *dst;
-	struct flowi6 fl6;
-
-	memset(&fl6, 0, sizeof(fl6));
-	if (tee_has_notifier(info)) {
-		if (info->priv->oif == -1)
-			return false;
-		fl6.flowi6_oif = info->priv->oif;
-	}
-	fl6.daddr = info->gw.in6;
-	fl6.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
-			   (iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
-	fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH;
-	dst = ip6_route_output(net, NULL, &fl6);
-	if (dst->error) {
-		dst_release(dst);
-		return false;
-	}
-	skb_dst_drop(skb);
-	skb_dst_set(skb, dst);
-	skb->dev      = dst->dev;
-	skb->protocol = htons(ETH_P_IPV6);
-	return true;
-}
-
 static unsigned int
 tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
 {
 	const struct xt_tee_tginfo *info = par->targinfo;
 
-	if (__this_cpu_read(tee_active))
-		return XT_CONTINUE;
-	skb = pskb_copy(skb, GFP_ATOMIC);
-	if (skb == NULL)
-		return XT_CONTINUE;
-
-#ifdef WITH_CONNTRACK
-	nf_conntrack_put(skb->nfct);
-	skb->nfct     = &nf_ct_untracked_get()->ct_general;
-	skb->nfctinfo = IP_CT_NEW;
-	nf_conntrack_get(skb->nfct);
-#endif
-	if (par->hooknum == NF_INET_PRE_ROUTING ||
-	    par->hooknum == NF_INET_LOCAL_IN) {
-		struct ipv6hdr *iph = ipv6_hdr(skb);
-		--iph->hop_limit;
-	}
-	if (tee_tg_route6(skb, info)) {
-		__this_cpu_write(tee_active, true);
-		ip6_local_out(skb);
-		__this_cpu_write(tee_active, false);
-	} else {
-		kfree_skb(skb);
-	}
-	return XT_CONTINUE;
+	return nf_tee_ipv6(skb, info->priv, par->hooknum, &info->gw.in6);
 }
 #endif
 
-static int tee_netdev_event(struct notifier_block *this, unsigned long event,
-			    void *ptr)
-{
-	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
-	struct xt_tee_priv *priv;
-
-	priv = container_of(this, struct xt_tee_priv, notifier);
-	switch (event) {
-	case NETDEV_REGISTER:
-		if (!strcmp(dev->name, priv->tginfo->oif))
-			priv->oif = dev->ifindex;
-		break;
-	case NETDEV_UNREGISTER:
-		if (dev->ifindex == priv->oif)
-			priv->oif = -1;
-		break;
-	case NETDEV_CHANGENAME:
-		if (!strcmp(dev->name, priv->tginfo->oif))
-			priv->oif = dev->ifindex;
-		else if (dev->ifindex == priv->oif)
-			priv->oif = -1;
-		break;
-	}
-
-	return NOTIFY_DONE;
-}
+static const union nf_inet_addr tee_zero_address;
 
 static int tee_tg_check(const struct xt_tgchk_param *par)
 {
 	struct xt_tee_tginfo *info = par->targinfo;
-	struct xt_tee_priv *priv;
+	struct nf_tee *tee;
+	int ret;
 
 	/* 0.0.0.0 and :: not allowed */
-	if (memcmp(&info->gw, &tee_zero_address,
-		   sizeof(tee_zero_address)) == 0)
+	if (memcmp(&info->gw, &tee_zero_address, sizeof(tee_zero_address)) == 0)
 		return -EINVAL;
 
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (priv == NULL)
+	tee = kzalloc(sizeof(*tee), GFP_KERNEL);
+	if (tee == NULL)
 		return -ENOMEM;
 
-	priv->tginfo	= info;
-	priv->oif	= -1;
-
-	if (info->oif[0]) {
-		if (info->oif[sizeof(info->oif)-1] != '\0')
-			goto err1;
+	ret = nf_tee_init(tee, info->oif);
+	if (ret < 0)
+		goto err1;
 
-		priv->notifier.notifier_call = tee_netdev_event;
-		register_netdevice_notifier(&priv->notifier);
-	}
-
-	info->priv	= priv;
+	info->priv = tee;
 
 	return 0;
 err1:
-	kfree(priv);
+	kfree(tee);
 	return -EINVAL;
 }
 
@@ -267,9 +67,7 @@ static void tee_tg_destroy(const struct xt_tgdtor_param *par)
 {
 	struct xt_tee_tginfo *info = par->targinfo;
 
-	if (tee_has_notifier(info))
-		unregister_netdevice_notifier(&info->priv->notifier);
-
+	nf_tee_fini(info->priv);
 	kfree(info->priv);
 }
 
-- 
1.7.10.4

--
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 related	[flat|nested] 3+ messages in thread

* [PATCH nf-next, v2 3/3] netfilter: nf_tables: add nft_tee expression
  2015-06-18 18:13 [PATCH nf-next, v2 1/3] netfilter: xt_TEE: always allocate private area Pablo Neira Ayuso
  2015-06-18 18:13 ` =?y?q?=5BPATCH=20nf-next=2C=20v2=202/3=5D=20netfilter=3A=20move=20generic=20TEE=20code=20from=20xtables=20to=20nf=5Ftee=5Fipv=7B4=2C6=7D=20modules?= Pablo Neira Ayuso
@ 2015-06-18 18:13 ` Pablo Neira Ayuso
  1 sibling, 0 replies; 3+ messages in thread
From: Pablo Neira Ayuso @ 2015-06-18 18:13 UTC (permalink / raw)
  To: netfilter-devel; +Cc: kaber, arturo.borrero.glez

This new expression uses the nf_tee engine to clone packets to a given gateway.

It should be possible to reduce memory consumption a bit through select_ops(),
but this would make it more complicated to share code with x_tables though.  I
expect little rules using this expression, so I think it's fine to start with
this approach.

Based on original work from Arturo Borrero Gonzalez, although this patch has
diverted quite a bit from this initial effort due to the change to support maps.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: This includes support for maps.

 include/net/netfilter/nft_tee.h          |   11 +++
 include/uapi/linux/netfilter/nf_tables.h |   14 ++++
 net/ipv4/netfilter/Kconfig               |    7 ++
 net/ipv4/netfilter/Makefile              |    1 +
 net/ipv4/netfilter/nft_tee_ipv4.c        |  120 ++++++++++++++++++++++++++++++
 net/ipv6/netfilter/Kconfig               |    7 ++
 net/ipv6/netfilter/Makefile              |    1 +
 net/ipv6/netfilter/nft_tee_ipv6.c        |  119 +++++++++++++++++++++++++++++
 8 files changed, 280 insertions(+)
 create mode 100644 include/net/netfilter/nft_tee.h
 create mode 100644 net/ipv4/netfilter/nft_tee_ipv4.c
 create mode 100644 net/ipv6/netfilter/nft_tee_ipv6.c

diff --git a/include/net/netfilter/nft_tee.h b/include/net/netfilter/nft_tee.h
new file mode 100644
index 0000000..8b39b9a
--- /dev/null
+++ b/include/net/netfilter/nft_tee.h
@@ -0,0 +1,11 @@
+#ifndef _NFT_TEE_H_
+#define _NFT_TEE_H_
+
+#include <net/netfilter/nf_tee.h>
+
+struct nft_tee {
+	enum nft_registers	sreg_gw:8;
+	struct nf_tee		tee;
+};
+
+#endif /* _NFT_TEE_H_ */
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index da3b505..28f0e93 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -950,6 +950,20 @@ enum nft_redir_attributes {
 #define NFTA_REDIR_MAX		(__NFTA_REDIR_MAX - 1)
 
 /**
+ * enum nft_tee_attributes - nf_tables tee expression netlink attributes
+ *
+ * @NFTA_TEE_SREG_GW: source register of gateway address (NLA_NESTED: nft_data_attributes)
+ * @NFTA_TEE_OIFNAME: output interface name (NLA_STRING)
+ */
+enum nft_tee_attributes {
+	NFTA_TEE_UNSPEC,
+	NFTA_TEE_SREG_GW,
+	NFTA_TEE_OIFNAME,
+	__NFTA_TEE_MAX
+};
+#define NFTA_TEE_MAX		(__NFTA_TEE_MAX - 1)
+
+/**
  * enum nft_gen_attributes - nf_tables ruleset generation attributes
  *
  * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32)
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 2153bb2..73c3842 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -58,6 +58,13 @@ config NFT_REJECT_IPV4
 	default NFT_REJECT
 	tristate
 
+config NFT_TEE_IPV4
+	tristate "IPv4 tee suport for nf_tables"
+	select NF_TEE
+	select NF_TEE_IPV4
+	help
+	  This is the module that provides IPv4 tee support for nf_tables.
+
 endif # NF_TABLES_IPV4
 
 config NF_TABLES_ARP
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 6b492de..08a008c 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_NFT_CHAIN_NAT_IPV4) += nft_chain_nat_ipv4.o
 obj-$(CONFIG_NFT_REJECT_IPV4) += nft_reject_ipv4.o
 obj-$(CONFIG_NFT_MASQ_IPV4) += nft_masq_ipv4.o
 obj-$(CONFIG_NFT_REDIR_IPV4) += nft_redir_ipv4.o
+obj-$(CONFIG_NFT_TEE_IPV4) += nft_tee_ipv4.o
 obj-$(CONFIG_NF_TABLES_ARP) += nf_tables_arp.o
 
 # generic IP tables 
diff --git a/net/ipv4/netfilter/nft_tee_ipv4.c b/net/ipv4/netfilter/nft_tee_ipv4.c
new file mode 100644
index 0000000..a29dceb
--- /dev/null
+++ b/net/ipv4/netfilter/nft_tee_ipv4.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
+ * Copyright (c) 2015 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
+ *
+ * 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 published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nft_tee.h>
+#include <net/netfilter/ipv4/nf_tee_ipv4.h>
+
+static void nft_tee_ipv4_eval(const struct nft_expr *expr,
+			      struct nft_regs *regs,
+			      const struct nft_pktinfo *pkt)
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+	struct in_addr gw = {
+		.s_addr = regs->data[priv->sreg_gw],
+	};
+
+	nf_tee_ipv4(pkt->skb, &priv->tee, pkt->ops->hooknum, &gw);
+}
+
+static int nft_tee_ipv4_init(const struct nft_ctx *ctx,
+			     const struct nft_expr *expr,
+			     const struct nlattr * const tb[])
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+	char oifname[IFNAMSIZ];
+	int err;
+
+	if (tb[NFTA_TEE_SREG_GW] == NULL)
+		return -EINVAL;
+
+	priv->sreg_gw = nft_parse_register(tb[NFTA_TEE_SREG_GW]);
+	err = nft_validate_register_load(priv->sreg_gw, sizeof(struct in_addr));
+	if (err < 0)
+		return err;
+
+	memset(oifname, 0, sizeof(oifname));
+	if (tb[NFTA_TEE_OIFNAME] != NULL)
+		nla_strlcpy(oifname, tb[NFTA_TEE_OIFNAME], sizeof(oifname));
+
+	return nf_tee_init(&priv->tee, oifname);
+}
+
+static void nft_tee_ipv4_destroy(const struct nft_ctx *ctx,
+				 const struct nft_expr *expr)
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+
+	nf_tee_fini(&priv->tee);
+}
+
+static int nft_tee_ipv4_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+
+	if (nft_dump_register(skb, NFTA_TEE_SREG_GW, priv->sreg_gw))
+		goto nla_put_failure;
+
+	if (priv->tee.oifname[0]) {
+		if (nla_put_string(skb, NFTA_TEE_OIFNAME, priv->tee.oifname))
+			goto nla_put_failure;
+	}
+	return 0;
+
+nla_put_failure:
+	return -1;
+}
+
+static struct nft_expr_type nft_tee_ipv4_type;
+static const struct nft_expr_ops nft_tee_ipv4_ops = {
+	.type		= &nft_tee_ipv4_type,
+	.size		= NFT_EXPR_SIZE(sizeof(struct nf_tee)),
+	.eval		= nft_tee_ipv4_eval,
+	.init		= nft_tee_ipv4_init,
+	.destroy	= nft_tee_ipv4_destroy,
+	.dump		= nft_tee_ipv4_dump,
+};
+
+static const struct nla_policy nft_tee_ipv4_policy[NFTA_TEE_MAX + 1] = {
+	[NFTA_TEE_SREG_GW]	= { .type = NLA_U32 },
+	[NFTA_TEE_OIFNAME]	= { .type = NLA_STRING,
+				    .len  = IFNAMSIZ - 1 },
+};
+
+static struct nft_expr_type nft_tee_ipv4_type __read_mostly = {
+	.family		= NFPROTO_IPV4,
+	.name		= "tee",
+	.ops		= &nft_tee_ipv4_ops,
+	.policy		= nft_tee_ipv4_policy,
+	.maxattr	= NFTA_TEE_MAX,
+	.owner		= THIS_MODULE,
+};
+
+static int __init nft_tee_ipv4_module_init(void)
+{
+	return nft_register_expr(&nft_tee_ipv4_type);
+}
+
+static void __exit nft_tee_ipv4_module_exit(void)
+{
+	nft_unregister_expr(&nft_tee_ipv4_type);
+}
+
+module_init(nft_tee_ipv4_module_init);
+module_exit(nft_tee_ipv4_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+MODULE_ALIAS_NFT_AF_EXPR(AF_INET, "tee");
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index 92c37bb..ec8ece5 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -47,6 +47,13 @@ config NFT_REJECT_IPV6
 	default NFT_REJECT
 	tristate
 
+config NFT_TEE_IPV6
+	tristate "IPv6 tee support for nf_tables"
+	select NF_TEE
+	select NF_TEE_IPV6
+	help
+	  This is the module that provides IPv6 tee support for nf_tables.
+
 endif # NF_TABLES_IPV6
 endif # NF_TABLES
 
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index b3a2946..da871e8 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_NFT_CHAIN_NAT_IPV6) += nft_chain_nat_ipv6.o
 obj-$(CONFIG_NFT_REJECT_IPV6) += nft_reject_ipv6.o
 obj-$(CONFIG_NFT_MASQ_IPV6) += nft_masq_ipv6.o
 obj-$(CONFIG_NFT_REDIR_IPV6) += nft_redir_ipv6.o
+obj-$(CONFIG_NFT_TEE_IPV6) += nft_tee_ipv6.o
 
 # matches
 obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o
diff --git a/net/ipv6/netfilter/nft_tee_ipv6.c b/net/ipv6/netfilter/nft_tee_ipv6.c
new file mode 100644
index 0000000..e222487
--- /dev/null
+++ b/net/ipv6/netfilter/nft_tee_ipv6.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
+ * Copyright (c) 2015 Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>
+ *
+ * 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 published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netlink.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
+#include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nft_tee.h>
+#include <net/netfilter/ipv6/nf_tee_ipv6.h>
+
+static void nft_tee_ipv6_eval(const struct nft_expr *expr,
+			      struct nft_regs *regs,
+			      const struct nft_pktinfo *pkt)
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+	struct in6_addr gw;
+
+	memcpy(&gw, &regs->data[priv->sreg_gw], sizeof(struct in6_addr));
+	nf_tee_ipv6(pkt->skb, &priv->tee, pkt->ops->hooknum, &gw);
+}
+
+static int nft_tee_ipv6_init(const struct nft_ctx *ctx,
+			     const struct nft_expr *expr,
+			     const struct nlattr * const tb[])
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+	char oifname[IFNAMSIZ];
+	int err;
+
+	if (tb[NFTA_TEE_SREG_GW] == NULL)
+		return -EINVAL;
+
+	priv->sreg_gw = nft_parse_register(tb[NFTA_TEE_SREG_GW]);
+	err = nft_validate_register_load(priv->sreg_gw, sizeof(struct in6_addr));
+	if (err < 0)
+		return err;
+
+	memset(oifname, 0, sizeof(oifname));
+	if (tb[NFTA_TEE_OIFNAME] != NULL)
+		nla_strlcpy(oifname, tb[NFTA_TEE_OIFNAME], sizeof(oifname));
+
+	return nf_tee_init(&priv->tee, oifname);
+}
+
+static void nft_tee_ipv6_destroy(const struct nft_ctx *ctx,
+				 const struct nft_expr *expr)
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+
+	nf_tee_fini(&priv->tee);
+}
+
+static int nft_tee_ipv6_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+	struct nft_tee *priv = nft_expr_priv(expr);
+
+	if (nft_dump_register(skb, NFTA_TEE_SREG_GW, priv->sreg_gw))
+		goto nla_put_failure;
+
+	if (priv->tee.oifname[0]) {
+		if (nla_put_string(skb, NFTA_TEE_OIFNAME, priv->tee.oifname))
+			goto nla_put_failure;
+	}
+
+
+nla_put_failure:
+	return -1;
+}
+
+static struct nft_expr_type nft_tee_ipv6_type;
+static const struct nft_expr_ops nft_tee_ipv6_ops = {
+	.type		= &nft_tee_ipv6_type,
+	.size		= NFT_EXPR_SIZE(sizeof(struct nf_tee)),
+	.eval		= nft_tee_ipv6_eval,
+	.init		= nft_tee_ipv6_init,
+	.destroy	= nft_tee_ipv6_destroy,
+	.dump		= nft_tee_ipv6_dump,
+};
+
+static const struct nla_policy nft_tee_ipv6_policy[NFTA_TEE_MAX + 1] = {
+	[NFTA_TEE_SREG_GW]	= { .type = NLA_U32 },
+	[NFTA_TEE_OIFNAME]	= { .type = NLA_STRING,
+				    .len  = IFNAMSIZ - 1 },
+};
+
+static struct nft_expr_type nft_tee_ipv6_type __read_mostly = {
+	.family		= NFPROTO_IPV6,
+	.name		= "tee",
+	.ops		= &nft_tee_ipv6_ops,
+	.policy		= nft_tee_ipv6_policy,
+	.maxattr	= NFTA_TEE_MAX,
+	.owner		= THIS_MODULE,
+};
+
+static int __init nft_tee_ipv6_module_init(void)
+{
+	return nft_register_expr(&nft_tee_ipv6_type);
+}
+
+static void __exit nft_tee_ipv6_module_exit(void)
+{
+	nft_unregister_expr(&nft_tee_ipv6_type);
+}
+
+module_init(nft_tee_ipv6_module_init);
+module_exit(nft_tee_ipv6_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
+MODULE_ALIAS_NFT_AF_EXPR(AF_INET6, "tee");
-- 
1.7.10.4


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

end of thread, other threads:[~2015-06-18 18:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-18 18:13 [PATCH nf-next, v2 1/3] netfilter: xt_TEE: always allocate private area Pablo Neira Ayuso
2015-06-18 18:13 ` =?y?q?=5BPATCH=20nf-next=2C=20v2=202/3=5D=20netfilter=3A=20move=20generic=20TEE=20code=20from=20xtables=20to=20nf=5Ftee=5Fipv=7B4=2C6=7D=20modules?= Pablo Neira Ayuso
2015-06-18 18:13 ` [PATCH nf-next, v2 3/3] netfilter: nf_tables: add nft_tee expression Pablo Neira Ayuso

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.