]> git.ipfire.org Git - thirdparty/xtables-addons.git/commitdiff
Import Chaostables extensions
authorJan Engelhardt <jengelh@computergmbh.de>
Thu, 21 Feb 2008 13:29:36 +0000 (14:29 +0100)
committerJan Engelhardt <jengelh@computergmbh.de>
Thu, 21 Feb 2008 17:56:21 +0000 (18:56 +0100)
Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
16 files changed:
extensions/Kbuild
extensions/compat_xtables.c
extensions/compat_xtables.h
extensions/compat_xtnu.h
extensions/libxt_CHAOS.c [new file with mode: 0644]
extensions/libxt_CHAOS.man [new file with mode: 0644]
extensions/libxt_DELUDE.c [new file with mode: 0644]
extensions/libxt_DELUDE.man [new file with mode: 0644]
extensions/libxt_portscan.c [new file with mode: 0644]
extensions/libxt_portscan.man [new file with mode: 0644]
extensions/xt_CHAOS.c [new file with mode: 0644]
extensions/xt_CHAOS.h [new file with mode: 0644]
extensions/xt_DELUDE.c [new file with mode: 0644]
extensions/xt_portscan.c [new file with mode: 0644]
extensions/xt_portscan.h [new file with mode: 0644]
mconfig

index 0c2867395cc46835691978542c640a6dd156f72e..7155e3eaaf217da3770b9a6e2f939c41b651befc 100644 (file)
@@ -5,8 +5,11 @@ include ${XA_TOPSRCDIR}/mconfig
 
 obj-m                += compat_xtables.o
 
+obj-${build_CHAOS}   += xt_CHAOS.o
+obj-${build_DELUDE}  += xt_DELUDE.o
 obj-${build_LOGMARK} += xt_LOGMARK.o
 obj-${build_TARPIT}  += xt_TARPIT.o
 obj-${build_TEE}     += xt_TEE.o
+obj-${build_portscan} += xt_portscan.o
 
 -include ${M}/*.Kbuild
index 35dad77ccf97536bac1303b8ff19901c8821fdf9..2e3cd60195cce4941fe2d1fb2901e8eb49c145e0 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/version.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/netfilter/x_tables.h>
+#include <linux/netfilter_arp.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include "compat_xtnu.h"
@@ -228,6 +229,25 @@ void xtnu_unregister_targets(struct xtnu_target *nt, unsigned int num)
 EXPORT_SYMBOL_GPL(xtnu_unregister_targets);
 #endif
 
+struct xt_match *xtnu_request_find_match(unsigned int af, const char *name,
+    uint8_t revision)
+{
+       static const char *const xt_prefix[] = {
+               [AF_INET]  = "ip",
+               [AF_INET6] = "ip6",
+               [NF_ARP]   = "arp",
+       };
+       struct xt_match *match;
+
+       match = try_then_request_module(xt_find_match(af, name, revision),
+               "%st_%s", xt_prefix[af], name);
+       if (IS_ERR(match) || match == NULL)
+               return NULL;
+
+       return match;
+}
+EXPORT_SYMBOL_GPL(xtnu_request_find_match);
+
 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
 int xtnu_ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
 {
index 666408bf7cf2b024038382459173a374f6b50bcf..184e495b078c5f03b003c6f966ae68000484bc4c 100644 (file)
 #      define NF_INET_FORWARD      NF_IP_FORWARD
 #      define NF_INET_LOCAL_OUT    NF_IP_LOCAL_OUT
 #      define NF_INET_POST_ROUTING NF_IP_POST_ROUTING
-#      define init_net             xtnu_ip_route_output_key /* yes */
+#      define ip_local_out         xtnu_ip_local_out
 #      define ip_route_output_key  xtnu_ip_route_output_key
 #      include "compat_nfinetaddr.h"
 #endif
 
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+#      define init_net               xtnu_ip_route_output_key /* yes */
+#      define init_net__loopback_dev (&loopback_dev)
+#else
+#      define init_net__loopback_dev init_net.loopback_dev
+#endif
+
 #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)
 #      define xt_match              xtnu_match
 #      define xt_register_match     xtnu_register_match
@@ -35,6 +42,7 @@
 #      define xt_unregister_targets xtnu_unregister_targets
 #endif
 
+#define xt_request_find_match xtnu_request_find_match
 #include "compat_xtnu.h"
 
 #endif /* _XTABLES_COMPAT_H */
index 62d5c651369e334a138c23516d8345bd028fbbd9..77018e7afcc92518b1e1e9cc295c0449a80a761f 100644 (file)
@@ -61,6 +61,7 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
        return q;
 }
 
+extern int xtnu_ip_local_out(struct sk_buff *);
 extern int xtnu_ip_route_me_harder(struct sk_buff *, unsigned int);
 extern int xtnu_register_match(struct xtnu_match *);
 extern int xtnu_ip_route_output_key(void *, struct rtable **, struct flowi *);
