--- /dev/null
+.*.cmd
+*.ko
+*.la
+*.lo
+*.loT
+*.mod.c
+*.o
+.deps
+.libs
+.tmp_versions
+Makefile
+Makefile.in
+Module.symvers
+
+/aclocal.m4
+/autom4te*.cache
+/compile
+/config.*
+/configure
+/depcomp
+/install-sh
+/libtool
+/ltmain.sh
+/missing
+/stamp-h1
--- /dev/null
+
+Prerequirements
+===============
+
+ * iptables-devel 1.4.1
+
+ * kernel-source
+
+
+Compiling
+=========
+
+./configure [options]
+
+--with-kbuild=
+
+ Specifies the path to the kernel build output directory. We
+ need it for building the kernel extensions. For example, on
+ openSUSE:
+
+ --with-kbuild=/usr/src/linux-obj/x86_64/default
+
+--with-ksource=
+
+ Specifies the path to the kernel source directory. This is
+ currently needed for building the userspace extensions because
+ we use unsanitized kernel headers, but the option MAY
+ DISAPPEAR IN FUTURE.
+
+ --with-ksource=/usr/src/linux
+
+--with-iptables=
+
+ Specifies the path to the directory where we may find
+ xtables.h, should it not be within the standard C compiler
+ include path, or if you want to override it. The directory
+ will be checked for xtables.h and include/xtables.h. (This is
+ to support the following specs:)
+
+ --with-iptables=/usr/src/iptables
+ --with-iptables=/usr/src/iptables/include
+ --with-iptables=/opt/iptables/include
+
+--with-iptdir=
+
+ Specifies the path to where the newly built extensions should
+ be installed when `make install` is run. It uses the same
+ default as the iptables package, ${libexecdir}/iptables.
+
+
+Note to distribution packagers
+==============================
+
+Except for --with-kbuild, distributions should not have a need to
+supply any other flags (besides --prefix=/usr and perhaps
+--libdir=/usr/lib64, etc.) to configure when all prerequired packages
+are installed. If iptables-devel is installed, necessary headers
+should be in /usr/include, so --with-iptables is not needed.
--- /dev/null
+# -*- Makefile -*-
+
+AUTOMAKE_OPTIONS = foreign subdir-objects
+SUBDIRS = extensions
--- /dev/null
+iptables-addons
+===============
+
+iptables-addons is what previously has been patch-o-matic and
+patch-o-matic-ng. Extensions that do not need immediate kernel
+patching are collected here in this repository and can immediately be
+built against a kernel and iptables.
--- /dev/null
+#!/bin/bash
+
+autoreconf -fi;
+rm -Rf autom4te*.cache;
--- /dev/null
+
+AC_INIT([iptables-addons], [1.4.1])
+AC_CONFIG_HEADERS([config.h])
+AC_PROG_INSTALL
+AM_INIT_AUTOMAKE
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
+
+kbuilddir="/lib/modules/$(uname -r)/build";
+ksourcedir="/lib/modules/$(uname -r)/source";
+AC_ARG_WITH([kbuild],
+ AS_HELP_STRING([--with-kbuild=PATH],
+ [Path to kernel build directory [[/lib/modules/CURRENT/build]]]),
+ [kbuilddir="$withval"])
+AC_ARG_WITH([ksource],
+ AS_HELP_STRING([--with-ksource=PATH],
+ [Path to kernel source directory [[/lib/modules/CURRENT/source]]]),
+ [ksourcedir="$withval"])
+AC_ARG_WITH([iptables],
+ AS_HELP_STRING([--with-iptables=PATH],
+ [Path to the iptables includes [[PREFIX/include]]]),
+ [iptables_location="$withval"])
+AC_ARG_WITH([iptdir],
+ AS_HELP_STRING([--with-iptdir=PATH],
+ [Path to iptables modules [[LIBEXECDIR/iptables]]]),
+ [iptdir="$withval"],
+ [iptdir='${libexecdir}/iptables'])
+
+AC_CHECK_HEADER([netinet/ip6.h], [], [AC_MSG_ERROR(but we need that for IPv6)])
+
+AC_MSG_CHECKING([xtables.h presence])
+if [[ -n "$iptables_location" ]]; then
+ if [[ -f "$iptables_location/xtables.h" ]]; then
+ AC_MSG_RESULT([$iptables_location/xtables.h])
+ iptables_CFLAGS="-I$iptables_location";
+ elif [[ -f "$iptables_location/include/xtables.h" ]]; then
+ AC_MSG_RESULT([$iptables_location/include/xtables.h])
+ iptables_CFLAGS="-I$iptables_location/include";
+ fi;
+fi;
+if [[ -z "$iptables_CFLAGS" ]]; then
+ if [[ -f "$includedir/xtables.h" ]]; then
+ AC_MSG_RESULT([$includedir/xtables.h])
+ else
+ AC_MSG_RESULT([no])
+ fi;
+fi;
+
+regular_CFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \
+ -D_REENTRANT -Wall -Waggregate-return -Wmissing-declarations \
+ -Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
+ -Winline -pipe -DIPTABLES_VERSION=\\\"$PACKAGE_VERSION\\\" \
+ -DIPT_LIB_DIR=\\\"\${iptdir}\\\" -DIP6T_LIB_DIR=\\\"\${iptdir}\\\"";
+kinclude_CFLAGS="-I\"$kbuilddir/include\" -I\"$ksourcedir/include\"";
+
+AC_SUBST([regular_CFLAGS iptables_CFLAGS kinclude_CFLAGS])
+AC_SUBST([kbuilddir])
+AC_SUBST([ksourcedir])
+AC_SUBST([iptdir])
+AC_OUTPUT([Makefile extensions/Makefile])
--- /dev/null
+# -*- Makefile -*-
+
+obj-m += xt_TARPIT.o
+obj-m += xt_TEE.o
--- /dev/null
+# -*- Makefile -*-
+
+AUTOMAKE_OPTIONS = foreign subdir-objects
+abssrcdir = $(shell readlink -f ${srcdir})
+
+regular_CFLAGS := @regular_CFLAGS@
+iptables_CFLAGS := @iptables_CFLAGS@
+kinclude_CFLAGS := @kinclude_CFLAGS@
+AM_CFLAGS = ${regular_CFLAGS} ${iptables_CFLAGS} ${kinclude_CFLAGS} \
+ -D_INIT=$*_init
+AM_LDFLAGS = -module -avoid-version
+ipt_LTLIBRARIES = \
+ libxt_TARPIT.la \
+ libxt_TEE.la
+
+#
+# Call out to kbuild
+#
+.PHONY: modules modules_install clean_modules
+
+all-local: modules
+
+install-exec-local: modules_install
+
+clean-local: clean_modules
+
+modules:
+ make -C ${kbuilddir} M=${abssrcdir} modules;
+
+modules_install:
+ make -C ${kbuilddir} M=${abssrcdir} INSTALL_MOD_PATH=${DESTDIR} modules_install;
+
+clean_modules:
+ make -C ${kbuilddir} M=${abssrcdir} clean;
--- /dev/null
+#include <stdio.h>
+#include <getopt.h>
+#include <xtables.h>
+
+static void tarpit_tg_help(void)
+{
+ printf("TARPIT takes no options\n\n");
+}
+
+static int tarpit_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ return 0;
+}
+
+static void tarpit_tg_check(unsigned int flags)
+{
+}
+
+static struct xtables_target tarpit_tg_reg = {
+ .version = IPTABLES_VERSION,
+ .name = "TARPIT",
+ .family = AF_INET,
+ .size = XT_ALIGN(0),
+ .userspacesize = XT_ALIGN(0),
+ .help = tarpit_tg_help,
+ .parse = tarpit_tg_parse,
+ .final_check = tarpit_tg_check,
+};
+
+static void _init(void)
+{
+ xtables_register_target(&tarpit_tg_reg);
+}
--- /dev/null
++Captures and holds incoming TCP connections using no local per-connection
++resources. Connections are accepted, but immediately switched to the persist
++state (0 byte window), in which the remote side stops sending data and asks to
++continue every 60-240 seconds. Attempts to close the connection are ignored,
++forcing the remote side to time out the connection in 12-24 minutes.
++
++This offers similar functionality to LaBrea
++<http://www.hackbusters.net/LaBrea/> but does not require dedicated hardware or
++IPs. Any TCP port that you would normally DROP or REJECT can instead become a
++tarpit.
++
++To tarpit connections to TCP port 80 destined for the current machine:
++.IP
++-A INPUT -p tcp -m tcp --dport 80 -j TARPIT
++.P
++To significantly slow down Code Red/Nimda-style scans of unused address space,
++forward unused ip addresses to a Linux box not acting as a router (e.g. "ip
++route 10.0.0.0 255.0.0.0 ip.of.linux.box" on a Cisco), enable IP forwarding on
++the Linux box, and add:
++.IP
++-A FORWARD -p tcp -j TARPIT
++.IP
++-A FORWARD -j DROP
++.TP
++NOTE:
++If you use the conntrack module while you are using TARPIT, you should also use
++the NOTRACK target, or the kernel will unnecessarily allocate resources for
++each TARPITted connection. To TARPIT incoming connections to the standard IRC
++port while using conntrack, you could:
++.IP
++-t raw -A PREROUTING -p tcp --dport 6667 -j NOTRACK
++.IP
++-A INPUT -p tcp --dport 6667 -j TARPIT
--- /dev/null
+/*
+ * libxt_TEE
+ *
+ * Copyright © Sebastian Claßen <sebastian.classen@freenet.ag>, 2007
+ * Copyright © CC Computer Consultants GmbH, 2007 - 2008
+ * Jan Engelhardt <jengelh@computergmbh.de>
+ */
+#include <sys/socket.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <xtables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/x_tables.h>
+#include "xt_TEE.h"
+
+enum {
+ FLAG_GATEWAY = 1 << 0,
+};
+
+static const struct option tee_tg_opts[] = {
+ {.name = "gateway", .has_arg = true, .val = 'g'},
+ {},
+};
+
+static void tee_tg_help(void)
+{
+ printf(
+"TEE target options:\n"
+" --gateway IPADDR Route packet via the gateway given by address\n"
+"\n");
+}
+
+static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+ const void *entry, struct xt_entry_target **target)
+{
+ struct xt_tee_tginfo *info = (void *)(*target)->data;
+ const struct in_addr *ia;
+
+ switch (c) {
+ case 'g':
+ if (*flags & FLAG_GATEWAY)
+ exit_error(PARAMETER_PROBLEM,
+ "Cannot specify --gw more than once");
+
+ if (check_inverse(optarg, &invert, NULL, 0))
+ exit_error(PARAMETER_PROBLEM,
+ "Unexpected \"!\" after --gateway");
+
+ ia = numeric_to_ipaddr(optarg);
+ if (ia == NULL)
+ exit_error(PARAMETER_PROBLEM,
+ "Invalid IP address %s", optarg);
+
+ memcpy(&info->gw, &ia, sizeof(ia));
+ *flags |= FLAG_GATEWAY;
+ return true;
+ }
+
+ return false;
+}
+
+static void tee_tg_check(unsigned int flags)
+{
+ if (flags == 0)
+ exit_error(PARAMETER_PROBLEM, "TEE target: "
+ "--gateway parameter required");
+}
+
+static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
+ int numeric)
+{
+ const struct xt_tee_tginfo *info = (const void *)target->data;
+
+ if (numeric)
+ printf("TEE gw:%s ", ipaddr_to_anyname(&info->gw.in));
+ else
+ printf("TEE gw:%s ", ipaddr_to_numeric(&info->gw.in));
+}
+
+static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+ const struct xt_tee_tginfo *info = (const void *)target->data;
+
+ printf("--gateway %s ", ipaddr_to_numeric(&info->gw.in));
+}
+
+static struct xtables_target tee_tg_reg = {
+ .name = "TEE",
+ .version = IPTABLES_VERSION,
+ .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
+ .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
+ .help = tee_tg_help,
+ .parse = tee_tg_parse,
+ .final_check = tee_tg_check,
+ .print = tee_tg_print,
+ .save = tee_tg_save,
+ .extra_opts = tee_tg_opts,
+};
+
+static void _init(void)
+{
+ xtables_register_target(&tee_tg_reg);
+}
--- /dev/null
+config NETFILTER_XT_TARGET_TARPIT
+ tristate '"TARPIT" target support'
+ depends on NETFILTER_XTABLES
+ ---help---
+ Adds a TARPIT target to iptables, which captures and holds incoming TCP
+ connections using no local per-connection resources. Connections are
+ accepted, but immediately switched to the persist state (0 byte
+ window), in which the remote side stops sending data and asks to
+ continue every 60-240 seconds. Attempts to close the connection are
+ ignored, forcing the remote side to time out the connection in 12-24
+ minutes.
+
+ This offers similar functionality to LaBrea
+ <http://www.hackbusters.net/LaBrea/>, but does not require dedicated
+ hardware or IPs. Any TCP port that you would normally DROP or REJECT
+ can instead become a tar pit.
--- /dev/null
+/*
+ * Kernel module to capture and hold incoming TCP connections using
+ * no local per-connection resources.
+ *
+ * Based on ipt_REJECT.c and offering functionality similar to
+ * LaBrea <http://www.hackbusters.net/LaBrea/>.
+ *
+ * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Goal:
+ * - Allow incoming TCP connections to be established.
+ * - Passing data should result in the connection being switched to the
+ * persist state (0 byte window), in which the remote side stops sending
+ * data and asks to continue every 60 seconds.
+ * - Attempts to shut down the connection should be ignored completely, so
+ * the remote side ends up having to time it out.
+ *
+ * This means:
+ * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
+ * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
+ * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
+ */
+
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter/x_tables.h>
+#ifdef CONFIG_BRIDGE_NETFILTER
+# include <linux/netfilter_bridge.h>
+#endif
+#include <net/route.h>
+#include <net/tcp.h>
+
+static inline void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
+{
+ struct tcphdr _otcph, *oth, *tcph;
+ unsigned int addr_type;
+ struct sk_buff *nskb;
+ struct iphdr *niph;
+ u_int16_t tmp;
+
+ /* A truncated TCP header is not going to be useful */
+ if (oldskb->len < ip_hdrlen(oldskb) + sizeof(struct tcphdr))
+ return;
+
+ oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
+ sizeof(_otcph), &_otcph);
+ if (oth == NULL)
+ return;
+
+ /* No replies for RST, FIN or !SYN,!ACK */
+ if (oth->rst || oth->fin || (!oth->syn && !oth->ack))
+ return;
+
+ /* Rate-limit replies to !SYN,ACKs */
+#if 0
+ if (!oth->syn && oth->ack)
+ if (!xrlim_allow(&ort->u.dst, HZ))
+ return;
+#endif
+
+ /* Check checksum. */
+ if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
+ return;
+
+ /*
+ * Copy skb (even if skb is about to be dropped, we cannot just
+ * clone it because there may be other things, such as tcpdump,
+ * interested in it)
+ */
+ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER,
+ skb_tailroom(oldskb), GFP_ATOMIC);
+ if (nskb == NULL)
+ return;
+
+ /* This packet will not be the same as the other: clear nf fields */
+ nf_reset(nskb);
+ nskb->mark = 0;
+ skb_init_secmark(nskb);
+
+ skb_shinfo(nskb)->gso_size = 0;
+ skb_shinfo(nskb)->gso_segs = 0;
+ skb_shinfo(nskb)->gso_type = 0;
+
+ tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
+
+ /* Swap source and dest */
+ niph = ip_hdr(nskb);
+ niph->daddr = xchg(&niph->saddr, niph->daddr);
+ tmp = tcph->source;
+ tcph->source = tcph->dest;
+ tcph->dest = tmp;
+
+ /* Truncate to length (no data) */
+ tcph->doff = sizeof(struct tcphdr) / 4;
+ skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
+ niph->tot_len = htons(nskb->len);
+
+ /* Use supplied sequence number or make a new one */
+ tcph->seq = oth->ack ? oth->ack_seq : 0;
+
+ /* Our SYN-ACKs must have a >0 window */
+ tcph->window = (oth->syn && !oth->ack) ? htons(5) : 0;
+ tcph->urg_ptr = 0;
+
+ /* Reset flags */
+ ((u_int8_t *)tcph)[13] = 0;
+
+ if (oth->syn && oth->ack) {
+ tcph->rst = true;
+ tcph->ack_seq = false;
+ } else {
+ tcph->syn = oth->syn;
+ tcph->ack = 1;
+ tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
+ }
+
+ /* Adjust TCP checksum */
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
+ niph->daddr, csum_partial((char *)tcph,
+ sizeof(struct tcphdr), 0));
+
+ /* Set DF, id = 0 */
+ niph->frag_off = htons(IP_DF);
+ niph->id = 0;
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
+ nskb->nf_bridge->mask & BRNF_BRIDGED))
+#else
+ if (hook != NF_INET_FORWARD)
+#endif
+ addr_type = RTN_LOCAL;
+
+ if (ip_route_me_harder(nskb, addr_type))
+ goto free_nskb;
+
+ nskb->ip_summed = CHECKSUM_NONE;
+
+ /* Adjust IP TTL */
+ niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+
+ /* Adjust IP checksum */
+ niph->check = 0;
+ niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
+
+ /* "Never happens" */
+ if (nskb->len > dst_mtu(nskb->dst))
+ goto free_nskb;
+
+ nf_ct_attach(nskb, oldskb);
+
+ NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+ dst_output);
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
+}
+
+static unsigned int
+tarpit_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 iphdr *iph = ip_hdr(skb);
+ const struct rtable *rt = (const void *)skb->dst;
+
+ /* Do we have an input route cache entry? (Not in PREROUTING.) */
+ if (rt == NULL)
+ return NF_DROP;
+
+ /* No replies to physical multicast/broadcast */
+ /* skb != PACKET_OTHERHOST handled by ip_rcv() */
+ if (skb->pkt_type != PACKET_HOST)
+ return NF_DROP;
+
+ /* Now check at the protocol level */
+ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+ return NF_DROP;
+
+ /*
+ * Our naive response construction does not deal with IP
+ * options, and probably should not try.
+ */
+ if (ip_hdrlen(skb) != sizeof(struct iphdr))
+ return NF_DROP;
+
+ /* We are not interested in fragments */
+ if (iph->frag_off & htons(IP_OFFSET))
+ return NF_DROP;
+
+ tarpit_tcp(skb, hooknum);
+ return NF_DROP;
+}
+
+static struct xt_target tarpit_tg_reg __read_mostly = {
+ .name = "TARPIT",
+ .family = AF_INET,
+ .table = "filter",
+ .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
+ .proto = IPPROTO_TCP,
+ .target = tarpit_tg,
+ .me = THIS_MODULE,
+};
+
+static int __init tarpit_tg_init(void)
+{
+ return xt_register_target(&tarpit_tg_reg);
+}
+
+static void __exit tarpit_tg_exit(void)
+{
+ xt_unregister_target(&tarpit_tg_reg);
+}
+
+module_init(tarpit_tg_init);
+module_exit(tarpit_tg_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("Xtables: \"TARPIT\", capture and hold TCP connections");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_TARPIT");
--- /dev/null
+config NETFILTER_XT_TARGET_TEE
+ tristate '"TEE" target support'
+ depends on NETFILTER_XTABLES
+ depends on NETFILTER_ADVANCED
+ depends on IP_NF_MANGLE || IP6_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.
--- /dev/null
+/*
+ * This implements the TEE target.
+ *
+ * Copyright (C) 2007 Sebastian Claßen <sebastian.classen@freenet.de> and
+ * CC Computer Consultants GmbH, 2007
+ *
+ * based on ipt_ROUTE.c from Cédric de Launois <delaunois@info.ucl.ac.be>
+ *
+ * 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>
+#ifdef CONFIG_NETFILTER_XT_TARGET_TEE
+# include <linux/netfilter/xt_TEE.h>
+#else
+# include "xt_TEE.h"
+#endif
+
+#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
+
+static const union nf_inet_addr zero_address;
+
+/*
+ * 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_tginfo *info)
+{
+ int err;
+ struct rtable *rt;
+ struct iphdr *iph = ip_hdr(skb);
+ struct flowi fl = {
+ .nl_u = {
+ .ip4_u = {
+ .daddr = info->gw.ip,
+ .tos = RT_TOS(iph->tos),
+ .scope = RT_SCOPE_UNIVERSE,
+ }
+ }
+ };
+
+ /* 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_tginfo *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 (tee_routing(skb, info))
+ tee_ip_direct_send(skb);
+
+ return XT_CONTINUE;
+}
+
+static bool tee_tg_check(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+ unsigned int hook_mask)
+{
+ const struct xt_tee_tginfo *info = targinfo;
+
+ /* 0.0.0.0 and :: not allowed */
+ return memcmp(&info->gw, &zero_address, sizeof(zero_address)) != 0;
+}
+
+static struct xt_target tee_tg_reg __read_mostly = {
+ .name = "TEE",
+ .family = AF_INET,
+ .table = "mangle",
+ .target = tee_tg,
+ .targetsize = sizeof(struct xt_tee_tginfo),
+ .checkentry = tee_tg_check,
+ .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 Claßen <sebastian.classen@freenet.ag>");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("Xtables: Reroute packet copy");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_TEE");
--- /dev/null
+#ifndef _XT_TEE_TARGET_H
+#define _XT_TEE_TARGET_H
+
+struct xt_tee_tginfo {
+ union nf_inet_addr gw;
+};
+
+#endif /* _XT_TEE_TARGET_H */