mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-20 19:44:56 +02:00
Compare commits
92 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
176e829e9f | ||
![]() |
d5ee47e9da | ||
![]() |
2c2527bdc4 | ||
![]() |
f931e34365 | ||
![]() |
f34be8445f | ||
![]() |
37e51dc44d | ||
![]() |
a680c1bcde | ||
![]() |
1060138f77 | ||
![]() |
03eeabb4bd | ||
![]() |
2c7b1d5330 | ||
![]() |
b63ac3be45 | ||
![]() |
4b8ec990b8 | ||
![]() |
59ef68fecc | ||
![]() |
3bf45b60b2 | ||
![]() |
e037035bd4 | ||
![]() |
d432d8041a | ||
![]() |
05359d1ab2 | ||
![]() |
29139c1414 | ||
![]() |
585cfd49ab | ||
![]() |
54f78ac3ef | ||
![]() |
376d41618c | ||
![]() |
01df89eb8b | ||
![]() |
a1d307e336 | ||
![]() |
0712d0fdca | ||
![]() |
3c8131b976 | ||
![]() |
569643ac8c | ||
![]() |
cc23d0a2e7 | ||
![]() |
c237fe2486 | ||
![]() |
edcbcee84e | ||
![]() |
44d6f47ad6 | ||
![]() |
20f6e47525 | ||
![]() |
e304252f4b | ||
![]() |
32f06cbedf | ||
![]() |
75f6f14aaf | ||
![]() |
7dd8b1a678 | ||
![]() |
f5f17a27c5 | ||
![]() |
c9579115c3 | ||
![]() |
586353342f | ||
![]() |
317a944fec | ||
![]() |
24dad368dd | ||
![]() |
7d0efafdb3 | ||
![]() |
330c1fe783 | ||
![]() |
72dc73e6a5 | ||
![]() |
d7c5473cf6 | ||
![]() |
0ee80e4147 | ||
![]() |
9778022c37 | ||
![]() |
2f6bc4c8cb | ||
![]() |
5fbc01b991 | ||
![]() |
b749916313 | ||
![]() |
818cd3b47e | ||
![]() |
8302faad44 | ||
![]() |
8fa47480f8 | ||
![]() |
463dceb709 | ||
![]() |
cd323565d7 | ||
![]() |
a39bfdf98e | ||
![]() |
cd7c8fc4fa | ||
![]() |
5d431b45f1 | ||
![]() |
f4c4208e75 | ||
![]() |
52a0ed7f15 | ||
![]() |
000d813171 | ||
![]() |
e45cb21ad6 | ||
![]() |
7aae90da5a | ||
![]() |
fd5321c7d8 | ||
![]() |
65eeb7f1f6 | ||
![]() |
848484c08c | ||
![]() |
8c58a61f52 | ||
![]() |
93c7d0ac47 | ||
![]() |
df063ab61c | ||
![]() |
d480ea2b1f | ||
![]() |
205a006ac9 | ||
![]() |
9f45aa737a | ||
![]() |
f1615a03f3 | ||
![]() |
3554e348bc | ||
![]() |
5fd97e9973 | ||
![]() |
10e3d8fe0d | ||
![]() |
6c06796e3b | ||
![]() |
98f943cb6c | ||
![]() |
cedbb110e1 | ||
![]() |
c703be229a | ||
![]() |
c338e8f827 | ||
![]() |
7c09f5db2f | ||
![]() |
6177839a04 | ||
![]() |
4d22fbd97a | ||
![]() |
dd42c61581 | ||
![]() |
2fbfbe6cd4 | ||
![]() |
ec9663f680 | ||
![]() |
75e88a7321 | ||
![]() |
1e34f02034 | ||
![]() |
b69d3de40e | ||
![]() |
c1592673fb | ||
![]() |
da011c8871 | ||
![]() |
f360ec3c85 |
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,16 +1,13 @@
|
||||
.*.cmd
|
||||
*.ko
|
||||
*.la
|
||||
*.lo
|
||||
*.loT
|
||||
*.mod.c
|
||||
*.o
|
||||
.deps
|
||||
.libs
|
||||
.tmp_versions
|
||||
Makefile
|
||||
Makefile.in
|
||||
Module.symvers
|
||||
|
||||
/downloads
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te*.cache
|
||||
@@ -23,3 +20,4 @@ Module.symvers
|
||||
/ltmain.sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
/xtables-addons.8
|
||||
|
11
INSTALL
11
INSTALL
@@ -12,9 +12,16 @@ in combination with the kernel's Kbuild system.
|
||||
Prerequirements
|
||||
===============
|
||||
|
||||
* xtables(-devel) 1.5.0
|
||||
* xtables(-devel) 1.5.2
|
||||
|
||||
* kernel-source >= 2.6.19 with prepared output directory
|
||||
* kernel-source >= 2.6.18 with prepared build/output directory
|
||||
|
||||
|
||||
Selecting extensions
|
||||
====================
|
||||
|
||||
You can edit the "mconfig" file to select what modules to build and
|
||||
install. By default, all modules are enabled.
|
||||
|
||||
|
||||
Configuring and compiling
|
||||
|
16
Makefile.am
16
Makefile.am
@@ -2,3 +2,19 @@
|
||||
|
||||
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};
|
||||
pushd ${top_srcdir} && git-archive --prefix=xtables-addons-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd;
|
||||
pushd /tmp/xtables-addons-${PACKAGE_VERSION} && ./autogen.sh && popd;
|
||||
tar -C /tmp -cjf xtables-addons-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root xtables-addons-${PACKAGE_VERSION}/;
|
||||
rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION};
|
||||
|
30
README
30
README
@@ -8,3 +8,33 @@ package.
|
||||
Xtables-addons is different from patch-o-matic in that you do not have
|
||||
to patch or recompile either kernel or Xtables(iptables). But please
|
||||
see the INSTALL file for the minimum requirements of this package.
|
||||
|
||||
|
||||
External extensions
|
||||
===================
|
||||
|
||||
The program "xa-download-more" can be used to download more extensions
|
||||
from 3rd parties into the source tree. The URLs are listed in the
|
||||
"sources" file. If the "sources" file contains an entry like
|
||||
|
||||
http://foobar.org/xa/
|
||||
|
||||
xa-download-more will inspect http://foobar.org/xa/xa-index.txt for files
|
||||
to download. That file may contain
|
||||
|
||||
foobar.tar.bz2
|
||||
|
||||
and xa-download-more will then retrieve and unpack
|
||||
http://foobar.org/xa/foobar.tar.bz2.
|
||||
|
||||
Files that should be contained in the tarball are an mconfig and Kbuild
|
||||
files to control building the extension, libxt_foobar.c for the userspace
|
||||
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
|
||||
extensions/xt_foobar.h
|
||||
|
16
configure.ac
16
configure.ac
@@ -1,5 +1,5 @@
|
||||
|
||||
AC_INIT([xtables-addons], [1.5.0])
|
||||
AC_INIT([xtables-addons], [1.5.4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PROG_INSTALL
|
||||
AM_INIT_AUTOMAKE
|
||||
@@ -9,7 +9,6 @@ AC_DISABLE_STATIC
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
kbuilddir="/lib/modules/$(uname -r)/build";
|
||||
ksourcedir="/lib/modules/$(uname -r)/source";
|
||||
AC_ARG_WITH([kbuild],
|
||||
AS_HELP_STRING([--with-kbuild=PATH],
|
||||
[Path to kernel build directory [[/lib/modules/CURRENT/build]]]),
|
||||
@@ -51,12 +50,17 @@ fi;
|
||||
regular_CFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \
|
||||
-D_REENTRANT -Wall -Waggregate-return -Wmissing-declarations \
|
||||
-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
|
||||
-Winline -pipe -DIPTABLES_VERSION=\\\"$PACKAGE_VERSION\\\" \
|
||||
-DXTABLES_LIBDIR=\\\"\${xtlibdir}\\\"";
|
||||
kinclude_CFLAGS="-I $kbuilddir/include -I $ksourcedir/include";
|
||||
-Winline -pipe -DXTABLES_LIBDIR=\\\"\${xtlibdir}\\\"";
|
||||
kinclude_CFLAGS="";
|
||||
if [[ -n "$kbuilddir" ]]; then
|
||||
kinclude_CFLAGS="$kinclude_CFLAGS -I $kbuilddir/include";
|
||||
fi;
|
||||
if [[ -n "$ksourcedir" ]]; then
|
||||
kinclude_CFLAGS="$kinclude_CFLAGS -I $ksourcedir/include";
|
||||
fi;
|
||||
|
||||
AC_SUBST([regular_CFLAGS xtables_CFLAGS kinclude_CFLAGS])
|
||||
AC_SUBST([kbuilddir])
|
||||
AC_SUBST([ksourcedir])
|
||||
AC_SUBST([xtlibdir])
|
||||
AC_OUTPUT([Makefile extensions/Makefile])
|
||||
AC_OUTPUT([Makefile extensions/GNUmakefile])
|
||||
|
13
extensions/.gitignore
vendored
Normal file
13
extensions/.gitignore
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
.*.cmd
|
||||
.*.d
|
||||
.manpages.lst
|
||||
.tmp_versions
|
||||
*.ko
|
||||
*.mod.c
|
||||
*.so
|
||||
*.oo
|
||||
GNUmakefile
|
||||
Module.symvers
|
||||
modules.order
|
||||
matches.man
|
||||
targets.man
|
129
extensions/GNUmakefile.in
Normal file
129
extensions/GNUmakefile.in
Normal file
@@ -0,0 +1,129 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
top_srcdir := @top_srcdir@
|
||||
srcdir := @srcdir@
|
||||
abstop_srcdir := $(shell readlink -e ${top_srcdir})
|
||||
abssrcdir := $(shell readlink -e ${srcdir})
|
||||
|
||||
ifeq (${abstop_srcdir},)
|
||||
$(error Path resolution of ${top_srcdir} failed)
|
||||
endif
|
||||
ifeq (${abssrcdir},)
|
||||
$(error Path resolution of ${srcdir} failed)
|
||||
endif
|
||||
|
||||
prefix := @prefix@
|
||||
exec_prefix := @exec_prefix@
|
||||
libdir := @libdir@
|
||||
libexecdir := @libexecdir@
|
||||
xtlibdir := @xtlibdir@
|
||||
kbuilddir := @kbuilddir@
|
||||
|
||||
CC := @CC@
|
||||
CCLD := ${CC}
|
||||
CFLAGS := @CFLAGS@
|
||||
LDFLAGS := @LDFLAGS@
|
||||
regular_CFLAGS := @regular_CFLAGS@
|
||||
kinclude_CFLAGS := @kinclude_CFLAGS@
|
||||
xtables_CFLAGS := @xtables_CFLAGS@
|
||||
|
||||
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS}
|
||||
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
|
||||
|
||||
ifeq (${V},)
|
||||
AM_LIBTOOL_SILENT = --silent
|
||||
AM_VERBOSE_CC = @echo " CC " $@;
|
||||
AM_VERBOSE_CCLD = @echo " CCLD " $@;
|
||||
AM_VERBOSE_CXX = @echo " CXX " $@;
|
||||
AM_VERBOSE_CXXLD = @echo " CXXLD " $@;
|
||||
AM_VERBOSE_AR = @echo " AR " $@;
|
||||
AM_VERBOSE_GEN = @echo " GEN " $@;
|
||||
endif
|
||||
|
||||
#
|
||||
# Wildcard module list
|
||||
#
|
||||
include ${top_srcdir}/mconfig
|
||||
-include ${top_srcdir}/mconfig.*
|
||||
include ${srcdir}/Mbuild
|
||||
|
||||
|
||||
#
|
||||
# Building blocks
|
||||
#
|
||||
targets := ${obj-m}
|
||||
targets_install := ${obj-m}
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
.PHONY: all install clean distclean FORCE
|
||||
|
||||
all: modules ${targets} matches.man targets.man
|
||||
|
||||
install: modules_install ${targets_install}
|
||||
@mkdir -p "${DESTDIR}${xtlibdir}";
|
||||
install -pm0755 ${targets_install} "${DESTDIR}${xtlibdir}/";
|
||||
|
||||
clean: clean_modules
|
||||
rm -f *.oo *.so;
|
||||
|
||||
distclean: clean
|
||||
rm -f .*.d .manpages.lst;
|
||||
|
||||
-include .*.d
|
||||
|
||||
|
||||
#
|
||||
# Call out to kbuild
|
||||
#
|
||||
.PHONY: modules modules_install clean_modules
|
||||
|
||||
modules:
|
||||
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} modules;
|
||||
|
||||
modules_install:
|
||||
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} INSTALL_MOD_PATH=${DESTDIR} modules_install;
|
||||
|
||||
clean_modules:
|
||||
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} clean;
|
||||
|
||||
|
||||
#
|
||||
# Shared libraries
|
||||
#
|
||||
lib%.so: lib%.oo
|
||||
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
|
||||
|
||||
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})
|
@@ -1,6 +1,20 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
obj-m += xt_LOGMARK.o
|
||||
obj-m += xt_TARPIT.o
|
||||
obj-m += xt_TEE.o
|
||||
obj-m += compat_xtables.o
|
||||
include ${XA_TOPSRCDIR}/mconfig
|
||||
-include ${XA_TOPSRCDIR}/mconfig.*
|
||||
|
||||
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
|
||||
|
@@ -1,36 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
abssrcdir = $(shell readlink -f ${srcdir})
|
||||
|
||||
regular_CFLAGS := @regular_CFLAGS@
|
||||
xtables_CFLAGS := @xtables_CFLAGS@
|
||||
kinclude_CFLAGS := @kinclude_CFLAGS@
|
||||
AM_CFLAGS = ${regular_CFLAGS} -I ${top_srcdir}/include \
|
||||
${xtables_CFLAGS} ${kinclude_CFLAGS} \
|
||||
-D_INIT=$*_init
|
||||
AM_LDFLAGS = -module -avoid-version
|
||||
xtlib_LTLIBRARIES = \
|
||||
libxt_LOGMARK.la \
|
||||
libxt_TARPIT.la \
|
||||
libxt_TEE.la
|
||||
|
||||
#
|
||||
# Call out to kbuild
|
||||
#
|
||||
.PHONY: modules modules_install clean_modules
|
||||
|
||||
all-local: modules
|
||||
|
||||
install-exec-local: modules_install
|
||||
|
||||
clean-local: clean_modules
|
||||
|
||||
modules:
|
||||
make -C ${kbuilddir} M=${abssrcdir} modules;
|
||||
|
||||
modules_install:
|
||||
make -C ${kbuilddir} M=${abssrcdir} INSTALL_MOD_PATH=${DESTDIR} modules_install;
|
||||
|
||||
clean_modules:
|
||||
make -C ${kbuilddir} M=${abssrcdir} clean;
|
11
extensions/Mbuild
Normal file
11
extensions/Mbuild
Normal 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
|
33
extensions/compat_skbuff.h
Normal file
33
extensions/compat_skbuff.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#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
|
||||
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
|
||||
#endif
|
||||
|
||||
#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 */
|
@@ -1,3 +1,4 @@
|
||||
#include <linux/ip.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -5,10 +6,21 @@
|
||||
#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_skbuff.h"
|
||||
#include "compat_xtnu.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && \
|
||||
LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
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,
|
||||
const struct xt_match *cm, const void *matchinfo, int offset,
|
||||
@@ -24,9 +36,17 @@ static int xtnu_match_run(const struct sk_buff *skb,
|
||||
*hotdrop = lo_drop;
|
||||
return lo_ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static int xtnu_match_check(const char *table, const void *entry,
|
||||
const struct xt_match *cm, void *matchinfo, unsigned int matchinfosize,
|
||||
unsigned int hook_mask)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_match_check(const char *table, const void *entry,
|
||||
const struct xt_match *cm, void *matchinfo, unsigned int hook_mask)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
{
|
||||
struct xtnu_match *nm = xtcompat_numatch(cm);
|
||||
|
||||
@@ -36,15 +56,24 @@ static int xtnu_match_check(const char *table, const void *entry,
|
||||
return true;
|
||||
return nm->checkentry(table, entry, nm, matchinfo, hook_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo,
|
||||
unsigned int matchinfosize)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
{
|
||||
struct xtnu_match *nm = xtcompat_numatch(cm);
|
||||
|
||||
if (nm != NULL && nm->destroy != NULL)
|
||||
nm->destroy(nm, matchinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
int xtnu_register_match(struct xtnu_match *nt)
|
||||
{
|
||||
struct xt_match *ct;
|
||||
@@ -114,53 +143,63 @@ void xtnu_unregister_matches(struct xtnu_match *nt, unsigned int num)
|
||||
EXPORT_SYMBOL_GPL(xtnu_unregister_matches);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt == NULL)
|
||||
return false;
|
||||
if (nt->checkentry == NULL)
|
||||
/* this is valid, just like if there was no function */
|
||||
return true;
|
||||
return nt->checkentry(table, entry, nt, targinfo, hook_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 23)
|
||||
static bool xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt == NULL)
|
||||
return false;
|
||||
if (nt->checkentry == NULL)
|
||||
/* this is valid, just like if there was no function */
|
||||
return true;
|
||||
return nt->checkentry(table, entry, nt, targinfo, hook_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && \
|
||||
LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static unsigned int xtnu_target_run(struct sk_buff **pskb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
unsigned int hooknum, const struct xt_target *ct, const void *targinfo,
|
||||
void *userdata)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
static unsigned int xtnu_target_run(struct sk_buff **pskb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
unsigned int hooknum, const struct xt_target *ct, const void *targinfo)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt != NULL && nt->target != NULL)
|
||||
return nt->target(*pskb, in, out, hooknum, nt, targinfo);
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static int xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo,
|
||||
unsigned int targinfosize, unsigned int hook_mask)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
static bool xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt == NULL)
|
||||
return false;
|
||||
if (nt->checkentry == NULL)
|
||||
/* this is valid, just like if there was no function */
|
||||
return true;
|
||||
return nt->checkentry(table, entry, nt, targinfo, hook_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo,
|
||||
unsigned int targinfosize)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt != NULL && nt->destroy != NULL)
|
||||
nt->destroy(nt, targinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
int xtnu_register_target(struct xtnu_target *nt)
|
||||
{
|
||||
struct xt_target *ct;
|
||||
@@ -230,12 +269,127 @@ 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_UNSPEC] = "x",
|
||||
[AF_INET] = "ip",
|
||||
[AF_INET6] = "ip6",
|
||||
#ifdef AF_ARP
|
||||
[AF_ARP] = "arp",
|
||||
#elif defined(NF_ARP) && NF_ARP != AF_UNSPEC
|
||||
[NF_ARP] = "arp",
|
||||
#endif
|
||||
};
|
||||
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)
|
||||
{
|
||||
return ip_route_me_harder(&skb, addr_type);
|
||||
struct sk_buff *nskb = skb;
|
||||
int ret;
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
ret = ip_route_me_harder(&skb);
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
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)
|
||||
static int __xtnu_ip_local_out(struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
iph->tot_len = htons(skb->len);
|
||||
ip_send_check(iph);
|
||||
return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
|
||||
skb->dst->dev, dst_output);
|
||||
}
|
||||
|
||||
int xtnu_ip_local_out(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __xtnu_ip_local_out(skb);
|
||||
if (likely(err == 1))
|
||||
err = dst_output(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_local_out);
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
static int __xtnu_ip_local_out(struct sk_buff **pskb)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(*pskb);
|
||||
|
||||
iph->tot_len = htons((*pskb)->len);
|
||||
ip_send_check(iph);
|
||||
return nf_hook(PF_INET, NF_IP_LOCAL_OUT, pskb, NULL,
|
||||
(*pskb)->dst->dev, dst_output);
|
||||
}
|
||||
|
||||
int xtnu_ip_local_out(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __xtnu_ip_local_out(&skb);
|
||||
if (likely(err == 1))
|
||||
err = dst_output(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_local_out);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
||||
int xtnu_ip_route_output_key(void *net, struct rtable **rp, struct flowi *flp)
|
||||
{
|
||||
return ip_route_output_flow(rp, flp, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
int xtnu_neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
|
||||
{
|
||||
unsigned int hh_alen;
|
||||
|
||||
read_lock_bh(&hh->hh_lock);
|
||||
hh_alen = HH_DATA_ALIGN(hh->hh_len);
|
||||
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
|
||||
read_unlock_bh(&hh->hh_lock);
|
||||
skb_push(skb, hh->hh_len);
|
||||
return hh->hh_output(skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_neigh_hh_output);
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -2,17 +2,50 @@
|
||||
#define _XTABLES_COMPAT_H 1
|
||||
|
||||
#include <linux/version.h>
|
||||
#include "compat_skbuff.h"
|
||||
#include "compat_xtnu.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
|
||||
# warning Kernels below 2.6.18 not supported.
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
||||
# if !defined(CONFIG_NF_CONNTRACK_MARK) || !defined(CONFIG_NF_CONNTRACK_SECMARK)
|
||||
# warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK or CONFIG_NF_CONNTRACK_SECMARK are not (please enable).
|
||||
# endif
|
||||
# include <net/netfilter/nf_conntrack.h>
|
||||
#elif defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
# if !defined(CONFIG_IP_NF_CONNTRACK_MARK) || !defined(CONFIG_IP_NF_CONNTRACK_SECMARK)
|
||||
# warning You have CONFIG_IP_NF_CONNTRACK enabled, but CONFIG_IP_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_SECMARK are not (please enable).
|
||||
# endif
|
||||
# include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
# define nf_conn ip_conntrack
|
||||
# define nf_ct_get ip_conntrack_get
|
||||
# define nf_conntrack_untracked ip_conntrack_untracked
|
||||
#else
|
||||
# warning You need either CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK.
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
# define neigh_hh_output xtnu_neigh_hh_output
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
||||
# define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING
|
||||
# define NF_INET_LOCAL_IN NF_IP_LOCAL_IN
|
||||
# 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 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, 24)
|
||||
# include "compat_nfinetaddr.h"
|
||||
#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)
|
||||
@@ -26,12 +59,13 @@
|
||||
#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
|
||||
# define xt_unregister_targets xtnu_unregister_targets
|
||||
#endif
|
||||
|
||||
#include "compat_xtnu.h"
|
||||
#define xt_request_find_match xtnu_request_find_match
|
||||
|
||||
#endif /* _XTABLES_COMPAT_H */
|
||||
|
@@ -5,8 +5,16 @@
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
typedef _Bool bool;
|
||||
enum { false = 0, true = 1, };
|
||||
#endif
|
||||
|
||||
struct flowi;
|
||||
struct hh_cache;
|
||||
struct module;
|
||||
struct net_device;
|
||||
struct rtable;
|
||||
struct sk_buff;
|
||||
|
||||
struct xtnu_match {
|
||||
@@ -59,8 +67,11 @@ 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_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 *);
|
||||
extern int xtnu_register_matches(struct xtnu_match *, unsigned int);
|
||||
extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int);
|
||||
@@ -68,5 +79,8 @@ 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);
|
||||
extern int xtnu_neigh_hh_output(struct hh_cache *, struct sk_buff *);
|
||||
|
||||
#endif /* _COMPAT_XTNU_H */
|
||||
|
113
extensions/libxt_CHAOS.c
Normal file
113
extensions/libxt_CHAOS.c
Normal 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 = XTABLES_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);
|
||||
}
|
18
extensions/libxt_CHAOS.man
Normal file
18
extensions/libxt_CHAOS.man
Normal 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\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.
|
47
extensions/libxt_DELUDE.c
Normal file
47
extensions/libxt_DELUDE.c
Normal 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 = XTABLES_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);
|
||||
}
|
4
extensions/libxt_DELUDE.man
Normal file
4
extensions/libxt_DELUDE.man
Normal 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.
|
34
extensions/libxt_ECHO.c
Normal file
34
extensions/libxt_ECHO.c
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
|
||||
static void echo_tg_help(void)
|
||||
{
|
||||
printf("ECHO takes no options\n\n");
|
||||
}
|
||||
|
||||
static int echo_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void echo_tg_check(unsigned int flags)
|
||||
{
|
||||
}
|
||||
|
||||
static struct xtables_target echo_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "ECHO",
|
||||
.family = AF_UNSPEC,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.help = echo_tg_help,
|
||||
.parse = echo_tg_parse,
|
||||
.final_check = echo_tg_check,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_target(&echo_tg_reg);
|
||||
}
|
179
extensions/libxt_IPMARK.c
Normal file
179
extensions/libxt_IPMARK.c
Normal 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);
|
||||
}
|
56
extensions/libxt_IPMARK.man
Normal file
56
extensions/libxt_IPMARK.man
Normal 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
|
@@ -6,19 +6,13 @@
|
||||
#include "xt_LOGMARK.h"
|
||||
|
||||
enum {
|
||||
F_LEVEL = 1 << 0,
|
||||
F_PREFIX = 1 << 1,
|
||||
F_NFMARK = 1 << 2,
|
||||
F_CTMARK = 1 << 3,
|
||||
F_SECMARK = 1 << 4,
|
||||
F_LEVEL = 1 << 0,
|
||||
F_PREFIX = 1 << 1,
|
||||
};
|
||||
|
||||
static const struct option logmark_tg_opts[] = {
|
||||
{.name = "log-level", .has_arg = true, .val = 'l'},
|
||||
{.name = "log-prefix", .has_arg = true, .val = 'p'},
|
||||
{.name = "log-nfmark", .has_arg = false, .val = 'n'},
|
||||
{.name = "log-ctmark", .has_arg = false, .val = 'c'},
|
||||
{.name = "log-secmark", .has_arg = false, .val = 's'},
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -28,9 +22,6 @@ static void logmark_tg_help(void)
|
||||
"LOGMARK target options:\n"
|
||||
" --log-level level Level of logging (numeric, 0-8)\n"
|
||||
" --log-prefix prefix Prefix log messages with this string\n"
|
||||
" --log-nfmark Log the packet mark\n"
|
||||
" --log-ctmark Log the connection mark\n"
|
||||
" --log-secmark Log the security mark of the packet\n"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,27 +63,6 @@ logmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
strncpy(info->prefix, optarg, sizeof(info->prefix));
|
||||
*flags |= F_PREFIX;
|
||||
return true;
|
||||
|
||||
case 'n': /* --log-nfmark */
|
||||
param_act(P_ONLY_ONCE, "LOGMARK", "--log-nfmark", *flags & F_NFMARK);
|
||||
param_act(P_NO_INVERT, "LOGMARK", "--log-nfmark", invert);
|
||||
info->flags |= XT_LOGMARK_NFMARK;
|
||||
*flags |= F_NFMARK;
|
||||
return true;
|
||||
|
||||
case 'c': /* --log-ctmark */
|
||||
param_act(P_ONLY_ONCE, "LOGMARK", "--log-ctmark", *flags & F_CTMARK);
|
||||
param_act(P_NO_INVERT, "LOGMARK", "--log-ctmark", invert);
|
||||
info->flags |= XT_LOGMARK_CTMARK;
|
||||
*flags |= F_CTMARK;
|
||||
return true;
|
||||
|
||||
case 's': /* --log-secmark */
|
||||
param_act(P_ONLY_ONCE, "LOGMARK", "--log-secmark", *flags & F_SECMARK);
|
||||
param_act(P_NO_INVERT, "LOGMARK", "--log-secmark", invert);
|
||||
info->flags |= XT_LOGMARK_SECMARK;
|
||||
*flags |= F_SECMARK;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -103,14 +73,7 @@ logmark_tg_print(const void *ip, const struct xt_entry_target *target,
|
||||
{
|
||||
const struct xt_logmark_tginfo *info = (void *)target->data;
|
||||
|
||||
printf("LOGMARK level %u prefix \"%s\"", info->level, info->prefix);
|
||||
if (info->flags & XT_LOGMARK_NFMARK)
|
||||
printf(" nfmark");
|
||||
if (info->flags & XT_LOGMARK_CTMARK)
|
||||
printf(" ctmark");
|
||||
if (info->flags & XT_LOGMARK_SECMARK)
|
||||
printf(" secmark");
|
||||
printf("; ");
|
||||
printf("LOGMARK level %u prefix \"%s\" ", info->level, info->prefix);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -122,34 +85,13 @@ logmark_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
printf("--log-level %u ", info->level);
|
||||
if (*info->prefix != '\0')
|
||||
printf("--log-prefix \"%s\" ", info->prefix);
|
||||
if (info->flags & XT_LOGMARK_NFMARK)
|
||||
printf("--log-nfmark ");
|
||||
if (info->flags & XT_LOGMARK_CTMARK)
|
||||
printf("--log-ctmark ");
|
||||
if (info->flags & XT_LOGMARK_SECMARK)
|
||||
printf("--log-secmark ");
|
||||
}
|
||||
|
||||
static struct xtables_target logmark_tg_reg = {
|
||||
.version = IPTABLES_VERSION,
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "LOGMARK",
|
||||
.revision = 0,
|
||||
.family = AF_INET,
|
||||
.size = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
|
||||
.help = logmark_tg_help,
|
||||
.init = logmark_tg_init,
|
||||
.parse = logmark_tg_parse,
|
||||
.print = logmark_tg_print,
|
||||
.save = logmark_tg_save,
|
||||
.extra_opts = logmark_tg_opts,
|
||||
};
|
||||
|
||||
static struct xtables_target logmark_tg6_reg = {
|
||||
.version = IPTABLES_VERSION,
|
||||
.name = "LOGMARK",
|
||||
.revision = 0,
|
||||
.family = AF_INET6,
|
||||
.family = AF_UNSPEC,
|
||||
.size = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
|
||||
.help = logmark_tg_help,
|
||||
@@ -164,5 +106,4 @@ void _init(void);
|
||||
void _init(void)
|
||||
{
|
||||
xtables_register_target(&logmark_tg_reg);
|
||||
xtables_register_target(&logmark_tg6_reg);
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ static void tarpit_tg_check(unsigned int flags)
|
||||
}
|
||||
|
||||
static struct xtables_target tarpit_tg_reg = {
|
||||
.version = IPTABLES_VERSION,
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "TARPIT",
|
||||
.family = AF_INET,
|
||||
.size = XT_ALIGN(0),
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
@@ -94,7 +94,7 @@ static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
|
||||
static struct xtables_target tee_tg_reg = {
|
||||
.name = "TEE",
|
||||
.version = IPTABLES_VERSION,
|
||||
.version = XTABLES_VERSION,
|
||||
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
|
||||
.help = tee_tg_help,
|
||||
|
105
extensions/libxt_condition.c
Normal file
105
extensions/libxt_condition.c
Normal 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);
|
||||
}
|
4
extensions/libxt_condition.man
Normal file
4
extensions/libxt_condition.man
Normal 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.
|
278
extensions/libxt_geoip.c
Normal file
278
extensions/libxt_geoip.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/* Shared library add-on to iptables to add geoip match support.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright (c) 2004, 2005, 2006, 2007, 2008
|
||||
* Samuel Jean & Nicolas Bouliane
|
||||
*
|
||||
* For comments, bugs or suggestions, please contact
|
||||
* Samuel Jean <peejix@people.netfilter.org>
|
||||
* Nicolas Bouliane <peejix@people.netfilter.org>
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <ctype.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_geoip.h"
|
||||
#define GEOIP_DB_DIR "/var/geoip"
|
||||
|
||||
static void geoip_help(void)
|
||||
{
|
||||
printf (
|
||||
"geoip match options:\n"
|
||||
"[!] --src-cc, --source-country country[,country...]\n"
|
||||
" Match packet coming from (one of) the specified country(ies)\n"
|
||||
"[!] --dst-cc, --destination-country country[,country...]\n"
|
||||
" Match packet going to (one of) the specified country(ies)\n"
|
||||
"\n"
|
||||
"NOTE: The country is inputed by its ISO3166 code.\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
static struct option geoip_opts[] = {
|
||||
{.name = "dst-cc", .has_arg = true, .val = '2'},
|
||||
{.name = "destination-country", .has_arg = true, .val = '2'},
|
||||
{.name = "src-cc", .has_arg = true, .val = '1'},
|
||||
{.name = "source-country", .has_arg = true, .val = '1'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count)
|
||||
{
|
||||
struct geoip_subnet *subnets;
|
||||
struct stat sb;
|
||||
char buf[256];
|
||||
int fd;
|
||||
|
||||
/* Use simple integer vector files */
|
||||
#if __BYTE_ORDER == _BIG_ENDIAN
|
||||
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv0", code);
|
||||
#else
|
||||
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv0", code);
|
||||
#endif
|
||||
|
||||
if ((fd = open(buf, O_RDONLY)) < 0) {
|
||||
fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
|
||||
exit_error(OTHER_PROBLEM, "Could not read geoip database");
|
||||
}
|
||||
|
||||
fstat(fd, &sb);
|
||||
if (sb.st_size % sizeof(struct geoip_subnet) != 0)
|
||||
exit_error(OTHER_PROBLEM, "Database file %s seems to be "
|
||||
"corrupted", buf);
|
||||
subnets = malloc(sb.st_size);
|
||||
if (subnets == NULL)
|
||||
exit_error(OTHER_PROBLEM, "geoip: insufficient memory");
|
||||
read(fd, subnets, sb.st_size);
|
||||
close(fd);
|
||||
*count = sb.st_size / sizeof(struct geoip_subnet);
|
||||
return subnets;
|
||||
}
|
||||
|
||||
static struct geoip_country_user *geoip_load_cc(const char *code,
|
||||
unsigned short cc)
|
||||
{
|
||||
struct geoip_country_user *ginfo;
|
||||
ginfo = malloc(sizeof(struct geoip_country_user));
|
||||
|
||||
if (!ginfo)
|
||||
return NULL;
|
||||
|
||||
ginfo->subnets = (unsigned long)geoip_get_subnets(code, &ginfo->count);
|
||||
ginfo->cc = cc;
|
||||
|
||||
return ginfo;
|
||||
}
|
||||
|
||||
static u_int16_t
|
||||
check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
|
||||
{
|
||||
u_int8_t i;
|
||||
u_int16_t cc_int16;
|
||||
|
||||
if (strlen(cc) != 2) /* Country must be 2 chars long according
|
||||
to the ISO3166 standard */
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: invalid country code '%s'", cc);
|
||||
|
||||
// Verification will fail if chars aren't uppercased.
|
||||
// Make sure they are..
|
||||
for (i = 0; i < 2; i++)
|
||||
if (isalnum(cc[i]) != 0)
|
||||
cc[i] = toupper(cc[i]);
|
||||
else
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: invalid country code '%s'", cc);
|
||||
|
||||
/* Convert chars into a single 16 bit integer.
|
||||
* FIXME: This assumes that a country code is
|
||||
* exactly 2 chars long. If this is
|
||||
* going to change someday, this whole
|
||||
* match will need to be rewritten, anyway.
|
||||
* - SJ */
|
||||
cc_int16 = (cc[0] << 8) | cc[1];
|
||||
|
||||
// Check for presence of value in cc_used
|
||||
for (i = 0; i < count; i++)
|
||||
if (cc_int16 == cc_used[i])
|
||||
return 0; // Present, skip it!
|
||||
|
||||
return cc_int16;
|
||||
}
|
||||
|
||||
static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
|
||||
union geoip_country_group *mem)
|
||||
{
|
||||
char *buffer, *cp, *next;
|
||||
u_int8_t i, count = 0;
|
||||
u_int16_t cctmp;
|
||||
|
||||
buffer = strdup(ccstr);
|
||||
if (!buffer)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"geoip: insufficient memory available");
|
||||
|
||||
for (cp = buffer, i = 0; cp && i < XT_GEOIP_MAX; cp = next, i++)
|
||||
{
|
||||
next = strchr(cp, ',');
|
||||
if (next) *next++ = '\0';
|
||||
|
||||
if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
|
||||
if ((mem[count++].user = (unsigned long)geoip_load_cc(cp, cctmp)) == 0)
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"geoip: insufficient memory available");
|
||||
cc[count-1] = cctmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (cp)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: too many countries specified");
|
||||
free(buffer);
|
||||
|
||||
if (count == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: don't know what happened");
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_match **match)
|
||||
{
|
||||
struct xt_geoip_match_info *info = (void *)(*match)->data;
|
||||
|
||||
switch(c) {
|
||||
case '1':
|
||||
// Ensure that XT_GEOIP_SRC *OR* XT_GEOIP_DST haven't been used yet.
|
||||
if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: only use --source-country *OR* --destination-country once!");
|
||||
|
||||
*flags |= XT_GEOIP_SRC;
|
||||
break;
|
||||
|
||||
case '2':
|
||||
// Ensure that XT_GEOIP_SRC *OR* XT_GEOIP_DST haven't been used yet.
|
||||
if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: only use --source-country *OR* --destination-country once!");
|
||||
|
||||
*flags |= XT_GEOIP_DST;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (invert)
|
||||
*flags |= XT_GEOIP_INV;
|
||||
|
||||
info->count = parse_geoip_cc(argv[optind-1], info->cc, info->mem);
|
||||
info->flags = *flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
geoip_final_check(unsigned int flags)
|
||||
{
|
||||
if (!flags)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"geoip: missing arguments");
|
||||
}
|
||||
|
||||
static void
|
||||
geoip_print(const void *ip, const struct xt_entry_match *match, int numeric)
|
||||
{
|
||||
const struct xt_geoip_match_info *info = (void*)match->data;
|
||||
|
||||
u_int8_t i;
|
||||
|
||||
if (info->flags & XT_GEOIP_SRC)
|
||||
printf("Source ");
|
||||
else
|
||||
printf("Destination ");
|
||||
|
||||
if (info->count > 1)
|
||||
printf("countries: ");
|
||||
else
|
||||
printf("country: ");
|
||||
|
||||
if (info->flags & XT_GEOIP_INV)
|
||||
printf("! ");
|
||||
|
||||
for (i = 0; i < info->count; i++)
|
||||
printf("%s%c%c", i ? "," : "", COUNTRY(info->cc[i]));
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
static void
|
||||
geoip_save(const void *ip, const struct xt_entry_match *match)
|
||||
{
|
||||
const struct xt_geoip_match_info *info = (void *)match->data;
|
||||
u_int8_t i;
|
||||
|
||||
if (info->flags & XT_GEOIP_INV)
|
||||
printf("! ");
|
||||
|
||||
if (info->flags & XT_GEOIP_SRC)
|
||||
printf("--source-country ");
|
||||
else
|
||||
printf("--destination-country ");
|
||||
|
||||
for (i = 0; i < info->count; i++)
|
||||
printf("%s%c%c", i ? "," : "", COUNTRY(info->cc[i]));
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
static struct xtables_match geoip_match = {
|
||||
.family = AF_INET,
|
||||
.name = "geoip",
|
||||
.version = XTABLES_VERSION,
|
||||
.size = XT_ALIGN(sizeof(struct xt_geoip_match_info)),
|
||||
.userspacesize = XT_ALIGN(offsetof(struct xt_geoip_match_info, mem)),
|
||||
.help = geoip_help,
|
||||
.parse = geoip_parse,
|
||||
.final_check = geoip_final_check,
|
||||
.print = geoip_print,
|
||||
.save = geoip_save,
|
||||
.extra_opts = geoip_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_match(&geoip_match);
|
||||
}
|
16
extensions/libxt_geoip.man
Normal file
16
extensions/libxt_geoip.man
Normal file
@@ -0,0 +1,16 @@
|
||||
Match a packet by its source or destination country.
|
||||
.TP
|
||||
[\fB!\fP] \fB--src-cc\fP, \fB--source-country\fP \fIcountry\fP[\fB,\fP\fIcountry\fP\fB...\fP]
|
||||
Match packet coming from (one of) the specified country(ies)
|
||||
.TP
|
||||
[\fB!\fP] \fB--dst-cc\fP, \fB--destination-country\fP \fIcountry\fP[\fB,\fP\fIcountry\fP\fB...\fP]
|
||||
Match packet going to (one of) the specified country(ies)
|
||||
.TP
|
||||
NOTE:
|
||||
The country is inputed by its ISO3166 code.
|
||||
.P
|
||||
The extra files you will need is the binary database files. They are generated
|
||||
from a country-subnet database with the geoip_csv_iv0.pl tool, available at
|
||||
http://jengelh.hopto.org/files/geoip/ . The files MUST be moved to /var/geoip/
|
||||
as the shared library is statically looking for this pathname (e.g.
|
||||
/var/geoip/LE/de.iv0).
|
238
extensions/libxt_ipp2p.c
Normal file
238
extensions/libxt_ipp2p.c
Normal 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);
|
||||
}
|
40
extensions/libxt_ipp2p.man
Normal file
40
extensions/libxt_ipp2p.man
Normal 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!
|
121
extensions/libxt_portscan.c
Normal file
121
extensions/libxt_portscan.c
Normal 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 = XTABLES_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);
|
||||
}
|
27
extensions/libxt_portscan.man
Normal file
27
extensions/libxt_portscan.man
Normal 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.
|
9
extensions/xt_CHAOS.Kconfig
Normal file
9
extensions/xt_CHAOS.Kconfig
Normal 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.
|
210
extensions/xt_CHAOS.c
Normal file
210
extensions/xt_CHAOS.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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, 18)
|
||||
destiny->target(&skb, in, out, hooknum, destiny, NULL, NULL);
|
||||
#elif 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, 18)
|
||||
return xt_reject->target(&skb, in, out, hooknum,
|
||||
target->__compat_target, &reject_params, NULL);
|
||||
#elif 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
14
extensions/xt_CHAOS.h
Normal 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 */
|
6
extensions/xt_DELUDE.Kconfig
Normal file
6
extensions/xt_DELUDE.Kconfig
Normal 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.
|
181
extensions/xt_DELUDE.c
Normal file
181
extensions/xt_DELUDE.c
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 20)
|
||||
tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), niph->saddr,
|
||||
niph->daddr, csum_partial((char *)tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
#else
|
||||
tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
|
||||
niph->daddr, csum_partial((char *)tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
#endif
|
||||
|
||||
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");
|
6
extensions/xt_ECHO.Kconfig
Normal file
6
extensions/xt_ECHO.Kconfig
Normal 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.
|
131
extensions/xt_ECHO.c
Normal file
131
extensions/xt_ECHO.c
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* ECHO target (RFC 862)
|
||||
* Copyright © CC Computer Consultants GmbH, 2008
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 or 3 as published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/ip.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
# include <linux/netfilter_bridge.h>
|
||||
#endif
|
||||
#include <net/ip.h>
|
||||
#include "compat_xtables.h"
|
||||
|
||||
static unsigned int echo_tg4(struct sk_buff *oldskb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
unsigned int hooknum, const struct xt_target *target, const void *targinfo)
|
||||
{
|
||||
const struct udphdr *oldudp;
|
||||
const struct iphdr *oldip;
|
||||
struct udphdr *newudp, oldudp_buf;
|
||||
struct iphdr *newip;
|
||||
struct sk_buff *newskb;
|
||||
unsigned int addr_type, data_len;
|
||||
void *payload;
|
||||
|
||||
/* This allows us to do the copy operation in fewer lines of code. */
|
||||
if (skb_linearize(oldskb) < 0)
|
||||
return NF_DROP;
|
||||
|
||||
oldip = ip_hdr(oldskb);
|
||||
oldudp = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
|
||||
sizeof(struct udphdr), &oldudp_buf);
|
||||
if (oldudp == NULL)
|
||||
return NF_DROP;
|
||||
if (ntohs(oldudp->len) <= sizeof(struct udphdr))
|
||||
return NF_DROP;
|
||||
|
||||
newskb = alloc_skb(LL_MAX_HEADER + sizeof(struct iphdr) +
|
||||
ntohs(oldudp->len), GFP_ATOMIC);
|
||||
if (newskb == NULL)
|
||||
return NF_DROP;
|
||||
|
||||
skb_reserve(newskb, LL_MAX_HEADER);
|
||||
skb_reset_network_header(newskb);
|
||||
newip = (void *)skb_put(newskb, sizeof(struct iphdr));
|
||||
newip->version = 4;
|
||||
newip->ihl = sizeof(struct iphdr) / 4;
|
||||
newip->tos = oldip->tos;
|
||||
newip->id = 0;
|
||||
newip->frag_off = htons(IP_DF);
|
||||
newip->protocol = oldip->protocol;
|
||||
newip->check = 0;
|
||||
newip->saddr = oldip->daddr;
|
||||
newip->daddr = oldip->saddr;
|
||||
|
||||
newudp = (void *)skb_put(newskb, sizeof(struct udphdr));
|
||||
newudp->source = oldudp->dest;
|
||||
newudp->dest = oldudp->source;
|
||||
newudp->len = oldudp->len;
|
||||
newudp->check = 0;
|
||||
|
||||
data_len = htons(oldudp->len) - sizeof(*oldudp);
|
||||
payload = skb_header_pointer(oldskb, ip_hdrlen(oldskb) +
|
||||
sizeof(*oldudp), data_len, NULL);
|
||||
memcpy(skb_put(newskb, data_len), payload, data_len);
|
||||
|
||||
addr_type = RTN_UNSPEC;
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
if (hooknum != NF_INET_FORWARD || (newskb->nf_bridge != NULL &&
|
||||
newskb->nf_bridge->mask & BRNF_BRIDGED))
|
||||
#else
|
||||
if (hooknum != NF_INET_FORWARD)
|
||||
#endif
|
||||
addr_type = RTN_LOCAL;
|
||||
|
||||
/* ip_route_me_harder expects skb->dst to be set */
|
||||
dst_hold(oldskb->dst);
|
||||
newskb->dst = oldskb->dst;
|
||||
|
||||
if (ip_route_me_harder(newskb, addr_type) < 0)
|
||||
goto free_nskb;
|
||||
|
||||
newip->ttl = dst_metric(newskb->dst, RTAX_HOPLIMIT);
|
||||
newskb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
/* "Never happens" (?) */
|
||||
if (newskb->len > dst_mtu(newskb->dst))
|
||||
goto free_nskb;
|
||||
|
||||
nf_ct_attach(newskb, oldskb);
|
||||
ip_local_out(newskb);
|
||||
return NF_DROP;
|
||||
|
||||
free_nskb:
|
||||
kfree_skb(newskb);
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
static struct xt_target echo_tg_reg __read_mostly = {
|
||||
.name = "ECHO",
|
||||
.revision = 0,
|
||||
.family = AF_INET,
|
||||
.proto = IPPROTO_UDP,
|
||||
.table = "filter",
|
||||
.target = echo_tg4,
|
||||
.targetsize = XT_ALIGN(0),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init echo_tg_init(void)
|
||||
{
|
||||
return xt_register_target(&echo_tg_reg);
|
||||
}
|
||||
|
||||
static void __exit echo_tg_exit(void)
|
||||
{
|
||||
return xt_unregister_target(&echo_tg_reg);
|
||||
}
|
||||
|
||||
module_init(echo_tg_init);
|
||||
module_exit(echo_tg_exit);
|
||||
MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
|
||||
MODULE_DESCRIPTION("Xtables: ECHO diagnosis target");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_ECHO");
|
12
extensions/xt_IPMARK.Kconfig
Normal file
12
extensions/xt_IPMARK.Kconfig
Normal 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
106
extensions/xt_IPMARK.c
Normal 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
16
extensions/xt_IPMARK.h
Normal 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 */
|
@@ -11,36 +11,73 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netfilter/nf_conntrack_common.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
//#include <net/netfilter/nf_conntrack.h>
|
||||
#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,
|
||||
const struct xt_target *target, const void *targinfo)
|
||||
{
|
||||
const struct xt_logmark_tginfo *info = targinfo;
|
||||
const struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
bool prev = false;
|
||||
|
||||
printk("<%u>%.*s", info->level, sizeof(info->prefix), info->prefix);
|
||||
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);
|
||||
|
||||
if (info->flags & XT_LOGMARK_NFMARK)
|
||||
printk(" nfmark=0x%x", skb->mark);
|
||||
if (info->flags & XT_LOGMARK_CTMARK) {
|
||||
const struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
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) {
|
||||
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
|
||||
} else {
|
||||
printk(" ct=0x%p ctmark=0x%x ctstate=", ct, ct->mark);
|
||||
ctinfo %= IP_CT_IS_REPLY;
|
||||
if (ctinfo == IP_CT_NEW)
|
||||
printk("NEW");
|
||||
else if (ctinfo == IP_CT_ESTABLISHED)
|
||||
printk("ESTABLISHED");
|
||||
else if (ctinfo == IP_CT_RELATED)
|
||||
printk("RELATED");
|
||||
if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
|
||||
printk(",SNAT");
|
||||
if (test_bit(IPS_DST_NAT_BIT, &ct->status))
|
||||
printk(",DNAT");
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct == NULL)
|
||||
printk(" ctmark=X");
|
||||
else
|
||||
printk(" ctmark=0x%x", ct->mark);
|
||||
printk(" ctstatus=");
|
||||
if (ct->status & IPS_EXPECTED) {
|
||||
printk("EXPECTED");
|
||||
prev = true;
|
||||
}
|
||||
if (ct->status & IPS_SEEN_REPLY)
|
||||
printk("%s""SEEN_REPLY", prev++ ? "," : "");
|
||||
if (ct->status & IPS_ASSURED)
|
||||
printk("%s""ASSURED", prev++ ? "," : "");
|
||||
if (ct->status & IPS_CONFIRMED)
|
||||
printk("%s""CONFIRMED", prev++ ? "," : "");
|
||||
}
|
||||
if (info->flags & XT_LOGMARK_SECMARK)
|
||||
printk(" secmark=0x%x", skb->secmark);
|
||||
printk("\n");
|
||||
|
||||
printk("\n");
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,9 @@
|
||||
#ifndef _LINUX_NETFILTER_XT_LOGMARK_TARGET_H
|
||||
#define _LINUX_NETFILTER_XT_LOGMARK_TARGET_H 1
|
||||
|
||||
enum {
|
||||
XT_LOGMARK_NFMARK = 1 << 0,
|
||||
XT_LOGMARK_CTMARK = 1 << 1,
|
||||
XT_LOGMARK_SECMARK = 1 << 2,
|
||||
};
|
||||
|
||||
struct xt_logmark_tginfo {
|
||||
char prefix[14];
|
||||
u_int8_t level;
|
||||
u_int8_t flags;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_NETFILTER_XT_LOGMARK_TARGET_H */
|
||||
|
@@ -90,7 +90,7 @@ static inline void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
|
||||
/* This packet will not be the same as the other: clear nf fields */
|
||||
nf_reset(nskb);
|
||||
nskb->mark = 0;
|
||||
skb_nfmark(nskb) = 0;
|
||||
skb_init_secmark(nskb);
|
||||
|
||||
skb_shinfo(nskb)->gso_size = 0;
|
||||
@@ -132,9 +132,15 @@ static inline void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
|
||||
/* Adjust TCP checksum */
|
||||
tcph->check = 0;
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 20)
|
||||
tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), niph->saddr,
|
||||
niph->daddr, csum_partial((char *)tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
#else
|
||||
tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
|
||||
niph->daddr, csum_partial((char *)tcph,
|
||||
sizeof(struct tcphdr), 0));
|
||||
#endif
|
||||
|
||||
/* Set DF, id = 0 */
|
||||
niph->frag_off = htons(IP_DF);
|
||||
|
@@ -62,7 +62,7 @@ static bool tee_routing(struct sk_buff *skb,
|
||||
};
|
||||
|
||||
/* Trying to route the packet using the standard routing table. */
|
||||
err = ip_route_output_key(&rt, &fl);
|
||||
err = ip_route_output_key(&init_net, &rt, &fl);
|
||||
if (err != 0) {
|
||||
if (net_ratelimit())
|
||||
pr_debug(KBUILD_MODNAME
|
||||
@@ -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.
|
||||
|
6
extensions/xt_condition.Kconfig
Normal file
6
extensions/xt_condition.Kconfig
Normal 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
259
extensions/xt_condition.c
Normal 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
16
extensions/xt_condition.h
Normal 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 */
|
10
extensions/xt_geoip.Kconfig
Normal file
10
extensions/xt_geoip.Kconfig
Normal 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
|
246
extensions/xt_geoip.c
Normal file
246
extensions/xt_geoip.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/* iptables kernel module for the geoip match
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright (c) 2004, 2005, 2006, 2007, 2008
|
||||
* Samuel Jean & Nicolas Bouliane
|
||||
*/
|
||||
#include <linux/ip.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "xt_geoip.h"
|
||||
#include "compat_xtables.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Nicolas Bouliane");
|
||||
MODULE_AUTHOR("Samuel Jean");
|
||||
MODULE_DESCRIPTION("xtables module for geoip match");
|
||||
MODULE_ALIAS("ipt_geoip");
|
||||
|
||||
struct geoip_country_kernel {
|
||||
struct list_head list;
|
||||
struct geoip_subnet *subnets;
|
||||
atomic_t ref;
|
||||
unsigned int count;
|
||||
unsigned short cc;
|
||||
};
|
||||
|
||||
static LIST_HEAD(geoip_head);
|
||||
static DEFINE_SPINLOCK(geoip_lock);
|
||||
|
||||
static struct geoip_country_kernel *
|
||||
geoip_add_node(const struct geoip_country_user __user *umem_ptr)
|
||||
{
|
||||
struct geoip_country_user umem;
|
||||
struct geoip_country_kernel *p;
|
||||
struct geoip_subnet *s;
|
||||
|
||||
if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0)
|
||||
return NULL;
|
||||
|
||||
p = kmalloc(sizeof(struct geoip_country_kernel), GFP_KERNEL);
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
p->count = umem.count;
|
||||
p->cc = umem.cc;
|
||||
|
||||
s = vmalloc(p->count * sizeof(struct geoip_subnet));
|
||||
if (s == NULL)
|
||||
goto free_p;
|
||||
if (copy_from_user(s, (const void __user *)(unsigned long)umem.subnets,
|
||||
p->count * sizeof(struct geoip_subnet)) != 0)
|
||||
goto free_s;
|
||||
|
||||
p->subnets = s;
|
||||
atomic_set(&p->ref, 1);
|
||||
INIT_LIST_HEAD(&p->list);
|
||||
|
||||
spin_lock(&geoip_lock);
|
||||
list_add_tail_rcu(&p->list, &geoip_head);
|
||||
spin_unlock(&geoip_lock);
|
||||
|
||||
return p;
|
||||
|
||||
free_s:
|
||||
vfree(s);
|
||||
free_p:
|
||||
kfree(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void geoip_try_remove_node(struct geoip_country_kernel *p)
|
||||
{
|
||||
spin_lock(&geoip_lock);
|
||||
if (!atomic_dec_and_test(&p->ref)) {
|
||||
spin_unlock(&geoip_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* So now am unlinked or the only one alive, right ?
|
||||
* What are you waiting ? Free up some memory!
|
||||
*/
|
||||
list_del_rcu(&p->list);
|
||||
spin_unlock(&geoip_lock);
|
||||
|
||||
synchronize_rcu();
|
||||
vfree(p->subnets);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
static struct geoip_country_kernel *find_node(unsigned short cc)
|
||||
{
|
||||
struct geoip_country_kernel *p;
|
||||
spin_lock(&geoip_lock);
|
||||
|
||||
list_for_each_entry_rcu(p, &geoip_head, list)
|
||||
if (p->cc == cc) {
|
||||
atomic_inc(&p->ref);
|
||||
spin_unlock(&geoip_lock);
|
||||
return p;
|
||||
}
|
||||
|
||||
spin_unlock(&geoip_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool geoip_bsearch(const struct geoip_subnet *range,
|
||||
uint32_t addr, int lo, int hi)
|
||||
{
|
||||
int mid;
|
||||
|
||||
if (hi < lo)
|
||||
return false;
|
||||
mid = (lo + hi) / 2;
|
||||
if (range[mid].begin <= addr && addr <= range[mid].end)
|
||||
return true;
|
||||
if (range[mid].begin > addr)
|
||||
return geoip_bsearch(range, addr, lo, mid - 1);
|
||||
else if (range[mid].end < addr)
|
||||
return geoip_bsearch(range, addr, mid + 1, hi);
|
||||
|
||||
WARN_ON(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xt_geoip_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_geoip_match_info *info = matchinfo;
|
||||
const struct geoip_country_kernel *node;
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
unsigned int i;
|
||||
uint32_t ip;
|
||||
|
||||
if (info->flags & XT_GEOIP_SRC)
|
||||
ip = ntohl(iph->saddr);
|
||||
else
|
||||
ip = ntohl(iph->daddr);
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < info->count; i++) {
|
||||
if ((node = info->mem[i].kernel) == NULL) {
|
||||
printk(KERN_ERR "xt_geoip: what the hell ?? '%c%c' isn't loaded into memory... skip it!\n",
|
||||
COUNTRY(info->cc[i]));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (geoip_bsearch(node->subnets, ip, 0, node->count)) {
|
||||
rcu_read_unlock();
|
||||
return !(info->flags & XT_GEOIP_INV);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
return info->flags & XT_GEOIP_INV;
|
||||
}
|
||||
|
||||
static bool xt_geoip_mt_checkentry(const char *table, const void *entry,
|
||||
const struct xt_match *match, void *matchinfo, unsigned int hook_mask)
|
||||
{
|
||||
struct xt_geoip_match_info *info = matchinfo;
|
||||
struct geoip_country_kernel *node;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < info->count; i++) {
|
||||
node = find_node(info->cc[i]);
|
||||
if (node == NULL)
|
||||
if ((node = geoip_add_node((const void __user *)(unsigned long)info->mem[i].user)) == NULL) {
|
||||
printk(KERN_ERR
|
||||
"xt_geoip: unable to load '%c%c' into memory\n",
|
||||
COUNTRY(info->cc[i]));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Overwrite the now-useless pointer info->mem[i] with
|
||||
* a pointer to the node's kernelspace structure.
|
||||
* This avoids searching for a node in the match() and
|
||||
* destroy() functions.
|
||||
*/
|
||||
info->mem[i].kernel = node;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void xt_geoip_mt_destroy(const struct xt_match *match, void *matchinfo)
|
||||
{
|
||||
struct xt_geoip_match_info *info = matchinfo;
|
||||
struct geoip_country_kernel *node;
|
||||
unsigned int i;
|
||||
|
||||
/* This entry has been removed from the table so
|
||||
* decrease the refcount of all countries it is
|
||||
* using.
|
||||
*/
|
||||
|
||||
for (i = 0; i < info->count; i++)
|
||||
if ((node = info->mem[i].kernel) != NULL) {
|
||||
/* Free up some memory if that node isn't used
|
||||
* anymore. */
|
||||
geoip_try_remove_node(node);
|
||||
}
|
||||
else
|
||||
/* Something strange happened. There's no memory allocated for this
|
||||
* country. Please send this bug to the mailing list. */
|
||||
printk(KERN_ERR
|
||||
"xt_geoip: What happened peejix ? What happened acidfu ?\n"
|
||||
"xt_geoip: please report this bug to the maintainers\n");
|
||||
}
|
||||
|
||||
static struct xt_match xt_geoip_match __read_mostly = {
|
||||
.family = AF_INET,
|
||||
.name = "geoip",
|
||||
.match = xt_geoip_mt,
|
||||
.checkentry = xt_geoip_mt_checkentry,
|
||||
.destroy = xt_geoip_mt_destroy,
|
||||
.matchsize = sizeof(struct xt_geoip_match_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init xt_geoip_mt_init(void)
|
||||
{
|
||||
return xt_register_match(&xt_geoip_match);
|
||||
}
|
||||
|
||||
static void __exit xt_geoip_mt_fini(void)
|
||||
{
|
||||
xt_unregister_match(&xt_geoip_match);
|
||||
}
|
||||
|
||||
module_init(xt_geoip_mt_init);
|
||||
module_exit(xt_geoip_mt_fini);
|
54
extensions/xt_geoip.h
Normal file
54
extensions/xt_geoip.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* ipt_geoip.h header file for libipt_geoip.c and ipt_geoip.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Copyright (c) 2004, 2005, 2006, 2007, 2008
|
||||
*
|
||||
* Samuel Jean
|
||||
* Nicolas Bouliane
|
||||
*/
|
||||
#ifndef _LINUX_NETFILTER_XT_GEOIP_H
|
||||
#define _LINUX_NETFILTER_XT_GEOIP_H 1
|
||||
|
||||
enum {
|
||||
XT_GEOIP_SRC = 1 << 0, /* Perform check on Source IP */
|
||||
XT_GEOIP_DST = 1 << 1, /* Perform check on Destination IP */
|
||||
XT_GEOIP_INV = 1 << 2, /* Negate the condition */
|
||||
|
||||
XT_GEOIP_MAX = 15, /* Maximum of countries */
|
||||
};
|
||||
|
||||
/* Yup, an address range will be passed in with host-order */
|
||||
struct geoip_subnet {
|
||||
__u32 begin;
|
||||
__u32 end;
|
||||
};
|
||||
|
||||
struct geoip_country_user {
|
||||
aligned_u64 subnets;
|
||||
__u32 count;
|
||||
__u16 cc;
|
||||
};
|
||||
|
||||
struct geoip_country_kernel;
|
||||
|
||||
union geoip_country_group {
|
||||
aligned_u64 user;
|
||||
struct geoip_country_kernel *kernel;
|
||||
};
|
||||
|
||||
struct xt_geoip_match_info {
|
||||
__u8 flags;
|
||||
__u8 count;
|
||||
__u16 cc[XT_GEOIP_MAX];
|
||||
|
||||
/* Used internally by the kernel */
|
||||
union geoip_country_group mem[XT_GEOIP_MAX];
|
||||
};
|
||||
|
||||
#define COUNTRY(cc) (cc >> 8), (cc & 0x00FF)
|
||||
|
||||
#endif /* _LINUX_NETFILTER_XT_GEOIP_H */
|
6
extensions/xt_ipp2p.Kconfig
Normal file
6
extensions/xt_ipp2p.Kconfig
Normal 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
890
extensions/xt_ipp2p.c
Normal 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
46
extensions/xt_ipp2p.h
Normal 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
|
8
extensions/xt_portscan.Kconfig
Normal file
8
extensions/xt_portscan.Kconfig
Normal 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.
|
262
extensions/xt_portscan.c
Normal file
262
extensions/xt_portscan.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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_conntrack.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_nfmark(skb) & 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;
|
||||
skb_nfmark(skb) = (skb_nfmark(skb) & ~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
8
extensions/xt_portscan.h
Normal 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 */
|
13
mconfig
Normal file
13
mconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- Makefile -*-
|
||||
#
|
||||
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
|
83
xa-download-more
Executable file
83
xa-download-more
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use HTTP::Request;
|
||||
use LWP::UserAgent;
|
||||
use strict;
|
||||
|
||||
&main(\@ARGV);
|
||||
|
||||
sub main ($)
|
||||
{
|
||||
local *FH;
|
||||
|
||||
if (!-d "downloads") {
|
||||
if (!mkdir("downloads")) {
|
||||
die "Could not create downloads/ directory";
|
||||
}
|
||||
}
|
||||
|
||||
open(FH, "<sources");
|
||||
while (defined($_ = <FH>)) {
|
||||
chomp $_;
|
||||
$_ =~ s/#.*//gs;
|
||||
$_ =~ s/^\s+|\s+$//gs;
|
||||
if (length($_) == 0) {
|
||||
next;
|
||||
}
|
||||
&process_index($_);
|
||||
}
|
||||
|
||||
close FH;
|
||||
}
|
||||
|
||||
sub process_index ($)
|
||||
{
|
||||
my $top = shift @_;
|
||||
my($agent, $res, $url);
|
||||
local *FH;
|
||||
|
||||
$agent = LWP::UserAgent->new();
|
||||
$agent->env_proxy();
|
||||
|
||||
$url = &slash_remove("$top/xa-index.txt");
|
||||
print " GET $url\n";
|
||||
$res = $agent->get($url);
|
||||
if (!$res->is_success()) {
|
||||
print STDERR " `-> ", $res->status_line(), "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
foreach my $ext (split(/\s+/, $res->content())) {
|
||||
my($ex_url, $ex_res);
|
||||
|
||||
$ex_url = &slash_remove("$top/$ext");
|
||||
print " GET $ex_url\n";
|
||||
|
||||
$ex_res = $agent->mirror($ex_url, "downloads/$ext");
|
||||
if ($ex_res->code() == 304) {
|
||||
# "Not modified" = up to date
|
||||
next;
|
||||
}
|
||||
if (!$ex_res->is_success()) {
|
||||
print STDERR " `-> ", $ex_res->status_line(), "\n";
|
||||
next;
|
||||
}
|
||||
|
||||
print " UNPACK downloads/$ext\n";
|
||||
system "tar", "-xjf", "downloads/$ext";
|
||||
}
|
||||
}
|
||||
|
||||
sub slash_remove ($)
|
||||
{
|
||||
my $s = shift @_;
|
||||
$s =~ s{(\w+://)(.*)}{$1.&slash_remove2($2)}eg;
|
||||
return $s;
|
||||
}
|
||||
|
||||
sub slash_remove2 ($)
|
||||
{
|
||||
my $s = shift @_;
|
||||
$s =~ s{/+}{/}g;
|
||||
return $s;
|
||||
}
|
13
xtables-addons.8.in
Normal file
13
xtables-addons.8.in
Normal 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.
|
Reference in New Issue
Block a user