Compare commits

..

52 Commits

Author SHA1 Message Date
Jan Engelhardt
176e829e9f Xtables-addons 1.5.4 2008-04-09 21:18:05 +02:00
Jan Engelhardt
d5ee47e9da manpages: generate manpages 2008-04-09 20:55:35 +02:00
Jan Engelhardt
2c2527bdc4 manpages: remove diff markers from CHAOS,TARIPT 2008-04-09 20:34:57 +02:00
Jan Engelhardt
f931e34365 compat: resolve missing tcp_hdr and udp_hdr for xt_ipp2p 2008-04-09 20:16:33 +02:00
Jan Engelhardt
f34be8445f TEE: make skb writable before attempting checksum update
This also adds the compat function xtnu_skb_make_writable().
2008-04-09 20:06:17 +02:00
Jan Engelhardt
37e51dc44d condition: resolve typesize compiler warning
Fix warning: field precision should have type "int", but argument 2
has type "long unsigned int".
2008-04-09 19:56:11 +02:00
Jan Engelhardt
a680c1bcde Merge reworked "IPMARK" target 2008-04-09 19:45:01 +02:00
Jan Engelhardt
1060138f77 IPMARK: redo ipmark_tg_parse()
- check for illegal inversion on flags
- use param_act() and strtonum() instead of open-coded checks
2008-04-09 19:24:24 +02:00
Jan Engelhardt
03eeabb4bd IPMARK: style cleanup 2008-04-09 19:24:23 +02:00
Jan Engelhardt
2c7b1d5330 IPMARK: IPv6 support 2008-04-09 19:24:01 +02:00
Jan Engelhardt
b63ac3be45 IPMARK: print --addr flag the usual way 2008-04-09 19:24:01 +02:00
Jan Engelhardt
4b8ec990b8 IPMARK: omit printing unset mask 2008-04-09 19:23:45 +02:00
Jan Engelhardt
59ef68fecc IPMARK: remove incorrect --and/--or check
It is perfectly valid for no --and-mask and also no --or-mask to
appear, in which case the IP(v4) address is taken as mark without
modification.
2008-04-09 19:23:08 +02:00
Jan Engelhardt
3bf45b60b2 IPMARK: misc cleanups
- order #include lists
- const annotations, removal of casts
- add ipt_IPMARK alias
- make symbol names distinct
2008-04-09 13:10:00 +02:00
Jan Engelhardt
e037035bd4 IPMARK: rebuild parameter structure (fixed-size types)
Rebuild the parameter structure to have fixed-size members only.
2008-04-09 13:09:45 +02:00
Jan Engelhardt
d432d8041a IPMARK: import 20080304 code base
With truly minimal changes to make it compile.
2008-04-08 20:37:59 +02:00
Jan Engelhardt
05359d1ab2 Merge reworked "ipp2p" match 2008-04-08 20:34:23 +02:00
Jan Engelhardt
29139c1414 ipp2p: add missing MODULE_ALIAS(ipt_ipp2p) 2008-04-08 20:34:06 +02:00
Jan Engelhardt
585cfd49ab ipp2p: use c99 initializers in getopt structure 2008-04-08 20:34:05 +02:00
Jan Engelhardt
54f78ac3ef ipp2p: use param_act() for parameter validation 2008-04-08 20:34:05 +02:00
Jan Engelhardt
376d41618c ipp2p: use OR in flag settings in libxt_ipp2p 2008-04-08 20:34:05 +02:00
Jan Engelhardt
01df89eb8b ipp2p: enable experimental data stream analyzers
(get rid of "function unused" warnings)
2008-04-08 20:34:05 +02:00
Jan Engelhardt
a1d307e336 ipp2p: internally simplify selecting protocol searches 2008-04-08 20:34:05 +02:00
Jan Engelhardt
0712d0fdca ipp2p: guard against potential unaligned access
get_u16() and get_u32() may get passed unaligned pointers;
let's play it safe.
2008-04-08 20:34:05 +02:00
Jan Engelhardt
3c8131b976 ipp2p: use auxiliary skb functions 2008-04-08 20:34:04 +02:00
Jan Engelhardt
569643ac8c ipp2p: static and const annotations, type usage 2008-04-08 20:34:04 +02:00
Jan Engelhardt
cc23d0a2e7 ipp2p: fix match function signature 2008-04-08 20:34:04 +02:00
Jan Engelhardt
c237fe2486 ipp2p: adhere to codingstyle 2008-04-08 20:34:04 +02:00
Jan Engelhardt
edcbcee84e ipp2p: remove compat and obsolete code 2008-04-08 20:34:04 +02:00
Jan Engelhardt
44d6f47ad6 ipp2p: import 20080304 code base 2008-04-08 20:34:03 +02:00
Jan Engelhardt
20f6e47525 Merge reworked "condition" match 2008-04-08 20:33:32 +02:00
Jan Engelhardt
e304252f4b condition: greatly improve processing speed
Replace the loop over all possible condvars by a simple deref. This
changes the runtime from O(n) to O(1) at the expense of only 8 bytes
for rule.
2008-04-08 11:58:35 +02:00
Jan Engelhardt
32f06cbedf condition: squash variables 2008-04-08 11:58:35 +02:00
Jan Engelhardt
75f6f14aaf condition: remove support for nonstandard inversion 2008-04-08 11:58:34 +02:00
Jan Engelhardt
7dd8b1a678 condition: reenable IPv6 support in userspace extension 2008-04-08 11:58:34 +02:00
Jan Engelhardt
f5f17a27c5 condition: style cleanup 2008-04-08 11:58:34 +02:00
Jan Engelhardt
c9579115c3 condition: rework condvar name check
Use memchr() instead of a for loop to detect '/' in the condvar name.
Also unconditionally disallow names starting with a dot.
2008-04-08 11:58:34 +02:00
Jan Engelhardt
586353342f condition: use appropriate types and return values 2008-04-08 11:58:34 +02:00
Jan Engelhardt
317a944fec condition: use unique symbol names and rewrite init function
Use an array of xt_match for the match vtable.
2008-04-08 11:58:34 +02:00
Jan Engelhardt
24dad368dd condition: use new structure type
Use __u8 for the invert flag instead of int. Reduce CONDITION_NAME_LEN
from 32 to 31 so that the entire structure can fit into a cacheline.
2008-04-08 11:58:34 +02:00
Jan Engelhardt
7d0efafdb3 condition: remove casts, add const qualifiers 2008-04-08 11:58:33 +02:00
Jan Engelhardt
330c1fe783 condition: remove version #ifs and compat selectors 2008-04-08 11:58:33 +02:00
Jan Engelhardt
72dc73e6a5 condition: import 20080125 code base 2008-04-08 11:58:33 +02:00
Jan Engelhardt
d7c5473cf6 LOGMARK: fix comma output in ctstatus= list 2008-04-08 11:51:24 +02:00
Jan Engelhardt
0ee80e4147 LOGMARK: add hook= and ctdir= fields 2008-04-08 11:49:45 +02:00
Jan Engelhardt
9778022c37 compat: add ipv6_hdr 2008-04-08 11:33:26 +02:00
Jan Engelhardt
2f6bc4c8cb TEE: reenable header_ops check 2008-04-07 08:44:25 +02:00
Jan Engelhardt
5fbc01b991 compat: add check for pskb relocation
The Xtables-addons compat layer does not support pskb relocation
(result of possible memory allocation in kernels before 2.6.24) and
we just assume it does not happen. Add a check to warn if relocation
did happen and packet loss is to be expected.
2008-04-01 09:12:38 +02:00
Jan Engelhardt
b749916313 ECHO: Catch skb_linearize out-of-memory condition 2008-03-31 06:40:29 +02:00
Jan Engelhardt
818cd3b47e Makefile: support building multiple files with one config option 2008-03-26 08:11:04 +01:00
Jan Engelhardt
8302faad44 TEE: fix address copying bug 2008-03-24 16:56:18 +01:00
Jan Engelhardt
8fa47480f8 Add Kconfig descriptions for Chaostables, ECHO, geoip 2008-03-24 16:28:14 +01:00
40 changed files with 2230 additions and 73 deletions

1
.gitignore vendored
View File

@@ -20,3 +20,4 @@ Makefile.in
/ltmain.sh
/missing
/stamp-h1
/xtables-addons.8

View File

@@ -3,6 +3,14 @@
AUTOMAKE_OPTIONS = foreign subdir-objects
SUBDIRS = extensions
man_MANS := xtables-addons.8
xtables-addons.8: ${srcdir}/xtables-addons.8.in extensions/matches.man extensions/targets.man
${AM_VERBOSE_GEN} sed -e '/@MATCHES@/ r extensions/matches.man' -e '/@TARGET@/ r extensions/targets.man' $< >$@;
extensions/%:
${MAKE} ${AM_MAKEFLAGS} -C $(@D) $(@F)
.PHONY: tarball
tarball:
rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION};

1
README
View File

@@ -33,6 +33,7 @@ extension and xt_foobar.c for the kernel extension.
mconfig.foobar
extensions/Kbuild.foobar
extensions/Mbuild.foobar
extensions/libxt_foobar.c
extensions/libxt_foobar.man
extensions/xt_foobar.c

View File

@@ -1,5 +1,5 @@
AC_INIT([xtables-addons], [1.5.3])
AC_INIT([xtables-addons], [1.5.4])
AC_CONFIG_HEADERS([config.h])
AC_PROG_INSTALL
AM_INIT_AUTOMAKE

View File

@@ -1,5 +1,6 @@
.*.cmd
.*.d
.manpages.lst
.tmp_versions
*.ko
*.mod.c
@@ -8,3 +9,5 @@
GNUmakefile
Module.symvers
modules.order
matches.man
targets.man

View File

