All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: kaber@trash.net, arturo.borrero.glez@gmail.com
Subject: =?y?q?=5BPATCH=20nf-next=203/4=5D=20netfilter=3A=20move=20generic=20TEE=20code=20from=20xtables=20to=20nf=5Ftee=5Fipv=7B4=2C6=7D=20modules?=
Date: Fri, 12 Jun 2015 13:59:37 +0200	[thread overview]
Message-ID: <1434110378-6284-2-git-send-email-pablo@netfilter.org> (raw)
In-Reply-To: <1434110378-6284-1-git-send-email-pablo@netfilter.org>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=y, Size: 23864 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           |   23 +++
 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         |  115 +++++++++++++++
 net/ipv6/netfilter/Kconfig               |    7 +
 net/ipv6/netfilter/Makefile              |    2 +
 net/ipv6/netfilter/nf_tee_ipv6.c         |   89 +++++++++++
 net/netfilter/Kconfig                    |   10 ++
 net/netfilter/Makefile                   |    2 +
 net/netfilter/nf_tee.c                   |   98 +++++++++++++
 net/netfilter/xt_TEE.c                   |  236 ++----------------------------
 14 files changed, 388 insertions(+), 223 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..434e561
--- /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);
+
+#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..842cbcf
--- /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);
+
+#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..7a93cb1
--- /dev/null
+++ b/include/net/netfilter/nf_tee.h
@@ -0,0 +1,23 @@
+#ifndef _NF_TEE_H_
+#define _NF_TEE_H_
+
+#include <linux/netfilter.h>
+#include <linux/if.h>
+
+struct nf_tee {
+	union nf_inet_addr	gw;
+	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, union nf_inet_addr gw, 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..2dcc1a8
--- /dev/null
+++ b/net/ipv4/netfilter/nf_tee_ipv4.c
@@ -0,0 +1,115 @@
+/*
+ * (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 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 = tee->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;
+}
+
+unsigned int nf_tee_ipv4(struct sk_buff *skb, const struct nf_tee *tee,
+			 unsigned int hooknum)
+{
+	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)) {
+		__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..f13b61f9
--- /dev/null
+++ b/net/ipv6/netfilter/nf_tee_ipv6.c
@@ -0,0 +1,89 @@
+/*
+ * (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 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 = tee->gw.in6;
+	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)
+{
+	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)) {
+		__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..a53f351
--- /dev/null
+++ b/net/netfilter/nf_tee.c
@@ -0,0 +1,98 @@
+/*
+ * (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;
+}
+
+static const union nf_inet_addr tee_zero_address;
+
+int nf_tee_init(struct nf_tee *tee, union nf_inet_addr gw, const char *oifname)
+{
+	/* 0.0.0.0 and :: not allowed */
+	if (memcmp(&gw, &tee_zero_address, sizeof(tee_zero_address)) == 0)
+		return -EOPNOTSUPP;
+
+	memcpy(&tee->gw, &gw, sizeof(gw));
+	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..6bd9a4d 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -10,256 +10,50 @@
  *	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);
 }
 
 #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);
 }
 #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 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)
-		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->gw, 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 +61,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

  reply	other threads:[~2015-06-12 11:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-12 11:59 [PATCH nf-next 2/4] netfilter: xt_TEE: always allocate private area Pablo Neira Ayuso
2015-06-12 11:59 ` Pablo Neira Ayuso [this message]
2015-06-16 16:33   ` [PATCH nf-next 3/4] netfilter: move generic TEE code from xtables to nf_tee_ipv{4,6} modules Pablo Neira Ayuso
2015-06-16 16:37     ` Pablo Neira Ayuso
2015-06-17  6:05       ` Patrick McHardy
2015-06-12 11:59 ` [PATCH nf-next 4/4] netfilter: nf_tables: add nft_tee expression Pablo Neira Ayuso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1434110378-6284-2-git-send-email-pablo@netfilter.org \
    --to=pablo@netfilter.org \
    --cc=arturo.borrero.glez@gmail.com \
    --cc=kaber@trash.net \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.