Import Chaostables extensions

Signed-off-by: Jan Engelhardt <jengelh@computergmbh.de>
This commit is contained in:
Jan Engelhardt
2008-02-21 14:29:36 +01:00
parent ec9663f680
commit 2fbfbe6cd4
16 changed files with 1033 additions and 1 deletions

View 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

View 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)
{

View File

@@ -13,11 +13,18 @@
# 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 */

View 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 */

113
extensions/libxt_CHAOS.c Normal file
View File

@@ -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);
}

View File

@@ -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.

47
extensions/libxt_DELUDE.c Normal file
View File

@@ -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);
}

View File

@@ -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.

121
extensions/libxt_portscan.c Normal file
View File

@@ -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);
}

View File

@@ -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.

205
extensions/xt_CHAOS.c Normal file
View File

@@ -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");

14
extensions/xt_CHAOS.h Normal file
View File

@@ -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 */

175
extensions/xt_DELUDE.c Normal file
View File

@@ -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");

263
extensions/xt_portscan.c Normal file
View File

@@ -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");

8
extensions/xt_portscan.h Normal file
View File

@@ -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 */

View File

@@ -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