@@ -45,22 +45,20 @@ endif
#
include ${top_srcdir}/mconfig
-include ${top_srcdir}/mconfig.*
pfx_all_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(wildcard ${srcdir}/libxt_*.c))
pfx_build_mod := $(foreach i,${pfx_all_mod},$(if ${build_${i}},${i},))
pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod})
include ${srcdir}/Mbuild
#
# Building blocks
#
targets := ${pfx_solibs}
targets_install := ${pfx_solibs}
targets := ${obj-m}
targets_install := ${obj-m}
.SECONDARY:
.PHONY: all install clean distclean FORCE
all: modules ${targets}
all: modules ${targets} matches.man targets.man
install: modules_install ${targets_install}
@mkdir -p "${DESTDIR}${xtlibdir}";
@@ -70,7 +68,7 @@ clean: clean_modules
rm -f *.oo *.so;
distclean: clean
rm -f .*.d;
rm -f .*.d .manpages.lst;
-include .*.d
@@ -98,3 +96,34 @@ lib%.so: lib%.oo
lib%.oo: ${srcdir}/lib%.c
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
#
# Manpages
#
wcman_matches := $(wildcard ${srcdir}/libxt_[a-z]*.man)
wcman_targets := $(wildcard ${srcdir}/libxt_[A-Z]*.man)
wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches})
wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
.manpages.lst: FORCE
@echo "${wlist_targets} ${wlist_matches}" >$@.tmp; \
cmp -s $@ $@.tmp || mv $@.tmp $@; \
rm -f $@.tmp;
man_run = \
${AM_VERBOSE_GEN} \
for ext in $(1); do \
f="${srcdir}/libxt_$$ext.man"; \
if [ -f "$$f" ]; then \
echo ".SS $$ext"; \
cat "$$f"; \
continue; \
fi; \
done >$@;
matches.man: .manpages.lst ${wcman_matches}
$(call man_run,${wlist_matches})
targets.man: .manpages.lst ${wcman_targets}
$(call man_run,${wlist_targets})

View File

@@ -8,10 +8,13 @@ obj-m += compat_xtables.o
obj-${build_CHAOS} += xt_CHAOS.o
obj-${build_DELUDE} += xt_DELUDE.o
obj-${build_ECHO} += xt_ECHO.o
obj-${build_IPMARK} += xt_IPMARK.o
obj-${build_LOGMARK} += xt_LOGMARK.o
obj-${build_TARPIT} += xt_TARPIT.o
obj-${build_TEE} += xt_TEE.o
obj-${build_condition} += xt_condition.o
obj-${build_geoip} += xt_geoip.o
obj-${build_ipp2p} += xt_ipp2p.o
obj-${build_portscan} += xt_portscan.o
-include ${M}/*.Kbuild

11
extensions/Mbuild Normal file
View File

@@ -0,0 +1,11 @@
obj-${build_CHAOS} += libxt_CHAOS.so
obj-${build_DELUDE} += libxt_DELUDE.so
obj-${build_ECHO} += libxt_ECHO.so
obj-${build_IPMARK} += libxt_IPMARK.so
obj-${build_LOGMARK} += libxt_LOGMARK.so
obj-${build_TARPIT} += libxt_TARPIT.so
obj-${build_TEE} += libxt_TEE.so
obj-${build_condition} += libxt_condition.so
obj-${build_geoip} += libxt_geoip.so
obj-${build_ipp2p} += libxt_ipp2p.so
obj-${build_portscan} += libxt_portscan.so

View File

@@ -1,6 +1,9 @@
#ifndef COMPAT_SKBUFF_H
#define COMPAT_SKBUFF_H 1
struct tcphdr;
struct udphdr;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->nfmark)
#else
@@ -10,11 +13,21 @@
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21)
# define ip_hdr(skb) ((skb)->nh.iph)
# define ip_hdrlen(skb) (ip_hdr(skb)->ihl * 4)
# define ipv6_hdr(skb) ((skb)->nh.ipv6h)
# define skb_network_header(skb) ((skb)->nh.raw)
# define skb_transport_header(skb) ((skb)->h.raw)
static inline void skb_reset_network_header(struct sk_buff *skb)
{
skb->nh.raw = skb->data;
}
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
{
return (void *)skb_transport_header(skb);
}
static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
{
return (void *)skb_transport_header(skb);
}
#endif
#endif /* COMPAT_SKBUFF_H */

View File

@@ -12,6 +12,14 @@
#include "compat_skbuff.h"
#include "compat_xtnu.h"
static inline int unable(const char *cause)
{
if (net_ratelimit())
printk(KERN_ERR KBUILD_MODNAME
": compat layer limits reached (%s) - dropping packets\n", cause);
return -1;
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
static int xtnu_match_run(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
@@ -288,13 +296,31 @@ 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)
{
struct sk_buff *nskb = skb;
int ret;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
return ip_route_me_harder(&skb);
ret = ip_route_me_harder(&skb);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return ip_route_me_harder(&skb, addr_type);
ret = ip_route_me_harder(&nskb, addr_type);
#endif
if (nskb != skb)
return unable(__func__);
return ret;
}
EXPORT_SYMBOL_GPL(xtnu_ip_route_me_harder);
int xtnu_skb_make_writable(struct sk_buff *skb, unsigned int len)
{
struct sk_buff *nskb = skb;
int ret;
ret = skb_make_writable(&skb, len);
if (nskb != skb)
return unable(__func__);
return ret;
}
EXPORT_SYMBOL_GPL(xtnu_skb_make_writable);
#endif
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 24)

View File

@@ -59,6 +59,7 @@
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
# define xt_target xtnu_target
# define ip_route_me_harder xtnu_ip_route_me_harder
# define skb_make_writable xtnu_skb_make_writable
# define xt_register_target xtnu_register_target
# define xt_unregister_target xtnu_unregister_target
# define xt_register_targets xtnu_register_targets

View File

@@ -69,6 +69,7 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
extern int xtnu_ip_local_out(struct sk_buff *);
extern int xtnu_ip_route_me_harder(struct sk_buff *, unsigned int);
extern int xtnu_skb_make_writable(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 *);
extern void xtnu_unregister_match(struct xtnu_match *);

View File

@@ -1,18 +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.
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\fP
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\fP
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.

179
extensions/libxt_IPMARK.c Normal file
View File

@@ -0,0 +1,179 @@
/* Shared library add-on to iptables to add IPMARK target support.
* (C) 2003 by Grzegorz Janoszka <Grzegorz.Janoszka@pro.onet.pl>
*
* based on original MARK target
*
* This program is distributed under the terms of GNU GPL
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xtables.h>
#include "xt_IPMARK.h"
enum {
FL_ADDR_USED = 1 << 0,
FL_AND_MASK_USED = 1 << 1,
FL_OR_MASK_USED = 1 << 2,
FL_SHIFT = 1 << 3,
};
/* Function which prints out usage message. */
static void ipmark_tg_help(void)
{
printf(
"IPMARK target options:\n"
" --addr {src|dst} use source or destination ip address\n"
" --and-mask value logical AND ip address with this value becomes MARK\n"
" --or-mask value logical OR ip address with this value becomes MARK\n"
" --shift value shift address right by value before copying to mark\n"
"\n");
}
static const struct option ipmark_tg_opts[] = {
{.name = "addr", .has_arg = true, .val = '1'},
{.name = "and-mask", .has_arg = true, .val = '2'},
{.name = "or-mask", .has_arg = true, .val = '3'},
{.name = "shift", .has_arg = true, .val = '4'},
{NULL},
};
/* Initialize the target. */
static void ipmark_tg_init(struct xt_entry_target *t)
{
struct xt_ipmark_tginfo *info = (void *)t->data;
info->andmask = ~0U;
}
static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_ipmark_tginfo *info = (void *)(*target)->data;
unsigned int n;
switch (c) {
case '1':
param_act(P_ONLY_ONCE, "IPMARK", "addr", *flags & FL_ADDR_USED);
param_act(P_NO_INVERT, "IPMARK", "addr", invert);
if (strcmp(optarg, "src") == 0)
info->selector = XT_IPMARK_SRC;
else if (strcmp(optarg, "dst") == 0)
info->selector = XT_IPMARK_DST;
else
exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg);
*flags |= FL_ADDR_USED;
return true;
case '2':
param_act(P_ONLY_ONCE, "IPMARK", "and-mask", *flags & FL_AND_MASK_USED);
param_act(P_NO_INVERT, "IPMARK", "and-mask", invert);
if (!strtonum(optarg, NULL, &n, 0, ~0U))
param_act(P_BAD_VALUE, "IPMARK", "and-mask", optarg);
info->andmask = n;
*flags |= FL_AND_MASK_USED;
return true;
case '3':
param_act(P_ONLY_ONCE, "IPMARK", "or-mask", *flags & FL_OR_MASK_USED);
param_act(P_NO_INVERT, "IPMARK", "or-mask", invert);
if (!strtonum(optarg, NULL, &n, 0, ~0U))
param_act(P_BAD_VALUE, "IPMARK", "or-mask", optarg);
info->ormask = n;
*flags |= FL_OR_MASK_USED;
return true;
case '4':
param_act(P_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT);
param_act(P_NO_INVERT, "IPMARK", "--shift", invert);
/*
* Anything >31 does not make sense for IPv4, but it still
* does the right thing.
*/
if (!strtonum(optarg, NULL, &n, 0, 128))
param_act(P_BAD_VALUE, "IPMARK", "--shift", optarg);
info->shift = n;
return true;
}
return false;
}
static void ipmark_tg_check(unsigned int flags)
{
if (!(flags & FL_ADDR_USED))
exit_error(PARAMETER_PROBLEM,
"IPMARK target: Parameter --addr is required");
}
static void
ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
const struct xt_ipmark_tginfo *info = (const void *)target->data;
if (info->selector == XT_IPMARK_SRC)
printf("IPMARK src ip");
else
printf("IPMARK dst ip");
if (info->andmask != ~0U)
printf(" and 0x%x ", (unsigned int)info->andmask);
if (info->ormask != 0)
printf(" or 0x%x ", (unsigned int)info->ormask);
}
static void
ipmark_tg_save(const void *entry, const struct xt_entry_target *target)
{
const struct xt_ipmark_tginfo *info = (const void *)target->data;
if (info->selector == XT_IPMARK_SRC)
printf("--addr src ");
else
printf("--addr dst ");
if (info->andmask != ~0U)
printf("--and-mask 0x%x ", (unsigned int)info->andmask);
if (info->ormask != 0)
printf("--or-mask 0x%x ", (unsigned int)info->ormask);
}
static struct xtables_target ipmark_tg4_reg = {
.version = XTABLES_VERSION,
.name = "IPMARK",
.family = PF_INET,
.revision = 0,
.size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.help = ipmark_tg_help,
.init = ipmark_tg_init,
.parse = ipmark_tg_parse,
.final_check = ipmark_tg_check,
.print = ipmark_tg_print,
.save = ipmark_tg_save,
.extra_opts = ipmark_tg_opts,
};
static struct xtables_target ipmark_tg6_reg = {
.version = XTABLES_VERSION,
.name = "IPMARK",
.family = PF_INET6,
.revision = 0,
.size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.help = ipmark_tg_help,
.init = ipmark_tg_init,
.parse = ipmark_tg_parse,
.final_check = ipmark_tg_check,
.print = ipmark_tg_print,
.save = ipmark_tg_save,
.extra_opts = ipmark_tg_opts,
};
static void _init(void)
{
xtables_register_target(&ipmark_tg4_reg);
xtables_register_target(&ipmark_tg6_reg);
}

