mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-20 19:44:56 +02:00
Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0959b60b07 | ||
![]() |
02a65e0af8 | ||
![]() |
84624f66cb | ||
![]() |
5f098b2c5a | ||
![]() |
086c8def12 | ||
![]() |
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 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,17 +1,11 @@
|
||||
.*.cmd
|
||||
*.ko
|
||||
*.la
|
||||
*.lo
|
||||
*.loT
|
||||
*.mod.c
|
||||
*.o
|
||||
.deps
|
||||
.libs
|
||||
.tmp_versions
|
||||
Makefile
|
||||
Makefile.in
|
||||
Module.symvers
|
||||
modules.order
|
||||
|
||||
/downloads
|
||||
|
||||
@@ -26,3 +20,4 @@ modules.order
|
||||
/ltmain.sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
/xtables-addons.8
|
||||
|
19
INSTALL
19
INSTALL
@@ -12,9 +12,13 @@ in combination with the kernel's Kbuild system.
|
||||
Prerequirements
|
||||
===============
|
||||
|
||||
* xtables(-devel) 1.5.0
|
||||
* a recent iptables snapshot
|
||||
- from the "xtables" git repository at dev.medozas.de
|
||||
(minimum as per git-describe: v1.4.0-77)
|
||||
- or the subversion repository at netfilter.org (minimum: r7502)
|
||||
- or the xtables-combined tarball that is currently distributed
|
||||
|
||||
* kernel-source >= 2.6.22 with prepared output directory
|
||||
* kernel-source >= 2.6.18.5 with prepared build/output directory
|
||||
|
||||
|
||||
Selecting extensions
|
||||
@@ -36,15 +40,6 @@ Configuring and compiling
|
||||
/lib/modules/$(running version)/build, which usually points to
|
||||
the right directory. (If not, you need to install something.)
|
||||
|
||||
--with-ksource=
|
||||
|
||||
Specifies the path to the kernel source directory. This is
|
||||
currently needed for building the userspace extensions because
|
||||
we use unsanitized kernel headers, but the option MAY
|
||||
DISAPPEAR IN FUTURE.
|
||||
|
||||
--with-ksource=/usr/src/linux
|
||||
|
||||
--with-xtables=
|
||||
|
||||
Specifies the path to the directory where we may find
|
||||
@@ -77,5 +72,5 @@ Note to distribution packagers
|
||||
Except for --with-kbuild, distributions should not have a need to
|
||||
supply any other flags (besides --prefix=/usr and perhaps
|
||||
--libdir=/usr/lib64, etc.) to configure when all prerequired packages
|
||||
are installed. If xtables-devel is installed, necessary headers should
|
||||
are installed. If iptables-devel is installed, necessary headers should
|
||||
be in /usr/include, so --with-xtables is not needed.
|
||||
|
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};
|
||||
|
1
README
1
README
@@ -33,6 +33,7 @@ extension and xt_foobar.c for the kernel extension.
|
||||
|
||||
mconfig.foobar
|
||||
extensions/Kbuild.foobar
|
||||
extensions/Mbuild.foobar
|
||||
extensions/libxt_foobar.c
|
||||
extensions/libxt_foobar.man
|
||||
extensions/xt_foobar.c
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
AC_INIT([xtables-addons], [1.5.1])
|
||||
AC_INIT([xtables-addons], [1.5.4.1])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PROG_INSTALL
|
||||
AM_INIT_AUTOMAKE
|
||||
@@ -50,8 +50,7 @@ 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 -DXTABLES_VERSION=\\\"$PACKAGE_VERSION\\\" \
|
||||
-DXTABLES_LIBDIR=\\\"\${xtlibdir}\\\"";
|
||||
-Winline -pipe -DXTABLES_LIBDIR=\\\"\${xtlibdir}\\\"";
|
||||
kinclude_CFLAGS="";
|
||||
if [[ -n "$kbuilddir" ]]; then
|
||||
kinclude_CFLAGS="$kinclude_CFLAGS -I $kbuilddir/include";
|
||||
@@ -60,7 +59,9 @@ if [[ -n "$ksourcedir" ]]; then
|
||||
kinclude_CFLAGS="$kinclude_CFLAGS -I $ksourcedir/include";
|
||||
fi;
|
||||
|
||||
AC_SUBST([regular_CFLAGS xtables_CFLAGS kinclude_CFLAGS])
|
||||
AC_SUBST([regular_CFLAGS])
|
||||
AC_SUBST([xtables_CFLAGS])
|
||||
AC_SUBST([kinclude_CFLAGS])
|
||||
AC_SUBST([kbuilddir])
|
||||
AC_SUBST([ksourcedir])
|
||||
AC_SUBST([xtlibdir])
|
||||
|
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
|
@@ -2,8 +2,16 @@
|
||||
|
||||
top_srcdir := @top_srcdir@
|
||||
srcdir := @srcdir@
|
||||
abstop_srcdir := $(realpath ${top_srcdir})
|
||||
abssrcdir := $(realpath ${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@
|
||||
@@ -17,8 +25,9 @@ CFLAGS := @CFLAGS@
|
||||
LDFLAGS := @LDFLAGS@
|
||||
regular_CFLAGS := @regular_CFLAGS@
|
||||
kinclude_CFLAGS := @kinclude_CFLAGS@
|
||||
xtables_CFLAGS := @xtables_CFLAGS@
|
||||
|
||||
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${kinclude_CFLAGS}
|
||||
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS}
|
||||
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
|
||||
|
||||
ifeq (${V},)
|
||||
@@ -36,22 +45,20 @@ endif
|
||||
#
|
||||
include ${top_srcdir}/mconfig
|
||||
-include ${top_srcdir}/mconfig.*
|
||||
pfx_all_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(wildcard ${srcdir}/libxt_*.c))
|
||||
pfx_build_mod := $(foreach i,${pfx_all_mod},$(if ${build_${i}},${i},))
|
||||
pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod})
|
||||
include ${srcdir}/Mbuild
|
||||
|
||||
|
||||
#
|
||||
# Building blocks
|
||||
#
|
||||
targets := ${pfx_solibs}
|
||||
targets_install := ${pfx_solibs}
|
||||
targets := ${obj-m}
|
||||
targets_install := ${obj-m}
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
.PHONY: all install clean distclean FORCE
|
||||
|
||||
all: modules ${targets}
|
||||
all: modules ${targets} matches.man targets.man
|
||||
|
||||
install: modules_install ${targets_install}
|
||||
@mkdir -p "${DESTDIR}${xtlibdir}";
|
||||
@@ -61,7 +68,7 @@ clean: clean_modules
|
||||
rm -f *.oo *.so;
|
||||
|
||||
distclean: clean
|
||||
rm -f .*.d;
|
||||
rm -f .*.d .manpages.lst;
|
||||
|
||||
-include .*.d
|
||||
|
||||
@@ -89,3 +96,34 @@ lib%.so: lib%.oo
|
||||
|
||||
lib%.oo: ${srcdir}/lib%.c
|
||||
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
|
||||
|
||||
|
||||
#
|
||||
# Manpages
|
||||
#
|
||||
wcman_matches := $(wildcard ${srcdir}/libxt_[a-z]*.man)
|
||||
wcman_targets := $(wildcard ${srcdir}/libxt_[A-Z]*.man)
|
||||
wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches})
|
||||
wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
|
||||
|
||||
.manpages.lst: FORCE
|
||||
@echo "${wlist_targets} ${wlist_matches}" >$@.tmp; \
|
||||
cmp -s $@ $@.tmp || mv $@.tmp $@; \
|
||||
rm -f $@.tmp;
|
||||
|
||||
man_run = \
|
||||
${AM_VERBOSE_GEN} \
|
||||
for ext in $(1); do \
|
||||
f="${srcdir}/libxt_$$ext.man"; \
|
||||
if [ -f "$$f" ]; then \
|
||||
echo ".SS $$ext"; \
|
||||
cat "$$f"; \
|
||||
continue; \
|
||||
fi; \
|
||||
done >$@;
|
||||
|
||||
matches.man: .manpages.lst ${wcman_matches}
|
||||
$(call man_run,${wlist_matches})
|
||||
|
||||
targets.man: .manpages.lst ${wcman_targets}
|
||||
$(call man_run,${wlist_targets})
|
||||
|
@@ -7,9 +7,14 @@ obj-m += compat_xtables.o
|
||||
|
||||
obj-${build_CHAOS} += xt_CHAOS.o
|
||||
obj-${build_DELUDE} += xt_DELUDE.o
|
||||
obj-${build_ECHO} += xt_ECHO.o
|
||||
obj-${build_IPMARK} += xt_IPMARK.o
|
||||
obj-${build_LOGMARK} += xt_LOGMARK.o
|
||||
obj-${build_TARPIT} += xt_TARPIT.o
|
||||
obj-${build_TEE} += xt_TEE.o
|
||||
obj-${build_condition} += xt_condition.o
|
||||
obj-${build_geoip} += xt_geoip.o
|
||||
obj-${build_ipp2p} += xt_ipp2p.o
|
||||
obj-${build_portscan} += xt_portscan.o
|
||||
|
||||
-include ${M}/*.Kbuild
|
||||
|
11
extensions/Mbuild
Normal file
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>
|
||||
@@ -8,9 +9,18 @@
|
||||
#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, 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,
|
||||
@@ -26,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);
|
||||
|
||||
@@ -38,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,52 +141,65 @@ void xtnu_unregister_matches(struct xtnu_match *nt, unsigned int num)
|
||||
xtnu_unregister_match(&nt[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_unregister_matches);
|
||||
|
||||
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, 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;
|
||||
@@ -233,9 +273,14 @@ struct xt_match *xtnu_request_find_match(unsigned int af, const char *name,
|
||||
uint8_t revision)
|
||||
{
|
||||
static const char *const xt_prefix[] = {
|
||||
[AF_INET] = "ip",
|
||||
[AF_INET6] = "ip6",
|
||||
[NF_ARP] = "arp",
|
||||
[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;
|
||||
|
||||
@@ -251,9 +296,32 @@ 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, 17)
|
||||
/* Actually this one is valid up to 2.6.18.4, but changed in 2.6.18.5 */
|
||||
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)
|
||||
@@ -310,4 +378,19 @@ int xtnu_ip_route_output_key(void *net, struct rtable **rp, struct flowi *flp)
|
||||
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,9 +2,32 @@
|
||||
#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, 22)
|
||||
# warning Kernels below 2.6.22 not supported anymore
|
||||
#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)
|
||||
@@ -25,7 +48,7 @@
|
||||
# define init_net__loopback_dev init_net.loopback_dev
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
# define xt_match xtnu_match
|
||||
# define xt_register_match xtnu_register_match
|
||||
# define xt_unregister_match xtnu_unregister_match
|
||||
@@ -36,6 +59,7 @@
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
# define xt_target xtnu_target
|
||||
# define ip_route_me_harder xtnu_ip_route_me_harder
|
||||
# define skb_make_writable xtnu_skb_make_writable
|
||||
# define xt_register_target xtnu_register_target
|
||||
# define xt_unregister_target xtnu_unregister_target
|
||||
# define xt_register_targets xtnu_register_targets
|
||||
@@ -43,6 +67,5 @@
|
||||
#endif
|
||||
|
||||
#define xt_request_find_match xtnu_request_find_match
|
||||
#include "compat_xtnu.h"
|
||||
|
||||
#endif /* _XTABLES_COMPAT_H */
|
||||
|
@@ -5,7 +5,13 @@
|
||||
#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;
|
||||
@@ -63,6 +69,7 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
|
||||
|
||||
extern int xtnu_ip_local_out(struct sk_buff *);
|
||||
extern int xtnu_ip_route_me_harder(struct sk_buff *, unsigned int);
|
||||
extern int xtnu_skb_make_writable(struct sk_buff *, unsigned int);
|
||||
extern int xtnu_register_match(struct xtnu_match *);
|
||||
extern int xtnu_ip_route_output_key(void *, struct rtable **, struct flowi *);
|
||||
extern void xtnu_unregister_match(struct xtnu_match *);
|
||||
@@ -74,5 +81,6 @@ 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 */
|
||||
|
@@ -1,18 +1,18 @@
|
||||
+Causes confusion on the other end by doing odd things with incoming packets.
|
||||
+CHAOS will randomly reply (or not) with one of its configurable subtargets:
|
||||
+.TP
|
||||
+\fB--delude\fR
|
||||
+Use the REJECT and DELUDE targets as a base to do a sudden or deferred
|
||||
+connection reset, fooling some network scanners to return non-deterministic
|
||||
+(randomly open/closed) results, and in case it is deemed open, it is actually
|
||||
+closed/filtered.
|
||||
+.TP
|
||||
+\fB--tarpit\fR
|
||||
+Use the REJECT and TARPIT target as a base to hold the connection until it
|
||||
+times out. This consumes conntrack entries when connection tracking is loaded
|
||||
+(which usually is on most machines), and routers inbetween you and the Internet
|
||||
+may fail to do their connection tracking if they have to handle more
|
||||
+connections than they can.
|
||||
+.PP
|
||||
+The randomness factor of not replying vs. replying can be set during load-time
|
||||
+of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters.
|
||||
Causes confusion on the other end by doing odd things with incoming packets.
|
||||
CHAOS will randomly reply (or not) with one of its configurable subtargets:
|
||||
.TP
|
||||
\fB--delude\fP
|
||||
Use the REJECT and DELUDE targets as a base to do a sudden or deferred
|
||||
connection reset, fooling some network scanners to return non-deterministic
|
||||
(randomly open/closed) results, and in case it is deemed open, it is actually
|
||||
closed/filtered.
|
||||
.TP
|
||||
\fB--tarpit\fP
|
||||
Use the REJECT and TARPIT target as a base to hold the connection until it
|
||||
times out. This consumes conntrack entries when connection tracking is loaded
|
||||
(which usually is on most machines), and routers inbetween you and the Internet
|
||||
may fail to do their connection tracking if they have to handle more
|
||||
connections than they can.
|
||||
.PP
|
||||
The randomness factor of not replying vs. replying can be set during load-time
|
||||
of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters.
|
||||
|
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
|
@@ -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;
|
||||
}
|
||||
|
89
extensions/libxt_condition.c
Normal file
89
extensions/libxt_condition.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/* 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_mt_reg = {
|
||||
.name = "condition",
|
||||
.revision = 0,
|
||||
.family = PF_UNSPEC,
|
||||
.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 void _init(void)
|
||||
{
|
||||
xtables_register_match(&condition_mt_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!
|
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.
|
@@ -53,7 +53,7 @@ static void xt_chaos_total(const struct xt_chaos_tginfo *info,
|
||||
const int offset = ntohs(iph->frag_off) & IP_OFFSET;
|
||||
typeof(xt_tarpit) destiny;
|
||||
bool ret;
|
||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
int hotdrop = false;
|
||||
#else
|
||||
bool hotdrop = false;
|
||||
@@ -65,7 +65,9 @@ static void xt_chaos_total(const struct xt_chaos_tginfo *info,
|
||||
return;
|
||||
|
||||
destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude;
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
#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);
|
||||
@@ -89,7 +91,10 @@ static unsigned int chaos_tg(struct sk_buff *skb, const struct net_device *in,
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
if ((unsigned int)net_random() <= reject_percentage)
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
#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
|
||||
|
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.
|
@@ -99,9 +99,15 @@ static void delude_send_reset(struct sk_buff *oldskb, unsigned int hook)
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
|
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,11 +11,24 @@
|
||||
#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,
|
||||
@@ -24,12 +37,15 @@ logmark_tg(struct sk_buff *skb, const struct net_device *in,
|
||||
const struct xt_logmark_tginfo *info = targinfo;
|
||||
const struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
bool prev = false;
|
||||
|
||||
printk("<%u>%.*s""nfmark=0x%x secmark=0x%x classify=0x%x",
|
||||
printk("<%u>%.*s""hook=%s nfmark=0x%x secmark=0x%x classify=0x%x",
|
||||
info->level, (unsigned int)sizeof(info->prefix), info->prefix,
|
||||
skb->mark, skb->secmark, skb->priority);
|
||||
hook_names[hooknum],
|
||||
skb_nfmark(skb), skb->secmark, skb->priority);
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]);
|
||||
if (ct == NULL) {
|
||||
printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE");
|
||||
} else if (ct == &nf_conntrack_untracked) {
|
||||
@@ -49,14 +65,16 @@ logmark_tg(struct sk_buff *skb, const struct net_device *in,
|
||||
printk(",DNAT");
|
||||
|
||||
printk(" ctstatus=");
|
||||
if (ct->status & IPS_EXPECTED)
|
||||
if (ct->status & IPS_EXPECTED) {
|
||||
printk("EXPECTED");
|
||||
prev = true;
|
||||
}
|
||||
if (ct->status & IPS_SEEN_REPLY)
|
||||
printk(",SEEN_REPLY");
|
||||
printk("%s""SEEN_REPLY", prev++ ? "," : "");
|
||||
if (ct->status & IPS_ASSURED)
|
||||
printk(",ASSURED");
|
||||
printk("%s""ASSURED", prev++ ? "," : "");
|
||||
if (ct->status & IPS_CONFIRMED)
|
||||
printk(",CONFIRMED");
|
||||
printk("%s""CONFIRMED", prev++ ? "," : "");
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
@@ -17,7 +17,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/xt_tcpudp.h>
|
||||
#include <net/netfilter/nf_nat_rule.h>
|
||||
//#include <net/netfilter/nf_conntrack.h>
|
||||
#include "xt_portscan.h"
|
||||
#include "compat_xtables.h"
|
||||
#define PFX KBUILD_MODNAME ": "
|
||||
@@ -203,7 +203,7 @@ static bool portscan_mt(const struct sk_buff *skb,
|
||||
* it either when the connection is already VALID.
|
||||
*/
|
||||
if ((ctdata->mark & connmark_mask) == mark_valid ||
|
||||
(skb->mark & packet_mask) != mark_seen) {
|
||||
(skb_nfmark(skb) & packet_mask) != mark_seen) {
|
||||
unsigned int n;
|
||||
|
||||
n = portscan_mt_full(ctdata->mark & connmark_mask, ctstate,
|
||||
@@ -211,8 +211,7 @@ static bool portscan_mt(const struct sk_buff *skb,
|
||||
skb->len - protoff - 4 * tcph->doff);
|
||||
|
||||
ctdata->mark = (ctdata->mark & ~connmark_mask) | n;
|
||||
((struct sk_buff *)skb)->mark =
|
||||
(skb->mark & ~packet_mask) ^ mark_seen;
|
||||
skb_nfmark(skb) = (skb_nfmark(skb) & ~packet_mask) ^ mark_seen;
|
||||
}
|
||||
|
||||
return (info->match_syn && ctdata->mark == mark_synscan) ||
|
||||
|
8
mconfig
8
mconfig
@@ -1,11 +1,13 @@
|
||||
# -*- Makefile -*-
|
||||
#
|
||||
# Only "build_${name}=m" (build extensions) or "build_${name}="
|
||||
# (do not build) are valid!
|
||||
#
|
||||
build_CHAOS=m
|
||||
build_DELUDE=m
|
||||
build_ECHO=
|
||||
build_IPMARK=m
|
||||
build_LOGMARK=m
|
||||
build_TARPIT=m
|
||||
build_TEE=m
|
||||
build_condition=m
|
||||
build_geoip=m
|
||||
build_ipp2p=m
|
||||
build_portscan=m
|
||||
|
13
xtables-addons.8.in
Normal file
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