mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-20 19:44:56 +02:00
Compare commits
52 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
176e829e9f | ||
![]() |
d5ee47e9da | ||
![]() |
2c2527bdc4 | ||
![]() |
f931e34365 | ||
![]() |
f34be8445f | ||
![]() |
37e51dc44d | ||
![]() |
a680c1bcde | ||
![]() |
1060138f77 | ||
![]() |
03eeabb4bd | ||
![]() |
2c7b1d5330 | ||
![]() |
b63ac3be45 | ||
![]() |
4b8ec990b8 | ||
![]() |
59ef68fecc | ||
![]() |
3bf45b60b2 | ||
![]() |
e037035bd4 | ||
![]() |
d432d8041a | ||
![]() |
05359d1ab2 | ||
![]() |
29139c1414 | ||
![]() |
585cfd49ab | ||
![]() |
54f78ac3ef | ||
![]() |
376d41618c | ||
![]() |
01df89eb8b | ||
![]() |
a1d307e336 | ||
![]() |
0712d0fdca | ||
![]() |
3c8131b976 | ||
![]() |
569643ac8c | ||
![]() |
cc23d0a2e7 | ||
![]() |
c237fe2486 | ||
![]() |
edcbcee84e | ||
![]() |
44d6f47ad6 | ||
![]() |
20f6e47525 | ||
![]() |
e304252f4b | ||
![]() |
32f06cbedf | ||
![]() |
75f6f14aaf | ||
![]() |
7dd8b1a678 | ||
![]() |
f5f17a27c5 | ||
![]() |
c9579115c3 | ||
![]() |
586353342f | ||
![]() |
317a944fec | ||
![]() |
24dad368dd | ||
![]() |
7d0efafdb3 | ||
![]() |
330c1fe783 | ||
![]() |
72dc73e6a5 | ||
![]() |
d7c5473cf6 | ||
![]() |
0ee80e4147 | ||
![]() |
9778022c37 | ||
![]() |
2f6bc4c8cb | ||
![]() |
5fbc01b991 | ||
![]() |
b749916313 | ||
![]() |
818cd3b47e | ||
![]() |
8302faad44 | ||
![]() |
8fa47480f8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,3 +20,4 @@ Makefile.in
|
||||
/ltmain.sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
/xtables-addons.8
|
||||
|
@@ -3,6 +3,14 @@
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
SUBDIRS = extensions
|
||||
|
||||
man_MANS := xtables-addons.8
|
||||
|
||||
xtables-addons.8: ${srcdir}/xtables-addons.8.in extensions/matches.man extensions/targets.man
|
||||
${AM_VERBOSE_GEN} sed -e '/@MATCHES@/ r extensions/matches.man' -e '/@TARGET@/ r extensions/targets.man' $< >$@;
|
||||
|
||||
extensions/%:
|
||||
${MAKE} ${AM_MAKEFLAGS} -C $(@D) $(@F)
|
||||
|
||||
.PHONY: tarball
|
||||
tarball:
|
||||
rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION};
|
||||
|
1
README
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.3])
|
||||
AC_INIT([xtables-addons], [1.5.4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_PROG_INSTALL
|
||||
AM_INIT_AUTOMAKE
|
||||
|
3
extensions/.gitignore
vendored
3
extensions/.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.*.cmd
|
||||
.*.d
|
||||
.manpages.lst
|
||||
.tmp_versions
|
||||
*.ko
|
||||
*.mod.c
|
||||
@@ -8,3 +9,5 @@
|
||||
GNUmakefile
|
||||
Module.symvers
|
||||
modules.order
|
||||
matches.man
|
||||
targets.man
|
||||
|
@@ -45,22 +45,20 @@ endif
|
||||
#
|
||||
include ${top_srcdir}/mconfig
|
||||
-include ${top_srcdir}/mconfig.*
|
||||
pfx_all_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(wildcard ${srcdir}/libxt_*.c))
|
||||
pfx_build_mod := $(foreach i,${pfx_all_mod},$(if ${build_${i}},${i},))
|
||||
pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod})
|
||||
include ${srcdir}/Mbuild
|
||||
|
||||
|
||||
#
|
||||
# Building blocks
|
||||
#
|
||||
targets := ${pfx_solibs}
|
||||
targets_install := ${pfx_solibs}
|
||||
targets := ${obj-m}
|
||||
targets_install := ${obj-m}
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
.PHONY: all install clean distclean FORCE
|
||||
|
||||
all: modules ${targets}
|
||||
all: modules ${targets} matches.man targets.man
|
||||
|
||||
install: modules_install ${targets_install}
|
||||
@mkdir -p "${DESTDIR}${xtlibdir}";
|
||||
@@ -70,7 +68,7 @@ clean: clean_modules
|
||||
rm -f *.oo *.so;
|
||||
|
||||
distclean: clean
|
||||
rm -f .*.d;
|
||||
rm -f .*.d .manpages.lst;
|
||||
|
||||
-include .*.d
|
||||
|
||||
@@ -98,3 +96,34 @@ lib%.so: lib%.oo
|
||||
|
||||
lib%.oo: ${srcdir}/lib%.c
|
||||
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
|
||||
|
||||
|
||||
#
|
||||
# Manpages
|
||||
#
|
||||
wcman_matches := $(wildcard ${srcdir}/libxt_[a-z]*.man)
|
||||
wcman_targets := $(wildcard ${srcdir}/libxt_[A-Z]*.man)
|
||||
wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches})
|
||||
wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
|
||||
|
||||
.manpages.lst: FORCE
|
||||
@echo "${wlist_targets} ${wlist_matches}" >$@.tmp; \
|
||||
cmp -s $@ $@.tmp || mv $@.tmp $@; \
|
||||
rm -f $@.tmp;
|
||||
|
||||
man_run = \
|
||||
${AM_VERBOSE_GEN} \
|
||||
for ext in $(1); do \
|
||||
f="${srcdir}/libxt_$$ext.man"; \
|
||||
if [ -f "$$f" ]; then \
|
||||
echo ".SS $$ext"; \
|
||||
cat "$$f"; \
|
||||
continue; \
|
||||
fi; \
|
||||
done >$@;
|
||||
|
||||
matches.man: .manpages.lst ${wcman_matches}
|
||||
$(call man_run,${wlist_matches})
|
||||
|
||||
targets.man: .manpages.lst ${wcman_targets}
|
||||
$(call man_run,${wlist_targets})
|
||||
|
@@ -8,10 +8,13 @@ obj-m += compat_xtables.o
|
||||
obj-${build_CHAOS} += xt_CHAOS.o
|
||||
obj-${build_DELUDE} += xt_DELUDE.o
|
||||
obj-${build_ECHO} += xt_ECHO.o
|
||||
obj-${build_IPMARK} += xt_IPMARK.o
|
||||
obj-${build_LOGMARK} += xt_LOGMARK.o
|
||||
obj-${build_TARPIT} += xt_TARPIT.o
|
||||
obj-${build_TEE} += xt_TEE.o
|
||||
obj-${build_condition} += xt_condition.o
|
||||
obj-${build_geoip} += xt_geoip.o
|
||||
obj-${build_ipp2p} += xt_ipp2p.o
|
||||
obj-${build_portscan} += xt_portscan.o
|
||||
|
||||
-include ${M}/*.Kbuild
|
||||
|
11
extensions/Mbuild
Normal file
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
|
@@ -1,6 +1,9 @@
|
||||
#ifndef COMPAT_SKBUFF_H
|
||||
#define COMPAT_SKBUFF_H 1
|
||||
|
||||
struct tcphdr;
|
||||
struct udphdr;
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->nfmark)
|
||||
#else
|
||||
@@ -10,11 +13,21 @@
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21)
|
||||
# define ip_hdr(skb) ((skb)->nh.iph)
|
||||
# define ip_hdrlen(skb) (ip_hdr(skb)->ihl * 4)
|
||||
# define ipv6_hdr(skb) ((skb)->nh.ipv6h)
|
||||
# define skb_network_header(skb) ((skb)->nh.raw)
|
||||
# define skb_transport_header(skb) ((skb)->h.raw)
|
||||
static inline void skb_reset_network_header(struct sk_buff *skb)
|
||||
{
|
||||
skb->nh.raw = skb->data;
|
||||
}
|
||||
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (void *)skb_transport_header(skb);
|
||||
}
|
||||
static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (void *)skb_transport_header(skb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMPAT_SKBUFF_H */
|
||||
|
@@ -12,6 +12,14 @@
|
||||
#include "compat_skbuff.h"
|
||||
#include "compat_xtnu.h"
|
||||
|
||||
static inline int unable(const char *cause)
|
||||
{
|
||||
if (net_ratelimit())
|
||||
printk(KERN_ERR KBUILD_MODNAME
|
||||
": compat layer limits reached (%s) - dropping packets\n", cause);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_match_run(const struct sk_buff *skb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
@@ -288,13 +296,31 @@ EXPORT_SYMBOL_GPL(xtnu_request_find_match);
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
int xtnu_ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type)
|
||||
{
|
||||
struct sk_buff *nskb = skb;
|
||||
int ret;
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
return ip_route_me_harder(&skb);
|
||||
ret = ip_route_me_harder(&skb);
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
return ip_route_me_harder(&skb, addr_type);
|
||||
ret = ip_route_me_harder(&nskb, addr_type);
|
||||
#endif
|
||||
if (nskb != skb)
|
||||
return unable(__func__);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_route_me_harder);
|
||||
|
||||
int xtnu_skb_make_writable(struct sk_buff *skb, unsigned int len)
|
||||
{
|
||||
struct sk_buff *nskb = skb;
|
||||
int ret;
|
||||
|
||||
ret = skb_make_writable(&skb, len);
|
||||
if (nskb != skb)
|
||||
return unable(__func__);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_skb_make_writable);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 24)
|
||||
|
@@ -59,6 +59,7 @@
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
# define xt_target xtnu_target
|
||||
# define ip_route_me_harder xtnu_ip_route_me_harder
|
||||
# define skb_make_writable xtnu_skb_make_writable
|
||||
# define xt_register_target xtnu_register_target
|
||||
# define xt_unregister_target xtnu_unregister_target
|
||||
# define xt_register_targets xtnu_register_targets
|
||||
|
@@ -69,6 +69,7 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
|
||||
|
||||
extern int xtnu_ip_local_out(struct sk_buff *);
|
||||
extern int xtnu_ip_route_me_harder(struct sk_buff *, unsigned int);
|
||||
extern int xtnu_skb_make_writable(struct sk_buff *, unsigned int);
|
||||
extern int xtnu_register_match(struct xtnu_match *);
|
||||
extern int xtnu_ip_route_output_key(void *, struct rtable **, struct flowi *);
|
||||
extern void xtnu_unregister_match(struct xtnu_match *);
|
||||
|
@@ -1,18 +1,18 @@
|
||||
+Causes confusion on the other end by doing odd things with incoming packets.
|
||||
+CHAOS will randomly reply (or not) with one of its configurable subtargets:
|
||||
+.TP
|
||||
+\fB--delude\fR
|
||||
+Use the REJECT and DELUDE targets as a base to do a sudden or deferred
|
||||
+connection reset, fooling some network scanners to return non-deterministic
|
||||
+(randomly open/closed) results, and in case it is deemed open, it is actually
|
||||
+closed/filtered.
|
||||
+.TP
|
||||
+\fB--tarpit\fR
|
||||
+Use the REJECT and TARPIT target as a base to hold the connection until it
|
||||
+times out. This consumes conntrack entries when connection tracking is loaded
|
||||
+(which usually is on most machines), and routers inbetween you and the Internet
|
||||
+may fail to do their connection tracking if they have to handle more
|
||||
+connections than they can.
|
||||
+.PP
|
||||
+The randomness factor of not replying vs. replying can be set during load-time
|
||||
+of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters.
|
||||
Causes confusion on the other end by doing odd things with incoming packets.
|
||||
CHAOS will randomly reply (or not) with one of its configurable subtargets:
|
||||
.TP
|
||||
\fB--delude\fP
|
||||
Use the REJECT and DELUDE targets as a base to do a sudden or deferred
|
||||
connection reset, fooling some network scanners to return non-deterministic
|
||||
(randomly open/closed) results, and in case it is deemed open, it is actually
|
||||
closed/filtered.
|
||||
.TP
|
||||
\fB--tarpit\fP
|
||||
Use the REJECT and TARPIT target as a base to hold the connection until it
|
||||
times out. This consumes conntrack entries when connection tracking is loaded
|
||||
(which usually is on most machines), and routers inbetween you and the Internet
|
||||
may fail to do their connection tracking if they have to handle more
|
||||
connections than they can.
|
||||
.PP
|
||||
The randomness factor of not replying vs. replying can be set during load-time
|
||||
of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters.
|
||||
|
179
extensions/libxt_IPMARK.c
Normal file
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;
|
||||
}
|
||||
|
105
extensions/libxt_condition.c
Normal file
105
extensions/libxt_condition.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/* Shared library add-on to iptables for condition match */
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_condition.h"
|
||||
|
||||
static void condition_help(void)
|
||||
{
|
||||
printf(
|
||||
"condition match options:\n"
|
||||
"[!] --condition name Match on boolean value stored in procfs file\n"
|
||||
);
|
||||
}
|
||||
|
||||
static const struct option condition_opts[] = {
|
||||
{.name = "condition", .has_arg = true, .val = 'X'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_match **match)
|
||||
{
|
||||
struct xt_condition_mtinfo *info = (void *)(*match)->data;
|
||||
|
||||
if (c == 'X') {
|
||||
if (*flags)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Can't specify multiple conditions");
|
||||
|
||||
if (strlen(optarg) < sizeof(info->name))
|
||||
strcpy(info->name, optarg);
|
||||
else
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"File name too long");
|
||||
|
||||
info->invert = invert;
|
||||
*flags = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void condition_check(unsigned int flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Condition match: must specify --condition");
|
||||
}
|
||||
|
||||
static void condition_print(const void *ip, const struct xt_entry_match *match,
|
||||
int numeric)
|
||||
{
|
||||
const struct xt_condition_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("condition %s%s ", (info->invert) ? "!" : "", info->name);
|
||||
}
|
||||
|
||||
|
||||
static void condition_save(const void *ip, const struct xt_entry_match *match)
|
||||
{
|
||||
const struct xt_condition_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name);
|
||||
}
|
||||
|
||||
static struct xtables_match condition_mt4_reg = {
|
||||
.name = "condition",
|
||||
.revision = 0,
|
||||
.family = PF_INET,
|
||||
.version = XTABLES_VERSION,
|
||||
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
|
||||
.help = condition_help,
|
||||
.parse = condition_parse,
|
||||
.final_check = condition_check,
|
||||
.print = condition_print,
|
||||
.save = condition_save,
|
||||
.extra_opts = condition_opts,
|
||||
};
|
||||
|
||||
static struct xtables_match condition_mt6_reg = {
|
||||
.name = "condition",
|
||||
.revision = 0,
|
||||
.family = PF_INET6,
|
||||
.version = XTABLES_VERSION,
|
||||
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
|
||||
.userspacesize = offsetof(struct xt_condition_mtinfo, condvar),
|
||||
.help = condition_help,
|
||||
.parse = condition_parse,
|
||||
.final_check = condition_check,
|
||||
.print = condition_print,
|
||||
.save = condition_save,
|
||||
.extra_opts = condition_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_match(&condition_mt4_reg);
|
||||
xtables_register_match(&condition_mt6_reg);
|
||||
}
|
4
extensions/libxt_condition.man
Normal file
4
extensions/libxt_condition.man
Normal file
@@ -0,0 +1,4 @@
|
||||
This matches if a specific condition variable is (un)set.
|
||||
.TP
|
||||
[\fB!\fP] \fB--condition\fP \fIname\fP
|
||||
Match on boolean value stored in /proc/net/nf_condition/\fIname\fP.
|
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.
|
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.
|
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.
|
@@ -30,7 +30,8 @@ static unsigned int echo_tg4(struct sk_buff *oldskb,
|
||||
void *payload;
|
||||
|
||||
/* This allows us to do the copy operation in fewer lines of code. */
|
||||
skb_linearize(oldskb);
|
||||
if (skb_linearize(oldskb) < 0)
|
||||
return NF_DROP;
|
||||
|
||||
oldip = ip_hdr(oldskb);
|
||||
oldudp = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
|
||||
|
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 */
|
@@ -17,6 +17,18 @@
|
||||
#include "compat_xtables.h"
|
||||
#include "xt_LOGMARK.h"
|
||||
|
||||
static const char *const hook_names[] = {
|
||||
[NF_INET_PRE_ROUTING] = "PREROUTING",
|
||||
[NF_INET_LOCAL_IN] = "INPUT",
|
||||
[NF_INET_FORWARD] = "FORWARD",
|
||||
[NF_INET_LOCAL_OUT] = "OUTPUT",
|
||||
[NF_INET_POST_ROUTING] = "POSTROUTING",
|
||||
};
|
||||
|
||||
static const char *const dir_names[] = {
|
||||
"ORIGINAL", "REPLY",
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
logmark_tg(struct sk_buff *skb, const struct net_device *in,
|
||||
const struct net_device *out, unsigned int hooknum,
|
||||
@@ -25,12 +37,15 @@ logmark_tg(struct sk_buff *skb, const struct net_device *in,
|
||||
const struct xt_logmark_tginfo *info = targinfo;
|
||||
const struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
bool prev = false;
|
||||
|
||||
printk("<%u>%.*s""nfmark=0x%x secmark=0x%x classify=0x%x",
|
||||
printk("<%u>%.*s""hook=%s nfmark=0x%x secmark=0x%x classify=0x%x",
|
||||
info->level, (unsigned int)sizeof(info->prefix), info->prefix,
|
||||
hook_names[hooknum],
|
||||
skb_nfmark(skb), skb->secmark, skb->priority);
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]);
|
||||
if (ct == NULL) {
|
||||
printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE");
|
||||
} else if (ct == &nf_conntrack_untracked) {
|
||||
@@ -50,14 +65,16 @@ logmark_tg(struct sk_buff *skb, const struct net_device *in,
|
||||
printk(",DNAT");
|
||||
|
||||
printk(" ctstatus=");
|
||||
if (ct->status & IPS_EXPECTED)
|
||||
if (ct->status & IPS_EXPECTED) {
|
||||
printk("EXPECTED");
|
||||
prev = true;
|
||||
}
|
||||
if (ct->status & IPS_SEEN_REPLY)
|
||||
printk(",SEEN_REPLY");
|
||||
printk("%s""SEEN_REPLY", prev++ ? "," : "");
|
||||
if (ct->status & IPS_ASSURED)
|
||||
printk(",ASSURED");
|
||||
printk("%s""ASSURED", prev++ ? "," : "");
|
||||
if (ct->status & IPS_CONFIRMED)
|
||||
printk(",CONFIRMED");
|
||||
printk("%s""CONFIRMED", prev++ ? "," : "");
|
||||
}
|
||||
|
||||
printk("\n");
|
||||
|
@@ -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
|
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.
|
6
mconfig
6
mconfig
@@ -1,13 +1,13 @@
|
||||
# -*- Makefile -*-
|
||||
#
|
||||
# Only "build_${name}=m" (build extensions) or "build_${name}="
|
||||
# (do not build) are valid!
|
||||
#
|
||||
build_CHAOS=m
|
||||
build_DELUDE=m
|
||||
build_ECHO=
|
||||
build_IPMARK=m
|
||||
build_LOGMARK=m
|
||||
build_TARPIT=m
|
||||
build_TEE=m
|
||||
build_condition=m
|
||||
build_geoip=m
|
||||
build_ipp2p=m
|
||||
build_portscan=m
|
||||
|
13
xtables-addons.8.in
Normal file
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