View File

@@ -0,0 +1,56 @@
Allows you to mark a received packet basing on its IP address. This
can replace many mangle/mark entries with only one, if you use
firewall based classifier.
This target is to be used inside the \fBmangle\fP table.
.TP
\fB--addr\fP {\fBsrc\fP|\fBdst\fP}
Select source or destination IP address as a basis for the mark.
.TP
.BI "--and-mask " "mask"
Perform bitwise `and' on the IP address and this mask.
.TP
.BI "--or-mask " "mask"
Perform bitwise `or' on the IP address and this mask.
.TP
\fB--shift\fP \fIvalue\fP
Shift addresses to the right by the given number of bits before taking it
as a mark. (This is done before ANDing or ORing it.) This option is needed
to select part of an IPv6 address, because marks are only 32 bits in size.
.P
The order of IP address bytes is reversed to meet "human order of bytes":
192.168.0.1 is 0xc0a80001. At first the `and' operation is performed, then
`or'.
Examples:
We create a queue for each user, the queue number is adequate
to the IP address of the user, e.g.: all packets going to/from 192.168.5.2
are directed to 1:0502 queue, 192.168.5.12 -> 1:050c etc.
We have one classifier rule:
.IP
tc filter add dev eth3 parent 1:0 protocol ip fw
.P
Earlier we had many rules just like below:
.IP
iptables -t mangle -A POSTROUTING -o eth3 -d 192.168.5.2 -j MARK
--set-mark 0x10502
.IP
iptables -t mangle -A POSTROUTING -o eth3 -d 192.168.5.3 -j MARK
--set-mark 0x10503
.P
Using IPMARK target we can replace all the mangle/mark rules with only one:
.IP
iptables -t mangle -A POSTROUTING -o eth3 -j IPMARK --addr=dst
--and-mask=0xffff --or-mask=0x10000
.P
On the routers with hundreds of users there should be significant load
decrease (e.g. twice).
.PP
(IPv6 example) If the source address is of the form
2001:db8:45:1d:20d:93ff:fe9b:e443 and the resulting mark should be 0x93ff,
then a right-shift of 16 is needed first:
.IP
-t mangle -A PREROUTING -s 2001:db8::/32 -j IPMARK --addr src --shift 16
--and-mask 0xFFFF

View File

@@ -1,33 +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
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
.PP
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

View File

@@ -59,7 +59,7 @@ static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
exit_error(PARAMETER_PROBLEM,
"Invalid IP address %s", optarg);
memcpy(&info->gw, &ia, sizeof(ia));
memcpy(&info->gw, ia, sizeof(*ia));
*flags |= FLAG_GATEWAY;
return true;
}

View File

@@ -0,0 +1,105 @@
/* Shared library add-on to iptables for condition match */
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <xtables.h>
#include "xt_condition.h"
static void condition_help(void)
{
printf(
"condition match options:\n"
"[!] --condition name Match on boolean value stored in procfs file\n"
);
}
static const struct option condition_opts[] = {
{.name = "condition", .has_arg = true, .val = 'X'},
{NULL},
};
static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_condition_mtinfo *info = (void *)(*match)->data;
if (c == 'X') {
if (*flags)
exit_error(PARAMETER_PROBLEM,
"Can't specify multiple conditions");
if (strlen(optarg) < sizeof(info->name))
strcpy(info->name, optarg);
else
exit_error(PARAMETER_PROBLEM,
"File name too long");
info->invert = invert;
*flags = 1;
return true;
}
return false;
}
static void condition_check(unsigned int flags)
{
if (flags == 0)
exit_error(PARAMETER_PROBLEM,
"Condition match: must specify --condition");
}
static void condition_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_condition_mtinfo *info = (const void *)match->data;
printf("condition %s%s ", (info->invert) ? "!" : "", info->name);
}
static void condition_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_condition_mtinfo *info = (const void *)match->data;
printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name);
}
static struct xtables_match condition_mt4_reg = {
.name = "condition",
.revision = 0,
.family = PF_INET,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
.help = condition_help,
.parse = condition_parse,
.final_check = condition_check,
.print = condition_print,
.save = condition_save,
.extra_opts = condition_opts,
};
static struct xtables_match condition_mt6_reg = {
.name = "condition",
.revision = 0,
.family = PF_INET6,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
.userspacesize = offsetof(struct xt_condition_mtinfo, condvar),
.help = condition_help,
.parse = condition_parse,
.final_check = condition_check,
.print = condition_print,
.save = condition_save,
.extra_opts = condition_opts,
};
static void _init(void)
{
xtables_register_match(&condition_mt4_reg);
xtables_register_match(&condition_mt6_reg);
}

View File

@@ -0,0 +1,4 @@
This matches if a specific condition variable is (un)set.
.TP
[\fB!\fP] \fB--condition\fP \fIname\fP
Match on boolean value stored in /proc/net/nf_condition/\fIname\fP.

238
extensions/libxt_ipp2p.c Normal file
View File

