NF [PATCH 2/4] xt_TEE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Netfilter: Import xt_TEE


Originally from Sebastian Classen.
xt_TEE is the logical successor to ipt_ROUTE; routing based on packet
charactersitics is done using xt_MARK/iproute2/fwmark nowadays, so
what remains of ipt_ROUTE is the --tee option, which xt_TEE implements.

Signed-off-by: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>
Cc: Sebastian Classen <sebastian.classen@xxxxxxxxxx>

---
 include/linux/netfilter/xt_TEE.h |   12 +
 net/netfilter/Kconfig            |   13 ++
 net/netfilter/Makefile           |    1 
 net/netfilter/xt_TEE.c           |  240 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 266 insertions(+)

Index: linux-2.6/include/linux/netfilter/xt_TEE.h
===================================================================
--- /dev/null
+++ linux-2.6/include/linux/netfilter/xt_TEE.h
@@ -0,0 +1,12 @@
+#ifndef _XT_TEE_TARGET_H
+#define _XT_TEE_TARGET_H
+
+struct xt_tee_target_info {
+	union {
+		/* Address of gateway */
+		u_int32_t gateway_v4;
+		u_int32_t gateway_v6[4];
+	};
+};
+
+#endif /* _XT_TEE_TARGET_H */
Index: linux-2.6/net/netfilter/Kconfig
===================================================================
--- linux-2.6.orig/net/netfilter/Kconfig
+++ linux-2.6/net/netfilter/Kconfig
@@ -411,6 +411,19 @@ config NETFILTER_XT_TARGET_TCPMSS
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NETFILTER_XT_TARGET_TEE
+	tristate '"TEE" target support'
+	depends on NETFILTER_XTABLES && IP_NF_MANGLE
+	---help---
+	  This option adds a "TEE" target, which enables you to duplicate
+	  packets and route those duplicates to a different gateway.
+
+	  The target has to be used inside the mangle table.
+
+	  If you want to compile it as a module, say M here and read
+	  Documentation/modules.txt. The module will be called xt_TEE.ko.
+	  If unsure, say N.
+
 config NETFILTER_XT_MATCH_COMMENT
 	tristate  '"comment" match support'
 	depends on NETFILTER_XTABLES
Index: linux-2.6/net/netfilter/Makefile
===================================================================
--- linux-2.6.orig/net/netfilter/Makefile
+++ linux-2.6/net/netfilter/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE
 obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o
 obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
 
 # matches