@@ -71,5 +72,7 @@ extern int xtnu_register_target(struct xtnu_target *);
 extern void xtnu_unregister_target(struct xtnu_target *);
 extern int xtnu_register_targets(struct xtnu_target *, unsigned int);
 extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int);
+extern struct xt_match *xtnu_request_find_match(unsigned int,
+       const char *, uint8_t);
 
 #endif /* _COMPAT_XTNU_H */
diff --git a/extensions/libxt_CHAOS.c b/extensions/libxt_CHAOS.c
new file mode 100644 (file)
index 0000000..66edd3d
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *     CHAOS target for Xtables
+ *     Copyright © CC Computer Consultants GmbH, 2006 - 2008
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License; either version
+ *     2 or 3 as published by the Free Software Foundation.
+ */
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include "xt_CHAOS.h"
+
+enum {
+       F_DELUDE = 1 << 0,
+       F_TARPIT = 1 << 1,
+};
+
+static const struct option chaos_tg_opts[] = {
+       {.name = "delude", .has_arg = false, .val = 'd'},
+       {.name = "tarpit", .has_arg = false, .val = 't'},
+       {},
+};
+
+static void chaos_tg_help(void)
+{
+       printf(
+               "CHAOS target options:\n"
+               "  --delude    Enable DELUDE processing for TCP\n"
+               "  --tarpit    Enable TARPIT processing for TCP\n");
+}
+
+static int chaos_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+    const void *entry, struct xt_entry_target **target)
+{
+       struct xt_chaos_tginfo *info = (void *)((*target)->data);
+
+       switch (c) {
+       case 'd':
+               info->variant = XTCHAOS_DELUDE;
+               *flags |= F_DELUDE;
+               return true;
+       case 't':
+               info->variant = XTCHAOS_TARPIT;
+               *flags |= F_TARPIT;
+               return true;
+       }
+       return false;
+}
+
+static void chaos_tg_check(unsigned int flags)
+{
+       if (flags == (F_DELUDE | F_TARPIT))
+               /* If flags == 0x03, both were specified, which should not be. */
+               exit_error(PARAMETER_PROBLEM,
+                          "CHAOS: only one of --tarpit or --delude "
+                          "may be specified");
+}
+
+static void chaos_tg_print(const void *ip,
+    const struct xt_entry_target *target, int numeric)
+{
+       const struct xt_chaos_tginfo *info = (const void *)target->data;
+
+       switch (info->variant) {
+       case XTCHAOS_DELUDE:
+               printf("DELUDE ");
+               break;
+       case XTCHAOS_TARPIT:
+               printf("TARPIT ");
+               break;
+       }
+       return;
+}
+
+static void chaos_tg_save(const void *ip, const struct xt_entry_target *target)
+{
+       const struct xt_chaos_tginfo *info = (const void *)target->data;
+
+       switch (info->variant) {
+       case XTCHAOS_DELUDE:
+               printf("--delude ");
+               break;
+       case XTCHAOS_TARPIT:
+               printf("--tarpit ");
+               break;
+       }
+       return;
+}
+
+static struct xtables_target chaos_tg_reg = {
+       .version       = IPTABLES_VERSION,
+       .name          = "CHAOS",
+       .family        = AF_INET,
+       .size          = XT_ALIGN(sizeof(struct xt_chaos_tginfo)),
+       .userspacesize = XT_ALIGN(sizeof(struct xt_chaos_tginfo)),
+       .help          = chaos_tg_help,
+       .parse         = chaos_tg_parse,
+       .final_check   = chaos_tg_check,
+       .print         = chaos_tg_print,
+       .save          = chaos_tg_save,
+       .extra_opts    = chaos_tg_opts,
+};
+
+void _init(void);
+void _init(void)
+{
+       xtables_register_target(&chaos_tg_reg);
+}
diff --git a/extensions/libxt_CHAOS.man b/extensions/libxt_CHAOS.man
new file mode 100644 (file)
index 0000000..8e24482
--- /dev/null
@@ -0,0 +1,18 @@
++Causes confusion on the other end by doing odd things with incoming packets.
++CHAOS will randomly reply (or not) with one of its configurable subtargets:
++.TP
++\fB--delude\fR
++Use the REJECT and DELUDE targets as a base to do a sudden or deferred
++connection reset, fooling some network scanners to return non-deterministic
++(randomly open/closed) results, and in case it is deemed open, it is actually
++closed/filtered.
++.TP
++\fB--tarpit\fR
++Use the REJECT and TARPIT target as a base to hold the connection until it
++times out. This consumes conntrack entries when connection tracking is loaded
++(which usually is on most machines), and routers inbetween you and the Internet
++may fail to do their connection tracking if they have to handle more
++connections than they can.
++.PP
++The randomness factor of not replying vs. replying can be set during load-time
++of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters.
diff --git a/extensions/libxt_DELUDE.c b/extensions/libxt_DELUDE.c
new file mode 100644 (file)
index 0000000..e31d001
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *     DELUDE target for Xtables
+ *     Copyright © CC Computer Consultants GmbH, 2006 - 2008
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License; either version
+ *     2 or 3 as published by the Free Software Foundation.
+ */
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+
+static void delude_tg_help(void)
+{
+       printf("DELUDE takes no options\n");
+}
+
+static int delude_tg_parse(int c, char **argv, int invert, unsigned int *flags,
+    const void *entry, struct xt_entry_target **target)
+{
+       return 0;
+}
+
+static void delude_tg_check(unsigned int flags)
+{
+}
+
+static struct xtables_target delude_tg_reg = {
+       .version       = IPTABLES_VERSION,
+       .name          = "DELUDE",
+       .revision      = 0,
+       .family        = AF_INET,
+       .size          = XT_ALIGN(0),
+       .userspacesize = XT_ALIGN(0),
+       .help          = delude_tg_help,
+       .parse         = delude_tg_parse,
+       .final_check   = delude_tg_check,
+};
+
+void _init(void);
+void _init(void)
+{
+       xtables_register_target(&delude_tg_reg);
+}
diff --git a/extensions/libxt_DELUDE.man b/extensions/libxt_DELUDE.man
new file mode 100644 (file)
index 0000000..09c7832
--- /dev/null
@@ -0,0 +1,4 @@
+The DELUDE target will reply to a SYN packet with SYN-ACK, and to all other
+packets with an RST. This will terminate the connection much like REJECT, but
+network scanners doing TCP half-open discovery can be spoofed to make them
+belive the port is open rather than closed/filtered.
diff --git a/extensions/libxt_portscan.c b/extensions/libxt_portscan.c
new file mode 100644 (file)
index 0000000..8cea3b6
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ *     portscan target for Xtables
+ *     Copyright © CC Computer Consultants GmbH, 2006 - 2008
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License; either version
+ *     2 or 3 as published by the Free Software Foundation.
+ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <xtables.h>
+#include <linux/netfilter/x_tables.h>
+#include "xt_portscan.h"
+
+static const struct option portscan_mt_opts[] = {
+       {.name = "stealth", .has_arg = false, .val = 'x'},
+       {.name = "synscan", .has_arg = false, .val = 's'},
+       {.name = "cnscan",  .has_arg = false, .val = 'c'},
+       {.name = "grscan",  .has_arg = false, .val = 'g'},
+       {},
+};
+
+static void portscan_mt_help(void)
+{
+       printf(
+               "portscan match options:\n"
+               "(Combining them will make them match by OR-logic)\n"
+               "  --stealth    Match TCP Stealth packets\n"
+               "  --synscan    Match TCP SYN scans\n"
+               "  --cnscan     Match TCP Connect scans\n"
+               "  --grscan     Match Banner Grabbing scans\n");
+}
+
+static int portscan_mt_parse(int c, char **argv, int invert,
+    unsigned int *flags, const void *entry, struct xt_entry_match **match)
+{
+       struct xt_portscan_mtinfo *info = (void *)((*match)->data);
+
+       switch (c) {
+       case 'c':
+               info->match_cn = true;
+               return true;
+       case 'g':
+               info->match_gr = true;
+               return true;
+       case 's':
+               info->match_syn = true;
+               return true;
+       case 'x':
+               info->match_stealth = true;
+               return true;
+       }
+       return false;
+}
+
+static void portscan_mt_check(unsigned int flags)
+{
+}
+
+static void portscan_mt_print(const void *ip,
+    const struct xt_entry_match *match, int numeric)
+{
+       const struct xt_portscan_mtinfo *info = (const void *)(match->data);
+       const char *s = "";
+
+       printf("portscan ");
+       if (info->match_stealth) {
+               printf("STEALTH");
+               s = ",";
+       }
+       if (info->match_syn) {
+               printf("%sSYNSCAN", s);
+               s = ",";
+       }
+       if (info->match_cn) {
+               printf("%sCNSCAN", s);
+               s = ",";
+       }
+       if (info->match_gr)
+               printf("%sGRSCAN", s);
+       printf(" ");
+}
+
+static void portscan_mt_save(const void *ip, const struct xt_entry_match *match)
+{
+       const struct xt_portscan_mtinfo *info = (const void *)(match->data);
+
+       if (info->match_stealth)
+               printf("--stealth ");
+       if (info->match_syn)
+               printf("--synscan ");
+       if (info->match_cn)
+               printf("--cnscan ");
+       if (info->match_gr)
+               printf("--grscan ");
+}
+
+static struct xtables_match portscan_mt_reg = {
+       .version       = IPTABLES_VERSION,
+       .name          = "portscan",
+       .revision      = 0,
+       .family        = AF_INET,
+       .size          = XT_ALIGN(sizeof(struct xt_portscan_mtinfo)),
+       .userspacesize = XT_ALIGN(sizeof(struct xt_portscan_mtinfo)),
+       .help          = portscan_mt_help,
+       .parse         = portscan_mt_parse,
+       .final_check   = portscan_mt_check,
+       .print         = portscan_mt_print,
+       .save          = portscan_mt_save,
+       .extra_opts    = portscan_mt_opts,
+};
+
+void _init(void);
+void _init(void)
+{
+       xtables_register_match(&portscan_mt_reg);
+}
diff --git a/extensions/libxt_portscan.man b/extensions/libxt_portscan.man
new file mode 100644 (file)
index 0000000..60a4c1a
--- /dev/null
@@ -0,0 +1,27 @@
+Detects simple port scan attemps based upon the packet's contents. (This is
+different from other implementations, which also try to match the rate of new
+connections.) Note that an attempt is only discovered after it has been carried
+out, but this information can be used in conjunction with other rules to block
+the remote host's future connections. So this match module will match on the
+(probably) last packet the remote side will send to your machine.
+.TP
+\fB--stealth\fR
+Match if the packet did not belong to any known TCP connection
+(Stealth/FIN/XMAS/NULL scan).
+.TP
+\fB--synscan\fR
+Match if the connection was a TCP half-open discovery (SYN scan), i.e. the
+connection was torn down after the 2nd packet in the 3-way handshake.
+.TP
+\fB--cnscan\fR
+Match if the connection was a TCP full open discovery (connect scan), i.e. the
+connection was torn down after completion of the 3-way handshake.
+.TP
+\fB--grscan\fR
+Match if data in the connection only flew in the direction of the remote side,
+e.g. if the connection was terminated after a locally running daemon sent its
+identification. (e.g. openssh)
+.PP
+NOTE: Some clients (Windows XP for example) may do what looks like a SYN scan,
+so be advised to carefully use xt_portscan in conjunction with blocking rules,
+as it may lock out your very own internal network.
diff --git a/extensions/xt_CHAOS.c b/extensions/xt_CHAOS.c
new file mode 100644 (file)
index 0000000..a9ad67b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ *     CHAOS target for netfilter
+ *     Copyright © CC Computer Consultants GmbH, 2006 - 2007
+ *     Contact: Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License; either version
+ *     2 or 3 as published by the Free Software Foundation.
+ */
+#include <linux/icmp.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stat.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter_ipv4/ipt_REJECT.h>
+#include <net/ip.h>
+#include "xt_CHAOS.h"
+static struct xt_match *xm_tcp;
+static struct xt_target *xt_delude, *xt_reject, *xt_tarpit;
+#include "compat_xtables.h"
+#define PFX KBUILD_MODNAME ": "
+
+/* Module parameters */
+static unsigned int reject_percentage = ~0U * .01;
+static unsigned int delude_percentage = ~0U * .0101;
+module_param(reject_percentage, uint, S_IRUGO | S_IWUSR);
+module_param(delude_percentage, uint, S_IRUGO | S_IWUSR);
+
+/* References to other matches/targets */
+
+static int have_delude, have_tarpit;
+
+/* Static data for other matches/targets */
+static const struct ipt_reject_info reject_params = {
+       .with = ICMP_HOST_UNREACH,
+};
+
+static const struct xt_tcp tcp_params = {
+       .spts = {0, ~0},
+       .dpts = {0, ~0},
+};
+
+/* CHAOS functions */
+static void xt_chaos_total(const struct xt_chaos_tginfo *info,
+    struct sk_buff *skb, const struct net_device *in,
+    const struct net_device *out, unsigned int hooknum)
+{
+       const struct iphdr *iph = ip_hdr(skb);
+       const int protoff       = 4 * iph->ihl;
+       const int offset        = ntohs(iph->frag_off) & IP_OFFSET;
+       typeof(xt_tarpit) destiny;
+       bool ret;
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)
+       int hotdrop = false;
+#else
+       bool hotdrop = false;
+#endif
+
+       ret = xm_tcp->match(skb, in, out, xm_tcp, &tcp_params,
+                           offset, protoff, &hotdrop);
+       if (!ret || hotdrop || (unsigned int)net_random() > delude_percentage)
+               return;
+
+       destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude;
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+       destiny->target(&skb, in, out, hooknum, destiny, NULL);
+#else
+       destiny->target(skb, in, out, hooknum, destiny, NULL);
+#endif
+       return;
+}
+
+static unsigned int chaos_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)
+{
+       /*
+        * Equivalent to:
+        * -A chaos -m statistic --mode random --probability \
+        *         $reject_percentage -j REJECT --reject-with host-unreach;
+        * -A chaos -p tcp -m statistic --mode random --probability \
+        *         $delude_percentage -j DELUDE;
+        * -A chaos -j DROP;
+        */
+       const struct xt_chaos_tginfo *info = targinfo;
+       const struct iphdr *iph = ip_hdr(skb);
+
+       if ((unsigned int)net_random() <= reject_percentage)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
+               return xt_reject->target(&skb, in, out, hooknum,
+                      target->__compat_target, &reject_params);
+#else
+               return xt_reject->target(skb, in, out, hooknum, target,
+                      &reject_params);
+#endif
+
+       /* TARPIT/DELUDE may not be called from the OUTPUT chain */
+       if (iph->protocol == IPPROTO_TCP &&
+           info->variant != XTCHAOS_NORMAL && hooknum != NF_INET_LOCAL_OUT)
+               xt_chaos_total(info, skb, in, out, hooknum);
+
+       return NF_DROP;
+}
+
+static bool chaos_tg_check(const char *tablename, const void *entry,
+    const struct xt_target *target, void *targinfo, unsigned int hook_mask)
+{
+       const struct xt_chaos_tginfo *info = targinfo;
+
+       if (info->variant == XTCHAOS_DELUDE && !have_delude) {
+               printk(KERN_WARNING PFX "Error: Cannot use --delude when "
+                      "DELUDE module not available\n");
+               return false;
+       }
+       if (info->variant == XTCHAOS_TARPIT && !have_tarpit) {
+               printk(KERN_WARNING PFX "Error: Cannot use --tarpit when "
+                      "TARPIT module not available\n");
+               return false;
+       }
+
+       return true;
+}
+
+static struct xt_target chaos_tg_reg = {
+       .name       = "CHAOS",
+       .family     = AF_INET,
+       .table      = "filter",
+       .hooks      = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD) |
+                     (1 << NF_INET_LOCAL_OUT),
+       .target     = chaos_tg,
+       .checkentry = chaos_tg_check,
+       .targetsize = sizeof(struct xt_chaos_tginfo),
+       .me         = THIS_MODULE,
+};
+
+static int __init chaos_tg_init(void)
+{
+       int ret = -EINVAL;
+
+       xm_tcp = xt_request_find_match(AF_INET, "tcp", 0);
+       if (xm_tcp == NULL) {
+               printk(KERN_WARNING PFX "Error: Could not find or load "
+                      "\"tcp\" match\n");
+               return -EINVAL;
+       }
+
+       xt_reject = xt_request_find_target(AF_INET, "REJECT", 0);
+       if (xt_reject == NULL) {
+               printk(KERN_WARNING PFX "Error: Could not find or load "
+                      "\"REJECT\" target\n");
+               goto out2;
+       }
+
+       xt_tarpit   = xt_request_find_target(AF_INET, "TARPIT", 0);
+       have_tarpit = xt_tarpit != NULL;
+       if (!have_tarpit)
+               printk(KERN_WARNING PFX "Warning: Could not find or load "
+                      "\"TARPIT\" target\n");
+
+       xt_delude   = xt_request_find_target(AF_INET, "DELUDE", 0);
+       have_delude = xt_delude != NULL;
+       if (!have_delude)
+               printk(KERN_WARNING PFX "Warning: Could not find or load "
+                      "\"DELUDE\" target\n");
+
+       if ((ret = xt_register_target(&chaos_tg_reg)) != 0) {
+               printk(KERN_WARNING PFX "xt_register_target returned "
+                      "error %d\n", ret);
+               goto out3;
+       }
+
+       return 0;
+
+ out3:
+       if (have_delude)
+               module_put(xt_delude->me);
+       if (have_tarpit)
+               module_put(xt_tarpit->me);
+       module_put(xt_reject->me);
+ out2:
+       module_put(xm_tcp->me);
+       return ret;
+}
+
+static void __exit chaos_tg_exit(void)
+{
+       xt_unregister_target(&chaos_tg_reg);
+       module_put(xm_tcp->me);
+       module_put(xt_reject->me);
+       if (have_delude)
+               module_put(xt_delude->me);
+       if (have_tarpit)
+               module_put(xt_tarpit->me);
+       return;
+}
+
+module_init(chaos_tg_init);
+module_exit(chaos_tg_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("Xtables: Network scan slowdown with non-deterministic results");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_CHAOS");
diff --git a/extensions/xt_CHAOS.h b/extensions/xt_CHAOS.h
new file mode 100644 (file)
index 0000000..d9b74fd
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _LINUX_NETFILTER_XT_CHAOS_H
+#define _LINUX_NETFILTER_XT_CHAOS_H 1
+
+enum xt_chaos_target_variant {
+       XTCHAOS_NORMAL,
+       XTCHAOS_TARPIT,
+       XTCHAOS_DELUDE,
+};
+
+struct xt_chaos_tginfo {
+       uint8_t variant;
+};
+
+#endif /* _LINUX_NETFILTER_XT_CHAOS_H */
diff --git a/extensions/xt_DELUDE.c b/extensions/xt_DELUDE.c
new file mode 100644 (file)
index 0000000..cfa78d3
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ *     DELUDE target
+ *     Copyright © CC Computer Consultants GmbH, 2007 - 2008
+ *
+ *     Based upon linux-2.6.18.5/net/ipv4/netfilter/ipt_REJECT.c:
+ *     (C) 1999-2001 Paul `Rusty' Russell
+ *     (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ *     xt_DELUDE acts like REJECT, but does reply with SYN-ACK on SYN.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 as
+ *     published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/netfilter/x_tables.h>
+#ifdef CONFIG_BRIDGE_NETFILTER
+#      include <linux/netfilter_bridge.h>
+#endif
+#include <net/tcp.h>
+#include "compat_xtables.h"
+#define PFX KBUILD_MODNAME ": "
+
+static void delude_send_reset(struct sk_buff *oldskb, unsigned int hook)
+{
+       struct tcphdr _otcph, *tcph;
+       const struct tcphdr *oth;
+       const struct iphdr *oiph;
+       unsigned int addr_type;
+       struct sk_buff *nskb;
+       struct iphdr *niph;
+
+       oiph = ip_hdr(oldskb);
+
+       /* IP header checks: fragment. */
+       if (oiph->frag_off & htons(IP_OFFSET))
+               return;
+
+       oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
+                                sizeof(_otcph), &_otcph);
+       if (oth == NULL)
+               return;
+
+       /* No RST for RST. */
+       if (oth->rst)
+               return;
+
+       /* Check checksum */
+       if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
+               return;
+
+       nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
+                        LL_MAX_HEADER, GFP_ATOMIC);
+       if (nskb == NULL)
+               return;
+
+       skb_reserve(nskb, LL_MAX_HEADER);
+       skb_reset_network_header(nskb);
+       niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
+       niph->version  = 4;
+       niph->ihl      = sizeof(struct iphdr) / 4;
+       niph->tos      = 0;
+       niph->id       = 0;
+       niph->frag_off = htons(IP_DF);
+       niph->protocol = IPPROTO_TCP;
+       niph->check    = 0;
+       niph->saddr    = oiph->daddr;
+       niph->daddr    = oiph->saddr;
+
+       tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
+       memset(tcph, 0, sizeof(*tcph));
+       tcph->source = oth->dest;
+       tcph->dest   = oth->source;
+       tcph->doff   = sizeof(struct tcphdr) / 4;
+
+       /* DELUDE essential part */
+       if (oth->syn && !oth->ack && !oth->rst && !oth->fin) {
+               tcph->syn     = true;
+               tcph->seq     = 0;
+               tcph->ack     = true;
+               tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
+                               oldskb->len - ip_hdrlen(oldskb) -
+                               (oth->doff << 2));
+       } else {
+               tcph->rst = true;
+               if (!oth->ack) {
+                       tcph->seq     = 0;
+                       tcph->ack     = true;
+                       tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn +
+                                       oth->fin + oldskb->len -
+                                       ip_hdrlen(oldskb) - (oth->doff << 2));
+               } else {
+                       tcph->seq     = oth->ack_seq;
+                       tcph->ack     = false;
+                       tcph->ack_seq = 0;
+               }
+       }
+
+       tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
+                     niph->daddr, csum_partial((char *)tcph,
+                     sizeof(struct tcphdr), 0));
+
+       addr_type = RTN_UNSPEC;
+#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;
+
+       /* ip_route_me_harder expects skb->dst to be set */
+       dst_hold(oldskb->dst);
+       nskb->dst = oldskb->dst;
+
+       if (ip_route_me_harder(nskb, addr_type))
+               goto free_nskb;
+
+       niph->ttl       = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+       nskb->ip_summed = CHECKSUM_NONE;
+
+       /* "Never happens" */
+       if (nskb->len > dst_mtu(nskb->dst))
+               goto free_nskb;
+
+       nf_ct_attach(nskb, oldskb);
+
+       ip_local_out(nskb);
+       return;
+
+ free_nskb:
+       kfree_skb(nskb);
+}
+
+static unsigned int delude_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)
+{
+       /* WARNING: This code causes reentry within iptables.
+          This means that the iptables jump stack is now crap.  We
+          must return an absolute verdict. --RR */
+       delude_send_reset(skb, hooknum);
+       return NF_DROP;
+}
+
+static struct xt_target delude_tg_reg __read_mostly = {
+       .name     = "DELUDE",
+       .revision = 0,
+       .family   = AF_INET,
+       .table    = "filter",
+       .hooks    = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
+       .proto    = IPPROTO_TCP,
+       .target   = delude_tg,
+       .me       = THIS_MODULE,
+};
+
+static int __init delude_tg_init(void)
+{
+       return xt_register_target(&delude_tg_reg);
+}
+
+static void __exit delude_tg_exit(void)
+{
+       xt_unregister_target(&delude_tg_reg);
+}
+
+module_init(delude_tg_init);
+module_exit(delude_tg_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("Xtables: Close TCP connections after handshake");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_DELUDE");
diff --git a/extensions/xt_portscan.c b/extensions/xt_portscan.c
new file mode 100644 (file)
index 0000000..d975c60
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *     portscan match for netfilter
+ *     Copyright © CC Computer Consultants GmbH, 2006 - 2008
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License; either version
+ *     2 or 3 as published by the Free Software Foundation.
+ */
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/stat.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <net/netfilter/nf_nat_rule.h>
+#include "xt_portscan.h"
+#include "compat_xtables.h"
+#define PFX KBUILD_MODNAME ": "
+
+enum {
+       TCP_FLAGS_ALL3 = TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_SYN,
+       TCP_FLAGS_ALL4 = TCP_FLAGS_ALL3 | TCP_FLAG_ACK,
+       TCP_FLAGS_ALL6 = TCP_FLAGS_ALL4 | TCP_FLAG_PSH | TCP_FLAG_URG,
+};
+
+/* Module parameters */
+static unsigned int
+       connmark_mask = ~0,
+       packet_mask   = ~0,
+       mark_seen     = 0x9,
+       mark_synrcv   = 0x1,
+       mark_closed   = 0x2,
+       mark_synscan  = 0x3,
+       mark_estab1   = 0x4,
+       mark_estab2   = 0x5,
+       mark_cnscan   = 0x6,
+       mark_grscan   = 0x7,
+       mark_valid    = 0x8;
+
+module_param(connmark_mask, uint, S_IRUGO | S_IWUSR);
+module_param(packet_mask,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_seen,     uint, S_IRUGO | S_IWUSR);
+module_param(mark_synrcv,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_closed,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_synscan,  uint, S_IRUGO | S_IWUSR);
+module_param(mark_estab1,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_estab2,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_cnscan,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_grscan,   uint, S_IRUGO | S_IWUSR);
+module_param(mark_valid,    uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(connmark_mask, "only set specified bits in connection mark");
+MODULE_PARM_DESC(packet_mask,   "only set specified bits in packet mark");
+MODULE_PARM_DESC(mark_seen,     "nfmark value for packet-seen state");
+MODULE_PARM_DESC(mark_synrcv,   "connmark value for SYN Received state");
+MODULE_PARM_DESC(mark_closed,   "connmark value for closed state");
+MODULE_PARM_DESC(mark_synscan,  "connmark value for SYN Scan state");
+MODULE_PARM_DESC(mark_estab1,   "connmark value for Established-1 state");
+MODULE_PARM_DESC(mark_estab2,   "connmark value for Established-2 state");
+MODULE_PARM_DESC(mark_cnscan,   "connmark value for Connect Scan state");
+MODULE_PARM_DESC(mark_grscan,   "connmark value for Grab Scan state");
+MODULE_PARM_DESC(mark_valid,    "connmark value for Valid state");
+
+/* TCP flag functions */
+static inline bool tflg_ack4(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL4) == TCP_FLAG_ACK;
+}
+
+static inline bool tflg_ack6(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL6) == TCP_FLAG_ACK;
+}
+
+static inline bool tflg_fin(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL3) == TCP_FLAG_FIN;
+}
+
+static inline bool tflg_rst(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL3) == TCP_FLAG_RST;
+}
+
+static inline bool tflg_rstack(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL4) ==
+              (TCP_FLAG_ACK | TCP_FLAG_RST);
+}
+
+static inline bool tflg_syn(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL4) == TCP_FLAG_SYN;
+}
+
+static inline bool tflg_synack(const struct tcphdr *th)
+{
+       return (tcp_flag_word(th) & TCP_FLAGS_ALL4) ==
+              (TCP_FLAG_SYN | TCP_FLAG_ACK);
+}
+
+/* portscan functions */
+static inline bool portscan_mt_stealth(const struct tcphdr *th)
+{
+       /*
+        * "Connection refused" replies to our own probes must not be matched.
+        */
+       if (tflg_rstack(th))
+               return false;
+
+       if (tflg_rst(th) && printk_ratelimit()) {
+               printk(KERN_WARNING PFX "Warning: Pure RST received\n");
+               return false;
+       }
+
+       /*
+        * -p tcp ! --syn -m conntrack --ctstate INVALID: Looking for non-start
+        * packets that are not associated with any connection -- this will
+        * match most scan types (NULL, XMAS, FIN) and ridiculous flag
+        * combinations (SYN-RST, SYN-FIN, SYN-FIN-RST, FIN-RST, etc.).
+        */
+       return !tflg_syn(th);
+}
+
+static inline unsigned int portscan_mt_full(int mark,
+    enum ip_conntrack_info ctstate, bool loopback, const struct tcphdr *tcph,
+    unsigned int payload_len)
+{
+       if (mark == mark_estab2) {
+               /*
+                * -m connmark --mark $ESTAB2
+                */
+               if (tflg_ack4(tcph) && payload_len == 0)
+                       return mark; /* keep mark */
+               else if (tflg_rst(tcph) || tflg_fin(tcph))
+                       return mark_grscan;
+               else
+                       return mark_valid;
+       } else if (mark == mark_estab1) {
+               /*
+                * -m connmark --mark $ESTAB1
+                */
+               if (tflg_rst(tcph) || tflg_fin(tcph))
+                       return mark_cnscan;
+               else if (!loopback && tflg_ack4(tcph) && payload_len == 0)
+                       return mark_estab2;
+               else
+                       return mark_valid;
+       } else if (mark == mark_synrcv) {
+               /*
+                * -m connmark --mark $SYN
+                */
+               if (loopback && tflg_synack(tcph))
+                       return mark; /* keep mark */
+               else if (loopback && tflg_rstack(tcph))
+                       return mark_closed;
+               else if (tflg_ack6(tcph))
+                       return mark_estab1;
+               else
+                       return mark_synscan;
+       } else if (ctstate == IP_CT_NEW && tflg_syn(tcph)) {
+               /*
+                * -p tcp --syn --ctstate NEW
+                */
+               return mark_synrcv;
+       }
+       return mark;
+}
+
+static bool portscan_mt(const struct sk_buff *skb,
+    const struct net_device *in, const struct net_device *out,
+    const struct xt_match *match, const void *matchinfo, int offset,
+    unsigned int protoff, bool *hotdrop)
+{
+       const struct xt_portscan_mtinfo *info = matchinfo;
+       enum ip_conntrack_info ctstate;
+       const struct tcphdr *tcph;
+       struct nf_conn *ctdata;
+       struct tcphdr tcph_buf;
+
+       tcph = skb_header_pointer(skb, protoff, sizeof(tcph_buf), &tcph_buf);
+       if (tcph == NULL)
+               return false;
+
+       /* Check for invalid packets: -m conntrack --ctstate INVALID */
+       if ((ctdata = nf_ct_get(skb, &ctstate)) == NULL) {
+               if (info->match_stealth)
+                       return portscan_mt_stealth(tcph);
+               /*
+                * If @ctdata is NULL, we cannot match the other scan
+                * types, return.
+                */
+               return false;
+       }
+
+       /*
+        * If -m portscan was previously applied to this packet, the rules we
+        * simulate must not be run through again. And for speedup, do not call
+        * it either when the connection is already VALID.
+        */
+       if ((ctdata->mark & connmark_mask) == mark_valid ||
+            (skb->mark & packet_mask) != mark_seen) {
+               unsigned int n;
+
+               n = portscan_mt_full(ctdata->mark & connmark_mask, ctstate,
+                   in == init_net__loopback_dev, tcph,
+                   skb->len - protoff - 4 * tcph->doff);
+
+               ctdata->mark = (ctdata->mark & ~connmark_mask) | n;
+               ((struct sk_buff *)skb)->mark =
+                       (skb->mark & ~packet_mask) ^ mark_seen;
+       }
+
+       return (info->match_syn && ctdata->mark == mark_synscan) ||
+              (info->match_cn && ctdata->mark == mark_cnscan) ||
+              (info->match_gr && ctdata->mark == mark_grscan);
+}
+
+static bool portscan_mt_check(const char *tablename, const void *entry,
+    const struct xt_match *match, void *matchinfo, unsigned int hook_mask)
+{
+       const struct xt_portscan_mtinfo *info = matchinfo;
+
+       if ((info->match_stealth & ~1) || (info->match_syn & ~1) ||
+           (info->match_cn & ~1) || (info->match_gr & ~1)) {
+               printk(KERN_WARNING PFX "Invalid flags\n");
+               return false;
+       }
+       return true;
+}
+
+static struct xt_match portscan_mt_reg __read_mostly = {
+       .name       = "portscan",
+       .revision   = 0,
+       .family     = AF_INET,
+       .match      = portscan_mt,
+       .checkentry = portscan_mt_check,
+       .matchsize  = sizeof(struct xt_portscan_mtinfo),
+       .proto      = IPPROTO_TCP,
+       .me         = THIS_MODULE,
+};
+
+static int __init portscan_mt_init(void)
+{
+       return xt_register_match(&portscan_mt_reg);
+}
+
+static void __exit portscan_mt_exit(void)
+{
+       xt_unregister_match(&portscan_mt_reg);
+       return;
+}
+
+module_init(portscan_mt_init);
+module_exit(portscan_mt_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("netfilter \"portscan\" match");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_portscan");
diff --git a/extensions/xt_portscan.h b/extensions/xt_portscan.h
new file mode 100644 (file)
index 0000000..949a8ae
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _LINUX_NETFILTER_XT_PORTSCAN_H
+#define _LINUX_NETFILTER_XT_PORTSCAN_H 1
+
+struct xt_portscan_mtinfo {
+       uint8_t match_stealth, match_syn, match_cn, match_gr;
+};
+
+#endif /* _LINUX_NETFILTER_XT_PORTSCAN_H */
diff --git a/mconfig b/mconfig
index fa29bfccc60a2910cae94a620dcc8cc6b7e5a55d..afbe701a76f8dcf4f3dd4f022102da72bc3b0c4f 100644 (file)
--- a/mconfig
+++ b/mconfig
@@ -3,6 +3,9 @@
 # Only "build_${name}=m" (build extensions) or "build_${name}="
 # (do not build) are valid!
 #
+build_CHAOS=m
+build_DELUDE=m
 build_LOGMARK=m
 build_TARPIT=m
 build_TEE=m
+build_portscan=m