@@ -0,0 +1,238 @@
#include <stdbool.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
#include <xtables.h>
#include "xt_ipp2p.h"
#define param_act(t, s, f) param_act((t), "ipp2p", (s), (f))
static void ipp2p_mt_help(void)
{
printf(
"IPP2P v%s options:\n"
" --edk [tcp,udp] All known eDonkey/eMule/Overnet packets\n"
" --dc [tcp] All known Direct Connect packets\n"
" --kazaa [tcp,udp] All known KaZaA packets\n"
" --gnu [tcp,udp] All known Gnutella packets\n"
" --bit [tcp,udp] All known BitTorrent packets\n"
" --apple [tcp] All known AppleJuice packets\n"
" --winmx [tcp] All known WinMX\n"
" --soul [tcp] All known SoulSeek\n"
" --ares [tcp] All known Ares\n\n"
"EXPERIMENTAL protocols (please send feedback to: ipp2p@ipp2p.org) :\n"
" --mute [tcp] All known Mute packets\n"
" --waste [tcp] All known Waste packets\n"
" --xdcc [tcp] All known XDCC packets (only xdcc login)\n\n"
"DEBUG SUPPPORT, use only if you know why\n"
" --debug Generate kernel debug output, THIS WILL SLOW DOWN THE FILTER\n"
"\nIPP2P was intended for TCP only. Due to increasing usage of UDP we needed to change this.\n"
"You can now use -p udp to search UDP packets only or without -p switch to search UDP and TCP packets.\n"
"\nSee README included with this package for more details or visit http://www.ipp2p.org\n"
"\nExamples:\n"
" iptables -A FORWARD -m ipp2p --ipp2p -j MARK --set-mark 0x01\n"
" iptables -A FORWARD -p udp -m ipp2p --kazaa --bit -j DROP\n"
" iptables -A FORWARD -p tcp -m ipp2p --edk --soul -j DROP\n\n"
, IPP2P_VERSION);
}
static const struct option ipp2p_mt_opts[] = {
{.name = "edk", .has_arg = false, .val = '2'},
{.name = "dc", .has_arg = false, .val = '7'},
{.name = "gnu", .has_arg = false, .val = '9'},
{.name = "kazaa", .has_arg = false, .val = 'a'},
{.name = "bit", .has_arg = false, .val = 'b'},
{.name = "apple", .has_arg = false, .val = 'c'},
{.name = "soul", .has_arg = false, .val = 'd'},
{.name = "winmx", .has_arg = false, .val = 'e'},
{.name = "ares", .has_arg = false, .val = 'f'},
{.name = "mute", .has_arg = false, .val = 'g'},
{.name = "waste", .has_arg = false, .val = 'h'},
{.name = "xdcc", .has_arg = false, .val = 'i'},
{.name = "debug", .has_arg = false, .val = 'j'},
{NULL},
};
static int ipp2p_mt_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct ipt_p2p_info *info = (struct ipt_p2p_info *)(*match)->data;
switch (c) {
case '2': /*cmd: edk*/
param_act(P_ONLY_ONCE, "--edk", *flags & IPP2P_EDK);
param_act(P_NO_INVERT, "--edk", invert);
if (*flags & IPP2P_DATA_EDK)
exit_error(PARAMETER_PROBLEM,
"ipp2p: use `--edk' OR `--edk-data' but not both of them!");
*flags |= IPP2P_EDK;
info->cmd |= IPP2P_EDK;
break;
case '7': /*cmd: dc*/
param_act(P_ONLY_ONCE, "--dc", *flags & IPP2P_DC);
param_act(P_NO_INVERT, "--dc", invert);
if (*flags & IPP2P_DATA_DC)
exit_error(PARAMETER_PROBLEM,
"ipp2p: use `--dc' OR `--dc-data' but not both of them!");
*flags |= IPP2P_DC;
info->cmd |= IPP2P_DC;
break;
case '9': /*cmd: gnu*/
param_act(P_ONLY_ONCE, "--gnu", *flags & IPP2P_GNU);
param_act(P_NO_INVERT, "--gnu", invert);
if (*flags & IPP2P_DATA_GNU)
exit_error(PARAMETER_PROBLEM,
"ipp2p: use `--gnu' OR `--gnu-data' but not both of them!");
*flags |= IPP2P_GNU;
info->cmd |= IPP2P_GNU;
break;
case 'a': /*cmd: kazaa*/
param_act(P_ONLY_ONCE, "--kazaa", *flags & IPP2P_KAZAA);
param_act(P_NO_INVERT, "--kazaa", invert);
if (*flags & IPP2P_DATA_KAZAA)
exit_error(PARAMETER_PROBLEM,
"ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!");
*flags |= IPP2P_KAZAA;
info->cmd |= IPP2P_KAZAA;
break;
case 'b': /*cmd: bit*/
param_act(P_ONLY_ONCE, "--kazaa", *flags & IPP2P_BIT);
param_act(P_NO_INVERT, "--kazaa", invert);
*flags |= IPP2P_BIT;
info->cmd |= IPP2P_BIT;
break;
case 'c': /*cmd: apple*/
param_act(P_ONLY_ONCE, "--apple", *flags & IPP2P_APPLE);
param_act(P_NO_INVERT, "--apple", invert);
*flags |= IPP2P_APPLE;
info->cmd |= IPP2P_APPLE;
break;
case 'd': /*cmd: soul*/
param_act(P_ONLY_ONCE, "--soul", *flags & IPP2P_SOUL);
param_act(P_NO_INVERT, "--soul", invert);
*flags |= IPP2P_SOUL;
info->cmd |= IPP2P_SOUL;
break;
case 'e': /*cmd: winmx*/
param_act(P_ONLY_ONCE, "--winmx", *flags & IPP2P_WINMX);
param_act(P_NO_INVERT, "--winmx", invert);
*flags |= IPP2P_WINMX;
info->cmd |= IPP2P_WINMX;
break;
case 'f': /*cmd: ares*/
param_act(P_ONLY_ONCE, "--ares", *flags & IPP2P_ARES);
param_act(P_NO_INVERT, "--ares", invert);
*flags |= IPP2P_ARES;
info->cmd |= IPP2P_ARES;
break;
case 'g': /*cmd: mute*/
param_act(P_ONLY_ONCE, "--mute", *flags & IPP2P_MUTE);
param_act(P_NO_INVERT, "--mute", invert);
*flags |= IPP2P_MUTE;
info->cmd |= IPP2P_MUTE;
break;
case 'h': /*cmd: waste*/
param_act(P_ONLY_ONCE, "--waste", *flags & IPP2P_WASTE);
param_act(P_NO_INVERT, "--waste", invert);
*flags |= IPP2P_WASTE;
info->cmd |= IPP2P_WASTE;
break;
case 'i': /*cmd: xdcc*/
param_act(P_ONLY_ONCE, "--xdcc", *flags & IPP2P_XDCC);
param_act(P_NO_INVERT, "--xdcc", invert);
*flags |= IPP2P_XDCC;
info->cmd |= IPP2P_XDCC;
break;
case 'j': /*cmd: debug*/
param_act(P_ONLY_ONCE, "--debug", info->debug);
param_act(P_NO_INVERT, "--debug", invert);
info->debug = 1;
break;
default:
// exit_error(PARAMETER_PROBLEM,
// "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
return 0;
}
return 1;
}
static void ipp2p_mt_check(unsigned int flags)
{
if (!flags)
exit_error(PARAMETER_PROBLEM,
"\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
}
static const char *const ipp2p_cmds[] = {
[IPP2N_EDK] = "--edk",
[IPP2N_DATA_KAZAA] = "--kazaa-data",
[IPP2N_DATA_EDK] = "--edk-data",
[IPP2N_DATA_DC] = "--dc-data",
[IPP2N_DC] = "--dc",
[IPP2N_DATA_GNU] = "--gnu-data",
[IPP2N_GNU] = "--gnu",
[IPP2N_KAZAA] = "--kazaa",
[IPP2N_BIT] = "--bit",
[IPP2N_APPLE] = "--apple",
[IPP2N_SOUL] = "--soul",
[IPP2N_WINMX] = "--winmx",
[IPP2N_ARES] = "--ares",
[IPP2N_MUTE] = "--mute",
[IPP2N_WASTE] = "--waste",
[IPP2N_XDCC] = "--xdcc",
};
static void
ipp2p_mt_print(const void *entry, const struct xt_entry_match *match,
int numeric)
{
const struct ipt_p2p_info *info = (const void *)match->data;
unsigned int i;
for (i = IPP2N_EDK; i <= IPP2N_XDCC; ++i)
if (info->cmd & (1 << i))
printf("%s ", ipp2p_cmds[i]);
if (info->debug != 0)
printf("--debug ");
}
static void ipp2p_mt_save(const void *entry, const struct xt_entry_match *match)
{
ipp2p_mt_print(entry, match, true);
}
static struct xtables_match ipp2p_mt_reg = {
.version = XTABLES_VERSION,
.name = "ipp2p",
.revision = 0,
.family = AF_INET,
.size = XT_ALIGN(sizeof(struct ipt_p2p_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_p2p_info)),
.help = ipp2p_mt_help,
.parse = ipp2p_mt_parse,
.final_check = ipp2p_mt_check,
.print = ipp2p_mt_print,
.save = ipp2p_mt_save,
.extra_opts = ipp2p_mt_opts,
};
static void _init(void)
{
xtables_register_match(&ipp2p_mt_reg);
}

View File

@@ -0,0 +1,40 @@
This module matches certain packets in P2P flows. It is not
designed to match all packets belonging to a P2P connection -
use IPP2P together with CONNMARK for this purpose. Also visit
http://www.ipp2p.org for detailed information.
Use it together with -p tcp or -p udp to search these protocols
only or without -p switch to search packets of both protocols.
IPP2P provides the following options:
.TP
.B "--edk "
Matches as many eDonkey/eMule packets as possible.
.TP
.B "--kazaa "
Matches as many KaZaA packets as possible.
.TP
.B "--gnu "
Matches as many Gnutella packets as possible.
.TP
.B "--dc "
Matches as many Direct Connect packets as possible.
.TP
.B "--bit "
Matches BitTorrent packets.
.TP
.B "--apple "
Matches AppleJuice packets.
.TP
.B "--soul "
Matches some SoulSeek packets. Considered as beta, use careful!
.TP
.B "--winmx "
Matches some WinMX packets. Considered as beta, use careful!
.TP
.B "--ares "
Matches Ares and AresLite packets. Use together with -j DROP only.
.TP
.B "--debug "
Prints some information about each hit into kernel logfile. May
produce huge logfiles so beware!

View File

@@ -0,0 +1,9 @@
config NETFILTER_XT_TARGET_CHAOS
tristate '"CHAOS" target support'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
depends on NETFILTER_XT_TARGET_DELUDE || NETFILTER_XT_TARGET_TARPIT
depends on CONFIG_IP_NF_TARGET_REJECT
---help---
The CHAOS target is a module to report back false results to nmap
scans by randomly switching between DELUDE/TARPIT, REJECT and DROP
behavior.

View File

@@ -0,0 +1,6 @@
config NETFILTER_XT_TARGET_DELUDE
tristate '"DELUDE" target support'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
---help---
The DELUDE target acknowledges connection initiations but forcibly
closes on any other packet, therefore making the port look open.

View File

@@ -0,0 +1,6 @@
config NETFILTER_XT_TARGET_ECHO
tristate '"ECHO" sample target'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
---help---
The ECHO target provides a demonstrational implementation of an
Xtables target implementing RFC 862 for UDP.

View File

@@ -30,7 +30,8 @@ static unsigned int echo_tg4(struct sk_buff *oldskb,
void *payload;
/* This allows us to do the copy operation in fewer lines of code. */
skb_linearize(oldskb);
if (skb_linearize(oldskb) < 0)
return NF_DROP;
oldip = ip_hdr(oldskb);
oldudp = skb_header_pointer(oldskb, ip_hdrlen(oldskb),

View File

@@ -0,0 +1,12 @@
config NETFILTER_XT_TARGET_IPMARK
tristate '"IPMARK" target support'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
depends on IP_NF_MANGLE || IP6_NF_MANGLE
---help---
This option adds an "IPMARK" target, which allows you to create
rules in the "mangle" table which alter the netfilter mark field
basing on the source or destination ip address of the packet.
This is very useful for very fast massive shaping -- using only one
rule you can direct packets to houndreds different queues. You
will probably find it helpful only if your linux machine acts as a
shaper for many others computers.

106
extensions/xt_IPMARK.c Normal file
View File

@@ -0,0 +1,106 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <linux/netfilter/x_tables.h>
#include <net/checksum.h>
#include "xt_IPMARK.h"
#include "compat_xtables.h"
MODULE_AUTHOR("Grzegorz Janoszka <Grzegorz@Janoszka.pl>");
MODULE_DESCRIPTION("Xtables: mark based on IP address");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_IPMARK");
MODULE_ALIAS("ip6t_IPMARK");
static unsigned int
ipmark_tg4(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_ipmark_tginfo *ipmarkinfo = targinfo;
const struct iphdr *iph = ip_hdr(skb);
__u32 mark;
if (ipmarkinfo->selector == XT_IPMARK_SRC)
mark = ntohl(iph->saddr);
else
mark = ntohl(iph->daddr);
mark >>= ipmarkinfo->shift;
mark &= ipmarkinfo->andmask;
mark |= ipmarkinfo->ormask;
skb_nfmark(skb) = mark;
return XT_CONTINUE;
}
/* Function is safe for any value of @s */
static __u32 ipmark_from_ip6(const struct in6_addr *a, unsigned int s)
{
unsigned int q = s % 32;
__u32 mask;
if (s >= 128)
return 0;
mask = ntohl(a->s6_addr32[3 - s/32]) >> q;
if (s > 0 && s < 96 && q != 0)
mask |= ntohl(a->s6_addr32[2 - s/32]) << (32 - q);
return mask;
}
static unsigned int
ipmark_tg6(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_ipmark_tginfo *info = targinfo;
const struct ipv6hdr *iph = ipv6_hdr(skb);
__u32 mark;
if (info->selector == XT_IPMARK_SRC)
mark = ipmark_from_ip6(&iph->saddr, info->shift);
else
mark = ipmark_from_ip6(&iph->daddr, info->shift);
mark &= info->andmask;
mark |= info->ormask;
skb_nfmark(skb) = mark;
return XT_CONTINUE;
}
static struct xt_target ipmark_tg_reg[] __read_mostly = {
{
.name = "IPMARK",
.revision = 0,
.family = PF_INET,
.table = "mangle",
.target = ipmark_tg4,
.targetsize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.me = THIS_MODULE,
},
{
.name = "IPMARK",
.revision = 0,
.family = PF_INET6,
.table = "mangle",
.target = ipmark_tg6,
.targetsize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.me = THIS_MODULE,
},
};
static int __init ipmark_tg_init(void)
{
return xt_register_targets(ipmark_tg_reg, ARRAY_SIZE(ipmark_tg_reg));
}
static void __exit ipmark_tg_exit(void)
{
xt_unregister_targets(ipmark_tg_reg, ARRAY_SIZE(ipmark_tg_reg));
}
module_init(ipmark_tg_init);
module_exit(ipmark_tg_exit);

16
extensions/xt_IPMARK.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _LINUX_NETFILTER_XT_IPMARK_H
#define _LINUX_NETFILTER_XT_IPMARK_H 1
enum {
XT_IPMARK_SRC,
XT_IPMARK_DST,
};
struct xt_ipmark_tginfo {
__u32 andmask;
__u32 ormask;
__u8 selector;
__u8 shift;
};
#endif /* _LINUX_NETFILTER_XT_IPMARK_H */

View File

@@ -17,6 +17,18 @@
#include "compat_xtables.h"
#include "xt_LOGMARK.h"
static const char *const hook_names[] = {
[NF_INET_PRE_ROUTING] = "PREROUTING",
[NF_INET_LOCAL_IN] = "INPUT",
[NF_INET_FORWARD] = "FORWARD",
[NF_INET_LOCAL_OUT] = "OUTPUT",
[NF_INET_POST_ROUTING] = "POSTROUTING",
};
static const char *const dir_names[] = {
"ORIGINAL", "REPLY",
};
static unsigned int
logmark_tg(struct sk_buff *skb, const struct net_device *in,
const struct net_device *out, unsigned int hooknum,
@@ -25,12 +37,15 @@ logmark_tg(struct sk_buff *skb, const struct net_device *in,
const struct xt_logmark_tginfo *info = targinfo;
const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
bool prev = false;
printk("<%u>%.*s""nfmark=0x%x secmark=0x%x classify=0x%x",
printk("<%u>%.*s""hook=%s nfmark=0x%x secmark=0x%x classify=0x%x",
info->level, (unsigned int)sizeof(info->prefix), info->prefix,
hook_names[hooknum],
skb_nfmark(skb), skb->secmark, skb->priority);
ct = nf_ct_get(skb, &ctinfo);
printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]);
if (ct == NULL) {
printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE");
} else if (ct == &nf_conntrack_untracked) {
@@ -50,14 +65,16 @@ logmark_tg(struct sk_buff *skb, const struct net_device *in,
printk(",DNAT");
printk(" ctstatus=");
if (ct->status & IPS_EXPECTED)
if (ct->status & IPS_EXPECTED) {
printk("EXPECTED");
prev = true;
}
if (ct->status & IPS_SEEN_REPLY)
printk(",SEEN_REPLY");
printk("%s""SEEN_REPLY", prev++ ? "," : "");
if (ct->status & IPS_ASSURED)
printk(",ASSURED");
printk("%s""ASSURED", prev++ ? "," : "");
if (ct->status & IPS_CONFIRMED)
printk(",CONFIRMED");
printk("%s""CONFIRMED", prev++ ? "," : "");
}
printk("\n");

View File

@@ -85,6 +85,15 @@ static bool tee_routing(struct sk_buff *skb,
return true;
}
static bool dev_hh_avail(const struct net_device *dev)
{
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return dev->hard_header != NULL;
#else
return dev->header_ops != NULL;
#endif
}
/*
* Stolen from ip_finish_output2
* PRE : skb->dev is set to the device we are leaving by
@@ -99,8 +108,7 @@ static void tee_ip_direct_send(struct sk_buff *skb)
unsigned int hh_len = LL_RESERVED_SPACE(dev);
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len)) {
/* if (dev->header_ops != NULL) */
if (unlikely(skb_headroom(skb) < hh_len) && dev_hh_avail(dev)) {
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
@@ -150,6 +158,9 @@ tee_tg(struct sk_buff *skb, const struct net_device *in,
}
#endif
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
/*
* If we are in INPUT, the checksum must be recalculated since
* the length could have changed as a result of defragmentation.

View File

@@ -0,0 +1,6 @@
config NETFILTER_XT_MATCH_CONDITION
tristate '"condition" match support'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
---help---
This option allows you to match firewall rules against condition
variables stored in the /proc/net/nf_condition directory.

259
extensions/xt_condition.c Normal file
View File

@@ -0,0 +1,259 @@
/*
* xt_condition
*
* Description: This module allows firewall rules to match using
* condition variables available through procfs.
*
* Authors:
* Stephane Ouellette <ouellettes@videotron.ca>, 2002-10-22
* Massimiliano Hofer <max@nucleus.it>, 2006-05-15
*
* This software is distributed under the terms of the GNU GPL.
*/
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/netfilter/x_tables.h>
#include <asm/uaccess.h>
#include "xt_condition.h"
#include "compat_xtables.h"
#ifndef CONFIG_PROC_FS
# error "proc file system support is required for this module"
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
# define proc_net init_net.proc_net
#endif
/* Defaults, these can be overridden on the module command-line. */
static unsigned int condition_list_perms = S_IRUGO | S_IWUSR;
static unsigned int condition_uid_perms = 0;
static unsigned int condition_gid_perms = 0;
MODULE_AUTHOR("Stephane Ouellette <ouellettes@videotron.ca>");
MODULE_AUTHOR("Massimiliano Hofer <max@nucleus.it>");
MODULE_DESCRIPTION("Allows rules to match against condition variables");
MODULE_LICENSE("GPL");
module_param(condition_list_perms, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(condition_list_perms, "permissions on /proc/net/nf_condition/* files");
module_param(condition_uid_perms, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(condition_uid_perms, "user owner of /proc/net/nf_condition/* files");
module_param(condition_gid_perms, uint, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(condition_gid_perms, "group owner of /proc/net/nf_condition/* files");
MODULE_ALIAS("ipt_condition");
MODULE_ALIAS("ip6t_condition");
struct condition_variable {
struct list_head list;
struct proc_dir_entry *status_proc;
unsigned int refcount;
bool enabled;
};
/* proc_lock is a user context only semaphore used for write access */
/* to the conditions' list. */
static DECLARE_MUTEX(proc_lock);
static LIST_HEAD(conditions_list);
static struct proc_dir_entry *proc_net_condition;
static int condition_proc_read(char __user *buffer, char **start, off_t offset,
int length, int *eof, void *data)
{
const struct condition_variable *var = data;
buffer[0] = var->enabled ? '1' : '0';
buffer[1] = '\n';
if (length >= 2)
*eof = true;
return 2;
}
static int condition_proc_write(struct file *file, const char __user *buffer,
unsigned long length, void *data)
{
struct condition_variable *var = data;
char newval;
if (length > 0) {
if (get_user(newval, buffer) != 0)
return -EFAULT;
/* Match only on the first character */
switch (newval) {
case '0':
var->enabled = false;
break;
case '1':
var->enabled = true;
break;
}
}
return length;
}
static bool
condition_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_condition_mtinfo *info = matchinfo;
const struct condition_variable *var = info->condvar;
bool x;
rcu_read_lock();
x = rcu_dereference(var->enabled);
rcu_read_unlock();
return x ^ info->invert;
}
static bool
condition_mt_check(const char *tablename, const void *entry,
const struct xt_match *match, void *matchinfo,
unsigned int hook_mask)
{
struct xt_condition_mtinfo *info = matchinfo;
struct condition_variable *var;
/* Forbid certain names */
if (*info->name == '\0' || *info->name == '.' ||
info->name[sizeof(info->name)-1] != '\0' ||
memchr(info->name, '/', sizeof(info->name)) != NULL) {
printk(KERN_INFO KBUILD_MODNAME ": name not allowed or too "
"long: \"%.*s\"\n", (unsigned int)sizeof(info->name),
info->name);
return false;
}
/*
* Let's acquire the lock, check for the condition and add it
* or increase the reference counter.
*/
if (down_interruptible(&proc_lock))
return false;
list_for_each_entry(var, &conditions_list, list) {
if (strcmp(info->name, var->status_proc->name) == 0) {
var->refcount++;
up(&proc_lock);
info->condvar = var;
return true;
}
}
/* At this point, we need to allocate a new condition variable. */
var = kmalloc(sizeof(struct condition_variable), GFP_KERNEL);
if (var == NULL) {
up(&proc_lock);
return false;
}
/* Create the condition variable's proc file entry. */
var->status_proc = create_proc_entry(info->name, condition_list_perms, proc_net_condition);
if (var->status_proc == NULL) {
kfree(var);
up(&proc_lock);
return false;
}
var->refcount = 1;
var->enabled = false;
var->status_proc->owner = THIS_MODULE;
var->status_proc->data = var;
wmb();
var->status_proc->read_proc = condition_proc_read;
var->status_proc->write_proc = condition_proc_write;
list_add_rcu(&var->list, &conditions_list);
var->status_proc->uid = condition_uid_perms;
var->status_proc->gid = condition_gid_perms;
up(&proc_lock);
info->condvar = var;
return true;
}
static void condition_mt_destroy(const struct xt_match *match, void *matchinfo)
{
const struct xt_condition_mtinfo *info = matchinfo;
struct condition_variable *var = info->condvar;
down(&proc_lock);
if (--var->refcount == 0) {
list_del_rcu(&var->list);
remove_proc_entry(var->status_proc->name, proc_net_condition);
up(&proc_lock);
/*
* synchronize_rcu() would be good enough, but
* synchronize_net() guarantees that no packet
* will go out with the old rule after
* succesful removal.
*/
synchronize_net();
kfree(var);
return;
}
up(&proc_lock);
}
static struct xt_match condition_mt_reg[] __read_mostly = {
{
.name = "condition",
.revision = 0,
.family = PF_INET,
.matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
.match = condition_mt,
.checkentry = condition_mt_check,
.destroy = condition_mt_destroy,
.me = THIS_MODULE,
},
{
.name = "condition",
.revision = 0,
.family = PF_INET6,
.matchsize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
.match = condition_mt,
.checkentry = condition_mt_check,
.destroy = condition_mt_destroy,
.me = THIS_MODULE,
},
};
static const char *const dir_name = "nf_condition";
static int __init condition_mt_init(void)
{
int ret;
proc_net_condition = proc_mkdir(dir_name, proc_net);
if (proc_net_condition == NULL)
return -EACCES;
ret = xt_register_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg));
if (ret < 0) {
remove_proc_entry(dir_name, proc_net);
return ret;
}
return 0;
}
static void __exit condition_mt_exit(void)
{
xt_unregister_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg));
remove_proc_entry(dir_name, proc_net);
}
module_init(condition_mt_init);
module_exit(condition_mt_exit);

16
extensions/xt_condition.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef _XT_CONDITION_H
#define _XT_CONDITION_H
enum {
CONDITION_NAME_LEN = 31,
};
struct xt_condition_mtinfo {
char name[CONDITION_NAME_LEN];
__u8 invert;
/* Used internally by the kernel */
void *condvar __attribute__((aligned(8)));
};
#endif /* _XT_CONDITION_H */

View File

@@ -0,0 +1,10 @@
config NETFILTER_XT_MATCH_GEOIP
tristate '"geoip" match support'
depends on NETFILTER_XTABLES
---help---
This option allows you to match a packet by its source or destination
country. Basically, you need a country's database containing all
subnets and associated countries.
For the complete procedure and understanding, read:
http://people.netfilter.org/acidfu/geoip/howto/geoip-HOWTO.html

View File

@@ -0,0 +1,6 @@
config NETFILTER_XT_MATCH_IPP2P
tristate '"ipp2p" match support'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
---help---
This option makes possible to match some P2P packets
therefore helps controlling such traffic.

890
extensions/xt_ipp2p.c Normal file
View File

@@ -0,0 +1,890 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <asm/unaligned.h>
#include "xt_ipp2p.h"
#include "compat_xtables.h"
//#define IPP2P_DEBUG_ARES
//#define IPP2P_DEBUG_SOUL
//#define IPP2P_DEBUG_WINMX
#define get_u8(X, O) (*(__u8 *)(X + O))
#define get_u16(X, O) get_unaligned((__u16 *)(X + O))
#define get_u32(X, O) get_unaligned((__u32 *)(X + O))
MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>");
MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
MODULE_LICENSE("GPL");
/* Search for UDP eDonkey/eMule/Kad commands */
static unsigned int
udp_search_edk(const unsigned char *haystack, const unsigned int packet_len)
{
const unsigned char *t = haystack;
t += 8;
switch (t[0]) {
case 0xe3:
/* edonkey */
switch (t[1]) {
/* client -> server status request */
case 0x96:
if (packet_len == 14)
return IPP2P_EDK * 100 + 50;
break;
/* server -> client status request */
case 0x97:
if (packet_len == 42)
return IPP2P_EDK * 100 + 51;
break;
/* server description request */
/* e3 2a ff f0 .. | size == 6 */
case 0xa2:
if (packet_len == 14 &&
get_u16(t, 2) == __constant_htons(0xfff0))
return IPP2P_EDK * 100 + 52;
break;
/* server description response */
/* e3 a3 ff f0 .. | size > 40 && size < 200 */
/*
case 0xa3:
return IPP2P_EDK * 100 + 53;
break;
*/
case 0x9a:
if (packet_len == 26)
return IPP2P_EDK * 100 + 54;
break;
case 0x92:
if (packet_len == 18)
return IPP2P_EDK * 100 + 55;
break;
}
break;
case 0xe4:
switch (t[1]) {
/* e4 20 .. | size == 43 */
case 0x20:
if (packet_len == 43 && t[2] != 0x00 && t[34] != 0x00)
return IPP2P_EDK * 100 + 60;
break;
/* e4 00 .. 00 | size == 35 ? */
case 0x00:
if (packet_len == 35 && t[26] == 0x00)
return IPP2P_EDK * 100 + 61;
break;
/* e4 10 .. 00 | size == 35 ? */
case 0x10:
if (packet_len == 35 && t[26] == 0x00)
return IPP2P_EDK * 100 + 62;
break;
/* e4 18 .. 00 | size == 35 ? */
case 0x18:
if (packet_len == 35 && t[26] == 0x00)
return IPP2P_EDK * 100 + 63;
break;
/* e4 52 .. | size = 44 */
case 0x52:
if (packet_len == 44)
return IPP2P_EDK * 100 + 64;
break;
/* e4 58 .. | size == 6 */
case 0x58:
if (packet_len == 14)
return IPP2P_EDK * 100 + 65;
break;
/* e4 59 .. | size == 2 */
case 0x59:
if (packet_len == 10)
return IPP2P_EDK * 100 + 66;
break;
/* e4 28 .. | packet_len == 52,77,102,127... */
case 0x28:
if ((packet_len - 52) % 25 == 0)
return IPP2P_EDK * 100 + 67;
break;
/* e4 50 xx xx | size == 4 */
case 0x50:
if (packet_len == 12)
return IPP2P_EDK * 100 + 68;
break;
/* e4 40 xx xx | size == 48 */
case 0x40:
if (packet_len == 56)
return IPP2P_EDK * 100 + 69;
break;
}
break;
}
return 0;
}
/* Search for UDP Gnutella commands */
static unsigned int
udp_search_gnu(const unsigned char *haystack, const unsigned int packet_len)
{
const unsigned char *t = haystack;
t += 8;
if (memcmp(t, "GND", 3) == 0)
return IPP2P_GNU * 100 + 51;
if (memcmp(t, "GNUTELLA ", 9) == 0)
return IPP2P_GNU * 100 + 52;
return 0;
}
/* Search for UDP KaZaA commands */
static unsigned int
udp_search_kazaa(const unsigned char *haystack, const unsigned int packet_len)
{
const unsigned char *t = haystack;
if (t[packet_len-1] == 0x00) {
t += packet_len - 6;
if (memcmp(t, "KaZaA", 5) == 0)
return IPP2P_KAZAA * 100 + 50;
}
return 0;
}
/* Search for UDP DirectConnect commands */
static unsigned int udp_search_directconnect(const unsigned char *haystack,
const unsigned int packet_len)
{
const unsigned char *t = haystack;
if (*(t + 8) == 0x24 && *(t + packet_len - 1) == 0x7c) {
t += 8;
if (memcmp(t, "SR ", 3) == 0)
return IPP2P_DC * 100 + 60;
if (memcmp(t, "Ping ", 5) == 0)
return IPP2P_DC * 100 + 61;
}
return 0;
}
/* Search for UDP BitTorrent commands */
static unsigned int
udp_search_bit(const unsigned char *haystack, const unsigned int packet_len)
{
switch (packet_len) {
case 24:
/* ^ 00 00 04 17 27 10 19 80 */
if (ntohl(get_u32(haystack, 8)) == 0x00000417 &&
ntohl(get_u32(haystack, 12)) == 0x27101980)
return IPP2P_BIT * 100 + 50;
break;
case 44:
if (get_u32(haystack, 16) == __constant_htonl(0x00000400) &&
get_u32(haystack, 36) == __constant_htonl(0x00000104))
return IPP2P_BIT * 100 + 51;
if (get_u32(haystack, 16) == __constant_htonl(0x00000400))
return IPP2P_BIT * 100 + 61;
break;
case 65:
if (get_u32(haystack, 16) == __constant_htonl(0x00000404) &&
get_u32(haystack, 36) == __constant_htonl(0x00000104))
return IPP2P_BIT * 100 + 52;
if (get_u32(haystack, 16) == __constant_htonl(0x00000404))
return IPP2P_BIT * 100 + 62;
break;
case 67:
if (get_u32(haystack, 16) == __constant_htonl(0x00000406) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
return (IPP2P_BIT * 100 + 53);
if (get_u32(haystack, 16) == __constant_htonl(0x00000406))
return (IPP2P_BIT * 100 + 63);
break;
case 211:
if (get_u32(haystack, 8) == __constant_htonl(0x00000405))
return IPP2P_BIT * 100 + 54;
break;
case 29:
if (get_u32(haystack, 8) == __constant_htonl(0x00000401))
return IPP2P_BIT * 100 + 55;
break;
case 52:
if (get_u32(haystack, 8) == __constant_htonl(0x00000827) &&
get_u32(haystack, 12) == __constant_htonl(0x37502950))
return IPP2P_BIT * 100 + 80;
break;
default:
/* this packet does not have a constant size */
if (packet_len >= 40 &&
get_u32(haystack, 16) == __constant_htonl(0x00000402) &&
get_u32(haystack, 36) == __constant_htonl(0x00000104))
return IPP2P_BIT * 100 + 56;
break;
}
/* some extra-bitcomet rules: "d1:" [a|r] "d2:id20:" */
if (packet_len > 30 && get_u8(haystack, 8) == 'd' &&
get_u8(haystack, 9) == '1' && get_u8(haystack, 10) == ':')
if (get_u8(haystack, 11) == 'a' ||
get_u8(haystack, 11) == 'r')
if (memcmp(haystack + 12, "d2:id20:", 8) == 0)
return IPP2P_BIT * 100 + 57;
#if 0
/* bitlord rules */
/* packetlen must be bigger than 40 */
/* first 4 bytes are zero */
if (packet_len > 40 && get_u32(haystack, 8) == 0x00000000) {
/* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/
if (get_u32(haystack, 12) == 0x00000000 &&
get_u32(haystack, 16) == 0x00010000 &&
get_u32(haystack, 24) == 0x00000000)
return IPP2P_BIT * 100 + 71;
/* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/
if (get_u32(haystack, 12) == 0x00000001 &&
get_u32(haystack, 16) == 0x000d0000 &&
get_u32(haystack, 24) == 0x00000000)
return IPP2P_BIT * 100 + 71;
}
#endif
return 0;
}
/* Search for Ares commands */
static unsigned int
search_ares(const unsigned char *payload, const unsigned int plen)
{
/* all ares packets start with */
if (payload[1] == 0 && plen - payload[0] == 3) {
switch (payload[2]) {
case 0x5a:
/* ares connect */
if (plen == 6 && payload[5] == 0x05)
return IPP2P_ARES * 100 + 1;
break;
case 0x09:
/*
* ares search, min 3 chars --> 14 bytes
* lets define a search can be up to 30 chars
* --> max 34 bytes
*/
if (plen >= 14 && plen <= 34)
return IPP2P_ARES * 100 + 1;
break;
#ifdef IPP2P_DEBUG_ARES
default:
printk(KERN_DEBUG "Unknown Ares command %x "
"recognized, len: %u\n",
(unsigned int)payload[2], plen);
#endif
}
}
#if 0
/* found connect packet: 03 00 5a 04 03 05 */
/* new version ares 1.8: 03 00 5a xx xx 05 */
if (plen == 6)
/* possible connect command */
if (payload[0] == 0x03 && payload[1] == 0x00 &&
payload[2] == 0x5a && payload[5] == 0x05)
return IPP2P_ARES * 100 + 1;
if (plen == 60)
/* possible download command*/
if (payload[59] == 0x0a && payload[58] == 0x0a)
if (memcmp(t, "PUSH SHA1:", 10) == 0)
/* found download command */
return IPP2P_ARES * 100 + 2;
#endif
return 0;
}
/* Search for SoulSeek commands */
static unsigned int
search_soul(const unsigned char *payload, const unsigned int plen)
{
/* match: xx xx xx xx | xx = sizeof(payload) - 4 */
if (get_u32(payload, 0) == plen - 4) {
const uint32_t m = get_u32(payload, 4);
/* match 00 yy yy 00, yy can be everything */
if (get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "0: Soulseek command 0x%x "
"recognized\n", get_u32(payload, 4));
#endif
return IPP2P_SOUL * 100 + 1;
}
/* next match: 01 yy 00 00 | yy can be everything */
if (get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "1: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 2;
}
/* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */
/* try to do this in an intelligent way */
/* get all small commandos */
switch (m) {
case 7:
case 9:
case 22:
case 23:
case 26:
case 28:
case 50:
case 51:
case 60:
case 91:
case 92:
case 1001:
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "2: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 3;
}
if (m > 0 && m < 6) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "3: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 4;
}
if (m > 12 && m < 19) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "4: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 5;
}
if (m > 34 && m < 38) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "5: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 6;
}
if (m > 39 && m < 47) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "6: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 7;
}
if (m > 61 && m < 70) {
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "7: Soulseek command 0x%x "
"recognized\n", get_u16(payload, 4));
#endif
return IPP2P_SOUL * 100 + 8;
}
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first "
"16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",
get_u32(payload, 4), get_u16(payload, 4) >> 16,
get_u8(payload, 4) >> 24);
#endif
}
/* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */
/* without size at the beginning !!! */
if (get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01) {
uint32_t y = get_u32(payload, 5);
/* we need 19 chars + string */
if (y + 19 <= plen) {
const unsigned char *w = payload + 9 + y;
if (get_u32(w, 0) == 0x01 &&
(get_u16(w, 4) == 0x4600 ||
get_u16(w, 4) == 0x5000) &&
get_u32(w, 6) == 0x00)
;
#ifdef IPP2P_DEBUG_SOUL
printk(KERN_DEBUG "Soulssek special client command recognized\n");
#endif
return IPP2P_SOUL * 100 + 9;
}
}
return 0;
}
/* Search for WinMX commands */
static unsigned int
search_winmx(const unsigned char *payload, const unsigned int plen)
{
if (plen == 4 && memcmp(payload, "SEND", 4) == 0)
return IPP2P_WINMX * 100 + 1;
if (plen == 3 && memcmp(payload, "GET", 3) == 0)
return IPP2P_WINMX * 100 + 2;
/*
if (packet_len < head_len + 10)
return 0;
*/
if (plen < 10)
return 0;
if (memcmp(payload, "SEND", 4) == 0 || memcmp(payload, "GET", 3) == 0) {
uint16_t c = 4;
const uint16_t end = plen - 2;
uint8_t count = 0;
while (c < end) {
if (payload[c] == 0x20 && payload[c+1] == 0x22) {
c++;
count++;
if (count >= 2)
return IPP2P_WINMX * 100 + 3;
}
c++;
}
}
if (plen == 149 && payload[0] == '8') {
#ifdef IPP2P_DEBUG_WINMX
printk(KERN_INFO "maybe WinMX\n");
#endif
if (get_u32(payload, 17) == 0 && get_u32(payload, 21) == 0 &&
get_u32(payload, 25) == 0 &&
// get_u32(payload, 33) == __constant_htonl(0x71182b1a) &&
// get_u32(payload, 37) == __constant_htonl(0x05050000) &&
// get_u32(payload, 133) == __constant_htonl(0x31097edf) &&
// get_u32(payload, 145) == __constant_htonl(0xdcb8f792))
get_u16(payload, 39) == 0 &&
get_u16(payload, 135) == __constant_htons(0x7edf) &&
get_u16(payload,147) == __constant_htons(0xf792))
{
#ifdef IPP2P_DEBUG_WINMX
printk(KERN_INFO "got WinMX\n");
#endif
return IPP2P_WINMX * 100 + 4;
}
}
return 0;
}
/* Search for appleJuice commands */
static unsigned int
search_apple(const unsigned char *payload, const unsigned int plen)
{
if (plen > 7 && payload[6] == 0x0d && payload[7] == 0x0a &&
memcmp(payload, "ajprot", 6) == 0)
return IPP2P_APPLE * 100;
return 0;
}
/* Search for BitTorrent commands */
static unsigned int
search_bittorrent(const unsigned char *payload, const unsigned int plen)
{
if (plen > 20) {
/* test for match 0x13+"BitTorrent protocol" */
if (payload[0] == 0x13)
if (memcmp(payload + 1, "BitTorrent protocol", 19) == 0)
return IPP2P_BIT * 100;
/*
* get tracker commandos, all starts with GET /
* then it can follow: scrape| announce
* and then ?hash_info=
*/
if (memcmp(payload, "GET /", 5) == 0) {
/* message scrape */
if (memcmp(payload + 5, "scrape?info_hash=", 17) == 0)
return IPP2P_BIT * 100 + 1;
/* message announce */
if (memcmp(payload + 5, "announce?info_hash=", 19) == 0)
return IPP2P_BIT * 100 + 2;
}
} else {
/* bitcomet encryptes the first packet, so we have to detect another
* one later in the flow */
/* first try failed, too many missdetections */
/*
if (size == 5 && get_u32(t, 0) == __constant_htonl(1) &&
t[4] < 3)
return IPP2P_BIT * 100 + 3;
*/
/* second try: block request packets */
if (plen == 17 &&
get_u32(payload, 0) == __constant_htonl(0x0d) &&
payload[4] == 0x06 &&
get_u32(payload,13) == __constant_htonl(0x4000))
return IPP2P_BIT * 100 + 3;
}
return 0;
}
/* check for Kazaa get command */
static unsigned int
search_kazaa(const unsigned char *payload, const unsigned int plen)
{
if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a &&
memcmp(payload, "GET /.hash=", 11) == 0)
return IPP2P_DATA_KAZAA * 100;
return 0;
}
/* check for gnutella get command */
static unsigned int
search_gnu(const unsigned char *payload, const unsigned int plen)
{
if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a) {
if (memcmp(payload, "GET /get/", 9) == 0)
return IPP2P_DATA_GNU * 100 + 1;
if (memcmp(payload, "GET /uri-res/", 13) == 0)
return IPP2P_DATA_GNU * 100 + 2;
}
return 0;
}
/* check for gnutella get commands and other typical data */
static unsigned int
search_all_gnu(const unsigned char *payload, const unsigned int plen)
{
if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a) {
if (memcmp(payload, "GNUTELLA CONNECT/", 17) == 0)
return IPP2P_GNU * 100 + 1;
if (memcmp(payload, "GNUTELLA/", 9) == 0)
return IPP2P_GNU * 100 + 2;
if (memcmp(payload, "GET /get/", 9) == 0 ||
memcmp(payload, "GET /uri-res/", 13) == 0)
{
uint16_t c = 8;
const uint16_t end = plen - 22;
while (c < end) {
if (payload[c] == 0x0a &&
payload[c+1] == 0x0d &&
(memcmp(&payload[c+2], "X-Gnutella-", 11) == 0 ||
memcmp(&payload[c+2], "X-Queue:", 8) == 0))
return IPP2P_GNU * 100 + 3;
c++;
}
}
}
return 0;
}
/* check for KaZaA download commands and other typical data */
static unsigned int
search_all_kazaa(const unsigned char *payload, const unsigned int plen)
{
if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a) {
if (memcmp(payload, "GIVE ", 5) == 0)
return IPP2P_KAZAA * 100 + 1;
if (memcmp(payload, "GET /", 5) == 0) {
uint16_t c = 8;
const uint16_t end = plen - 22;
while (c < end) {
if (payload[c] == 0x0a &&
payload[c+1] == 0x0d &&
(memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0 ||
memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0))
return IPP2P_KAZAA * 100 + 2;
c++;
}
}
}
return 0;
}
/* fast check for edonkey file segment transfer command */
static unsigned int
search_edk(const unsigned char *payload, const unsigned int plen)
{
if (payload[0] != 0xe3) {
return 0;
} else {
if (payload[5] == 0x47)
return IPP2P_DATA_EDK * 100;
else
return 0;
}
}
/* intensive but slower search for some edonkey packets including size-check */
static unsigned int
search_all_edk(const unsigned char *payload, const unsigned int plen)
{
if (payload[0] != 0xe3) {
return 0;
} else {
//t += head_len;
const uint16_t cmd = get_u16(payload, 1);
if (cmd == plen - 5) {
switch (payload[5]) {
case 0x01:
/* Client: hello or Server:hello */
return IPP2P_EDK * 100 + 1;
case 0x4c:
/* Client: Hello-Answer */
return IPP2P_EDK * 100 + 9;
}
}
return 0;
}
}
/* fast check for Direct Connect send command */
static unsigned int
search_dc(const unsigned char *payload, const unsigned int plen)
{
if (payload[0] != 0x24) {
return 0;
} else {
if (memcmp(&payload[1], "Send|", 5) == 0)
return IPP2P_DATA_DC * 100;
else
return 0;
}
}
/* intensive but slower check for all direct connect packets */
static unsigned int
search_all_dc(const unsigned char *payload, const unsigned int plen)
{
if (payload[0] == 0x24 && payload[plen-1] == 0x7c) {
const unsigned char *t = &payload[1];
/* Client-Hub-Protocol */
if (memcmp(t, "Lock ", 5) == 0)
return IPP2P_DC * 100 + 1;
/*
* Client-Client-Protocol, some are already recognized by
* client-hub (like lock)
*/
if (memcmp(t, "MyNick ", 7) == 0)
return IPP2P_DC * 100 + 38;
}
return 0;
}
/* check for mute */
static unsigned int
search_mute(const unsigned char *payload, const unsigned int plen)
{
if (plen == 209 || plen == 345 || plen == 473 || plen == 609 ||
plen == 1121) {
//printk(KERN_DEBUG "size hit: %u", size);
if (memcmp(payload,"PublicKey: ", 11) == 0) {
return IPP2P_MUTE * 100 + 0;
/*
if (memcmp(t + size - 14, "\x0aEndPublicKey\x0a", 14) == 0)
printk(KERN_DEBUG "end pubic key hit: %u", size);
*/
}
}
return 0;
}
/* check for xdcc */
static unsigned int
search_xdcc(const unsigned char *payload, const unsigned int plen)
{
/* search in small packets only */
if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a &&
payload[plen-2] == 0x0d && memcmp(payload, "PRIVMSG ", 8) == 0)
{
uint16_t x = 10;
const uint16_t end = plen - 13;
/*
* is seems to be a irc private massage, chedck for
* xdcc command
*/
while (x < end) {
if (payload[x] == ':')
if (memcmp(&payload[x+1], "xdcc send #", 11) == 0)
return IPP2P_XDCC * 100 + 0;
x++;
}
}
return 0;
}
/* search for waste */
static unsigned int
search_waste(const unsigned char *payload, const unsigned int plen)
{
if (plen >= 8 && memcmp(payload, "GET.sha1:", 9) == 0)
return IPP2P_WASTE * 100 + 0;
return 0;
}
static const struct {
unsigned int command;
unsigned int packet_len;
unsigned int (*function_name)(const unsigned char *, const unsigned int);
} matchlist[] = {
{IPP2P_EDK, 20, search_all_edk},
{IPP2P_DATA_KAZAA, 200, search_kazaa}, /* exp */
{IPP2P_DATA_EDK, 60, search_edk}, /* exp */
{IPP2P_DATA_DC, 26, search_dc}, /* exp */
{IPP2P_DC, 5, search_all_dc},
{IPP2P_DATA_GNU, 40, search_gnu}, /* exp */
{IPP2P_GNU, 5, search_all_gnu},
{IPP2P_KAZAA, 5, search_all_kazaa},
{IPP2P_BIT, 20, search_bittorrent},
{IPP2P_APPLE, 5, search_apple},
{IPP2P_SOUL, 5, search_soul},
{IPP2P_WINMX, 2, search_winmx},
{IPP2P_ARES, 5, search_ares},
{IPP2P_MUTE, 200, search_mute},
{IPP2P_WASTE, 5, search_waste},
{IPP2P_XDCC, 5, search_xdcc},
{0},
};
static const struct {
unsigned int command;
unsigned int packet_len;
unsigned int (*function_name)(const unsigned char *, const unsigned int);
} udp_list[] = {
{IPP2P_KAZAA, 14, udp_search_kazaa},
{IPP2P_BIT, 23, udp_search_bit},
{IPP2P_GNU, 11, udp_search_gnu},
{IPP2P_EDK, 9, udp_search_edk},
{IPP2P_DC, 12, udp_search_directconnect},
{0},
};
static bool
ipp2p_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 ipt_p2p_info *info = matchinfo;
const unsigned char *haystack;
const struct iphdr *ip = ip_hdr(skb);
bool p2p_result = false;
int i = 0;
unsigned int hlen = ntohs(ip->tot_len) - ip_hdrlen(skb); /* hlen = packet-data length */
/* must not be a fragment */
if (offset != 0) {
if (info->debug)
printk("IPP2P.match: offset found %i \n", offset);
return 0;
}
/* make sure that skb is linear */
if (skb_is_nonlinear(skb)) {
if (info->debug)
printk("IPP2P.match: nonlinear skb found\n");
return 0;
}
haystack = skb_network_header(skb) + ip_hdrlen(skb);
switch (ip->protocol) {
case IPPROTO_TCP: /* what to do with a TCP packet */
{
const struct tcphdr *tcph = tcp_hdr(skb);
if (tcph->fin) return 0; /* if FIN bit is set bail out */
if (tcph->syn) return 0; /* if SYN bit is set bail out */
if (tcph->rst) return 0; /* if RST bit is set bail out */
haystack += tcph->doff * 4; /* get TCP-Header-Size */
hlen -= tcph->doff * 4;
while (matchlist[i].command) {
if ((info->cmd & matchlist[i].command) == matchlist[i].command &&
hlen > matchlist[i].packet_len)
{
p2p_result = matchlist[i].function_name(haystack, hlen);
if (p2p_result) {
if (info->debug)
printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
return p2p_result;
}
}
i++;
}
return p2p_result;
}
case IPPROTO_UDP: /* what to do with an UDP packet */
{
const struct udphdr *udph = udp_hdr(skb);
while (udp_list[i].command) {
if ((info->cmd & udp_list[i].command) == udp_list[i].command &&
hlen > udp_list[i].packet_len)
{
p2p_result = udp_list[i].function_name(haystack, hlen);
if (p2p_result) {
if (info->debug)
printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
p2p_result, NIPQUAD(ip->saddr), ntohs(udph->source), NIPQUAD(ip->daddr), ntohs(udph->dest), hlen);
return p2p_result;
}
}
i++;
}
return p2p_result;
}
default:
return 0;
}
}
static struct xt_match ipp2p_mt_reg __read_mostly = {
.name = "ipp2p",
.revision = 0,
.family = AF_INET,
.match = ipp2p_mt,
.matchsize = sizeof(struct ipt_p2p_info),
.me = THIS_MODULE,
};
static int __init ipp2p_mt_init(void)
{
return xt_register_match(&ipp2p_mt_reg);
}
static void __exit ipp2p_mt_exit(void)
{
xt_unregister_match(&ipp2p_mt_reg);
}
module_init(ipp2p_mt_init);
module_exit(ipp2p_mt_exit);
MODULE_ALIAS("ipt_ipp2p");