Index: linux-2.6/net/netfilter/xt_TEE.c
===================================================================
--- /dev/null
+++ linux-2.6/net/netfilter/xt_TEE.c
@@ -0,0 +1,240 @@
+/*
+ * This implements the TEE target.
+ *
+ * Copyright (C) 2007 Sebastian Classen <sebastian.classen@xxxxxxxxxx> and
+ * CC Computer Consultants GmbH, 2007
+ * (Contact: Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>)
+ *
+ * based on ipt_ROUTE.c from Cédric de Launois <delaunois@xxxxxxxxxxxxxx>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ */
+#include <linux/ip.h>
+#include <linux/module.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 <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_TEE.h>
+
+#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
+#	define WITH_CONNTRACK 1
+#	include <net/netfilter/nf_conntrack.h>
+static struct nf_conn tee_track;
+#endif
+
+/*
+ * Try to route the packet according to the routing keys specified in
+ * route_info. Keys are :
+ *  - ifindex :
+ *      0 if no oif preferred,
+ *      otherwise set to the index of the desired oif
+ *  - route_info->gateway :
+ *      0 if no gateway specified,
+ *      otherwise set to the next host to which the pkt must be routed
+ * If success, skb->dev is the output device to which the packet must
+ * be sent and skb->dst is not NULL
+ *
+ * RETURN: false - if an error occured
+ *         true  - if the packet was succesfully routed to the
+ *                 destination desired
+ */
+static bool tee_routing(struct sk_buff *skb,
+                        const struct xt_tee_target_info *info)
+{
+	int err;
+	struct rtable *rt;
+	struct iphdr *iph = ip_hdr(skb);
+	struct flowi fl = {
+		.nl_u = {
+			.ip4_u = {
+				.daddr = iph->daddr,
+				.tos   = RT_TOS(iph->tos),
+				.scope = RT_SCOPE_UNIVERSE,
+			}
+		}
+	};
+
+	/* The destination address may be overloaded by the target */
+	if (info->gateway_v4 != 0)
+		fl.fl4_dst = info->gateway_v4;
+
+	/* Trying to route the packet using the standard routing table. */
+	err = ip_route_output_key(&rt, &fl);
+	if (err != 0) {
+		if (net_ratelimit())
+			pr_debug(KBUILD_MODNAME
+			         ": could not route packet (%d)", err);
+		return false;
+	}
+
+	/* Drop old route. */
+	dst_release(skb->dst);
+	skb->dst = NULL;
+
+	/*
+	 * Success if no oif specified or if the oif correspond to the
+	 * one desired.
+	 * [SC]: always the case, because we have no oif.
+	 */
+	skb->dst      = &rt->u.dst;
+	skb->dev      = skb->dst->dev;
+	skb->protocol = htons(ETH_P_IP);
+	return true;
+}
+
+/*
+ * Stolen from ip_finish_output2
+ * PRE : skb->dev is set to the device we are leaving by
+ *       skb->dst is not NULL
+ * POST: the packet is sent with the link layer header pushed
+ *       the packet is destroyed
+ */
+static void tee_ip_direct_send(struct sk_buff *skb)
+{
+	const struct dst_entry *dst  = skb->dst;
+	const struct net_device *dev = dst->dev;
+	unsigned int hh_len = LL_RESERVED_SPACE(dev);
+
+	/* Be paranoid, rather than too clever. */
+	if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops != NULL)) {
+		struct sk_buff *skb2;
+
+		skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
+		if (skb2 == NULL) {
+			kfree_skb(skb);
+			return;
+		}
+		if (skb->sk != NULL)
+			skb_set_owner_w(skb2, skb->sk);
+		kfree_skb(skb);
+		skb = skb2;
+	}
+
+	if (dst->hh != NULL) {
+		neigh_hh_output(dst->hh, skb);
+	} else if (dst->neighbour != NULL) {
+		dst->neighbour->output(skb);
+	} else {
+		if (net_ratelimit())
+			pr_debug(KBUILD_MODNAME "no hdr & no neighbour cache!\n");
+		kfree_skb(skb);
+	}
+}
+
+/*
+ * To detect and deter routed packet loopback when using the --tee option, we
+ * take a page out of the raw.patch book: on the copied skb, we set up a fake
+ * ->nfct entry, pointing to the local &route_tee_track. We skip routing
+ * packets when we see they already have that ->nfct.
+ */
+static unsigned int
+tee_tg(struct sk_buff *skb, const struct net_device *in,
+       const struct net_device *out, unsigned int hooknum,
+       const struct xt_target *target, const void *targinfo)
+{
+	const struct xt_tee_target_info *info = targinfo;
+
+#ifdef WITH_CONNTRACK
+	if (skb->nfct == &tee_track.ct_general) {
+		/*
+		 * Loopback - a packet we already routed, is to be
+		 * routed another time. Avoid that, now.
+		 */
+		if (net_ratelimit())
+			pr_debug(KBUILD_MODNAME "loopback - DROP!\n");
+		return NF_DROP;
+	}
+#endif
+
+	/*
+	 * If we are in INPUT, the checksum must be recalculated since
+	 * the length could have changed as a result of defragmentation.
+	 */
+	if (hooknum == NF_INET_LOCAL_IN) {
+		struct iphdr *iph = ip_hdr(skb);
+		iph->check = 0;
+		iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+	}
+
+	/*
+	 * 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 independantly delivered to the TEE --gw.
+	 */
+	skb = skb_copy(skb, GFP_ATOMIC);
+	if (skb == NULL) {
+		if (net_ratelimit())
+			pr_debug(KBUILD_MODNAME "copy failed!\n");
+		return XT_CONTINUE;
+	}
+
+#ifdef WITH_CONNTRACK
+	/*
+	 * Tell conntrack to forget this packet since it may get confused
+	 * when a packet is leaving with dst address == our address.
+	 * Good idea? Dunno. Need advice.
+	 *
+	 * NEW: mark the skb with our &tee_track, so we avoid looping
+	 * on any already routed packet.
+	 */
+	nf_conntrack_put(skb->nfct);
+	skb->nfct     = &tee_track.ct_general;
+	skb->nfctinfo = IP_CT_NEW;
+	nf_conntrack_get(skb->nfct);
+#endif
+
+	if (info->gateway_v4 != 0) {
+		if (tee_routing(skb, info))
+			tee_ip_direct_send(skb);
+	} else {
+		if (net_ratelimit())
+			pr_debug(KBUILD_MODNAME ": no parameter!\n");
+	}
+
+	return XT_CONTINUE;
+}
+
+static struct xt_target tee_tg_reg __read_mostly = {
+	.name       = "TEE",
+	.family     = AF_INET,
+	.table      = "mangle",
+	.target     = tee_tg,
+	.targetsize = sizeof(struct xt_tee_target_info),
+	.me         = THIS_MODULE,
+};
+
+static int __init tee_tg_init(void)
+{
+#ifdef WITH_CONNTRACK
+	/*
+	 * Set up fake conntrack (stolen from raw.patch):
+	 * - to never be deleted, not in any hashes
+	 */
+	atomic_set(&tee_track.ct_general.use, 1);
+
+	/* - and look it like as a confirmed connection */
+	set_bit(IPS_CONFIRMED_BIT, &tee_track.status);
+
+	/* Initialize fake conntrack so that NAT will skip it */
+	tee_track.status |= IPS_NAT_DONE_MASK;
+#endif
+
+	return xt_register_target(&tee_tg_reg);
+}
+
+static void __exit tee_tg_exit(void)
+{
+	xt_unregister_target(&tee_tg_reg);
+	/* [SC]: shoud not we cleanup tee_track here? */
+}
+
+module_init(tee_tg_init);
+module_exit(tee_tg_exit);
+MODULE_AUTHOR("Sebastian Classen <sebastian.classen@xxxxxxxxxx>, Jan Engelhardt <jengelh@xxxxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("netfilter \"TEE\" target module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_TEE");
-
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux