]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
Initial commit.
authorJan Engelhardt <jengelh@computergmbh.de>
Tue, 29 Jan 2008 02:57:08 +0000 (03:57 +0100)
committerJan Engelhardt <jengelh@computergmbh.de>
Tue, 29 Jan 2008 02:57:08 +0000 (03:57 +0100)
Populate the iptables-addons repository with two modules, xt_TARPIT
and xt_TEE, as a starting point.

Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
16 files changed:
.gitignore [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
extensions/Kbuild [new file with mode: 0644]
extensions/Makefile.am [new file with mode: 0644]
extensions/libxt_TARPIT.c [new file with mode: 0644]
extensions/libxt_TARPIT.man [new file with mode: 0644]
extensions/libxt_TEE.c [new file with mode: 0644]
extensions/xt_TARPIT.Kconfig [new file with mode: 0644]
extensions/xt_TARPIT.c [new file with mode: 0644]
extensions/xt_TEE.Kconfig [new file with mode: 0644]
extensions/xt_TEE.c [new file with mode: 0644]
extensions/xt_TEE.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..9d09822
--- /dev/null
@@ -0,0 +1,25 @@
+.*.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
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..0102b49
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,58 @@
+
+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.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..ad77607
--- /dev/null
@@ -0,0 +1,4 @@
+# -*- Makefile -*-
+
+AUTOMAKE_OPTIONS = foreign subdir-objects
+SUBDIRS          = extensions
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..1c73d36
--- /dev/null
+++ b/README
@@ -0,0 +1,7 @@
+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.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..62a89e1
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+autoreconf -fi;
+rm -Rf autom4te*.cache;
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..eea6810
--- /dev/null
@@ -0,0 +1,62 @@
+
+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])
diff --git a/extensions/Kbuild b/extensions/Kbuild
new file mode 100644 (file)
index 0000000..96aca1a
--- /dev/null
@@ -0,0 +1,4 @@
+# -*- Makefile -*-
+
+obj-m += xt_TARPIT.o
+obj-m += xt_TEE.o
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
new file mode 100644 (file)
index 0000000..92403d1
--- /dev/null
@@ -0,0 +1,34 @@
+# -*- 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;
diff --git a/extensions/libxt_TARPIT.c b/extensions/libxt_TARPIT.c
new file mode 100644 (file)
index 0000000..5946aa6
--- /dev/null
@@ -0,0 +1,34 @@
+#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);
+}
diff --git a/extensions/libxt_TARPIT.man b/extensions/libxt_TARPIT.man
new file mode 100644 (file)
index 0000000..77b6c6e
--- /dev/null
@@ -0,0 +1,33 @@
++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
diff --git a/extensions/libxt_TEE.c b/extensions/libxt_TEE.c
new file mode 100644 (file)
index 0000000..e4373dd
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ *     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);
+}
diff --git a/extensions/xt_TARPIT.Kconfig b/extensions/xt_TARPIT.Kconfig
new file mode 100644 (file)
index 0000000..69ae7a2
--- /dev/null
@@ -0,0 +1,16 @@
+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.
diff --git a/extensions/xt_TARPIT.c b/extensions/xt_TARPIT.c
new file mode 100644 (file)
index 0000000..3338176
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * 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");
diff --git a/extensions/xt_TEE.Kconfig b/extensions/xt_TEE.Kconfig
new file mode 100644 (file)
index 0000000..894c019
--- /dev/null
@@ -0,0 +1,9 @@
+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.
diff --git a/extensions/xt_TEE.c b/extensions/xt_TEE.c
new file mode 100644 (file)
index 0000000..265d82f
--- /dev/null
@@ -0,0 +1,248 @@
+/*
+ * 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");
diff --git a/extensions/xt_TEE.h b/extensions/xt_TEE.h
new file mode 100644 (file)
index 0000000..83fa768
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _XT_TEE_TARGET_H
+#define _XT_TEE_TARGET_H
+
+struct xt_tee_tginfo {
+       union nf_inet_addr gw;
+};
+
+#endif /* _XT_TEE_TARGET_H */