46
extensions/xt_ipp2p.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef __IPT_IPP2P_H
#define __IPT_IPP2P_H
#define IPP2P_VERSION "0.8.1_rc1"
enum {
IPP2N_EDK,
IPP2N_DATA_KAZAA,
IPP2N_DATA_EDK,
IPP2N_DATA_DC,
IPP2N_DC,
IPP2N_DATA_GNU,
IPP2N_GNU,
IPP2N_KAZAA,
IPP2N_BIT,
IPP2N_APPLE,
IPP2N_SOUL,
IPP2N_WINMX,
IPP2N_ARES,
IPP2N_MUTE,
IPP2N_WASTE,
IPP2N_XDCC,
IPP2P_EDK = 1 << IPP2N_EDK,
IPP2P_DATA_KAZAA = 1 << IPP2N_DATA_KAZAA,
IPP2P_DATA_EDK = 1 << IPP2N_DATA_EDK,
IPP2P_DATA_DC = 1 << IPP2N_DATA_DC,
IPP2P_DC = 1 << IPP2N_DC,
IPP2P_DATA_GNU = 1 << IPP2N_DATA_GNU,
IPP2P_GNU = 1 << IPP2N_GNU,
IPP2P_KAZAA = 1 << IPP2N_KAZAA,
IPP2P_BIT = 1 << IPP2N_BIT,
IPP2P_APPLE = 1 << IPP2N_APPLE,
IPP2P_SOUL = 1 << IPP2N_SOUL,
IPP2P_WINMX = 1 << IPP2N_WINMX,
IPP2P_ARES = 1 << IPP2N_ARES,
IPP2P_MUTE = 1 << IPP2N_MUTE,
IPP2P_WASTE = 1 << IPP2N_WASTE,
IPP2P_XDCC = 1 << IPP2N_XDCC,
};
struct ipt_p2p_info {
int cmd;
int debug;
};
#endif //__IPT_IPP2P_H

View File

@@ -0,0 +1,8 @@
config NETFILTER_XT_MATCH_PORTSCAN
tristate '"portscan" target support'
depends on NETFILTER_XTABLES && NETFILTER_ADVANCED
---help---
The portscan match allows to match on the basic types of nmap
scans: Stealth Scan, SYN scan and connect scan. It can also match
"grab-only" connections, i.e. where data flows in only one
direction.

View File

@@ -1,13 +1,13 @@
# -*- Makefile -*-
#
# Only "build_${name}=m" (build extensions) or "build_${name}="
# (do not build) are valid!
#
build_CHAOS=m
build_DELUDE=m
build_ECHO=
build_IPMARK=m
build_LOGMARK=m
build_TARPIT=m
build_TEE=m
build_condition=m
build_geoip=m
build_ipp2p=m
build_portscan=m

13
xtables-addons.8.in Normal file
View File

@@ -0,0 +1,13 @@
.TH xtables-addons 8 2008-04-09
.SH NAME
Xtables-addons - additional extensions for iptables, ip6tables, etc.
.SH TARGETS
.\" @TARGET@
.SH MATCHES
.\" @MATCHES@
.SH "SEE ALSO"
\fBiptables\fP(8), \fBip6tables\fP(8)
.PP
For developers, the book "Writing your own Netfilter modules" at
http://jengelh.medozas.de/documents/Netfilter_Modules.pdf provides detailed
information on how to write such modules/extensions.