Compare commits

..

7 Commits

Author SHA1 Message Date
Jan Engelhardt
515dd81d8f doc: add xt_quota2 changelog items
Cherry-picked commit v2.4-1-gfb3e550.
2014-01-18 12:27:11 +01:00
Sam Liddicott
a2d22c427f xt_quota2: remove trailing junk which might have a digit in it
Cherry-pick commit v2.3-6-gbc2bcc3.

Signed-off-by: Sam Liddicott <sam@liddicott.com>
2014-01-18 12:21:49 +01:00
Sam Liddicott
7fcbbe7dee xt_quota2: fix 2 bugs when not in grow mode
Cherry-pick commit v2.3-5-gc6c70ab.

1. XT_QUOTA_NO_CHANGE should not alter quota to zero ever
2. XT_QUOTA_PACKET should not be set to zero based on skb->len

Signed-off-by: Sam Liddicott <sam@liddicott.com>
2014-01-18 12:21:48 +01:00
Jan Engelhardt
b78a309bcc Update .gitignore
Cherry-pick commit v2.3-4-ga0a8fbc.

Looks like GCOV is enabled somewhere.
2014-01-18 12:21:48 +01:00
Jan Engelhardt
c024c6b16e extensions: remove RAWSNAT/RAWDNAT
Cherry-picked commit v2.3-3-g9414a5d.

Remove unmaintained code.
2014-01-18 12:16:28 +01:00
Jan Engelhardt
19b15a5261 extensions: remove STEAL target
Cherry-picked commit v2.3-2-gf28cfff.

There is enough demo code in the "demos" branch.
2014-01-18 12:15:12 +01:00
Jan Engelhardt
df9d3c994e Merge branch 'maint' into gen1 2012-11-12 19:02:14 +01:00
117 changed files with 4143 additions and 2462 deletions

2
.gitignore vendored
View File

@@ -2,9 +2,7 @@
*.la *.la
*.lo *.lo
*.loT *.loT
*.mod
*.o *.o
.cache.mk
.deps/ .deps/
.dirstamp .dirstamp
.libs/ .libs/

12
INSTALL
View File

@@ -12,18 +12,16 @@ in combination with the kernel's Kbuild system.
Supported configurations for this release Supported configurations for this release
========================================= =========================================
* iptables >= 1.6.0 * iptables >= 1.4.5
* kernel-devel >= 4.15 * kernel-devel >= 2.6.32
with prepared build/output directory with prepared build/output directory
- CONFIG_NF_CONNTRACK - CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK
- CONFIG_NF_CONNTRACK_MARK enabled =y or as module (=m) - CONFIG_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_MARK
enabled =y or as module (=m)
- CONFIG_CONNECTOR y/m if you wish to receive userspace - CONFIG_CONNECTOR y/m if you wish to receive userspace
notifications from pknock through netlink/connector notifications from pknock through netlink/connector
(Use xtables-addons-1.x if you need support for Linux < 3.7.
Use xtables-addons-2.x if you need support for Linux < 4.15.)
Selecting extensions Selecting extensions
==================== ====================

View File

@@ -1,7 +1,7 @@
# -*- Makefile -*- # -*- Makefile -*-
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = extensions extensions/ACCOUNT extensions/pknock geoip SUBDIRS = extensions geoip
man_MANS := xtables-addons.8 man_MANS := xtables-addons.8
@@ -11,10 +11,8 @@ FORCE:
xtables-addons.8: FORCE xtables-addons.8: FORCE
${MAKE} -f Makefile.mans all; ${MAKE} -f Makefile.mans all;
clean-local-mans: install-exec-hook:
${MAKE} -f Makefile.mans clean; depmod -a || :;
clean-local: clean-local-mans
config.status: Makefile.iptrules.in config.status: Makefile.iptrules.in

View File

@@ -3,8 +3,8 @@
srcdir := @srcdir@ srcdir := @srcdir@
wcman_matches := $(shell find "${srcdir}/extensions" -name 'libxt_[a-z]*.man' -print | sort) wcman_matches := $(shell find "${srcdir}" -name 'libxt_[a-z]*.man' | sort)
wcman_targets := $(shell find "${srcdir}/extensions" -name 'libxt_[A-Z]*.man' -print | sort) wcman_targets := $(shell find "${srcdir}" -name 'libxt_[A-Z]*.man' | sort)
wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches}) wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches})
wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets}) wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
@@ -38,6 +38,3 @@ matches.man: .manpages.lst ${wcman_matches}
targets.man: .manpages.lst ${wcman_targets} targets.man: .manpages.lst ${wcman_targets}
$(call man_run,${wlist_targets}) $(call man_run,${wlist_targets})
clean:
rm -f xtables-addons.8 matches.man targets.man .manpages.lst

54
README
View File

@@ -1,15 +1,57 @@
Xtables-addons Xtables-addons
============== ==============
Xtables-addons is a set of extensions that were not accepted in the Xtables-addons is the proclaimed successor to patch-o-matic(-ng). It
Linux kernel and/or main Xtables/iptables package. contains extensions that were not accepted in the main Xtables
package.
It superseded the earlier patch-o-matic(-ng) package in that no Xtables-addons is different from patch-o-matic in that you do not
patching and/or recompilation of either the kernel or have to patch or recompile either kernel or Xtables(iptables). But
Xtables/iptables is required. However, do see the INSTALL file for please see the INSTALL file for the minimum requirements of this
the minimum requirements of Xtables-addons. package.
All code imported from patch-o-matic has been reviewed and all
apparent bugs like binary stability across multiarches, missing
sanity checks and incorrect endianess handling have been fixed,
simplified, and sped up.
Included in this package Included in this package
======================== ========================
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3 - xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
Inclusion into a kernel tree
============================
External extensions
===================
The program "xa-download-more" can be used to download more
extensions from 3rd parties into the source tree. The URLs are listed
in the "sources" file. If the "sources" file contains an entry like
http://foobar.org/xa/
xa-download-more will inspect http://foobar.org/xa/xa-index.txt for
files to download. That file may contain
foobar.tar.bz2
and xa-download-more will then retrieve and unpack
http://foobar.org/xa/foobar.tar.bz2.
Files that should be contained in the tarball are an mconfig and
Kbuild files to control building the extension, libxt_foobar.c for
the userspace extension and xt_foobar.c for the kernel extension.
mconfig.foobar
extensions/Kbuild.foobar
extensions/Mbuild.foobar
extensions/libxt_foobar.c
extensions/libxt_foobar.man
extensions/xt_foobar.c
extensions/xt_foobar.h

View File

@@ -1,4 +1,4 @@
AC_INIT([xtables-addons], [3.14]) AC_INIT([xtables-addons], [1.47.1])
AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@@ -26,8 +26,8 @@ fi
AC_CHECK_HEADERS([linux/netfilter/x_tables.h], [], AC_CHECK_HEADERS([linux/netfilter/x_tables.h], [],
[AC_MSG_ERROR([You need to have linux/netfilter/x_tables.h, see INSTALL file for details])]) [AC_MSG_ERROR([You need to have linux/netfilter/x_tables.h, see INSTALL file for details])])
PKG_CHECK_MODULES([libxtables], [xtables >= 1.6.0]) PKG_CHECK_MODULES([libxtables], [xtables >= 1.4.5])
xtlibdir="$($PKG_CONFIG --variable=xtlibdir xtables)" xtlibdir="$(pkg-config --variable=xtlibdir xtables)"
AC_ARG_WITH([xtlibdir], AC_ARG_WITH([xtlibdir],
AS_HELP_STRING([--with-xtlibdir=PATH], AS_HELP_STRING([--with-xtlibdir=PATH],
@@ -44,25 +44,31 @@ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
if test -n "$kbuilddir"; then if test -n "$kbuilddir"; then
AC_MSG_CHECKING([kernel version that we will build against]) AC_MSG_CHECKING([kernel version that we will build against])
krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease | $AWK -v 'FS=[[^0-9.]]' '{print $1; exit}')" krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease)";
save_IFS="$IFS" kmajor="${krel%%[[^0-9]]*}";
IFS='.' kmajor="$(($kmajor+0))";
set x $krel krel="${krel:${#kmajor}}";
IFS="$save_IFS" krel="${krel#.}";
kmajor="$(($2+0))" kminor="${krel%%[[^0-9]]*}";
kminor="$(($3+0))" kminor="$(($kminor+0))";
kmicro="$(($4+0))" krel="${krel:${#kminor}}";
kstable="$(($5+0))" krel="${krel#.}";
kmicro="${krel%%[[^0-9]]*}";
kmicro="$(($kmicro+0))";
krel="${krel:${#kmicro}}";
krel="${krel#.}";
kstable="${krel%%[[^0-9]]*}";
kstable="$(($kstable+0))";
if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then
echo "WARNING: Version detection did not succeed. Continue at own luck."; echo "WARNING: Version detection did not succeed. Continue at own luck.";
else else
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir"; echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
if test "$kmajor" -gt 5 -o "$kmajor" -eq 5 -a "$kminor" -gt 10; then if test "$kmajor" -gt 3 -o "$kmajor" -eq 3 -a "$kminor" -gt 6; then
echo "WARNING: That kernel version is not officially supported yet. Continue at own luck."; echo "WARNING: That kernel version is not officially supported.";
elif test "$kmajor" -eq 5 -a "$kminor" -ge 0; then elif test "$kmajor" -eq 3; then
: :;
elif test "$kmajor" -eq 4 -a "$kminor" -ge 15; then elif test "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -ge 32; then
: :;
else else
echo "WARNING: That kernel version is not officially supported."; echo "WARNING: That kernel version is not officially supported.";
fi; fi;

64
doc/api/2.6.17.c Normal file
View File

@@ -0,0 +1,64 @@
match:
/* true/false */
int
(*match)(
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,
int *hotdrop,
);
/* true/false */
int
(*checkentry)(
const char *tablename,
const void *ip,
const struct xt_match *match,
void *matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_match *match,
void *matchinfo,
unsigned int matchinfosize,
);
target:
/* verdict */
unsigned int
(*target)(
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo,
void *userdata,
);
/* true/false */
int
(*checkentry)(
const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_target *target,
void *targinfo,
unsigned int targinfosize,
);

59
doc/api/2.6.19.c Normal file
View File

@@ -0,0 +1,59 @@
match:
/* true/false */
int
(*match)(
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,
int *hotdrop,
);
/* true/false */
int
(*checkentry)(
const char *tablename,
const void *ip,
const struct xt_match *match,
void *matchinfo,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_match *match,
void *matchinfo,
);
target:
/* verdict */
unsigned int
(*target)(
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo,
);
/* true/false */
int
(*checkentry)(
const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_target *target,
void *targinfo,
);

59
doc/api/2.6.23.c Normal file
View File

@@ -0,0 +1,59 @@
match:
/* true/false */
bool
(*match)(
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,
);
/* true/false */
bool
(*checkentry)(
const char *tablename,
const void *ip,
const struct xt_match *match,
void *matchinfo,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_match *match,
void *matchinfo,
);
target:
/* verdict */
unsigned int
(*target)(
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
const struct xt_target *target,
const void *targinfo,
);
/* true/false */
bool
(*checkentry)(
const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_target *target,
void *targinfo,
);

59
doc/api/2.6.24.c Normal file
View File

@@ -0,0 +1,59 @@
match:
/* true/false */
bool
(*match)(
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,
);
/* true/false */
bool
(*checkentry)(
const char *tablename,
const void *ip,
const struct xt_match *match,
void *matchinfo,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_match *match,
void *matchinfo,
);
target:
/* verdict */
unsigned int
(*target)(
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,
);
/* true/false */
bool
(*checkentry)(
const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask,
);
void
(*destroy)(
const struct xt_target *target,
void *targinfo,
);

39
doc/api/2.6.28.c Normal file
View File

@@ -0,0 +1,39 @@
match:
/* true/false */
bool
(*match)(
const struct sk_buff *skb,
const struct xt_match_param *,
);
/* true/false */
bool
(*checkentry)(
const struct xt_mtchk_param *,
);
void
(*destroy)(
const struct xt_mtdtor_param *,
);
target:
/* verdict */
unsigned int
(*target)(
struct sk_buff *skb,
const struct xt_target_param *,
);
/* true/false */
bool
(*checkentry)(
const struct xt_tgchk_param *,
);
void
(*destroy)(
const struct xt_tgdtor_param *,
);

38
doc/api/2.6.31.c Normal file
View File

@@ -0,0 +1,38 @@
match:
/* true/false */
bool
(*match)(
const struct sk_buff *skb,
const struct xt_match_param *,
);
/* true/false */
bool
(*checkentry)(
const struct xt_mtchk_param *,
);
void
(*destroy)(
const struct xt_mtdtor_param *,
);
target:
unsigned int
(*target)(
struct sk_buff *skb,
const struct xt_target_param *,
);
/* true/false */
bool
(*checkentry)(
const struct xt_tgchk_param *,
);
void
(*destroy)(
const struct xt_tgdtor_param *,
);

39
doc/api/2.6.32.c Normal file
View File

@@ -0,0 +1,39 @@
match:
/* true/false */
bool
(*match)(
const struct sk_buff *skb,
const struct xt_match_param *,
);
/* true/false */
bool
(*checkentry)(
const struct xt_mtchk_param *,
);
void
(*destroy)(
const struct xt_mtdtor_param *,
);
target:
/* verdict */
unsigned int
(*target)(
struct sk_buff *skb,
const struct xt_target_param *,
);
/* true/false */
bool
(*checkentry)(
const struct xt_tgchk_param *,
);
void
(*destroy)(
const struct xt_tgdtor_param *,
);

View File

@@ -1,178 +1,8 @@
v3.14 (2020-11-24)
==================
- DELUDE, ECHO, TARPIT: use actual tunnel socket (ip_route_me_harder).
- geoip: scripts for use with MaxMind DB have been brought back,
partly under new names.
- Gave xt_geoip_fetch a more fitting name, xt_geoip_query.
HEAD
v3.13 (2020-11-20) ====
================== Changes
- Support for Linux 4.19.158 and 5.4.78 (ip_route_me_harder)
v3.12 (2020-11-19)
==================
- Support for Linux 5.10 and 5.9.9 API
(changes to ip_route_me_harder there)
v3.11 (2020-09-06)
==================
- Support for up to Linux 5.9
v3.10 (2020-07-28)
==================
- Support for up to Linux 5.8
v3.9 (2020-02-25)
=================
- Support for Linux 5.6 procfs changes
v3.8 (2020-02-03)
=================
- Support for Linux 5.5
- xt_geoip_build now expects the DBIP format as input,
Maxmind is thrown out.
v3.7 (2019-12-01)
=================
Fixes:
- xt_geoip: fix in6_addr little-endian byte swapping
v3.6 (2019-11-20)
=================
Enhancements:
- support for up to Linux 5.4
v3.5 (2019-09-10)
=================
Enhancements:
- xt_DELUDE, xt_TARPIT: added additional code needed to work with
bridges from Linux 5.0 onwards.
v3.4 (2019-09-06)
=================
Enhancements:
- support for up to Linux 5.3
- xt_PROTO module
v3.3 (2019-03-07)
=================
Enhancements:
- support for Linux 5.0
v3.2 (2018-09-07)
=================
Changes:
- rework xt_geoip_build to scan the immediate directory for .csv,
not to scan for GeoLite2-Country-CSV_\d+.
v3.1 (2018-08-14)
=================
Enhancements:
- support for Linux 4.17, 4.18
v3.0 (2018-02-12)
=================
Enhancements:
- support for Linux 4.15, 4.16
Changes:
- remove support for Linux 3.7--4.14
v2.14 (2017-11-22)
==================
Enhancements:
- support for Linux up to 4.14
Fixes:
- xt_DNETMAP: fix some reports from PVSStudio (a static checker)
v2.13 (2017-06-29)
==================
Enhancements:
- support for Linux up to 4.12
- xt_condition: namespace support
Fixes:
- xt_geoip: check for allocation overflow
- xt_DNETMAP: fix a buffer overflow
v2.12 (2017-01-11)
==================
Enhancements:
- support for Linux up to 4.10
v2.11 (2016-05-20)
==================
Enhancements:
- support for Linux 4.5, 4.6
- xt_ECHO: tentatively support responding to fragments
v2.10 (2015-11-20)
==================
Enhancements:
- Support for Linux 4.4
Fixes:
- xt_ACCOUNT: call free_page with the right amount of pages
v2.9 (2015-10-12)
=================
Enhancements:
- Support for Linux 4.3
v2.8 (2015-08-19)
=================
Enhancements:
- Support for Linux 4.2
- Enable xt_ECHO for Linux 4.0+
v2.7 (2015-07-06)
=================
Enhancements:
- Support for Linux up to 4.1
v2.6 (2014-09-29)
=================
Enhancements:
- Support for Linux up to 3.17
Fixes:
- xt_pknock: UDP SPA mode erroneously returned an error saying
crypto was unavailable
v2.5 (2014-04-18)
=================
Enhancements:
- Support for Linux up to 3.15
- xt_quota2: introduce support for network namespaces
v2.4 (2014-01-09)
=================
Enhancements:
- Support for Linux up to 3.13
Changes:
- remove unmaintained RAWSNAT/RAWDNAT code - remove unmaintained RAWSNAT/RAWDNAT code
- remove unused parts of compat_xtables that served Linux <3.7
Fixes: Fixes:
- xt_quota2: --no-change should not alter quota to zero ever - xt_quota2: --no-change should not alter quota to zero ever
- xt_quota2: --packet should not be set to zero based on skb->len - xt_quota2: --packet should not be set to zero based on skb->len
@@ -216,5 +46,515 @@ Changes:
Enhancements: Enhancements:
- Support for Linux 3.7 - Support for Linux 3.7
If you want to use Xtables-addons with kernels older than 4.15, If you want to use Xtables-addons with kernels older than 3.7,
use the addons 2.x series. use the addons 1.x series, which continues to be maintained for
the time being.
>>>>>>> fb3e550... doc: add xt_quota2 changelog items
v1.47.1 (2010-10-15)
====================
Enhancements:
- xt_psd gained IPv6 support
Notes for this release:
- Linux 3.7+ is expressly unsupported by this release.
v1.46 (2012-08-23)
==================
Fixes:
- length2, SYSRQ, RAWNAT: preinitialize values for ipv6_find_hdr
- TARPIT: fix memory leak when tarpit_generic() fails
- build: remove extraneous closing bracket in configure.ac
- doc: update xt_SYSRQ.man to reflect that the full IPv6 address is needed
Enhancements:
- Support for Linux 3.6
v1.45 (2012-07-16)
==================
Fixes:
- build: export missing functions
(fixes: "WARNING 'xtnu_ipv6_find_hdr' [xt_TARPIT.ko] not found")
- build: avoid use of unexported functions
(fixes: "WARNING 'ipv6_find_hdr' [xt_TARPIT.ko] not found"
in <= linux-2.6.37)
v1.44 (2012-07-15)
==================
Fixes:
- SYSRQ: fix double target initialization at module load
- build: do not attempt to build IPv6 parts if CONFIG_IP6_NF_IPTABLES=n
Enhancements:
- TARPIT gained IPv6 support
v1.43 (2012-06-30)
==================
Fixes:
- xt_psd: avoid crash due to curr->next corruption
Changes:
- xt_psd: reject invalid match options
Enhancements:
- Support for Linux 3.5
- DNETMAP: new type: static binding
- DNETMAP: new persistent flag option for prefix
- DNETMAP: add write support to procfs interface
v1.42 (2012-04-05)
==================
Fixes:
- compat_xtables: fixed mistranslation of checkentry return values
(affected kernels < 2.6.23)
- xt_SYSRQ: fix compile error when crypto is turned off
Changes:
- ipset6-genl has been dropped from the tree;
the libmnl build-time dependency is thus no longer needed
Enhancements:
- Support for Linux 3.3, 3.4
v1.41 (2012-01-04)
==================
Changes:
- Deactivate build of ipset-genl by default.
I think the original ipset package can now take over, given there are
a handful of kernels (2.6.39 onwards) that do not need patching.
Enhancements:
- Support for Linux 3.2
v1.40 (2011-11-30)
==================
Fixes:
- build: the code actually requires at least iptables 1.4.5 (would yield a
compile error otherwise), make sure configure checks for it; update INSTALL
- xt_ECHO: fix kernel warning about RTAX_HOPLIMIT being used
- xt_ipv4options: fix an infinite loop
Changes:
- xt_ECHO: now calculates UDP checksum
- Linux kernel versions below 2.6.32 are no longer officially
supported, and will not be part of compilation testing.
- update to ipset 6.10
Enhancements:
- xt_ECHO: IPv6 support
v1.39 (2011-09-21)
==================
Fixes:
- libxt_ACCOUNT: fix compilation after missing libxtables_CFLAGS
- build: fix compilation after missing libxtables_CFLAGS in submodules
- build: add missing linux/version.h includes where needed
Changes:
- Remove unsupported ipset 4.x from the Xtables-addons distribution
- ipset: move ipset_errcode from src to library to avoid undefined reference
- update to ipset 6.9.1
v1.38 (2011-08-20)
==================
- xt_CHECKSUM: abort build when the feature is already provided by mainline
- xt_SYSRQ: fix UDPLITE header lookup in IPv6
- xt_TARPIT: fix kernel warning about RTAX_HOPLIMIT being used
- xt_TEE: abort build when the feature is already provided by mainline
- xt_ipp2p: support UDPLITE
- xt_pknock: support UDPLITE
- xt_psd: restore functionality with UDP
- xt_psd: support UDPLITE
- update to ipset 6.8
- support for Linux 3.1
v1.37 (2011-06-25)
==================
Fixes:
- xt_SYSRQ: make IPv6 trigger work again
- xt_SYSRQ: improve security: include host address in digest
- xt_TARPIT: fix a kernel oops in --reset mode
v1.36 (2011-06-03)
==================
Changes:
- xt_geoip: avoid recursive function calls
- xt_TARPIT: unlock for use in all tables
- xt_TARPIT: honeypot and reset modes
- update to ipset 6.7
- support for Linux 3.0
v1.35 (2011-04-11)
==================
Enhancements:
- update to ipset 6.3
* allow "new" as a commad alias to "create"
* resolving IP addresses did not work at listing/saving sets, fixed
* check ICMP and ICMPv6 with the set match and target in the testsuite
* avoid possible syntax clashing at saving hostnames
* fix linking with CONFIG_IPV6=n
* sctp, udplite support for the hash:*port* types
- ipset-genl: handle EAGAIN return value emitted from autoloader
- ipset-genl: resolve nfgenmsg remains and fix spurious protocol abort
v1.34 (2011-04-07)
==================
Fixes:
- xt_pknock: avoid crash when hash TFM could not be allocated
- xt_pknock: avoid inversion of rule lookup that led to warnings
- xt_DNETMAP: add missing module alias
- xt_DNETMAP: support for kernels below 2.6.34
Changes:
- Linux kernel versions below 2.6.29 are no longer officially
supported, and will not be part of compilation testing.
v1.33 (2011-02-02)
==================
Fixes:
- build: restore functionality of `configure --without-kbuild`
- build: fix objdir builds for ipset-5 (xt-a specific)
- build: fix missing inclusion of dependency rules
- xt_LOGMARK: fix detection of untracked connection for Linux >= 2.6.36
Enhancements:
- IPv6 support for xt_geoip
- Update to ipset 5.3
* make IPv4 and IPv6 address handling similar
* show correct line numbers in restore output for parser errors
- Update to ipset 5.4
* fixed ICMP and ICMPv6 handling
* fixed trailing whitespaces and pr_* messages
* fixed module loading at create/header commands
- build: support for Linux up to 2.6.38
- build: preliminary support for iptables 1.4.11
v1.32 (2011-01-04)
==================
Fixes:
- Update to ipset 4.5
* the iptreemap type used wrong gfp flags when deleting entries
- Include ipset 5.2 with genetlink patch (beta)
* no kernel patch needed, but requires Linux >= 2.6.35
and thus needs to be manually enabled in mconfig
v1.31 (2010-11-05)
==================
Fixes:
- build: improve detection of kernel version and error handling
Changes:
- build: automatically derive Xtables module directory, thus
--with-xtlibdir is no longer needed for ./configure in most cases
(If I still see a distro using it, I will scold you for not
reading this changelog.)
Enhancements:
- LOGMARK: print remaining lifetime of cts
- xt_iface: allow matching against incoming/outgoing interface
- libxt_gradm: match packets based on status of grsecurity RBAC
(userspace part only - xt_gradm is in the grsec patch)
v1.30 (2010-010-02)
===================
Fixes:
- update to ipset 4.4
* ipport{,ip,net}hash did not work with mixed "src" and "dst"
destination parameters
Changes:
- deactivate building xt_TEE and xt_CHECKSUM by default, as these have been
merged upstream in Linux 2.6.35 and 2.6.36, respectively.
Distros still wishing to build this need to enable it in their build
script, e.g. perl -i -pe 's{^build_TEE=.*}{build_TEE=m}' mconfig;
v1.29 (2010-09-29)
==================
- compat_xtables: return bool for match_check and target_check in 2.6.23..34
- ipset: enable building of ip_set_ipport{ip,net}hash.ko
- support for Linux 2.6.36
- SYSRQ: resolve compile error with Linux 2.6.36
- TEE: resolve compile error with Linux 2.6.36
- add workaround for broken linux-glibc-devel 2.6.34 userspace headers
("implicit declaration of function 'ALIGN'")
v1.28 (2010-07-24)
==================
- RAWNAT: IPv6 variants erroneously rejected masks /33-/128
- new target xt_CHECKSUM
- xt_length2: add support for IPv6 jumbograms
- xt_geoip: fix possible out-of-bounds access
- import xt_geoip database scripts
v1.27 (2010-05-16)
==================
- further updates for the upcoming 2.6.35 changes
v1.26 (2010-04-30)
==================
- compat_xtables: fix 2.6.34 compile error due to a typo
v1.25 (2010-04-26)
==================
- TEE: do rechecksumming in PREROUTING too
- TEE: decrease TTL on cloned packet
- TEE: set dont-fragment on cloned packets
- TEE: free skb when route lookup failed
- TEE: do not limit use to mangle table
- TEE: do not retain iif and mark on cloned packet
- TEE: new loop detection logic
- TEE: use less expensive pskb_copy
- condition: remove unnecessary RCU protection
v1.24 (2010-03-17)
==================
- build: fix build of userspace modules against old (pre-2.6.25)
headers from linux-glibc-devel (/usr/include/linux)
- ipp2p: updated bittorent command recognition
- SYSRQ: let module load when crypto is unavailable
- SYSRQ: allow processing of UDP-Lite
v1.23 (2010-02-24)
==================
- build: support for Linux 2.6.34
- build: remove unused --with-ksource option
- build: remove unneeded --with-xtables option
- build: fix compilations in RAWNAT, SYSRQ and length2 when CONFIG_IPV6=n
- ipset: update to 4.2
- ECHO: fix compilation w.r.t. skb_dst
v1.22 (2010-01-22)
==================
- compat_xtables: support for 2.6.33 skb_iif changes
- geoip: for FHS compliance use /usr/share/xt_geoip instead of /var/geoip
- ipset: enable build of ip_set_setlist.ko
- quota2: add the --no-change mode
v1.21 (2009-12-09)
==================
- ACCOUNT: avoid collision with arp_tables setsockopt numbers
- doc: fix option mismatch --gw/--gateway in libxt_TEE.man
v1.20 (2009-11-19)
==================
- ipp2p: add more boundary checks
- ipp2p: fix Gnutelle line ending detection
- LOGMARK: remove unknown options from manpage
- ACCOUNT: endianess-correctness
- ipset: install manpage
- ipset: fast forward to v4.1
v1.19 (2009-10-12)
==================
- build: compile fixes for 2.6.31-rt
- build: support for Linux 2.6.32
- ipp2p: try to address underflows
- psd: avoid potential crash when dealing with non-linear skbs
- merge xt_ACCOUNT userspace utilities
- added reworked xt_pknock module
Changes from pknock v0.5:
- pknock: "strict" and "checkip" flags were not displayed in `iptables -L`
- pknock: the GC expire time's lower bound is now the default gc time
(65000 msec) to avoid rendering anti-spoof protection in SPA mode useless
- pknock: avoid crash on memory allocation failure and fix memleak
- pknock: avoid fillup of peer table during DDoS
- pknock: automatic closing of ports
- pknock: make non-zero time mandatory for TCP mode
- pknock: display only pknock mode and state relevant information in procfs
- pknock: check interknock time only for !ST_ALLOWED peers
- pknock: preserve time/autoclose values for rules added in
reverse/arbitrary order
- pknock: add a manpage
v1.18 (2009-09-09)
==================
- build: support for Linux 2.6.31
- ipset: fast forward to v3.2
- quota2: support anonymous counters
- quota2: reduce memory footprint for anonymous counters
- quota2: extend locked period during cleanup (locking bugfix)
- quota2: use strtoull instead of strtoul
- merged xt_ACCOUNT module
- merged xt_psd module
v1.17 (2009-06-16)
==================
- IPMARK: print missing --shift parameter
- build: use readlink -f in extensions/ipset/
- build: support for Linux 2.6.30
v1.16 (2009-05-27)
==================
- RAWNAT: make iptable_rawpost compile with 2.6.30-rc5
- ipset: fast forward to 3.0
v1.15 (2009-04-30)
==================
- build: add kernel version check to configure
- condition: compile fix for 2.6.30-rc
- condition: fix intrapositional negation sign
- fuzzy: fix bogus comparison logic leftover from move to new 1.4.3 API
- ipp2p: fix bogus varargs call
- ipp2p: fix typo in error message
- added "iface" match
- added rawpost table (for use with RAWNAT)
- added RAWSNAT/RAWDNAT targets
v1.14 (2009-03-31)
==================
- fuzzy: need to account for kernel-level modified variables in .userspacesize
- geoip: remove XT_ALIGN from .userspacesize when used with offsetof
- SYSRQ: ignore non-UDP packets
- SYSRQ: do proper L4 header access in IPv6 code
(must not use tcp/udp_hdr in input path)
- add "STEAL" target
- dhcpmac: rename from dhcpaddr
v1.13 (2009-03-23)
==================
- added a reworked ipv4options match
- upgrade to iptables 1.4.3 API
v1.12 (2009-03-07)
==================
- ipset: fix for compilation with 2.6.29-rt
- ipset: fast forward to 2.5.0
- rename xt_portscan to xt_lscan ("low-level scan") because
"portscan" as a word caused confusion
- xt_LOGMARK: print incoming interface index
- revert "TEE: do not use TOS for routing"
- xt_TEE: resolve unknown symbol error with CONFIG_IPV6=n
- xt_TEE: enable routing by iif, nfmark and flowlabel
v1.10 (2009-02-18)
==================
- compat: compile fixes for 2.6.29
- ipset: upgrade to ipset 2.4.9
v1.9 (2009-01-30)
=================
- add the xt_length2 extension
- xt_TEE: remove intrapositional '!' support
- ipset: upgrade to ipset 2.4.7
v1.8 (2009-01-10)
=================
- xt_TEE: IPv6 support
- xt_TEE: do not include TOS value in routing decision
- xt_TEE: fix switch-case inversion for name/IP display
- xt_ipp2p: update manpages and help text
- xt_ipp2p: remove log flooding
- xt_portscan: update manpage about --grscan option caveats
v1.7 (2008-12-25)
=================
- xt_ECHO: compile fix
- avoid the use of "_init" which led to compile errors on some installations
- build: do not unconditionally install ipset
- doc: add manpages for xt_ECHO and xt_TEE
- xt_ipp2p: kazaa detection code cleanup
- xt_ipp2p: fix newline inspection in kazaa detection
- xt_ipp2p: ensure better array bounds checking
- xt_SYSRQ: improve security by hashing password
v1.6 (2008-11-18)
=================
- build: support for Linux 2.6.17
- build: compile fixes for 2.6.18 and 2.6.19
- xt_ECHO: resolve compile errors in xt_ECHO
- xt_ipp2p: parenthesize unaligned-access macros
v1.5.7 (2008-09-01)
===================
- API layer: fix use of uninitialized 'hotdrop' variable
- API layer: move to pskb-based signatures
- xt_SYSRQ: compile fixes for Linux <= 2.6.19
- ipset: adjust semaphore.h include for Linux >= 2.6.27
- build: automatically run `depmod -a` on installation
- add reworked xt_fuzzy module
- add DHCP address match and mangle module
- xt_portscan: IPv6 support
- xt_SYSRQ: add missing module aliases
v1.5.5 (2008-08-03)
===================
- manpage updates for xt_CHAOS, xt_IPMARK; README updates
- build: properly recognize external Kbuild/Mbuild files
- build: remove dependency on CONFIG_NETWORK_SECMARK
- add the xt_SYSRQ target
- add the xt_quota2 extension
- import ipset extension group
v1.5.4.1 (2008-04-26)
=====================
- build: fix compile error for 2.6.18-stable
v1.5.4 (2008-04-09)
===================
- build: support building multiple files with one config option
- API layer: add check for pskb relocation
- doc: generate manpages
- xt_ECHO: catch skb_linearize out-of-memory condition
- xt_LOGMARK: add hook= and ctdir= fields in dump
- xt_LOGMARK: fix comma output in ctstatus= list
- xt_TEE: fix address copying bug
- xt_TEE: make skb writable before attempting checksum update
- add reworked xt_condition match
- add reworked xt_ipp2p match
- add reworked xt_IPMARK target
v1.5.3 (2008-03-22)
===================
- support for Linux 2.6.18
- add xt_ECHO sample target
- add reworked xt_geoip match
v1.5.2 (2008-03-04)
===================
- build: support for GNU make < 3.81 which does not have $(realpath)
v1.5.1 (2008-02-21)
===================
- build: allow user to select what extensions to compile and install
- build: allow external proejcts to be downloaded into the tree
- xt_LOGMARK: dump classify mark, ctstate and ctstatus
- add xt_CHAOS, xt_DELUDE and xt_portscan from Chaostables
v1.5.0 (2008-02-11)
===================
Initial release with:
- extensions: xt_LOGMARK, xt_TARPIT, xt_TEE
- support for Linux >= 2.6.19

View File

@@ -64,7 +64,7 @@ int main(int argc, char *argv[])
struct ipt_ACCOUNT_context ctx; struct ipt_ACCOUNT_context ctx;
struct ipt_acc_handle_ip *entry; struct ipt_acc_handle_ip *entry;
int i; int i;
int optchar; char optchar;
bool doHandleUsage = false, doHandleFree = false, doTableNames = false; bool doHandleUsage = false, doHandleFree = false, doTableNames = false;
bool doFlush = false, doContinue = false, doCSV = false; bool doFlush = false, doContinue = false, doCSV = false;
@@ -200,19 +200,13 @@ int main(int argc, char *argv[])
while ((entry = ipt_ACCOUNT_get_next_entry(&ctx)) != NULL) while ((entry = ipt_ACCOUNT_get_next_entry(&ctx)) != NULL)
{ {
if (doCSV) if (doCSV)
printf("%s;%llu;%llu;%llu;%llu\n", printf("%s;%u;%u;%u;%u\n",
addr_to_dotted(entry->ip), addr_to_dotted(entry->ip), entry->src_packets, entry->src_bytes,
(unsigned long long)entry->src_packets, entry->dst_packets, entry->dst_bytes);
(unsigned long long)entry->src_bytes,
(unsigned long long)entry->dst_packets,
(unsigned long long)entry->dst_bytes);
else else
printf("IP: %s SRC packets: %llu bytes: %llu DST packets: %llu bytes: %llu\n", printf("IP: %s SRC packets: %u bytes: %u DST packets: %u bytes: %u\n",
addr_to_dotted(entry->ip), addr_to_dotted(entry->ip), entry->src_packets, entry->src_bytes,
(unsigned long long)entry->src_packets, entry->dst_packets, entry->dst_bytes);
(unsigned long long)entry->src_bytes,
(unsigned long long)entry->dst_packets,
(unsigned long long)entry->dst_bytes);
} }
if (doContinue) if (doContinue)

View File

@@ -34,8 +34,7 @@ int ipt_ACCOUNT_init(struct ipt_ACCOUNT_context *ctx)
// 4096 bytes default buffer should save us from reallocations // 4096 bytes default buffer should save us from reallocations
// as it fits 200 concurrent active clients // as it fits 200 concurrent active clients
ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE); if ((ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE)) == NULL) {
if (ctx->data == NULL) {
close(ctx->sockfd); close(ctx->sockfd);
ctx->sockfd = -1; ctx->sockfd = -1;
ctx->error_str = "Out of memory for data buffer"; ctx->error_str = "Out of memory for data buffer";

View File

@@ -15,7 +15,6 @@
//#define DEBUG 1 //#define DEBUG 1
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h> #include <linux/version.h>
#include <net/net_namespace.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <net/icmp.h> #include <net/icmp.h>
@@ -23,17 +22,17 @@
#include <net/tcp.h> #include <net/tcp.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
#include <linux/semaphore.h> #include <linux/semaphore.h>
#else
#include <asm/semaphore.h>
#endif
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/string.h> #include <linux/string.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
#include <linux/sockptr.h>
#endif
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/netns/generic.h>
#include <net/route.h> #include <net/route.h>
#include "xt_ACCOUNT.h" #include "xt_ACCOUNT.h"
@@ -43,9 +42,6 @@
#error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096" #error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096"
#endif #endif
static unsigned int max_tables_limit = 128;
module_param(max_tables_limit, uint, 0);
/** /**
* Internal table structure, generated by check_entry() * Internal table structure, generated by check_entry()
* @name: name of the table * @name: name of the table
@@ -81,13 +77,13 @@ struct ipt_acc_handle {
}; };
/* Used for every IP entry /* Used for every IP entry
Size is 32 bytes so that 256 (class C network) * 16 Size is 16 bytes so that 256 (class C network) * 16
fits in a double kernel (zero) page (two consecutive kernel pages)*/ fits in one kernel (zero) page */
struct ipt_acc_ip { struct ipt_acc_ip {
uint64_t src_packets; uint32_t src_packets;
uint64_t src_bytes; uint32_t src_bytes;
uint64_t dst_packets; uint32_t dst_packets;
uint64_t dst_bytes; uint32_t dst_bytes;
}; };
/* /*
@@ -108,28 +104,25 @@ struct ipt_acc_mask_8 {
struct ipt_acc_mask_16 *mask_16[256]; struct ipt_acc_mask_16 *mask_16[256];
}; };
static int ipt_acc_net_id __read_mostly; static struct ipt_acc_table *ipt_acc_tables;
static struct ipt_acc_handle *ipt_acc_handles;
static void *ipt_acc_tmpbuf;
struct ipt_acc_net {
/* Spinlock used for manipulating the current accounting tables/data */ /* Spinlock used for manipulating the current accounting tables/data */
spinlock_t ipt_acc_lock; static DEFINE_SPINLOCK(ipt_acc_lock);
/* Mutex (semaphore) used for manipulating userspace handles/snapshot data */ /* Mutex (semaphore) used for manipulating userspace handles/snapshot data */
struct semaphore ipt_acc_userspace_mutex; static struct semaphore ipt_acc_userspace_mutex;
struct ipt_acc_table *ipt_acc_tables; /* Allocates a page and clears it */
struct ipt_acc_handle *ipt_acc_handles;
void *ipt_acc_tmpbuf;
};
/* Allocates a page pair and clears it */
static void *ipt_acc_zalloc_page(void) static void *ipt_acc_zalloc_page(void)
{ {
// Don't use get_zeroed_page until it's fixed in the kernel. // Don't use get_zeroed_page until it's fixed in the kernel.
// get_zeroed_page(GFP_ATOMIC) // get_zeroed_page(GFP_ATOMIC)
void *mem = (void *)__get_free_pages(GFP_ATOMIC, 2); void *mem = (void *)__get_free_page(GFP_ATOMIC);
if (mem != NULL) if (mem) {
memset(mem, 0, 2 *PAGE_SIZE); memset (mem, 0, PAGE_SIZE);
}
return mem; return mem;
} }
@@ -142,7 +135,7 @@ static void ipt_acc_data_free(void *data, uint8_t depth)
/* Free for 8 bit network */ /* Free for 8 bit network */
if (depth == 0) { if (depth == 0) {
free_pages((unsigned long)data, 2); free_page((unsigned long)data);
return; return;
} }
@@ -150,10 +143,12 @@ static void ipt_acc_data_free(void *data, uint8_t depth)
if (depth == 1) { if (depth == 1) {
struct ipt_acc_mask_16 *mask_16 = data; struct ipt_acc_mask_16 *mask_16 = data;
unsigned int b; unsigned int b;
for (b = 0; b <= 255; ++b) for (b = 0; b <= 255; b++) {
if (mask_16->mask_24[b]) if (mask_16->mask_24[b]) {
free_pages((unsigned long)mask_16->mask_24[b], 2); free_page((unsigned long)mask_16->mask_24[b]);
free_pages((unsigned long)data, 2); }
}
free_page((unsigned long)data);
return; return;
} }
@@ -165,13 +160,15 @@ static void ipt_acc_data_free(void *data, uint8_t depth)
struct ipt_acc_mask_16 *mask_16 = struct ipt_acc_mask_16 *mask_16 =
((struct ipt_acc_mask_8 *)data)->mask_16[a]; ((struct ipt_acc_mask_8 *)data)->mask_16[a];
for (b = 0; b <= 255; ++b) for (b = 0; b <= 255; b++) {
if (mask_16->mask_24[b]) if (mask_16->mask_24[b]) {
free_pages((unsigned long)mask_16->mask_24[b], 2); free_page((unsigned long)mask_16->mask_24[b]);
free_pages((unsigned long)mask_16, 2);
} }
} }
free_pages((unsigned long)data, 2); free_page((unsigned long)mask_16);
}
}
free_page((unsigned long)data);
return; return;
} }
@@ -182,27 +179,28 @@ static void ipt_acc_data_free(void *data, uint8_t depth)
/* Look for existing table / insert new one. /* Look for existing table / insert new one.
Return internal ID or -1 on error */ Return internal ID or -1 on error */
static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables, static int ipt_acc_table_insert(const char *name, __be32 ip, __be32 netmask)
const char *name, __be32 ip, __be32 netmask)
{ {
unsigned int i; unsigned int i;
pr_debug("ACCOUNT: ipt_acc_table_insert: %s, %pI4/%pI4\n", pr_debug("ACCOUNT: ipt_acc_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n",
name, &ip, &netmask); name, NIPQUAD(ip), NIPQUAD(netmask));
/* Look for existing table */ /* Look for existing table */
for (i = 0; i < max_tables_limit; i++) { for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (strncmp(ipt_acc_tables[i].name, name, if (strncmp(ipt_acc_tables[i].name, name,
ACCOUNT_TABLE_NAME_LEN) == 0) { ACCOUNT_TABLE_NAME_LEN) == 0) {
pr_debug("ACCOUNT: Found existing slot: %d - %pI4/%pI4\n", pr_debug("ACCOUNT: Found existing slot: %d - "
i, &ipt_acc_tables[i].ip, &ipt_acc_tables[i].netmask); "%u.%u.%u.%u/%u.%u.%u.%u\n", i,
NIPQUAD(ipt_acc_tables[i].ip),
NIPQUAD(ipt_acc_tables[i].netmask));
if (ipt_acc_tables[i].ip != ip if (ipt_acc_tables[i].ip != ip
|| ipt_acc_tables[i].netmask != netmask) { || ipt_acc_tables[i].netmask != netmask) {
printk("ACCOUNT: Table %s found, but IP/netmask mismatch. " printk("ACCOUNT: Table %s found, but IP/netmask mismatch. "
"IP/netmask found: %pI4/%pI4\n", "IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
name, &ipt_acc_tables[i].ip, name, NIPQUAD(ipt_acc_tables[i].ip),
&ipt_acc_tables[i].netmask); NIPQUAD(ipt_acc_tables[i].netmask));
return -1; return -1;
} }
@@ -213,7 +211,7 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
} }
/* Insert new table */ /* Insert new table */
for (i = 0; i < max_tables_limit; i++) { for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
/* Found free slot */ /* Found free slot */
if (ipt_acc_tables[i].name[0] == 0) { if (ipt_acc_tables[i].name[0] == 0) {
unsigned int netsize = 0; unsigned int netsize = 0;
@@ -262,21 +260,19 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
/* No free slot found */ /* No free slot found */
printk("ACCOUNT: No free table slot found (max: %d). " printk("ACCOUNT: No free table slot found (max: %d). "
"Please increase the \"max_tables_limit\" module parameter.\n", max_tables_limit); "Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
return -1; return -1;
} }
static int ipt_acc_checkentry(const struct xt_tgchk_param *par) static int ipt_acc_checkentry(const struct xt_tgchk_param *par)
{ {
struct ipt_acc_net *ian = net_generic(par->net, ipt_acc_net_id);
struct ipt_acc_info *info = par->targinfo; struct ipt_acc_info *info = par->targinfo;
int table_nr; int table_nr;
spin_lock_bh(&ian->ipt_acc_lock); spin_lock_bh(&ipt_acc_lock);
table_nr = ipt_acc_table_insert(ian->ipt_acc_tables, table_nr = ipt_acc_table_insert(info->table_name, info->net_ip,
info->table_name, info->net_ip,
info->net_mask); info->net_mask);
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
if (table_nr == -1) { if (table_nr == -1) {
printk("ACCOUNT: Table insert problem. Aborting\n"); printk("ACCOUNT: Table insert problem. Aborting\n");
@@ -291,11 +287,10 @@ static int ipt_acc_checkentry(const struct xt_tgchk_param *par)
static void ipt_acc_destroy(const struct xt_tgdtor_param *par) static void ipt_acc_destroy(const struct xt_tgdtor_param *par)
{ {
struct ipt_acc_net *ian = net_generic(par->net, ipt_acc_net_id);
unsigned int i; unsigned int i;
struct ipt_acc_info *info = par->targinfo; struct ipt_acc_info *info = par->targinfo;
spin_lock_bh(&ian->ipt_acc_lock); spin_lock_bh(&ipt_acc_lock);
pr_debug("ACCOUNT: ipt_acc_deleteentry called for table: %s (#%d)\n", pr_debug("ACCOUNT: ipt_acc_deleteentry called for table: %s (#%d)\n",
info->table_name, info->table_nr); info->table_name, info->table_nr);
@@ -303,32 +298,32 @@ static void ipt_acc_destroy(const struct xt_tgdtor_param *par)
info->table_nr = -1; /* Set back to original state */ info->table_nr = -1; /* Set back to original state */
/* Look for table */ /* Look for table */
for (i = 0; i < max_tables_limit; i++) { for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (strncmp(ian->ipt_acc_tables[i].name, info->table_name, if (strncmp(ipt_acc_tables[i].name, info->table_name,
ACCOUNT_TABLE_NAME_LEN) == 0) { ACCOUNT_TABLE_NAME_LEN) == 0) {
pr_debug("ACCOUNT: Found table at slot: %d\n", i); pr_debug("ACCOUNT: Found table at slot: %d\n", i);
ian->ipt_acc_tables[i].refcount--; ipt_acc_tables[i].refcount--;
pr_debug("ACCOUNT: Refcount left: %d\n", pr_debug("ACCOUNT: Refcount left: %d\n",
ian->ipt_acc_tables[i].refcount); ipt_acc_tables[i].refcount);
/* Table not needed anymore? */ /* Table not needed anymore? */
if (ian->ipt_acc_tables[i].refcount == 0) { if (ipt_acc_tables[i].refcount == 0) {
pr_debug("ACCOUNT: Destroying table at slot: %d\n", i); pr_debug("ACCOUNT: Destroying table at slot: %d\n", i);
ipt_acc_data_free(ian->ipt_acc_tables[i].data, ipt_acc_data_free(ipt_acc_tables[i].data,
ian->ipt_acc_tables[i].depth); ipt_acc_tables[i].depth);
memset(&ian->ipt_acc_tables[i], 0, memset(&ipt_acc_tables[i], 0,
sizeof(struct ipt_acc_table)); sizeof(struct ipt_acc_table));
} }
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
return; return;
} }
} }
/* Table not found */ /* Table not found */
printk("ACCOUNT: Table %s not found for destroy\n", info->table_name); printk("ACCOUNT: Table %s not found for destroy\n", info->table_name);
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
} }
static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24, static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
@@ -341,8 +336,9 @@ static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
/* Check if this entry is new */ /* Check if this entry is new */
bool is_src_new_ip = false, is_dst_new_ip = false; bool is_src_new_ip = false, is_dst_new_ip = false;
pr_debug("ACCOUNT: ipt_acc_depth0_insert: %pI4/%pI4 for net %pI4/%pI4," pr_debug("ACCOUNT: ipt_acc_depth0_insert: %u.%u.%u.%u/%u.%u.%u.%u "
" size: %u\n", &src_ip, &dst_ip, &net_ip, &netmask, size); "for net %u.%u.%u.%u/%u.%u.%u.%u, size: %u\n", NIPQUAD(src_ip),
NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask), size);
/* Check if src/dst is inside our network. */ /* Check if src/dst is inside our network. */
/* Special: net_ip = 0.0.0.0/0 gets stored as src in slot 0 */ /* Special: net_ip = 0.0.0.0/0 gets stored as src in slot 0 */
@@ -354,8 +350,9 @@ static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
is_dst = true; is_dst = true;
if (!is_src && !is_dst) { if (!is_src && !is_dst) {
pr_debug("ACCOUNT: Skipping packet %pI4/%pI4 for net %pI4/%pI4\n", pr_debug("ACCOUNT: Skipping packet %u.%u.%u.%u/%u.%u.%u.%u "
&src_ip, &dst_ip, &net_ip, &netmask); "for net %u.%u.%u.%u/%u.%u.%u.%u\n", NIPQUAD(src_ip),
NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask));
return; return;
} }
@@ -394,11 +391,11 @@ static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
} }
} else { } else {
if (is_src_new_ip) { if (is_src_new_ip) {
pr_debug("ACCOUNT: New src_ip: %pI4\n", &src_ip); pr_debug("ACCOUNT: New src_ip: %u.%u.%u.%u\n", NIPQUAD(src_ip));
++*itemcount; ++*itemcount;
} }
if (is_dst_new_ip) { if (is_dst_new_ip) {
pr_debug("ACCOUNT: New dst_ip: %pI4\n", &dst_ip); pr_debug("ACCOUNT: New dst_ip: %u.%u.%u.%u\n", NIPQUAD(dst_ip));
++*itemcount; ++*itemcount;
} }
} }
@@ -481,24 +478,22 @@ static void ipt_acc_depth2_insert(struct ipt_acc_mask_8 *mask_8,
} }
} }
static unsigned int static unsigned int ipt_acc_target(struct sk_buff **pskb, const struct xt_action_param *par)
ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
{ {
struct ipt_acc_net *ian = net_generic(par->state->net, ipt_acc_net_id);
struct ipt_acc_table *ipt_acc_tables = ian->ipt_acc_tables;
const struct ipt_acc_info *info = const struct ipt_acc_info *info =
par->targinfo; par->targinfo;
__be32 src_ip = ip_hdr(skb)->saddr; __be32 src_ip = ip_hdr(*pskb)->saddr;
__be32 dst_ip = ip_hdr(skb)->daddr; __be32 dst_ip = ip_hdr(*pskb)->daddr;
uint32_t size = ntohs(ip_hdr(skb)->tot_len); uint32_t size = ntohs(ip_hdr(*pskb)->tot_len);
spin_lock_bh(&ian->ipt_acc_lock); spin_lock_bh(&ipt_acc_lock);
if (ipt_acc_tables[info->table_nr].name[0] == 0) { if (ipt_acc_tables[info->table_nr].name[0] == 0) {
printk("ACCOUNT: ipt_acc_target: Invalid table id %u. " printk("ACCOUNT: ipt_acc_target: Invalid table id %u. "
"IPs %pI4/%pI4\n", info->table_nr, &src_ip, &dst_ip); "IPs %u.%u.%u.%u/%u.%u.%u.%u\n", info->table_nr,
spin_unlock_bh(&ian->ipt_acc_lock); NIPQUAD(src_ip), NIPQUAD(dst_ip));
spin_unlock_bh(&ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
@@ -510,7 +505,7 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
ipt_acc_tables[info->table_nr].ip, ipt_acc_tables[info->table_nr].ip,
ipt_acc_tables[info->table_nr].netmask, ipt_acc_tables[info->table_nr].netmask,
src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount); src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
@@ -521,7 +516,7 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
ipt_acc_tables[info->table_nr].ip, ipt_acc_tables[info->table_nr].ip,
ipt_acc_tables[info->table_nr].netmask, ipt_acc_tables[info->table_nr].netmask,
src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount); src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
@@ -532,19 +527,21 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
ipt_acc_tables[info->table_nr].ip, ipt_acc_tables[info->table_nr].ip,
ipt_acc_tables[info->table_nr].netmask, ipt_acc_tables[info->table_nr].netmask,
src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount); src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
printk("ACCOUNT: ipt_acc_target: Unable to process packet. Table id " printk("ACCOUNT: ipt_acc_target: Unable to process packet. "
"%u. IPs %pI4/%pI4\n", info->table_nr, &src_ip, &dst_ip); "Table id %u. IPs %u.%u.%u.%u/%u.%u.%u.%u\n",
spin_unlock_bh(&ian->ipt_acc_lock); info->table_nr, NIPQUAD(src_ip), NIPQUAD(dst_ip));
spin_unlock_bh(&ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
/* /*
Functions dealing with "handles": Functions dealing with "handles":
Handles are snapshots of an accounting state. Handles are snapshots of a accounting state.
read snapshots are only for debugging the code read snapshots are only for debugging the code
and are very expensive concerning speed/memory and are very expensive concerning speed/memory
@@ -559,7 +556,7 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
but there could be two or more applications accessing the data but there could be two or more applications accessing the data
at the same time. at the same time.
*/ */
static int ipt_acc_handle_find_slot(struct ipt_acc_handle *ipt_acc_handles) static int ipt_acc_handle_find_slot(void)
{ {
unsigned int i; unsigned int i;
/* Insert new table */ /* Insert new table */
@@ -579,8 +576,7 @@ static int ipt_acc_handle_find_slot(struct ipt_acc_handle *ipt_acc_handles)
return -1; return -1;
} }
static int ipt_acc_handle_free(struct ipt_acc_handle *ipt_acc_handles, static int ipt_acc_handle_free(unsigned int handle)
unsigned int handle)
{ {
if (handle >= ACCOUNT_MAX_HANDLES) { if (handle >= ACCOUNT_MAX_HANDLES) {
printk("ACCOUNT: Invalid handle for ipt_acc_handle_free() specified:" printk("ACCOUNT: Invalid handle for ipt_acc_handle_free() specified:"
@@ -596,19 +592,18 @@ static int ipt_acc_handle_free(struct ipt_acc_handle *ipt_acc_handles,
/* Prepare data for read without flush. Use only for debugging! /* Prepare data for read without flush. Use only for debugging!
Real applications should use read&flush as it's way more efficent */ Real applications should use read&flush as it's way more efficent */
static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables, static int ipt_acc_handle_prepare_read(char *tablename,
char *tablename,
struct ipt_acc_handle *dest, uint32_t *count) struct ipt_acc_handle *dest, uint32_t *count)
{ {
int table_nr = -1; int table_nr = -1;
uint8_t depth; uint8_t depth;
for (table_nr = 0; table_nr < max_tables_limit; table_nr++) for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
if (strncmp(ipt_acc_tables[table_nr].name, tablename, if (strncmp(ipt_acc_tables[table_nr].name, tablename,
ACCOUNT_TABLE_NAME_LEN) == 0) ACCOUNT_TABLE_NAME_LEN) == 0)
break; break;
if (table_nr == max_tables_limit) { if (table_nr == ACCOUNT_MAX_TABLES) {
printk("ACCOUNT: ipt_acc_handle_prepare_read(): " printk("ACCOUNT: ipt_acc_handle_prepare_read(): "
"Table %s not found\n", tablename); "Table %s not found\n", tablename);
return -1; return -1;
@@ -620,8 +615,7 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
dest->itemcount = ipt_acc_tables[table_nr].itemcount; dest->itemcount = ipt_acc_tables[table_nr].itemcount;
/* allocate "root" table */ /* allocate "root" table */
dest->data = ipt_acc_zalloc_page(); if ((dest->data = ipt_acc_zalloc_page()) == NULL) {
if (dest->data == NULL) {
printk("ACCOUNT: out of memory for root table " printk("ACCOUNT: out of memory for root table "
"in ipt_acc_handle_prepare_read()\n"); "in ipt_acc_handle_prepare_read()\n");
return -1; return -1;
@@ -640,8 +634,7 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
unsigned int b; unsigned int b;
for (b = 0; b <= 255; b++) { for (b = 0; b <= 255; b++) {
if (src_16->mask_24[b] == NULL) if (src_16->mask_24[b]) {
continue;
if ((network_16->mask_24[b] = if ((network_16->mask_24[b] =
ipt_acc_zalloc_page()) == NULL) { ipt_acc_zalloc_page()) == NULL) {
printk("ACCOUNT: out of memory during copy of 16 bit " printk("ACCOUNT: out of memory during copy of 16 bit "
@@ -653,6 +646,7 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
memcpy(network_16->mask_24[b], src_16->mask_24[b], memcpy(network_16->mask_24[b], src_16->mask_24[b],
sizeof(struct ipt_acc_mask_24)); sizeof(struct ipt_acc_mask_24));
} }
}
} else if (depth == 2) { } else if (depth == 2) {
struct ipt_acc_mask_8 *src_8 = struct ipt_acc_mask_8 *src_8 =
ipt_acc_tables[table_nr].data; ipt_acc_tables[table_nr].data;
@@ -661,8 +655,7 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
unsigned int a, b; unsigned int a, b;
for (a = 0; a <= 255; a++) { for (a = 0; a <= 255; a++) {
if (src_8->mask_16[a] == NULL) if (src_8->mask_16[a]) {
continue;
if ((network_8->mask_16[a] = if ((network_8->mask_16[a] =
ipt_acc_zalloc_page()) == NULL) { ipt_acc_zalloc_page()) == NULL) {
printk("ACCOUNT: out of memory during copy of 24 bit network" printk("ACCOUNT: out of memory during copy of 24 bit network"
@@ -678,8 +671,7 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
network_16 = network_8->mask_16[a]; network_16 = network_8->mask_16[a];
for (b = 0; b <= 255; b++) { for (b = 0; b <= 255; b++) {
if (src_16->mask_24[b] == NULL) if (src_16->mask_24[b]) {
continue;
if ((network_16->mask_24[b] = if ((network_16->mask_24[b] =
ipt_acc_zalloc_page()) == NULL) { ipt_acc_zalloc_page()) == NULL) {
printk("ACCOUNT: out of memory during copy of 16 bit" printk("ACCOUNT: out of memory during copy of 16 bit"
@@ -693,6 +685,8 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
} }
} }
} }
}
}
*count = ipt_acc_tables[table_nr].itemcount; *count = ipt_acc_tables[table_nr].itemcount;
@@ -700,27 +694,25 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
} }
/* Prepare data for read and flush it */ /* Prepare data for read and flush it */
static int ipt_acc_handle_prepare_read_flush(struct ipt_acc_table *ipt_acc_tables, static int ipt_acc_handle_prepare_read_flush(char *tablename,
char *tablename,
struct ipt_acc_handle *dest, uint32_t *count) struct ipt_acc_handle *dest, uint32_t *count)
{ {
int table_nr; int table_nr;
void *new_data_page; void *new_data_page;
for (table_nr = 0; table_nr < max_tables_limit; table_nr++) for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
if (strncmp(ipt_acc_tables[table_nr].name, tablename, if (strncmp(ipt_acc_tables[table_nr].name, tablename,
ACCOUNT_TABLE_NAME_LEN) == 0) ACCOUNT_TABLE_NAME_LEN) == 0)
break; break;
if (table_nr == max_tables_limit) { if (table_nr == ACCOUNT_MAX_TABLES) {
printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): " printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
"Table %s not found\n", tablename); "Table %s not found\n", tablename);
return -1; return -1;
} }
/* Try to allocate memory */ /* Try to allocate memory */
new_data_page = ipt_acc_zalloc_page(); if (!(new_data_page = ipt_acc_zalloc_page())) {
if (new_data_page == NULL) {
printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): " printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
"Out of memory!\n"); "Out of memory!\n");
return -1; return -1;
@@ -743,8 +735,7 @@ static int ipt_acc_handle_prepare_read_flush(struct ipt_acc_table *ipt_acc_table
/* Copy 8 bit network data into a prepared buffer. /* Copy 8 bit network data into a prepared buffer.
We only copy entries != 0 to increase performance. We only copy entries != 0 to increase performance.
*/ */
static int ipt_acc_handle_copy_data(struct ipt_acc_net *ian, static int ipt_acc_handle_copy_data(void *to_user, unsigned long *to_user_pos,
void *to_user, unsigned long *to_user_pos,
unsigned long *tmpbuf_pos, unsigned long *tmpbuf_pos,
struct ipt_acc_mask_24 *data, struct ipt_acc_mask_24 *data,
uint32_t net_ip, uint32_t net_OR_mask) uint32_t net_ip, uint32_t net_OR_mask)
@@ -754,11 +745,9 @@ static int ipt_acc_handle_copy_data(struct ipt_acc_net *ian,
unsigned int i; unsigned int i;
for (i = 0; i <= 255; i++) { for (i = 0; i <= 255; i++) {
if (data->ip[i].src_packets == 0 && if (data->ip[i].src_packets || data->ip[i].dst_packets) {
data->ip[i].dst_packets == 0)
continue;
handle_ip.ip = net_ip | net_OR_mask | i; handle_ip.ip = net_ip | net_OR_mask | i;
handle_ip.src_packets = data->ip[i].src_packets; handle_ip.src_packets = data->ip[i].src_packets;
handle_ip.src_bytes = data->ip[i].src_bytes; handle_ip.src_bytes = data->ip[i].src_bytes;
handle_ip.dst_packets = data->ip[i].dst_packets; handle_ip.dst_packets = data->ip[i].dst_packets;
@@ -766,15 +755,16 @@ static int ipt_acc_handle_copy_data(struct ipt_acc_net *ian,
/* Temporary buffer full? Flush to userspace */ /* Temporary buffer full? Flush to userspace */
if (*tmpbuf_pos + handle_ip_size >= PAGE_SIZE) { if (*tmpbuf_pos + handle_ip_size >= PAGE_SIZE) {
if (copy_to_user(to_user + *to_user_pos, ian->ipt_acc_tmpbuf, if (copy_to_user(to_user + *to_user_pos, ipt_acc_tmpbuf,
*tmpbuf_pos)) *tmpbuf_pos))
return -EFAULT; return -EFAULT;
*to_user_pos = *to_user_pos + *tmpbuf_pos; *to_user_pos = *to_user_pos + *tmpbuf_pos;
*tmpbuf_pos = 0; *tmpbuf_pos = 0;
} }
memcpy(ian->ipt_acc_tmpbuf + *tmpbuf_pos, &handle_ip, handle_ip_size); memcpy(ipt_acc_tmpbuf + *tmpbuf_pos, &handle_ip, handle_ip_size);
*tmpbuf_pos += handle_ip_size; *tmpbuf_pos += handle_ip_size;
} }
}
return 0; return 0;
} }
@@ -783,8 +773,7 @@ static int ipt_acc_handle_copy_data(struct ipt_acc_net *ian,
We only copy entries != 0 to increase performance. We only copy entries != 0 to increase performance.
Overwrites ipt_acc_tmpbuf. Overwrites ipt_acc_tmpbuf.
*/ */
static int ipt_acc_handle_get_data(struct ipt_acc_net *ian, static int ipt_acc_handle_get_data(uint32_t handle, void *to_user)
uint32_t handle, void *to_user)
{ {
unsigned long to_user_pos = 0, tmpbuf_pos = 0; unsigned long to_user_pos = 0, tmpbuf_pos = 0;
uint32_t net_ip; uint32_t net_ip;
@@ -796,25 +785,25 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
return -1; return -1;
} }
if (ian->ipt_acc_handles[handle].data == NULL) { if (ipt_acc_handles[handle].data == NULL) {
printk("ACCOUNT: handle %u is BROKEN: Contains no data\n", handle); printk("ACCOUNT: handle %u is BROKEN: Contains no data\n", handle);
return -1; return -1;
} }
net_ip = ntohl(ian->ipt_acc_handles[handle].ip); net_ip = ntohl(ipt_acc_handles[handle].ip);
depth = ian->ipt_acc_handles[handle].depth; depth = ipt_acc_handles[handle].depth;
/* 8 bit network */ /* 8 bit network */
if (depth == 0) { if (depth == 0) {
struct ipt_acc_mask_24 *network = struct ipt_acc_mask_24 *network =
ian->ipt_acc_handles[handle].data; ipt_acc_handles[handle].data;
if (ipt_acc_handle_copy_data(ian, to_user, &to_user_pos, &tmpbuf_pos, if (ipt_acc_handle_copy_data(to_user, &to_user_pos, &tmpbuf_pos,
network, net_ip, 0)) network, net_ip, 0))
return -1; return -1;
/* Flush remaining data to userspace */ /* Flush remaining data to userspace */
if (tmpbuf_pos) if (tmpbuf_pos)
if (copy_to_user(to_user + to_user_pos, ian->ipt_acc_tmpbuf, tmpbuf_pos)) if (copy_to_user(to_user + to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
return -1; return -1;
return 0; return 0;
@@ -823,13 +812,13 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
/* 16 bit network */ /* 16 bit network */
if (depth == 1) { if (depth == 1) {
struct ipt_acc_mask_16 *network_16 = struct ipt_acc_mask_16 *network_16 =
ian->ipt_acc_handles[handle].data; ipt_acc_handles[handle].data;
unsigned int b; unsigned int b;
for (b = 0; b <= 255; b++) { for (b = 0; b <= 255; b++) {
if (network_16->mask_24[b]) { if (network_16->mask_24[b]) {
struct ipt_acc_mask_24 *network = struct ipt_acc_mask_24 *network =
network_16->mask_24[b]; network_16->mask_24[b];
if (ipt_acc_handle_copy_data(ian, to_user, &to_user_pos, if (ipt_acc_handle_copy_data(to_user, &to_user_pos,
&tmpbuf_pos, network, net_ip, (b << 8))) &tmpbuf_pos, network, net_ip, (b << 8)))
return -1; return -1;
} }
@@ -837,7 +826,7 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
/* Flush remaining data to userspace */ /* Flush remaining data to userspace */
if (tmpbuf_pos) if (tmpbuf_pos)
if (copy_to_user(to_user + to_user_pos, ian->ipt_acc_tmpbuf, tmpbuf_pos)) if (copy_to_user(to_user + to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
return -1; return -1;
return 0; return 0;
@@ -846,7 +835,7 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
/* 24 bit network */ /* 24 bit network */
if (depth == 2) { if (depth == 2) {
struct ipt_acc_mask_8 *network_8 = struct ipt_acc_mask_8 *network_8 =
ian->ipt_acc_handles[handle].data; ipt_acc_handles[handle].data;
unsigned int a, b; unsigned int a, b;
for (a = 0; a <= 255; a++) { for (a = 0; a <= 255; a++) {
if (network_8->mask_16[a]) { if (network_8->mask_16[a]) {
@@ -856,7 +845,7 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
if (network_16->mask_24[b]) { if (network_16->mask_24[b]) {
struct ipt_acc_mask_24 *network = struct ipt_acc_mask_24 *network =
network_16->mask_24[b]; network_16->mask_24[b];
if (ipt_acc_handle_copy_data(ian, to_user, if (ipt_acc_handle_copy_data(to_user,
&to_user_pos, &tmpbuf_pos, &to_user_pos, &tmpbuf_pos,
network, net_ip, (a << 16) | (b << 8))) network, net_ip, (a << 16) | (b << 8)))
return -1; return -1;
@@ -867,7 +856,7 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
/* Flush remaining data to userspace */ /* Flush remaining data to userspace */
if (tmpbuf_pos) if (tmpbuf_pos)
if (copy_to_user(to_user + to_user_pos, ian->ipt_acc_tmpbuf, tmpbuf_pos)) if (copy_to_user(to_user + to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
return -1; return -1;
return 0; return 0;
@@ -877,15 +866,8 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
} }
static int ipt_acc_set_ctl(struct sock *sk, int cmd, static int ipt_acc_set_ctl(struct sock *sk, int cmd,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) void *user, unsigned int len)
void *user,
#else
sockptr_t arg,
#endif
unsigned int len)
{ {
struct net *net = sock_net(sk);
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
struct ipt_acc_handle_sockopt handle; struct ipt_acc_handle_sockopt handle;
int ret = -EINVAL; int ret = -EINVAL;
@@ -901,27 +883,22 @@ static int ipt_acc_set_ctl(struct sock *sk, int cmd,
break; break;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0) if (copy_from_user(&handle, user, len)) {
if (copy_from_user(&handle, user, len))
#else
if (copy_from_sockptr(&handle, arg, len))
#endif
{
printk("ACCOUNT: ipt_acc_set_ctl: copy_from_user failed for " printk("ACCOUNT: ipt_acc_set_ctl: copy_from_user failed for "
"IPT_SO_SET_HANDLE_FREE\n"); "IPT_SO_SET_HANDLE_FREE\n");
break; break;
} }
down(&ian->ipt_acc_userspace_mutex); down(&ipt_acc_userspace_mutex);
ret = ipt_acc_handle_free(ian->ipt_acc_handles, handle.handle_nr); ret = ipt_acc_handle_free(handle.handle_nr);
up(&ian->ipt_acc_userspace_mutex); up(&ipt_acc_userspace_mutex);
break; break;
case IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL: { case IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL: {
unsigned int i; unsigned int i;
down(&ian->ipt_acc_userspace_mutex); down(&ipt_acc_userspace_mutex);
for (i = 0; i < ACCOUNT_MAX_HANDLES; i++) for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
ipt_acc_handle_free(ian->ipt_acc_handles, i); ipt_acc_handle_free(i);
up(&ian->ipt_acc_userspace_mutex); up(&ipt_acc_userspace_mutex);
ret = 0; ret = 0;
break; break;
} }
@@ -934,8 +911,6 @@ static int ipt_acc_set_ctl(struct sock *sk, int cmd,
static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len) static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
{ {
struct net *net = sock_net(sk);
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
struct ipt_acc_handle_sockopt handle; struct ipt_acc_handle_sockopt handle;
int ret = -EINVAL; int ret = -EINVAL;
@@ -960,29 +935,28 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
break; break;
} }
spin_lock_bh(&ian->ipt_acc_lock); spin_lock_bh(&ipt_acc_lock);
if (cmd == IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH) if (cmd == IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH)
ret = ipt_acc_handle_prepare_read_flush( ret = ipt_acc_handle_prepare_read_flush(
ian->ipt_acc_tables, handle.name, &dest, &handle.itemcount); handle.name, &dest, &handle.itemcount);
else else
ret = ipt_acc_handle_prepare_read( ret = ipt_acc_handle_prepare_read(
ian->ipt_acc_tables, handle.name, &dest, &handle.itemcount); handle.name, &dest, &handle.itemcount);
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
// Error occured during prepare_read? // Error occured during prepare_read?
if (ret == -1) if (ret == -1)
return -EINVAL; return -EINVAL;
/* Allocate a userspace handle */ /* Allocate a userspace handle */
down(&ian->ipt_acc_userspace_mutex); down(&ipt_acc_userspace_mutex);
handle.handle_nr = ipt_acc_handle_find_slot(ian->ipt_acc_handles); if ((handle.handle_nr = ipt_acc_handle_find_slot()) == -1) {
if (handle.handle_nr == -1) {
ipt_acc_data_free(dest.data, dest.depth); ipt_acc_data_free(dest.data, dest.depth);
up(&ian->ipt_acc_userspace_mutex); up(&ipt_acc_userspace_mutex);
return -EINVAL; return -EINVAL;
} }
memcpy(&ian->ipt_acc_handles[handle.handle_nr], &dest, memcpy(&ipt_acc_handles[handle.handle_nr], &dest,
sizeof(struct ipt_acc_handle)); sizeof(struct ipt_acc_handle));
up(&ian->ipt_acc_userspace_mutex); up(&ipt_acc_userspace_mutex);
if (copy_to_user(user, &handle, if (copy_to_user(user, &handle,
sizeof(struct ipt_acc_handle_sockopt))) { sizeof(struct ipt_acc_handle_sockopt))) {
@@ -1011,19 +985,19 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
break; break;
} }
if (*len < ian->ipt_acc_handles[handle.handle_nr].itemcount if (*len < ipt_acc_handles[handle.handle_nr].itemcount
* sizeof(struct ipt_acc_handle_ip)) { * sizeof(struct ipt_acc_handle_ip)) {
printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %zu)" printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %zu)"
" to store data from IPT_SO_GET_ACCOUNT_GET_DATA\n", " to store data from IPT_SO_GET_ACCOUNT_GET_DATA\n",
*len, ian->ipt_acc_handles[handle.handle_nr].itemcount *len, ipt_acc_handles[handle.handle_nr].itemcount
* sizeof(struct ipt_acc_handle_ip)); * sizeof(struct ipt_acc_handle_ip));
ret = -ENOMEM; ret = -ENOMEM;
break; break;
} }
down(&ian->ipt_acc_userspace_mutex); down(&ipt_acc_userspace_mutex);
ret = ipt_acc_handle_get_data(ian, handle.handle_nr, user); ret = ipt_acc_handle_get_data(handle.handle_nr, user);
up(&ian->ipt_acc_userspace_mutex); up(&ipt_acc_userspace_mutex);
if (ret) { if (ret) {
printk("ACCOUNT: ipt_acc_get_ctl: ipt_acc_handle_get_data" printk("ACCOUNT: ipt_acc_get_ctl: ipt_acc_handle_get_data"
" failed for handle %u\n", handle.handle_nr); " failed for handle %u\n", handle.handle_nr);
@@ -1043,11 +1017,11 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
/* Find out how many handles are in use */ /* Find out how many handles are in use */
handle.itemcount = 0; handle.itemcount = 0;
down(&ian->ipt_acc_userspace_mutex); down(&ipt_acc_userspace_mutex);
for (i = 0; i < ACCOUNT_MAX_HANDLES; i++) for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
if (ian->ipt_acc_handles[i].data) if (ipt_acc_handles[i].data)
handle.itemcount++; handle.itemcount++;
up(&ian->ipt_acc_userspace_mutex); up(&ipt_acc_userspace_mutex);
if (copy_to_user(user, &handle, if (copy_to_user(user, &handle,
sizeof(struct ipt_acc_handle_sockopt))) { sizeof(struct ipt_acc_handle_sockopt))) {
@@ -1061,38 +1035,38 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
uint32_t size = 0, i, name_len; uint32_t size = 0, i, name_len;
char *tnames; char *tnames;
spin_lock_bh(&ian->ipt_acc_lock); spin_lock_bh(&ipt_acc_lock);
/* Determine size of table names */ /* Determine size of table names */
for (i = 0; i < max_tables_limit; i++) { for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (ian->ipt_acc_tables[i].name[0] != 0) if (ipt_acc_tables[i].name[0] != 0)
size += strlen(ian->ipt_acc_tables[i].name) + 1; size += strlen(ipt_acc_tables[i].name) + 1;
} }
size += 1; /* Terminating NULL character */ size += 1; /* Terminating NULL character */
if (*len < size || size > PAGE_SIZE) { if (*len < size || size > PAGE_SIZE) {
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %u < %lu)" printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %u < %lu)"
" to store table names\n", *len, size, PAGE_SIZE); " to store table names\n", *len, size, PAGE_SIZE);
ret = -ENOMEM; ret = -ENOMEM;
break; break;
} }
/* Copy table names to userspace */ /* Copy table names to userspace */
tnames = ian->ipt_acc_tmpbuf; tnames = ipt_acc_tmpbuf;
for (i = 0; i < max_tables_limit; i++) { for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (ian->ipt_acc_tables[i].name[0] != 0) { if (ipt_acc_tables[i].name[0] != 0) {
name_len = strlen(ian->ipt_acc_tables[i].name) + 1; name_len = strlen(ipt_acc_tables[i].name) + 1;
memcpy(tnames, ian->ipt_acc_tables[i].name, name_len); memcpy(tnames, ipt_acc_tables[i].name, name_len);
tnames += name_len; tnames += name_len;
} }
} }
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ipt_acc_lock);
/* Terminating NULL character */ /* Terminating NULL character */
*tnames = 0; *tnames = 0;
/* Transfer to userspace */ /* Transfer to userspace */
if (copy_to_user(user, ian->ipt_acc_tmpbuf, size)) if (copy_to_user(user, ipt_acc_tmpbuf, size))
return -EFAULT; return -EFAULT;
ret = 0; ret = 0;
@@ -1105,59 +1079,6 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
return ret; return ret;
} }
static int __net_init ipt_acc_net_init(struct net *net)
{
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
memset(ian, 0, sizeof(*ian));
sema_init(&ian->ipt_acc_userspace_mutex, 1);
ian->ipt_acc_tables = kcalloc(max_tables_limit,
sizeof(struct ipt_acc_table), GFP_KERNEL);
if (ian->ipt_acc_tables == NULL) {
printk("ACCOUNT: Out of memory allocating account_tables structure");
goto error_cleanup;
}
ian->ipt_acc_handles = kcalloc(ACCOUNT_MAX_HANDLES,
sizeof(struct ipt_acc_handle), GFP_KERNEL);
if (ian->ipt_acc_handles == NULL) {
printk("ACCOUNT: Out of memory allocating account_handles structure");
goto error_cleanup;
}
/* Allocate one page as temporary storage */
ian->ipt_acc_tmpbuf = (void *)__get_free_pages(GFP_KERNEL, 2);
if (ian->ipt_acc_tmpbuf == NULL) {
printk("ACCOUNT: Out of memory for temporary buffer page\n");
goto error_cleanup;
}
return 0;
error_cleanup:
kfree(ian->ipt_acc_tables);
kfree(ian->ipt_acc_handles);
free_pages((unsigned long)ian->ipt_acc_tmpbuf, 2);
return -ENOMEM;
}
static void __net_exit ipt_acc_net_exit(struct net *net)
{
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
kfree(ian->ipt_acc_tables);
kfree(ian->ipt_acc_handles);
free_pages((unsigned long)ian->ipt_acc_tmpbuf, 2);
}
static struct pernet_operations ipt_acc_net_ops = {
.init = ipt_acc_net_init,
.exit = ipt_acc_net_exit,
.id = &ipt_acc_net_id,
.size = sizeof(struct ipt_acc_net),
};
static struct xt_target xt_acc_reg __read_mostly = { static struct xt_target xt_acc_reg __read_mostly = {
.name = "ACCOUNT", .name = "ACCOUNT",
.revision = 1, .revision = 1,
@@ -1181,41 +1102,63 @@ static struct nf_sockopt_ops ipt_acc_sockopts = {
static int __init account_tg_init(void) static int __init account_tg_init(void)
{ {
int ret; sema_init(&ipt_acc_userspace_mutex, 1);
ret = register_pernet_subsys(&ipt_acc_net_ops); if ((ipt_acc_tables =
if (ret < 0) { kmalloc(ACCOUNT_MAX_TABLES *
pr_err("ACCOUNT: cannot register per net operations.\n"); sizeof(struct ipt_acc_table), GFP_KERNEL)) == NULL) {
goto error_out; printk("ACCOUNT: Out of memory allocating account_tables structure");
goto error_cleanup;
}
memset(ipt_acc_tables, 0,
ACCOUNT_MAX_TABLES * sizeof(struct ipt_acc_table));
if ((ipt_acc_handles =
kmalloc(ACCOUNT_MAX_HANDLES *
sizeof(struct ipt_acc_handle), GFP_KERNEL)) == NULL) {
printk("ACCOUNT: Out of memory allocating account_handles structure");
goto error_cleanup;
}
memset(ipt_acc_handles, 0,
ACCOUNT_MAX_HANDLES * sizeof(struct ipt_acc_handle));
/* Allocate one page as temporary storage */
if ((ipt_acc_tmpbuf = (void*)__get_free_page(GFP_KERNEL)) == NULL) {
printk("ACCOUNT: Out of memory for temporary buffer page\n");
goto error_cleanup;
} }
/* Register setsockopt */ /* Register setsockopt */
ret = nf_register_sockopt(&ipt_acc_sockopts); if (nf_register_sockopt(&ipt_acc_sockopts) < 0) {
if (ret < 0) { printk("ACCOUNT: Can't register sockopts. Aborting\n");
pr_err("ACCOUNT: cannot register sockopts.\n"); goto error_cleanup;
goto unreg_pernet;
} }
ret = xt_register_target(&xt_acc_reg); if (xt_register_target(&xt_acc_reg))
if (ret < 0) { goto error_cleanup;
pr_err("ACCOUNT: cannot register sockopts.\n");
goto unreg_sockopt;
}
return 0; return 0;
unreg_sockopt: error_cleanup:
nf_unregister_sockopt(&ipt_acc_sockopts); if (ipt_acc_tables)
unreg_pernet: kfree(ipt_acc_tables);
unregister_pernet_subsys(&ipt_acc_net_ops); if (ipt_acc_handles)
error_out: kfree(ipt_acc_handles);
return ret; if (ipt_acc_tmpbuf)
free_page((unsigned long)ipt_acc_tmpbuf);
return -EINVAL;
} }
static void __exit account_tg_exit(void) static void __exit account_tg_exit(void)
{ {
xt_unregister_target(&xt_acc_reg); xt_unregister_target(&xt_acc_reg);
nf_unregister_sockopt(&ipt_acc_sockopts); nf_unregister_sockopt(&ipt_acc_sockopts);
unregister_pernet_subsys(&ipt_acc_net_ops);
kfree(ipt_acc_tables);
kfree(ipt_acc_handles);
free_page((unsigned long)ipt_acc_tmpbuf);
} }
module_init(account_tg_init); module_init(account_tg_init);

View File

@@ -34,6 +34,7 @@
#define IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES (SO_ACCOUNT_BASE_CTL + 8) #define IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES (SO_ACCOUNT_BASE_CTL + 8)
#define IPT_SO_GET_ACCOUNT_MAX IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES #define IPT_SO_GET_ACCOUNT_MAX IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES
#define ACCOUNT_MAX_TABLES 128
#define ACCOUNT_TABLE_NAME_LEN 32 #define ACCOUNT_TABLE_NAME_LEN 32
#define ACCOUNT_MAX_HANDLES 10 #define ACCOUNT_MAX_HANDLES 10
@@ -58,11 +59,11 @@ struct ipt_acc_handle_sockopt {
Used for every IP when returning data Used for every IP when returning data
*/ */
struct ipt_acc_handle_ip { struct ipt_acc_handle_ip {
__be32 ip, __dummy; __be32 ip;
uint64_t src_packets; uint32_t src_packets;
uint64_t src_bytes; uint32_t src_bytes;
uint64_t dst_packets; uint32_t dst_packets;
uint64_t dst_bytes; uint32_t dst_bytes;
}; };
#endif /* _IPT_ACCOUNT_H */ #endif /* _IPT_ACCOUNT_H */

View File

@@ -7,15 +7,18 @@ obj-m += compat_xtables.o
obj-${build_ACCOUNT} += ACCOUNT/ obj-${build_ACCOUNT} += ACCOUNT/
obj-${build_CHAOS} += xt_CHAOS.o obj-${build_CHAOS} += xt_CHAOS.o
obj-${build_CHECKSUM} += xt_CHECKSUM.o
obj-${build_DELUDE} += xt_DELUDE.o obj-${build_DELUDE} += xt_DELUDE.o
obj-${build_DHCPMAC} += xt_DHCPMAC.o obj-${build_DHCPMAC} += xt_DHCPMAC.o
obj-${build_DNETMAP} += xt_DNETMAP.o obj-${build_DNETMAP} += xt_DNETMAP.o
ifeq (${VERSION},3)
obj-${build_ECHO} += xt_ECHO.o obj-${build_ECHO} += xt_ECHO.o
endif
obj-${build_IPMARK} += xt_IPMARK.o obj-${build_IPMARK} += xt_IPMARK.o
obj-${build_LOGMARK} += xt_LOGMARK.o obj-${build_LOGMARK} += xt_LOGMARK.o
obj-${build_PROTO} += xt_PROTO.o
obj-${build_SYSRQ} += xt_SYSRQ.o obj-${build_SYSRQ} += xt_SYSRQ.o
obj-${build_TARPIT} += xt_TARPIT.o obj-${build_TARPIT} += xt_TARPIT.o
obj-${build_TEE} += xt_TEE.o
obj-${build_condition} += xt_condition.o obj-${build_condition} += xt_condition.o
obj-${build_fuzzy} += xt_fuzzy.o obj-${build_fuzzy} += xt_fuzzy.o
obj-${build_geoip} += xt_geoip.o obj-${build_geoip} += xt_geoip.o

View File

@@ -2,15 +2,16 @@
obj-${build_ACCOUNT} += ACCOUNT/ obj-${build_ACCOUNT} += ACCOUNT/
obj-${build_CHAOS} += libxt_CHAOS.so obj-${build_CHAOS} += libxt_CHAOS.so
obj-${build_CHECKSUM} += libxt_CHECKSUM.so
obj-${build_DELUDE} += libxt_DELUDE.so obj-${build_DELUDE} += libxt_DELUDE.so
obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.so obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.so
obj-${build_DNETMAP} += libxt_DNETMAP.so obj-${build_DNETMAP} += libxt_DNETMAP.so
obj-${build_ECHO} += libxt_ECHO.so obj-${build_ECHO} += libxt_ECHO.so
obj-${build_IPMARK} += libxt_IPMARK.so obj-${build_IPMARK} += libxt_IPMARK.so
obj-${build_LOGMARK} += libxt_LOGMARK.so obj-${build_LOGMARK} += libxt_LOGMARK.so
obj-${build_PROTO} += libxt_PROTO.so
obj-${build_SYSRQ} += libxt_SYSRQ.so obj-${build_SYSRQ} += libxt_SYSRQ.so
obj-${build_TARPIT} += libxt_TARPIT.so obj-${build_TARPIT} += libxt_TARPIT.so
obj-${build_TEE} += libxt_TEE.so
obj-${build_condition} += libxt_condition.so obj-${build_condition} += libxt_condition.so
obj-${build_fuzzy} += libxt_fuzzy.so obj-${build_fuzzy} += libxt_fuzzy.so
obj-${build_geoip} += libxt_geoip.so obj-${build_geoip} += libxt_geoip.so

View File

@@ -0,0 +1,14 @@
#ifndef _COMPAT_NFINETADDR_H
#define _COMPAT_NFINETADDR_H 1
#include <linux/in.h>
#include <linux/in6.h>
union nf_inet_addr {
__be32 ip;
__be32 ip6[4];
struct in_addr in;
struct in6_addr in6;
};
#endif /* _COMPAT_NFINETADDR_H */

View File

@@ -4,8 +4,34 @@
struct tcphdr; struct tcphdr;
struct udphdr; struct udphdr;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
skb->dst = dst;
}
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
{
return skb->dst;
}
static inline struct rtable *skb_rtable(const struct sk_buff *skb)
{
return (void *)skb->dst;
}
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define skb_ifindex(skb) \
(((skb)->input_dev != NULL) ? (skb)->input_dev->ifindex : 0)
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->nfmark)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 32)
# define skb_ifindex(skb) (skb)->iif
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
#else
# define skb_ifindex(skb) (skb)->skb_iif # define skb_ifindex(skb) (skb)->skb_iif
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark) # define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
#endif
#ifdef CONFIG_NETWORK_SECMARK #ifdef CONFIG_NETWORK_SECMARK
# define skb_secmark(skb) ((skb)->secmark) # define skb_secmark(skb) ((skb)->secmark)
@@ -13,4 +39,24 @@ struct udphdr;
# define skb_secmark(skb) 0 # define skb_secmark(skb) 0
#endif #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 */ #endif /* COMPAT_SKBUFF_H */

View File

@@ -21,13 +21,588 @@
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/route.h> #include <net/route.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
# include <linux/export.h> # include <linux/export.h>
#endif
#include "compat_skbuff.h" #include "compat_skbuff.h"
#include "compat_xtnu.h" #include "compat_xtnu.h"
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
# define WITH_IPV6 1 # define WITH_IPV6 1
#endif #endif
#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,
unsigned int protoff, int *hotdrop)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static bool 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,
unsigned int protoff, bool *hotdrop)
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{
struct xtnu_match *nm = xtcompat_numatch(cm);
bool lo_ret;
struct xt_action_param local_par;
local_par.in = in;
local_par.out = out;
local_par.match = cm;
local_par.matchinfo = matchinfo;
local_par.fragoff = offset;
local_par.thoff = protoff;
local_par.hotdrop = false;
local_par.family = NFPROTO_UNSPEC; /* don't have that info */
if (nm == NULL || nm->match == NULL)
return false;
lo_ret = nm->match(skb, &local_par);
*hotdrop = local_par.hotdrop;
return lo_ret;
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) && \
LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
static bool xtnu_match_run(const struct sk_buff *skb,
const struct xt_match_param *par)
{
struct xtnu_match *nm = xtcompat_numatch(par->match);
struct xt_action_param local_par;
bool ret;
local_par.in = par->in;
local_par.out = par->out;
local_par.match = par->match;
local_par.matchinfo = par->matchinfo;
local_par.fragoff = par->fragoff;
local_par.thoff = par->thoff;
local_par.hotdrop = false;
local_par.family = par->family;
if (nm == NULL || nm->match == NULL)
return false;
ret = nm->match(skb, &local_par);
*par->hotdrop = local_par.hotdrop;
return 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)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static bool 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, 27)
{
struct xtnu_match *nm = xtcompat_numatch(cm);
struct xt_mtchk_param local_par = {
.table = table,
.entryinfo = entry,
.match = cm,
.matchinfo = matchinfo,
.hook_mask = hook_mask,
.family = NFPROTO_UNSPEC,
};
if (nm == NULL)
return false;
if (nm->checkentry == NULL)
return true;
return nm->checkentry(&local_par) == 0;
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) && \
LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
static bool xtnu_match_check(const struct xt_mtchk_param *par)
{
struct xtnu_match *nm = xtcompat_numatch(par->match);
if (nm == NULL)
return false;
if (nm->checkentry == NULL)
return true;
return nm->checkentry(par) == 0;
}
#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, 27)
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo)
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{
struct xtnu_match *nm = xtcompat_numatch(cm);
struct xt_mtdtor_param local_par = {
.match = cm,
.matchinfo = matchinfo,
.family = NFPROTO_UNSPEC,
};
if (nm != NULL && nm->destroy != NULL)
nm->destroy(&local_par);
}
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
int xtnu_register_match(struct xtnu_match *nt)
{
struct xt_match *ct;
char *tmp;
int ret;
ct = kzalloc(sizeof(struct xt_match), GFP_KERNEL);
if (ct == NULL)
return -ENOMEM;
tmp = (char *)ct->name;
memcpy(tmp, nt->name, sizeof(nt->name));
tmp = (char *)(ct->name + sizeof(ct->name) - sizeof(void *));
*(tmp-1) = '\0';
memcpy(tmp, &nt, sizeof(void *));
ct->revision = nt->revision;
ct->family = nt->family;
ct->table = (char *)nt->table;
ct->hooks = nt->hooks;
ct->proto = nt->proto;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
ct->match = xtnu_match_run;
ct->checkentry = xtnu_match_check;
ct->destroy = xtnu_match_destroy;
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
ct->match = xtnu_match_run;
ct->checkentry = xtnu_match_check;
ct->destroy = nt->destroy;
#else
ct->match = nt->match;
ct->checkentry = xtnu_match_check;
ct->destroy = nt->destroy;
#endif
ct->matchsize = nt->matchsize;
ct->me = nt->me;
nt->__compat_match = ct;
ret = xt_register_match(ct);
if (ret != 0)
kfree(ct);
return ret;
}
EXPORT_SYMBOL_GPL(xtnu_register_match);
int xtnu_register_matches(struct xtnu_match *nt, unsigned int num)
{
unsigned int i;
int ret;
for (i = 0; i < num; ++i) {
ret = xtnu_register_match(&nt[i]);
if (ret < 0) {
if (i > 0)
xtnu_unregister_matches(nt, i);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(xtnu_register_matches);
void xtnu_unregister_match(struct xtnu_match *nt)
{
xt_unregister_match(nt->__compat_match);
kfree(nt->__compat_match);
}
EXPORT_SYMBOL_GPL(xtnu_unregister_match);
void xtnu_unregister_matches(struct xtnu_match *nt, unsigned int num)
{
unsigned int i;
for (i = 0; i < num; ++i)
xtnu_unregister_match(&nt[i]);
}
EXPORT_SYMBOL_GPL(xtnu_unregister_matches);
#endif
#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)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static unsigned int xtnu_target_run(struct sk_buff *skb,
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, 27)
{
struct xtnu_target *nt = xtcompat_nutarget(ct);
struct xt_action_param local_par;
local_par.in = in;
local_par.out = out;
local_par.hooknum = hooknum;
local_par.target = ct;
local_par.targinfo = targinfo;
local_par.family = NFPROTO_UNSPEC;
if (nt != NULL && nt->target != NULL)
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return nt->target(pskb, &local_par);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
return nt->target(&skb, &local_par);
#endif
return XT_CONTINUE;
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) && \
LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
static unsigned int
xtnu_target_run(struct sk_buff *skb, const struct xt_target_param *par)
{
struct xtnu_target *nt = xtcompat_nutarget(par->target);
struct xt_action_param local_par;
local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
local_par.target = par->target;
local_par.targinfo = par->targinfo;
local_par.family = par->family;
return nt->target(&skb, &local_par);
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
static unsigned int
xtnu_target_run(struct sk_buff *skb, const struct xt_action_param *par)
{
struct xtnu_target *nt = xtcompat_nutarget(par->target);
return nt->target(&skb, par);
}
#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, 27)
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, 27)
{
struct xtnu_target *nt = xtcompat_nutarget(ct);
struct xt_tgchk_param local_par = {
.table = table,
.entryinfo = entry,
.target = ct,
.targinfo = targinfo,
.hook_mask = hook_mask,
.family = NFPROTO_UNSPEC,
};
if (nt == NULL)
return false;
if (nt->checkentry == NULL)
/* this is valid, just like if there was no function */
return true;
return nt->checkentry(&local_par) == 0;
}
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) && \
LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
static bool xtnu_target_check(const struct xt_tgchk_param *par)
{
struct xtnu_target *nt = xtcompat_nutarget(par->target);
if (nt == NULL)
return false;
if (nt->checkentry == NULL)
return true;
return nt->checkentry(par) == 0;
}
#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, 27)
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo)
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{
struct xtnu_target *nt = xtcompat_nutarget(ct);
struct xt_tgdtor_param local_par = {
.target = ct,
.targinfo = targinfo,
.family = NFPROTO_UNSPEC,
};
if (nt != NULL && nt->destroy != NULL)
nt->destroy(&local_par);
}
#endif
int xtnu_register_target(struct xtnu_target *nt)
{
struct xt_target *ct;
char *tmp;
int ret;
ct = kzalloc(sizeof(struct xt_target), GFP_KERNEL);
if (ct == NULL)
return -ENOMEM;
tmp = (char *)ct->name;
memcpy(tmp, nt->name, sizeof(nt->name));
tmp = (char *)(ct->name + sizeof(ct->name) - sizeof(void *));
*(tmp-1) = '\0';
memcpy(tmp, &nt, sizeof(void *));
ct->revision = nt->revision;
ct->family = nt->family;
ct->table = (char *)nt->table;
ct->hooks = nt->hooks;
ct->proto = nt->proto;
ct->target = xtnu_target_run;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
ct->checkentry = xtnu_target_check;
ct->destroy = xtnu_target_destroy;
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
ct->checkentry = xtnu_target_check;
ct->destroy = nt->destroy;
#else
ct->checkentry = nt->checkentry;
ct->destroy = nt->destroy;
#endif
ct->targetsize = nt->targetsize;
ct->me = nt->me;
nt->__compat_target = ct;
ret = xt_register_target(ct);
if (ret != 0)
kfree(ct);
return ret;
}
EXPORT_SYMBOL_GPL(xtnu_register_target);
int xtnu_register_targets(struct xtnu_target *nt, unsigned int num)
{
unsigned int i;
int ret;
for (i = 0; i < num; ++i) {
ret = xtnu_register_target(&nt[i]);
if (ret < 0) {
if (i > 0)
xtnu_unregister_targets(nt, i);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(xtnu_register_targets);
void xtnu_unregister_target(struct xtnu_target *nt)
{
xt_unregister_target(nt->__compat_target);
kfree(nt->__compat_target);
}
EXPORT_SYMBOL_GPL(xtnu_unregister_target);
void xtnu_unregister_targets(struct xtnu_target *nt, unsigned int num)
{
unsigned int i;
for (i = 0; i < num; ++i)
xtnu_unregister_target(&nt[i]);
}
EXPORT_SYMBOL_GPL(xtnu_unregister_targets);
struct xt_match *xtnu_request_find_match(unsigned int af, const char *name,
uint8_t revision)
{
static const char *const xt_prefix[] = {
[AF_UNSPEC] = "x",
[AF_INET] = "ip",
[AF_INET6] = "ip6",
#ifdef AF_ARP
[AF_ARP] = "arp",
#elif defined(NF_ARP) && NF_ARP != AF_UNSPEC
[NF_ARP] = "arp",
#endif
};
struct xt_match *match;
match = try_then_request_module(xt_find_match(af, name, revision),
"%st_%s", xt_prefix[af], name);
if (IS_ERR(match) || match == NULL)
return NULL;
return match;
}
EXPORT_SYMBOL_GPL(xtnu_request_find_match);
int xtnu_ip_route_me_harder(struct sk_buff **pskb, unsigned int addr_type)
{
#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 */
return ip_route_me_harder(pskb);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return ip_route_me_harder(pskb, addr_type);
#else
return ip_route_me_harder(*pskb, addr_type);
#endif
}
EXPORT_SYMBOL_GPL(xtnu_ip_route_me_harder);
int xtnu_skb_make_writable(struct sk_buff **pskb, unsigned int len)
{
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return skb_make_writable(pskb, len);
#else
return skb_make_writable(*pskb, len);
#endif
}
EXPORT_SYMBOL_GPL(xtnu_skb_make_writable);
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 24)
static int __xtnu_ip_local_out(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = htons(skb->len);
ip_send_check(iph);
return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
skb->dst->dev, dst_output);
}
int xtnu_ip_local_out(struct sk_buff *skb)
{
int err;
err = __xtnu_ip_local_out(skb);
if (likely(err == 1))
err = dst_output(skb);
return err;
}
EXPORT_SYMBOL_GPL(xtnu_ip_local_out);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
static int __xtnu_ip_local_out(struct sk_buff **pskb)
{
struct iphdr *iph = ip_hdr(*pskb);
iph->tot_len = htons((*pskb)->len);
ip_send_check(iph);
return nf_hook(PF_INET, NF_IP_LOCAL_OUT, pskb, NULL,
(*pskb)->dst->dev, dst_output);
}
int xtnu_ip_local_out(struct sk_buff *skb)
{
int err;
err = __xtnu_ip_local_out(&skb);
if (likely(err == 1))
err = dst_output(skb);
return err;
}
EXPORT_SYMBOL_GPL(xtnu_ip_local_out);
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
int xtnu_ip_route_output_key(void *net, struct rtable **rp, struct flowi *flp)
{
return ip_route_output_flow(rp, flp, NULL, 0);
}
EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key);
void xtnu_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
__be32 from, __be32 to, bool pseudohdr)
{
__be32 diff[] = {~from, to};
const void *dv = diff; /* kludge for < v2.6.19-555-g72685fc */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
if (skb->ip_summed != CHECKSUM_PARTIAL) {
*sum = csum_fold(csum_partial(dv, sizeof(diff),
~csum_unfold(*sum)));
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
skb->csum = ~csum_partial(dv, sizeof(diff),
~skb->csum);
} else if (pseudohdr) {
*sum = ~csum_fold(csum_partial(dv, sizeof(diff),
csum_unfold(*sum)));
}
#else
*sum = csum_fold(csum_partial(dv, sizeof(diff),
~csum_unfold(*sum)));
#endif
}
EXPORT_SYMBOL_GPL(xtnu_proto_csum_replace4);
#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);
static inline __wsum xtnu_csum_unfold(__sum16 n)
{
return (__force __wsum)n;
}
void xtnu_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
{
__be32 diff[] = {~from, to};
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
~xtnu_csum_unfold(*sum)));
}
void xtnu_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
{
xtnu_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
}
EXPORT_SYMBOL_GPL(xtnu_csum_replace2);
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
int xtnu_skb_linearize(struct sk_buff *skb)
{
return skb_linearize(skb, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(xtnu_skb_linearize);
#endif
void *HX_memmem(const void *space, size_t spacesize, void *HX_memmem(const void *space, size_t spacesize,
const void *point, size_t pointsize) const void *point, size_t pointsize)
{ {
@@ -42,4 +617,22 @@ void *HX_memmem(const void *space, size_t spacesize,
} }
EXPORT_SYMBOL_GPL(HX_memmem); EXPORT_SYMBOL_GPL(HX_memmem);
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0) && defined(WITH_IPV6)
int xtnu_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
uint8_t *nexthdrp, __be16 *fragoffp)
{
return ipv6_skip_exthdr(skb, start, nexthdrp);
}
EXPORT_SYMBOL_GPL(xtnu_ipv6_skip_exthdr);
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) && defined(WITH_IPV6)
int xtnu_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset,
int target, unsigned short *fragoff, int *fragflg)
{
return ipv6_find_hdr(skb, offset, target, fragoff);
}
EXPORT_SYMBOL_GPL(xtnu_ipv6_find_hdr);
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@@ -8,8 +8,8 @@
#define DEBUGP Use__pr_debug__instead #define DEBUGP Use__pr_debug__instead
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
# warning Kernels below 4.15 not supported. # warning Kernels below 2.6.17 not supported.
#endif #endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -17,35 +17,121 @@
# warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK is not (please enable). # warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK is not (please enable).
# endif # endif
# include <net/netfilter/nf_conntrack.h> # 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)
# warning You have CONFIG_IP_NF_CONNTRACK enabled, but CONFIG_IP_NF_CONNTRACK_MARK is 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 #else
# warning You need CONFIG_NF_CONNTRACK. # warning You need either CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK.
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \ #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 9) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) || \ # define skb_init_secmark(skb)
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 78) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) || \ # define skb_linearize xtnu_skb_linearize
LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 158) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0) #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define neigh_hh_output xtnu_neigh_hh_output
# define IPPROTO_UDPLITE 136
# define CSUM_MANGLED_0 ((__force __sum16)0xffff)
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
# define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING
# define NF_INET_LOCAL_IN NF_IP_LOCAL_IN
# define NF_INET_FORWARD NF_IP_FORWARD
# define NF_INET_LOCAL_OUT NF_IP_LOCAL_OUT
# define NF_INET_POST_ROUTING NF_IP_POST_ROUTING
# define ip_local_out xtnu_ip_local_out
# define ip_route_output_key xtnu_ip_route_output_key
# include "compat_nfinetaddr.h"
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
# define init_net xtnu_ip_route_output_key /* yes */
# define init_net__loopback_dev (&loopback_dev)
# define init_net__proc_net proc_net
#else #else
# define ip_route_me_harder(xnet, xsk, xskb, xaddrtype) ip_route_me_harder((xnet), (xskb), (xaddrtype)) # define init_net__loopback_dev init_net.loopback_dev
# define ip6_route_me_harder(xnet, xsk, xskb) ip6_route_me_harder((xnet), (xskb)) # define init_net__proc_net init_net.proc_net
#endif #endif
static inline struct net *par_net(const struct xt_action_param *par) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
{ # define xt_match xtnu_match
return par->state->net; # define xt_register_match xtnu_register_match
} # define xt_unregister_match xtnu_unregister_match
# define xt_register_matches xtnu_register_matches
#ifndef NF_CT_ASSERT # define xt_unregister_matches xtnu_unregister_matches
# define NF_CT_ASSERT(x) WARN_ON(!(x))
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define proc_ops file_operations # define csum_replace2 xtnu_csum_replace2
# define proc_open open # define csum_replace4 xtnu_csum_replace4
# define proc_read read # define inet_proto_csum_replace4 xtnu_proto_csum_replace4
# define proc_write write #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
# define proc_lseek llseek # define csum_replace2 nf_csum_replace2
# define proc_release release # define csum_replace4 nf_csum_replace4
# define inet_proto_csum_replace4 xtnu_proto_csum_replace4
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
# define ipt_unregister_table(tbl) ipt_unregister_table(&init_net, (tbl))
# define ip6t_unregister_table(tbl) ip6t_unregister_table(&init_net, (tbl))
#else
# define ipt_unregister_table(tbl) ipt_unregister_table(tbl)
# define ip6t_unregister_table(tbl) ip6t_unregister_table(tbl)
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
# define rt_dst(rt) (&(rt)->dst)
#else
# define rt_dst(rt) (&(rt)->u.dst)
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
# define nf_nat_ipv4_multi_range_compat nf_nat_multi_range_compat
# define nf_nat_ipv4_range nf_nat_range
# define NF_NAT_RANGE_MAP_IPS IP_NAT_RANGE_MAP_IPS
# define ipv6_skip_exthdr xtnu_ipv6_skip_exthdr
#endif
#if !defined(NIP6) && !defined(NIP6_FMT)
# define NIP6(addr) \
ntohs((addr).s6_addr16[0]), \
ntohs((addr).s6_addr16[1]), \
ntohs((addr).s6_addr16[2]), \
ntohs((addr).s6_addr16[3]), \
ntohs((addr).s6_addr16[4]), \
ntohs((addr).s6_addr16[5]), \
ntohs((addr).s6_addr16[6]), \
ntohs((addr).s6_addr16[7])
# define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
#endif
#if !defined(NIPQUAD) && !defined(NIPQUAD_FMT)
# define NIPQUAD(addr) \
((const unsigned char *)&addr)[0], \
((const unsigned char *)&addr)[1], \
((const unsigned char *)&addr)[2], \
((const unsigned char *)&addr)[3]
# define NIPQUAD_FMT "%u.%u.%u.%u"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)
# define ipv6_find_hdr xtnu_ipv6_find_hdr
#endif
#define ip_route_me_harder xtnu_ip_route_me_harder
#define skb_make_writable xtnu_skb_make_writable
#define xt_target xtnu_target
#define xt_register_target xtnu_register_target
#define xt_unregister_target xtnu_unregister_target
#define xt_register_targets xtnu_register_targets
#define xt_unregister_targets xtnu_unregister_targets
#define xt_request_find_match xtnu_request_find_match
#endif /* _XTABLES_COMPAT_H */ #endif /* _XTABLES_COMPAT_H */

View File

@@ -1,11 +1,93 @@
#ifndef _COMPAT_XTNU_H #ifndef _COMPAT_XTNU_H
#define _COMPAT_XTNU_H 1 #define _COMPAT_XTNU_H 1
#include <linux/list.h>
#include <linux/netfilter/x_tables.h> #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
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
typedef __u16 __bitwise __sum16;
typedef __u32 __bitwise __wsum;
#endif
struct flowi;
struct hh_cache;
struct module; struct module;
struct net_device;
struct rtable;
struct sk_buff; struct sk_buff;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
enum {
NFPROTO_UNSPEC = 0,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3,
NFPROTO_BRIDGE = 7,
NFPROTO_IPV6 = 10,
NFPROTO_DECNET = 12,
NFPROTO_NUMPROTO,
};
struct xt_mtchk_param {
const char *table;
const void *entryinfo;
const struct xt_match *match;
void *matchinfo;
unsigned int hook_mask;
u_int8_t family;
};
struct xt_mtdtor_param {
const struct xt_match *match;
void *matchinfo;
u_int8_t family;
};
struct xt_target_param {
const struct net_device *in, *out;
unsigned int hooknum;
const struct xt_target *target;
const void *targinfo;
u_int8_t family;
};
struct xt_tgchk_param {
const char *table;
const void *entryinfo;
const struct xt_target *target;
void *targinfo;
unsigned int hook_mask;
u_int8_t family;
};
struct xt_tgdtor_param {
const struct xt_target *target;
void *targinfo;
u_int8_t family;
};
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
struct xt_action_param {
union {
const struct xt_match *match;
const struct xt_target *target;
};
union {
const void *matchinfo, *targinfo;
};
const struct net_device *in, *out;
int fragoff;
unsigned int thoff, hooknum;
u_int8_t family;
bool hotdrop;
};
#endif
struct xtnu_match { struct xtnu_match {
/* /*
* Making it smaller by sizeof(void *) on purpose to catch * Making it smaller by sizeof(void *) on purpose to catch
@@ -53,7 +135,18 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
return q; return q;
} }
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
static inline __wsum csum_unfold(__sum16 n)
{
return (__force __wsum)n;
}
#endif
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_register_match(struct xtnu_match *);
extern int xtnu_ip_route_output_key(void *, struct rtable **, struct flowi *);
extern void xtnu_unregister_match(struct xtnu_match *); extern void xtnu_unregister_match(struct xtnu_match *);
extern int xtnu_register_matches(struct xtnu_match *, unsigned int); extern int xtnu_register_matches(struct xtnu_match *, unsigned int);
extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int); extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int);
@@ -61,6 +154,18 @@ extern int xtnu_register_target(struct xtnu_target *);
extern void xtnu_unregister_target(struct xtnu_target *); extern void xtnu_unregister_target(struct xtnu_target *);
extern int xtnu_register_targets(struct xtnu_target *, unsigned int); extern int xtnu_register_targets(struct xtnu_target *, unsigned int);
extern void xtnu_unregister_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 *);
extern void xtnu_csum_replace2(__u16 __bitwise *, __be16, __be16);
extern void xtnu_csum_replace4(__u16 __bitwise *, __be32, __be32);
extern void xtnu_proto_csum_replace4(__u16 __bitwise *, struct sk_buff *,
__be32, __be32, bool);
extern int xtnu_skb_linearize(struct sk_buff *);
extern int xtnu_ipv6_skip_exthdr(const struct sk_buff *, int,
uint8_t *, __be16 *);
extern int xtnu_ipv6_find_hdr(const struct sk_buff *, unsigned int *,
int, unsigned short *, int *);
extern void *HX_memmem(const void *, size_t, const void *, size_t); extern void *HX_memmem(const void *, size_t, const void *, size_t);

View File

@@ -64,6 +64,21 @@ static void chaos_tg_check(unsigned int flags)
"may be specified"); "may be specified");
} }
static void chaos_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct xt_chaos_tginfo *info = (const void *)target->data;
switch (info->variant) {
case XTCHAOS_DELUDE:
printf(" DELUDE ");
break;
case XTCHAOS_TARPIT:
printf(" TARPIT ");
break;
}
}
static void chaos_tg_save(const void *ip, const struct xt_entry_target *target) static void chaos_tg_save(const void *ip, const struct xt_entry_target *target)
{ {
const struct xt_chaos_tginfo *info = (const void *)target->data; const struct xt_chaos_tginfo *info = (const void *)target->data;
@@ -78,13 +93,6 @@ static void chaos_tg_save(const void *ip, const struct xt_entry_target *target)
} }
} }
static void chaos_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
printf(" -j CHAOS");
chaos_tg_save(ip, target);
}
static struct xtables_target chaos_tg_reg = { static struct xtables_target chaos_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "CHAOS", .name = "CHAOS",

View File

@@ -1,4 +1,3 @@
.PP
Causes confusion on the other end by doing odd things with incoming packets. 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: CHAOS will randomly reply (or not) with one of its configurable subtargets:
.TP .TP

View File

@@ -0,0 +1,94 @@
/*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Red Hat, Inc
* Author: Michael S. Tsirkin <mst@redhat.com>
*
* This program is distributed under the terms of GNU GPL v2, 1991
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <xtables.h>
#include "xt_CHECKSUM.h"
#include "compat_user.h"
static void CHECKSUM_help(void)
{
printf(
"CHECKSUM target options\n"
" --checksum-fill Fill in packet checksum.\n");
}
static const struct option CHECKSUM_opts[] = {
{ "checksum-fill", 0, NULL, 'F' },
{ .name = NULL }
};
static int CHECKSUM_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_CHECKSUM_info *einfo
= (struct xt_CHECKSUM_info *)(*target)->data;
switch (c) {
case 'F':
xtables_param_act(XTF_ONLY_ONCE, "CHECKSUM", "--checksum-fill",
*flags & XT_CHECKSUM_OP_FILL);
einfo->operation = XT_CHECKSUM_OP_FILL;
*flags |= XT_CHECKSUM_OP_FILL;
break;
default:
return 0;
}
return 1;
}
static void CHECKSUM_check(unsigned int flags)
{
if (!flags)
xtables_error(PARAMETER_PROBLEM,
"CHECKSUM target: Parameter --checksum-fill is required");
}
static void CHECKSUM_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_CHECKSUM_info *einfo =
(const struct xt_CHECKSUM_info *)target->data;
printf("CHECKSUM ");
if (einfo->operation & XT_CHECKSUM_OP_FILL)
printf(" fill ");
}
static void CHECKSUM_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_CHECKSUM_info *einfo =
(const struct xt_CHECKSUM_info *)target->data;
if (einfo->operation & XT_CHECKSUM_OP_FILL)
printf(" --checksum-fill ");
}
static struct xtables_target checksum_tg_reg = {
.name = "CHECKSUM",
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_CHECKSUM_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_CHECKSUM_info)),
.help = CHECKSUM_help,
.parse = CHECKSUM_parse,
.final_check = CHECKSUM_check,
.print = CHECKSUM_print,
.save = CHECKSUM_save,
.extra_opts = CHECKSUM_opts,
};
static __attribute__((constructor)) void _init(void)
{
xtables_register_target(&checksum_tg_reg);
}

View File

@@ -0,0 +1,8 @@
This target allows to selectively work around broken/old applications.
It can only be used in the mangle table.
.TP
\fB\-\-checksum\-fill\fP
Compute and fill in the checksum in a packet that lacks a checksum.
This is particularly useful, if you need to work around old applications
such as dhcp clients, that do not work well with checksum offloads,
but don't want to disable checksum offload in your device.

View File

@@ -1,4 +1,3 @@
.PP
The DELUDE target will reply to a SYN packet with SYN-ACK, and to all other The DELUDE target will reply to a SYN packet with SYN-ACK, and to all other
packets with an RST. This will terminate the connection much like REJECT, but packets with an RST. This will terminate the connection much like REJECT, but
network scanners doing TCP half-open discovery can be spoofed to make them network scanners doing TCP half-open discovery can be spoofed to make them

View File

@@ -61,6 +61,15 @@ static void dhcpmac_tg_check(unsigned int flags)
"--set-mac parameter required"); "--set-mac parameter required");
} }
static void dhcpmac_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct dhcpmac_info *info = (void *)target->data;
printf(" DHCPMAC %s" DH_MAC_FMT "/%u ",
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
}
static void dhcpmac_tg_save(const void *ip, static void dhcpmac_tg_save(const void *ip,
const struct xt_entry_target *target) const struct xt_entry_target *target)
{ {
@@ -72,13 +81,6 @@ static void dhcpmac_tg_save(const void *ip,
DH_MAC_HEX(info->addr), info->mask); DH_MAC_HEX(info->addr), info->mask);
} }
static void dhcpmac_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
printf(" -j DHCPMAC");
dhcpmac_tg_save(ip, target);
}
static struct xtables_target dhcpmac_tg_reg = { static struct xtables_target dhcpmac_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "DHCPMAC", .name = "DHCPMAC",

View File

@@ -1,4 +1,3 @@
.PP
In conjunction with ebtables, DHCPMAC can be used to completely change all MAC In conjunction with ebtables, DHCPMAC can be used to completely change all MAC
addresses from and to a VMware-based virtual machine. This is needed because addresses from and to a VMware-based virtual machine. This is needed because
VMware does not allow to set a non-VMware MAC address before an operating VMware does not allow to set a non-VMware MAC address before an operating

View File

@@ -69,8 +69,19 @@ static int netmask2bits(u_int32_t netmask)
return bits; return bits;
} }
static void DNETMAP_init(struct xt_entry_target *t)
{
struct xt_DNETMAP_tginfo *tginfo = (void *)&t->data;
struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
/* Actually, it's 0, but it's ignored at the moment. */
mr->rangesize = 1;
tginfo->ttl = 0;
tginfo->flags = 0;
}
/* Parses network address */ /* Parses network address */
static void parse_prefix(char *arg, struct nf_nat_range *range) static void parse_prefix(char *arg, struct nf_nat_ipv4_range *range)
{ {
char *slash; char *slash;
const struct in_addr *ip; const struct in_addr *ip;
@@ -86,7 +97,7 @@ static void parse_prefix(char *arg, struct nf_nat_range *range)
if (ip == NULL) if (ip == NULL)
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
arg); arg);
range->min_addr.in = *ip; range->min_ip = ip->s_addr;
if (slash) { if (slash) {
if (strchr(slash + 1, '.')) { if (strchr(slash + 1, '.')) {
ip = xtables_numeric_to_ipmask(slash + 1); ip = xtables_numeric_to_ipmask(slash + 1);
@@ -112,20 +123,20 @@ static void parse_prefix(char *arg, struct nf_nat_range *range)
} else } else
netmask = ~0; netmask = ~0;
if (range->min_addr.ip & ~netmask) { if (range->min_ip & ~netmask) {
if (slash) if (slash)
*slash = '/'; *slash = '/';
xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n", xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n",
arg); arg);
} }
range->max_addr.ip = range->min_addr.ip | ~netmask; range->max_ip = range->min_ip | ~netmask;
} }
static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags, static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target) const void *entry, struct xt_entry_target **target)
{ {
struct xt_DNETMAP_tginfo *tginfo = (void *)(*target)->data; struct xt_DNETMAP_tginfo *tginfo = (void *)(*target)->data;
struct nf_nat_range *mr = &tginfo->prefix; struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
char *end; char *end;
switch (c) { switch (c) {
@@ -136,7 +147,7 @@ static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
invert); invert);
/* TO-DO use xtables_ipparse_any instead? */ /* TO-DO use xtables_ipparse_any instead? */
parse_prefix(optarg, mr); parse_prefix(optarg, &mr->range[0]);
*flags |= XT_DNETMAP_PREFIX; *flags |= XT_DNETMAP_PREFIX;
tginfo->flags |= XT_DNETMAP_PREFIX; tginfo->flags |= XT_DNETMAP_PREFIX;
return 1; return 1;
@@ -181,13 +192,14 @@ static void DNETMAP_print_addr(const void *ip,
int numeric) int numeric)
{ {
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data; struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
const struct nf_nat_range *r = &tginfo->prefix; const struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
const struct nf_nat_ipv4_range *r = &mr->range[0];
struct in_addr a; struct in_addr a;
int bits; int bits;
a = r->min_addr.in; a.s_addr = r->min_ip;
printf("%s", xtables_ipaddr_to_numeric(&a)); printf("%s", xtables_ipaddr_to_numeric(&a));
a.s_addr = ~(r->min_addr.ip ^ r->max_addr.ip); a.s_addr = ~(r->min_ip ^ r->max_ip);
bits = netmask2bits(a.s_addr); bits = netmask2bits(a.s_addr);
if (bits < 0) if (bits < 0)
printf("/%s", xtables_ipaddr_to_numeric(&a)); printf("/%s", xtables_ipaddr_to_numeric(&a));
@@ -195,6 +207,33 @@ static void DNETMAP_print_addr(const void *ip,
printf("/%d", bits); printf("/%d", bits);
} }
static void DNETMAP_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
const __u8 *flags = &tginfo->flags;
printf(" prefix ");
if (*flags & XT_DNETMAP_PREFIX)
DNETMAP_print_addr(ip, target, numeric);
else
printf("any");
if (*flags & XT_DNETMAP_REUSE)
printf(" reuse");
if (*flags & XT_DNETMAP_STATIC)
printf(" static");
if (*flags & XT_DNETMAP_PERSISTENT)
printf(" persistent");
if (*flags & XT_DNETMAP_TTL)
printf(" ttl %i", tginfo->ttl);
else
printf(" ttl default");
}
static void DNETMAP_save(const void *ip, const struct xt_entry_target *target) static void DNETMAP_save(const void *ip, const struct xt_entry_target *target)
{ {
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data; struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
@@ -219,13 +258,6 @@ static void DNETMAP_save(const void *ip, const struct xt_entry_target *target)
printf(" --ttl %i ", tginfo->ttl); printf(" --ttl %i ", tginfo->ttl);
} }
static void DNETMAP_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
printf(" -j DNETMAP");
DNETMAP_save(ip, target);
}
static struct xtables_target dnetmap_tg_reg = { static struct xtables_target dnetmap_tg_reg = {
.name = MODULENAME, .name = MODULENAME,
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
@@ -233,6 +265,7 @@ static struct xtables_target dnetmap_tg_reg = {
.size = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)), .size = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
.help = DNETMAP_help, .help = DNETMAP_help,
.init = DNETMAP_init,
.parse = DNETMAP_parse, .parse = DNETMAP_parse,
.print = DNETMAP_print, .print = DNETMAP_print,
.save = DNETMAP_save, .save = DNETMAP_save,

View File

@@ -1,179 +1,172 @@
.PP The \fBDNETMAP\fR target allows dynamic two-way 1:1 mapping of IPv4 subnets.
The \fBDNETMAP\fR target allows dynamic two-way 1:1 mapping of IPv4 subnets. A Single rule can map private subnet to shorter public subnet creating and
single rule can map a private subnet to a shorter public subnet, creating and maintaining unambigeous private-public ip bindings. Second rule can be used to
maintaining unambiguous private-public IP address bindings. The second rule can map new flows to private subnet according to maintained bindings. Target allows
be used to map new flows to a private subnet according to maintained bindings. efficient public IPv4 space usage and unambigeous NAT at the same time.
The target allows efficient public IPv4 space usage and unambiguous NAT at the
same time. Target can be used only in \fBnat\fR table in \fBPOSTROUTING\fR or \fBOUTPUT\fR
.PP chains for SNAT and in \fBPREROUTING\fR for DNAT. Only flows directed to bound
The target can be used only in the \fBnat\fR table in \fBPOSTROUTING\fR or IPs will be DNATed. Packet continues chain traversal if there is no free
\fBOUTPUT\fR chains for SNAT, and in \fBPREROUTING\fR for DNAT. Only flows postnat-ip to be assigned to prenat-ip. Default binding \fBttl\fR is \fI10
directed to bound addresses will be DNATed. The packet continues chain minutes\fR and can be changed using \fBdefault_ttl\fR module option. Default ip
traversal if there is no free postnat address to be assigned to the prenat hash size is 256 and can be changed using \fBhash_size\fR module option.
address. The default binding \fBTTL\fR is \fI10 minutes\fR and can be changed
using the \fBdefault_ttl\fR module option. The default address hash size is 256
and can be changed using the \fBhash_size\fR module option.
.TP .TP
\fB\-\-prefix\fR \fIaddr\fR\fB/\fR\fImask\fR \fB\-\-prefix\fR \fIaddr\fR\fB/\fR\fImask\fR
The network subnet to map to. If not specified, all existing prefixes are used. Network subnet to map to. If not specified, all existing prefixes are used.
.TP .TP
\fB\-\-reuse\fR \fB\-\-reuse\fR
Reuse the entry for a given prenat address from any prefix even if the Reuse entry for given prenat-ip from any prefix despite bindings ttl < 0.
binding's TTL is < 0.
.TP .TP
\fB\-\-persistent\fR \fB\-\-persistent\fR
Set the prefix to be persistent. It will not be removed after deleting the last Set prefix persistent. It won't be removed after deleting last iptables rule.
iptables rule. The option is effective only in the first rule for a given Option is effective only in the first rule for a given prefix. If you
prefix. If you need to change persistency for an existing prefix, please use need to change persistency for existing prefix, please use proc interface
the procfs interface described below. described below.
.TP .TP
\fB\-\-static\fR \fB\-\-static\fR
Do not create dynamic mappings using this rule. Use static mappings only. Note Don't create dynamic mappings using this rule. Use static mappings only. Note
that you need to create static mappings via the procfs interface for this rule that you need to create static mappings via proc interface for this rule with
for this option to have any effect. this option to have any effect.
.TP .TP
\fB\-\-ttl\fR \fIseconds\fR \fB\-\-ttl\fR \fIseconds\fR
Reset the binding's TTL value to \fIseconds\fR. If a negative value is Regenerate bindings ttl value to \fIseconds\fR. If negative value is specified,
specified, the binding's TTL is kept unchanged. If this option is not bindings ttl is kept unchanged. If not specified then default ttl value (600s)
specified, then the default TTL value (600s) is used. is used.
.PP .PP
\fB* /proc interface\fR \fB* /proc interface\fR
.PP
The module creates the following entries for each new specified subnet: Module creates following entries for each new specified subnet:
.TP .TP
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR \fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR
Contains the binding table for the given \fIsubnet/mask\fP. Each line contains Contains binding table for subnet/mask. Each line contains \fBprenat-ip\fR,
\fBprenat address\fR, \fBpostnat address\fR, \fBttl\fR (seconds until the entry \fBpostnat-ip\fR,\fBttl\fR (seconds till entry times out), \fBlasthit\fR (last
times out), \fBlasthit\fR (last hit to the entry in seconds relative to system entry hit in seconds relative to system boot time). Please note that \fBttl\fR
boot time). Please note that the \fBttl\fR and \fBlasthit\fR entries contain an and \fBlasthit\fR entries contain \fBS\fR in case of static binding.
\(oq\fBS\fR\(cq in case of a static binding.
.TP .TP
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR \fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
Contains statistics for a given \fIsubnet/mask\fP. The line contains four Contains statistics for given subnet/mask. Line contains contains four
numerical values separated by spaces. The first one is the number of currently numerical values separated by spaces. First one is number of currently used
used dynamic addresses (bindings with negative TTL excluded), the second one is dynamic addresses (bindings with negative ttl excluded), second one is number
the number of static assignments, the third one is the number of all usable static assignments, third one is number of all usable addresses in subnet and
addresses in the subnet, and the fourth one is the mean \fBTTL\fR value for all the fourth one is mean \fBttl\fR value for all active entries. If prefix has
active entries. If the prefix has the persistent flag set, it will be noted as persistent flag set it'll be noted as fifth entry.
fifth entry.
.PP .PP
The following write operations are supported via the procfs interface: Following write operations are supported via proc interface:
.TP .TP
echo "+\fIprenat-address\fR:\fIpostnat-address\fR" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR echo "+\fIprenatIP\fR:\fIpostnatIP\fR" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Adds a static binding between the prenat and postnap address. If Adds static binding between prenatIP nad postnatIP. If postnatIP is already
postnat_address is already bound, any previous binding will be timed out bound, previous binding will be timedout immediatelly. Static binding is never
immediately. A static binding is never timed out. timedout.
.TP .TP
echo "\-\fIaddress\fR" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR echo "-\fIIP\fR" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Removes the binding with \fIaddress\fR as prenat or postnat address. If the Removes binding with \fIIP\fR as prenat or postnat address. If removed binding
removed binding is currently static, it will make the entry available for is currently static, it'll make entry available for dynamic allocation.
dynamic allocation.
.TP .TP
echo "+persistent" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR echo "+persistent" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Sets the persistent flag for the prefix. It is useful if you do not want Sets persistent flag for prefix. It's usefull if you don't want bindings to get
bindings to get flushed when the firewall is restarted. You can check if the flushed when firewall is restarted. You can check if prefix is persistent by
prefix is persistent by printing the contents of printing \fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR. contents.
.TP .TP
echo "\-persistent" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR echo "-persistent" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Unsets the persistent flag for the prefix. In this mode, the prefix will be Unsets persistent flag for prefix. In this mode prefix will be deleted if the
deleted if the last iptables rule for that prefix is removed. last iptables rule for that prefix is removed.
.TP .TP
echo "flush" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR echo "flush" > \fB/proc/net/xt_DNETMAP/subnet_mask\fR
Flushes all bindings for the specific prefix. All static entries are also Flushes all bindings for specific prefix. All static entries are also flushed
flushed and become available for dynamic bindings. and are available for dynamic bindings.
.PP .PP
Note! Entries are removed if the last iptables rule for a specific prefix is Note! Entries are removed if the last iptables rule for a specific prefix is
deleted unless the persistent flag is set. deleted unless there's persistent flag set.
.PP .PP
\fB* Logging\fR \fB* Logging\fR
.PP
The module logs binding add/timeout events to klog. This behaviour can be Module logs binding add/timeout events to klog. This behaviour can be disabled
disabled using the \fBdisable_log\fR module parameter. using \fBdisable_log\fR module parameter.
.PP
\fB* Examples\fR \fB* Examples\fR
.PP
\fB1.\fR Map subnet 192.168.0.0/24 to subnets 20.0.0.0/26. SNAT only: \fB1.\fR Map subnet 192.168.0.0/24 to subnets 20.0.0.0/26. SNAT only:
.PP
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26 iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
.PP
Active hosts from the 192.168.0.0/24 subnet are mapped to 20.0.0.0/26. If the Active hosts from 192.168.0.0/24 subnet are mapped to 20.0.0.0/26. If packet
packet from a not yet bound prenat address hits the rule and there are no free from not yet bound prenat-ip hits the rule and there are no free or timed-out
or timed-out (TTL<0) entries in prefix 20.0.0.0/28, then a notice is logged to (ttl<0) entries in prefix 20.0.0.0/28, then notice is logged to klog and chain
klog and chain traversal continues. If packet from an already-bound prenat traversal continues. If packet from already bound prenat-ip hits the rule,
address hits the rule, the binding's TTL value is reset to default_ttl and SNAT bindings ttl value is regenerated to default_ttl and SNAT is performed.
is performed.
.PP
\fB2.\fR Use of \fB\-\-reuse\fR and \fB\-\-ttl\fR switches, multiple rule \fB2.\fR Use of \fB\-\-reuse\fR and \fB\-\-ttl\fR switches, multiple rule
interaction: interaction:
.PP
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix
20.0.0.0/26 \-\-reuse \-\-ttl 200 20.0.0.0/26 --reuse --ttl 200
.PP
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 30.0.0.0/26 iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 30.0.0.0/26
.PP
Active hosts from 192.168.0.0/24 subnet are mapped to 20.0.0.0/26 with TTL = Active hosts from 192.168.0.0/24 subnet are mapped to 20.0.0.0/26 with ttl =
200 seconds. If there are no free addresses in first prefix, the next one 200 seconds. If there are no free addresses in first prefix the next one
(30.0.0.0/26) is used with the default TTL. It is important to note that the (30.0.0.0/26) is used with default ttl. It's important to note that the first
first rule SNATs all flows whose source address is already actively bound rule SNATs all flows whose source IP is already actively (ttl>0) bound to ANY
(TTL>0) to ANY prefix. The \fB\-\-reuse\fR parameter makes this functionality prefix. Parameter \fB\-\-reuse\fR makes this functionality work even for
work even for inactive (TTL<0) entries. inactive (ttl<0) entries.
.PP
If both subnets are exhausted, then chain traversal continues. If both subnets are exhaused, then chain traversal continues.
.PP
\fB3.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 in a bidirectional way: \fB3.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 bidirectional way:
.PP
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26 iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
.PP
iptables \-t nat \-A PREROUTING \-j DNETMAP iptables -t nat -A PREROUTING -j DNETMAP
.PP
If the host 192.168.0.10 generates some traffic, it gets bound to first free If host 192.168.0.10 generates some traffic, it gets bound to first free IP in
address in the subnet \(em 20.0.0.0. Now, any traffic directed to 20.0.0.0 gets subnet - 20.0.0.0. Now any traffic directed to 20.0.0.0 gets DNATed to
DNATed to 192.168.0.10 as long as there is an active (TTL>0) binding. There is 192.168.0.10 as long as there's an active (ttl>0) binding. There's no need to
no need to specify \fB\-\-prefix\fR parameter in a PREROUTING rule, because specify \fB\-\-prefix\fR parameter in PREROUTING rule, because this way it DNATs
this way, it DNATs traffic to all active prefixes. You could specify the prefix traffic to all active prefixes. You could specify prefix it you'd like to make
you would like to make DNAT work for a specific prefix only. DNAT work for specific prefix only.
.PP
\fB4.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 with static assignments \fB4.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 with static assignments only:
only:
.PP iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26 --static
\-\-static
.PP
echo "+192.168.0.10:20.0.0.1" > /proc/net/xt_DNETMAP/20.0.0.0_26 echo "+192.168.0.10:20.0.0.1" > /proc/net/xt_DNETMAP/20.0.0.0_26
.br .br
echo "+192.168.0.11:20.0.0.2" > /proc/net/xt_DNETMAP/20.0.0.0_26 echo "+192.168.0.11:20.0.0.2" > /proc/net/xt_DNETMAP/20.0.0.0_26
.br .br
echo "+192.168.0.51:20.0.0.3" > /proc/net/xt_DNETMAP/20.0.0.0_26 echo "+192.168.0.51:20.0.0.3" > /proc/net/xt_DNETMAP/20.0.0.0_26
.PP
This configuration will allow only preconfigured static bindings to work due to This configuration will allow only preconfigured static bindings to work due to
the \fBstatic\fR rule option. Without this flag, dynamic bindings would be \fBstatic\fR rule option. Without this flag dynamic bindings would be created
created using non-static entries. using non-static entries.
.PP
\fB5.\fR Persistent prefix: \fB5.\fR Persistent prefix:
.PP
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26 iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
\-\-persistent --persistent
.br .br
\fBor\fR \fBor\fR
.br .br
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26 iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
.br .br
echo "+persistent" > /proc/net/xt_DNETMAP/20.0.0.0_26 echo "+persistent" > /proc/net/xt_DNETMAP/20.0.0.0_26
.PP
Now, we can check the persistent flag of the prefix: Now we can check persistent flag of the prefix:
.br .br
cat /proc/net/xt_DNETMAP/20.0.0.0_26 cat /proc/net/xt_DNETMAP/20.0.0.0_26
.br .br
0 0 64 0 \fBpersistent\fR 0 0 64 0 \fBpersistent\fR
.PP
Flush the iptables nat table and see that prefix is still in existence: Flush iptables nat table and see that prefix is still in existence:
.br .br
iptables \-F \-t nat iptables -F -t nat
.br .br
ls \-l /proc/net/xt_DNETMAP ls -l /proc/net/xt_DNETMAP
.br .br
\-rw\-r\-\-r\-\- 1 root root 0 06\-10 09:01 20.0.0.0_26 -rw-r--r-- 1 root root 0 06-10 09:01 20.0.0.0_26
.br .br
\-rw\-r\-\-r\-\- 1 root root 0 06\-10 09:01 20.0.0.0_26_stat -rw-r--r-- 1 root root 0 06-10 09:01 20.0.0.0_26_stat
. .

View File

@@ -1,4 +1,3 @@
.PP
The \fBECHO\fP target will send back all packets it received. It serves as an The \fBECHO\fP target will send back all packets it received. It serves as an
examples for an Xtables target. examples for an Xtables target.
.PP .PP

View File

@@ -112,6 +112,25 @@ static void ipmark_tg_check(unsigned int flags)
"IPMARK target: Parameter --addr is required"); "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->shift != 0)
printf(" shift %u ", (unsigned int)info->shift);
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 static void
ipmark_tg_save(const void *entry, const struct xt_entry_target *target) ipmark_tg_save(const void *entry, const struct xt_entry_target *target)
{ {
@@ -130,14 +149,6 @@ ipmark_tg_save(const void *entry, const struct xt_entry_target *target)
printf(" --or-mask 0x%x ", (unsigned int)info->ormask); printf(" --or-mask 0x%x ", (unsigned int)info->ormask);
} }
static void
ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
printf(" -j IPMARK");
ipmark_tg_save(entry, target);
}
static struct xtables_target ipmark_tg_reg = { static struct xtables_target ipmark_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "IPMARK", .name = "IPMARK",

View File

@@ -1,8 +1,7 @@
.PP
Allows you to mark a received packet basing on its IP address. This 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 can replace many mangle/mark entries with only one, if you use
firewall based classifier. firewall based classifier.
.PP
This target is to be used inside the \fBmangle\fP table. This target is to be used inside the \fBmangle\fP table.
.TP .TP
\fB\-\-addr\fP {\fBsrc\fP|\fBdst\fP} \fB\-\-addr\fP {\fBsrc\fP|\fBdst\fP}

View File

@@ -77,6 +77,15 @@ logmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
return false; return false;
} }
static void
logmark_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_logmark_tginfo *info = (void *)target->data;
printf(" LOGMARK level %u prefix \"%s\" ", info->level, info->prefix);
}
static void static void
logmark_tg_save(const void *ip, const struct xt_entry_target *target) logmark_tg_save(const void *ip, const struct xt_entry_target *target)
{ {
@@ -88,14 +97,6 @@ logmark_tg_save(const void *ip, const struct xt_entry_target *target)
printf(" --log-prefix \"%s\" ", info->prefix); printf(" --log-prefix \"%s\" ", info->prefix);
} }
static void
logmark_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
printf(" -j LOGMARK");
logmark_tg_save(ip, target);
}
static struct xtables_target logmark_tg_reg = { static struct xtables_target logmark_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "LOGMARK", .name = "LOGMARK",

View File

@@ -1,4 +1,3 @@
.PP
The LOGMARK target will log packet and connection marks to syslog. The LOGMARK target will log packet and connection marks to syslog.
.TP .TP
\fB\-\-log\-level\fR \fIlevel\fR \fB\-\-log\-level\fR \fIlevel\fR

View File

@@ -1,105 +0,0 @@
/*
* PROTO Target module
* This program is distributed under the terms of GNU GPL
*/
#include <stdio.h>
#include <xtables.h>
#include "xt_PROTO.h"
enum {
O_PROTO_SET = 0,
O_PROTO_STOP_AT_FRAG = 1,
O_PROTO_STOP_AT_AUTH = 2,
F_PROTO_SET = 1 << O_PROTO_SET,
F_PROTO_STOP_AT_FRAG = 1 << O_PROTO_STOP_AT_FRAG,
F_PROTO_STOP_AT_AUTH = 1 << O_PROTO_STOP_AT_AUTH,
};
#define s struct xt_PROTO_info
static const struct xt_option_entry PROTO_opts[] = {
{.name = "proto-set", .type = XTTYPE_UINT8, .id = O_PROTO_SET,
.flags = XTOPT_PUT | XTOPT_MAND, XTOPT_POINTER(s, proto)},
{.name = "stop-at-frag", .type = XTTYPE_NONE, .id = O_PROTO_STOP_AT_FRAG},
{.name = "stop-at-auth", .type = XTTYPE_NONE, .id = O_PROTO_STOP_AT_AUTH},
XTOPT_TABLEEND,
};
#undef s
static void PROTO_help(void)
{
printf(
"PROTO target options\n"
" --proto-set value Set protocol to <value 0-255>\n"
);
}
static void PROTO_parse(struct xt_option_call *cb)
{
struct xt_PROTO_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_PROTO_SET:
info->mode |= 1 << XT_PROTO_SET;
break;
case O_PROTO_STOP_AT_FRAG:
info->mode |= 1 << XT_PROTO_STOP_AT_FRAG;
break;
case O_PROTO_STOP_AT_AUTH:
info->mode |= 1 << XT_PROTO_STOP_AT_AUTH;
break;
}
}
static void PROTO_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_PROTO_SET))
xtables_error(PARAMETER_PROBLEM,
"PROTO: You must specify the proto to be set");
}
static void PROTO_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_PROTO_info *info = (void *)target->data;
if (info->mode & (1 << XT_PROTO_SET))
printf(" --proto-set %u", info->proto);
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
printf(" --stop-at-frag");
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
printf(" --stop-at-auth");
}
static void PROTO_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_PROTO_info *info = (void *)target->data;
printf(" PROTO ");
if (info->mode & (1 << XT_PROTO_SET))
printf("set to %u", info->proto);
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
printf(" stop-at-frag");
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
printf(" stop-at-auth");
}
static struct xtables_target proto_tg_reg = {
.name = "PROTO",
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_PROTO_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_PROTO_info)),
.help = PROTO_help,
.print = PROTO_print,
.save = PROTO_save,
.x6_parse = PROTO_parse,
.x6_fcheck = PROTO_check,
.x6_options = PROTO_opts,
};
static __attribute__((constructor)) void _init(void)
{
xtables_register_target(&proto_tg_reg);
}

View File

@@ -1,30 +0,0 @@
.PP
The PROTO target modifies the protocol number in IP packet header.
.TP
\fB\-\-proto-set\fP \fIproto_num\fP
This option is mandatory. \fIproto_num\fP is the protocol number to which you want to
modify the packets.
.TP
\fB\-\-stop-at-frag\fP
This option is only valid for IPv6 rules. When specifying this option, the
fragment extension header will be seen as a non-extension header.
.TP
\fB\-\-stop-at-auth\fP
This option is only valid for IPv6 rules. When specifying this option, the
authentication extension header will be seen as a non-extension header.
.PP
For IPv4 packets, the \fBProtocol\fP field is modified and the checksum is
re-calculated.
.PP
For IPv6 packets, the scenario can be more complex due to the introduction of
the extension headers mechanism. By default, the PROTO target will scan the IPv6
packet, finding the last extension header and modify its \fBNext-header\fP field.
Normally, the following headers will be seen as an extension header:
\fINEXTHDR_HOP\fP,
\fINEXTHDR_ROUTING\fP,
\fINEXTHDR_FRAGMENT\fP,
\fINEXTHDR_AUTH\fP,
\fINEXTHDR_DEST\fP.
.PP
For fragmented packets, only the first fragment is processed and other fragments
are not touched.

View File

@@ -1,4 +1,3 @@
.PP
The SYSRQ target allows to remotely trigger sysrq on the local machine over the The SYSRQ target allows to remotely trigger sysrq on the local machine over the
network. This can be useful when vital parts of the machine hang, for example network. This can be useful when vital parts of the machine hang, for example
an oops in a filesystem causing locks to be not released and processes to get an oops in a filesystem causing locks to be not released and processes to get

View File

@@ -67,6 +67,24 @@ static void tarpit_tg_check(unsigned int flags)
"TARPIT: only one action can be used at a time"); "TARPIT: only one action can be used at a time");
} }
static void tarpit_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct xt_tarpit_tginfo *info = (void *)target->data;
switch (info->variant) {
case XTTARPIT_HONEYPOT:
printf(" honeypot mode ");
break;
case XTTARPIT_RESET:
printf(" reset mode ");
break;
default:
printf(" tarpit mode ");
break;
}
}
static void tarpit_tg_save(const void *ip, static void tarpit_tg_save(const void *ip,
const struct xt_entry_target *target) const struct xt_entry_target *target)
{ {
@@ -85,13 +103,6 @@ static void tarpit_tg_save(const void *ip,
} }
} }
static void tarpit_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
printf(" -j TARPIT");
tarpit_tg_save(ip, target);
}
static struct xtables_target tarpit_tg_reg = { static struct xtables_target tarpit_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "TARPIT", .name = "TARPIT",

View File

@@ -1,4 +1,3 @@
.PP
Captures and holds incoming TCP connections using no local per-connection Captures and holds incoming TCP connections using no local per-connection
resources. resources.
.PP .PP

173
extensions/libxt_TEE.c Normal file
View File

@@ -0,0 +1,173 @@
/*
* "TEE" target extension for iptables
* Copyright © Sebastian Claßen <sebastian.classen [at] freenet.ag>, 2007
* Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <sys/socket.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <xtables.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include "xt_TEE.h"
#include "compat_user.h"
enum {
FLAG_GATEWAY = 1 << 0,
};
static const struct option tee_tg_opts[] = {
{.name = "gateway", .has_arg = true, .val = 'g'},
{NULL},
};
static void tee_tg_help(void)
{
printf(
"TEE target options:\n"
" --gateway IPADDR Route packet via the gateway given by address\n"
"\n");
}
static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_tee_tginfo *info = (void *)(*target)->data;
const struct in_addr *ia;
switch (c) {
case 'g':
if (*flags & FLAG_GATEWAY)
xtables_error(PARAMETER_PROBLEM,
"Cannot specify --gateway more than once");
ia = xtables_numeric_to_ipaddr(optarg);
if (ia == NULL)
xtables_error(PARAMETER_PROBLEM,
"Invalid IP address %s", optarg);
memcpy(&info->gw, ia, sizeof(*ia));
*flags |= FLAG_GATEWAY;
return true;
}
return false;
}
static int tee_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_tee_tginfo *info = (void *)(*target)->data;
const struct in6_addr *ia;
switch (c) {
case 'g':
if (*flags & FLAG_GATEWAY)
xtables_error(PARAMETER_PROBLEM,
"Cannot specify --gateway more than once");
ia = xtables_numeric_to_ip6addr(optarg);
if (ia == NULL)
xtables_error(PARAMETER_PROBLEM,
"Invalid IP address %s", optarg);
memcpy(&info->gw, ia, sizeof(*ia));
*flags |= FLAG_GATEWAY;
return true;
}
return false;
}
static void tee_tg_check(unsigned int flags)
{
if (flags == 0)
xtables_error(PARAMETER_PROBLEM, "TEE target: "
"--gateway parameter required");
}
static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
if (numeric)
printf(" TEE gw:%s ", xtables_ipaddr_to_numeric(&info->gw.in));
else
printf(" TEE gw:%s ", xtables_ipaddr_to_anyname(&info->gw.in));
}
static void tee_tg6_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
if (numeric)
printf(" TEE gw:%s ", xtables_ip6addr_to_numeric(&info->gw.in6));
else
printf(" TEE gw:%s ", xtables_ip6addr_to_anyname(&info->gw.in6));
}
static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
printf(" --gateway %s ", xtables_ipaddr_to_numeric(&info->gw.in));
}
static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
printf(" --gateway %s ", xtables_ip6addr_to_numeric(&info->gw.in6));
}
static struct xtables_target tee_tg_reg[] = {
{
.name = "TEE",
.version = XTABLES_VERSION,
.revision = 0,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.help = tee_tg_help,
.parse = tee_tg_parse,
.final_check = tee_tg_check,
.print = tee_tg_print,
.save = tee_tg_save,
.extra_opts = tee_tg_opts,
},
{
.name = "TEE",
.version = XTABLES_VERSION,
.revision = 0,
.family = NFPROTO_IPV6,
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.help = tee_tg_help,
.parse = tee_tg6_parse,
.final_check = tee_tg_check,
.print = tee_tg6_print,
.save = tee_tg6_save,
.extra_opts = tee_tg_opts,
},
};
static __attribute__((constructor)) void tee_tg_ldr(void)
{
xtables_register_targets(tee_tg_reg,
sizeof(tee_tg_reg) / sizeof(*tee_tg_reg));
}

12
extensions/libxt_TEE.man Normal file
View File

@@ -0,0 +1,12 @@
The \fBTEE\fP target will clone a packet and redirect this clone to another
machine on the \fBlocal\fP network segment. In other words, the nexthop
must be the target, or you will have to configure the nexthop to forward it
further if so desired.
.TP
\fB\-\-gateway\fP \fIipaddr\fP
Send the cloned packet to the host reachable at the given IP address.
Use of 0.0.0.0 (for IPv4 packets) or :: (IPv6) is invalid.
.PP
To forward all incoming traffic on eth0 to an Network Layer logging box:
.PP
\-t mangle \-A PREROUTING \-i eth0 \-j TEE \-\-gateway 2001:db8::1

View File

@@ -62,6 +62,15 @@ static void condition_check(unsigned int flags)
"Condition match: must specify --condition"); "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) static void condition_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_condition_mtinfo *info = (const void *)match->data; const struct xt_condition_mtinfo *info = (const void *)match->data;
@@ -69,13 +78,6 @@ static void condition_save(const void *ip, const struct xt_entry_match *match)
printf("%s --condition \"%s\" ", info->invert ? " !" : "", info->name); printf("%s --condition \"%s\" ", info->invert ? " !" : "", info->name);
} }
static void condition_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
printf(" -m condition");
condition_save(ip, match);
}
static struct xtables_match condition_mt_reg = { static struct xtables_match condition_mt_reg = {
.name = "condition", .name = "condition",
.revision = 1, .revision = 1,

View File

@@ -1,4 +1,3 @@
.PP
This matches if a specific condition variable is (un)set. This matches if a specific condition variable is (un)set.
.TP .TP
[\fB!\fP] \fB\-\-condition\fP \fIname\fP [\fB!\fP] \fB\-\-condition\fP \fIname\fP

View File

@@ -62,6 +62,15 @@ static void dhcpmac_mt_check(unsigned int flags)
"--mac parameter required"); "--mac parameter required");
} }
static void dhcpmac_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
const struct dhcpmac_info *info = (void *)match->data;
printf(" dhcpmac %s" DH_MAC_FMT "/%u ",
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
}
static void dhcpmac_mt_save(const void *ip, static void dhcpmac_mt_save(const void *ip,
const struct xt_entry_match *match) const struct xt_entry_match *match)
{ {
@@ -73,13 +82,6 @@ static void dhcpmac_mt_save(const void *ip,
DH_MAC_HEX(info->addr), info->mask); DH_MAC_HEX(info->addr), info->mask);
} }
static void dhcpmac_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
printf(" -m dhcpmac");
dhcpmac_mt_save(ip, match);
}
static struct xtables_match dhcpmac_mt_reg = { static struct xtables_match dhcpmac_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "dhcpmac", .name = "dhcpmac",

View File

@@ -83,6 +83,15 @@ static void fuzzy_mt_check(unsigned int flags)
{ {
} }
static void fuzzy_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_fuzzy_mtinfo *info = (const void *)match->data;
printf(" fuzzy: lower limit = %u pps - upper limit = %u pps ",
info->minimum_rate, info->maximum_rate);
}
static void fuzzy_mt_save(const void *ip, const struct xt_entry_match *match) static void fuzzy_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_fuzzy_mtinfo *info = (const void *)match->data; const struct xt_fuzzy_mtinfo *info = (const void *)match->data;
@@ -91,13 +100,6 @@ static void fuzzy_mt_save(const void *ip, const struct xt_entry_match *match)
printf(" --upper-limit %u ", info->maximum_rate); printf(" --upper-limit %u ", info->maximum_rate);
} }
static void fuzzy_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
printf(" -m fuzzy");
fuzzy_mt_save(ip, match);
}
static struct xtables_match fuzzy_mt_reg = { static struct xtables_match fuzzy_mt_reg = {
.name = "fuzzy", .name = "fuzzy",
.revision = 1, .revision = 1,

View File

@@ -1,4 +1,3 @@
.PP
This module matches a rate limit based on a fuzzy logic controller (FLC). This module matches a rate limit based on a fuzzy logic controller (FLC).
.TP .TP
\fB\-\-lower\-limit\fP \fInumber\fP \fB\-\-lower\-limit\fP \fInumber\fP

View File

@@ -49,44 +49,30 @@ static struct option geoip_opts[] = {
{NULL}, {NULL},
}; };
#if __BYTE_ORDER == __LITTLE_ENDIAN
static void geoip_swap_le32(uint32_t *buf)
{
unsigned char *p = (void *)buf;
uint32_t n = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
p[0] = (n >> 24) & 0xff;
p[1] = (n >> 16) & 0xff;
p[2] = (n >> 8) & 0xff;
p[3] = n & 0xff;
}
static void geoip_swap_in6(struct in6_addr *in6)
{
geoip_swap_le32(&in6->s6_addr32[0]);
geoip_swap_le32(&in6->s6_addr32[1]);
geoip_swap_le32(&in6->s6_addr32[2]);
geoip_swap_le32(&in6->s6_addr32[3]);
}
#endif
static void * static void *
geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto) geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto)
{ {
void *subnets; void *subnets;
struct stat sb; struct stat sb;
char buf[256]; char buf[256];
#if __BYTE_ORDER == __LITTLE_ENDIAN int fd;
unsigned int n;
#endif
/* Use simple integer vector files */ /* Use simple integer vector files */
if (nfproto == NFPROTO_IPV6) if (nfproto == NFPROTO_IPV6) {
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/%s.iv6", code); #if __BYTE_ORDER == _BIG_ENDIAN
else snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv6", code);
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/%s.iv4", code); #else
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv6", code);
#endif
} else {
#if __BYTE_ORDER == _BIG_ENDIAN
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code);
#else
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code);
#endif
}
int fd = open(buf, O_RDONLY); if ((fd = open(buf, O_RDONLY)) < 0) {
if (fd < 0) {
fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno)); fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
xtables_error(OTHER_PROBLEM, "Could not read geoip database"); xtables_error(OTHER_PROBLEM, "Could not read geoip database");
} }
@@ -112,25 +98,6 @@ geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto)
xtables_error(OTHER_PROBLEM, "geoip: insufficient memory"); xtables_error(OTHER_PROBLEM, "geoip: insufficient memory");
read(fd, subnets, sb.st_size); read(fd, subnets, sb.st_size);
close(fd); close(fd);
#if __BYTE_ORDER == __LITTLE_ENDIAN
for (n = 0; n < *count; ++n) {
switch (nfproto) {
case NFPROTO_IPV6: {
struct geoip_subnet6 *gs6 = &(((struct geoip_subnet6 *)subnets)[n]);
geoip_swap_in6(&gs6->begin);
geoip_swap_in6(&gs6->end);
break;
}
case NFPROTO_IPV4: {
struct geoip_subnet4 *gs4 = &(((struct geoip_subnet4 *)subnets)[n]);
geoip_swap_le32(&gs4->begin);
geoip_swap_le32(&gs4->end);
break;
}
}
}
#endif
return subnets; return subnets;
} }
@@ -203,8 +170,7 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
next = strchr(cp, ','); next = strchr(cp, ',');
if (next) *next++ = '\0'; if (next) *next++ = '\0';
cctmp = check_geoip_cc(cp, cc, count); if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
if (cctmp != 0) {
if ((mem[count++].user = if ((mem[count++].user =
(unsigned long)geoip_load_cc(cp, cctmp, nfproto)) == 0) (unsigned long)geoip_load_cc(cp, cctmp, nfproto)) == 0)
xtables_error(OTHER_PROBLEM, xtables_error(OTHER_PROBLEM,
@@ -285,6 +251,31 @@ geoip_final_check(unsigned int flags)
"geoip: missing arguments"); "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 static void
geoip_save(const void *ip, const struct xt_entry_match *match) geoip_save(const void *ip, const struct xt_entry_match *match)
{ {
@@ -304,13 +295,6 @@ geoip_save(const void *ip, const struct xt_entry_match *match)
printf(" "); printf(" ");
} }
static void
geoip_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
printf(" -m geoip");
geoip_save(ip, match);
}
static struct xtables_match geoip_match[] = { static struct xtables_match geoip_match[] = {
{ {
.family = NFPROTO_IPV6, .family = NFPROTO_IPV6,

View File

@@ -1,4 +1,3 @@
.PP
Match a packet by its source or destination country. Match a packet by its source or destination country.
.TP .TP
[\fB!\fP] \fB\-\-src\-cc\fP, \fB\-\-source\-country\fP \fIcountry\fP[\fB,\fP\fIcountry\fP\fB...\fP] [\fB!\fP] \fB\-\-src\-cc\fP, \fB\-\-source\-country\fP \fIcountry\fP[\fB,\fP\fIcountry\fP\fB...\fP]
@@ -16,8 +15,8 @@ with the source package, and which should be available in compiled packages in
/usr/lib(exec)/xtables-addons/. The first command retrieves CSV files from /usr/lib(exec)/xtables-addons/. The first command retrieves CSV files from
MaxMind, while the other two build packed bisectable range files: MaxMind, while the other two build packed bisectable range files:
.PP .PP
mkdir \-p /usr/share/xt_geoip; cd /tmp; $path/to/xt_geoip_dl; mkdir -p /usr/share/xt_geoip; cd /tmp; $path/to/xt_geoip_dl;
.PP .PP
$path/to/xt_geoip_build \-D /usr/share/xt_geoip GeoIP*.csv; $path/to/xt_geoip_build -D /usr/share/xt_geoip GeoIP*.csv;
.PP .PP
The shared library is hardcoded to look in these paths, so use them. The shared library is hardcoded to look in these paths, so use them.

View File

@@ -57,6 +57,17 @@ static void gradm_mt_check(unsigned int flags)
{ {
} }
static void gradm_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_gradm_mtinfo *info = (const void *)match->data;
if (info->invflags)
printf("gradm: disabled");
else
printf("gradm: enabled");
}
static void gradm_mt_save(const void *ip, const struct xt_entry_match *match) static void gradm_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_gradm_mtinfo *info = (const void *)match->data; const struct xt_gradm_mtinfo *info = (const void *)match->data;
@@ -67,13 +78,6 @@ static void gradm_mt_save(const void *ip, const struct xt_entry_match *match)
printf(" --enabled "); printf(" --enabled ");
} }
static void gradm_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
printf(" -m gradm");
gradm_mt_save(ip, match);
}
static struct xtables_match gradm_mt_reg = { static struct xtables_match gradm_mt_reg = {
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.name = "gradm", .name = "gradm",

View File

@@ -1,4 +1,3 @@
.PP
This module matches packets based on grsecurity RBAC status. This module matches packets based on grsecurity RBAC status.
.TP .TP
[\fB!\fP] \fB\-\-enabled\fP [\fB!\fP] \fB\-\-enabled\fP

View File

@@ -175,6 +175,33 @@ static void iface_mt_check(unsigned int flags)
"iface: You must specify at least one option"); "iface: You must specify at least one option");
} }
static void iface_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_iface_mtinfo *info = (const void *)match->data;
printf(" iface: ");
if (info->flags & XT_IFACE_DEV_IN)
printf("(in)");
else if (info->flags & XT_IFACE_DEV_OUT)
printf("(out)");
else
printf("%s", info->ifname);
printf(" [state:");
iface_print_opt(info, XT_IFACE_UP, "up");
iface_print_opt(info, XT_IFACE_BROADCAST, "broadcast");
iface_print_opt(info, XT_IFACE_LOOPBACK, "loopback");
iface_print_opt(info, XT_IFACE_POINTOPOINT, "pointopoint");
iface_print_opt(info, XT_IFACE_RUNNING, "running");
iface_print_opt(info, XT_IFACE_NOARP, "noarp");
iface_print_opt(info, XT_IFACE_PROMISC, "promisc");
iface_print_opt(info, XT_IFACE_MULTICAST, "multicast");
iface_print_opt(info, XT_IFACE_DYNAMIC, "dynamic");
iface_print_opt(info, XT_IFACE_LOWER_UP, "lower_up");
iface_print_opt(info, XT_IFACE_DORMANT, "dormant");
printf("] ");
}
static void iface_mt_save(const void *ip, const struct xt_entry_match *match) static void iface_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_iface_mtinfo *info = (const void *)match->data; const struct xt_iface_mtinfo *info = (const void *)match->data;
@@ -199,13 +226,6 @@ static void iface_mt_save(const void *ip, const struct xt_entry_match *match)
printf(" "); printf(" ");
} }
static void iface_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
printf(" -m iface");
iface_mt_save(ip, match);
}
static struct xtables_match iface_mt_reg = { static struct xtables_match iface_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "iface", .name = "iface",

View File

@@ -1,4 +1,3 @@
.PP
Allows you to check interface states. First, an interface needs to be selected Allows you to check interface states. First, an interface needs to be selected
for comparison. Exactly one option of the following three must be specified: for comparison. Exactly one option of the following three must be specified:
.TP .TP

View File

@@ -217,7 +217,7 @@ ipp2p_mt_print1(const void *entry, const struct xt_entry_match *match,
static void ipp2p_mt_print(const void *entry, static void ipp2p_mt_print(const void *entry,
const struct xt_entry_match *match, int numeric) const struct xt_entry_match *match, int numeric)
{ {
printf(" -m ipp2p "); printf(" ipp2p ");
ipp2p_mt_print1(entry, match, true); ipp2p_mt_print1(entry, match, true);
} }

View File

@@ -1,4 +1,3 @@
.PP
This module matches certain packets in P2P flows. It is not This module matches certain packets in P2P flows. It is not
designed to match all packets belonging to a P2P connection \(em designed to match all packets belonging to a P2P connection \(em
use IPP2P together with CONNMARK for this purpose. use IPP2P together with CONNMARK for this purpose.

View File

@@ -133,6 +133,17 @@ static void ipv4options_print_flags(const struct xt_ipv4options_mtinfo1 *info,
} }
} }
static void ipv4options_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
const struct xt_ipv4options_mtinfo1 *info = (void *)match->data;
printf(" ipv4options %s ",
(info->flags & XT_V4OPTS_ANY) ? "any-of" : "all-of");
ipv4options_print_flags(info, numeric);
printf(" ");
}
static void ipv4options_mt_save(const void *ip, static void ipv4options_mt_save(const void *ip,
const struct xt_entry_match *match) const struct xt_entry_match *match)
{ {
@@ -147,13 +158,6 @@ static void ipv4options_mt_save(const void *ip,
printf(" "); printf(" ");
} }
static void ipv4options_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
printf(" -m ipv4options");
ipv4options_mt_save(ip, match);
}
static struct xtables_match ipv4options_mt_reg = { static struct xtables_match ipv4options_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "ipv4options", .name = "ipv4options",

View File

@@ -1,4 +1,3 @@
.PP
The "ipv4options" module allows to match against a set of IPv4 header options. The "ipv4options" module allows to match against a set of IPv4 header options.
.TP .TP
\fB\-\-flags\fP [\fB!\fP]\fIsymbol\fP[\fB,\fP[\fB!\fP]\fIsymbol...\fP] \fB\-\-flags\fP [\fB!\fP]\fIsymbol\fP[\fB,\fP[\fB!\fP]\fIsymbol...\fP]

View File

@@ -107,6 +107,29 @@ static void length_mt_check(unsigned int flags)
"--layer3. Consider specifying it explicitly.\n"); "--layer3. Consider specifying it explicitly.\n");
} }
static void length_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_length_mtinfo2 *info = (const void *)match->data;
if (info->flags & XT_LENGTH_LAYER3)
printf(" layer3 ");
else if (info->flags & XT_LENGTH_LAYER4)
printf(" layer4 ");
else if (info->flags & XT_LENGTH_LAYER5)
printf(" layer5 ");
else if (info->flags & XT_LENGTH_LAYER7)
printf(" layer7 ");
printf(" length ");
if (info->flags & XT_LENGTH_INVERT)
printf("! ");
if (info->min == info->max)
printf("%u ", (unsigned int)info->min);
else
printf("%u-%u ", (unsigned int)info->min,
(unsigned int)info->max);
}
static void length_mt_save(const void *ip, const struct xt_entry_match *match) static void length_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_length_mtinfo2 *info = (const void *)match->data; const struct xt_length_mtinfo2 *info = (const void *)match->data;
@@ -129,13 +152,6 @@ static void length_mt_save(const void *ip, const struct xt_entry_match *match)
(unsigned int)info->max); (unsigned int)info->max);
} }
static void length_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
printf(" -m length2");
length_mt_save(ip, match);
}
static struct xtables_match length2_mt_reg = { static struct xtables_match length2_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "length2", .name = "length2",

View File

@@ -1,4 +1,3 @@
.PP
This module matches the length of a packet against a specific value or range of This module matches the length of a packet against a specific value or range of
values. values.
.TP .TP

View File

@@ -64,6 +64,30 @@ static void lscan_mt_check(unsigned int flags)
{ {
} }
static void lscan_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
const struct xt_lscan_mtinfo *info = (const void *)(match->data);
const char *s = "";
printf(" lscan ");
if (info->match_stealth) {
printf("STEALTH");
s = ",";
}
if (info->match_syn) {
printf("%sSYNSCAN", s);
s = ",";
}
if (info->match_cn) {
printf("%sCNSCAN", s);
s = ",";
}
if (info->match_gr)
printf("%sGRSCAN", s);
printf(" ");
}
static void lscan_mt_save(const void *ip, const struct xt_entry_match *match) static void lscan_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_lscan_mtinfo *info = (const void *)(match->data); const struct xt_lscan_mtinfo *info = (const void *)(match->data);
@@ -78,13 +102,6 @@ static void lscan_mt_save(const void *ip, const struct xt_entry_match *match)
printf(" --grscan "); printf(" --grscan ");
} }
static void lscan_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
printf(" -m lscan");
lscan_mt_save(ip, match);
}
static struct xtables_match lscan_mt_reg = { static struct xtables_match lscan_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "lscan", .name = "lscan",

View File

@@ -1,5 +1,4 @@
.PP Detects simple low-level scan attemps based upon the packet's contents.
Detects simple low-level scan attempts based upon the packet's contents.
(This is (This is
different from other implementations, which also try to match the rate of new different from other implementations, which also try to match the rate of new
connections.) Note that an attempt is only discovered after it has been carried connections.) Note that an attempt is only discovered after it has been carried

View File

@@ -117,6 +117,18 @@ static int psd_mt_parse(int c, char **argv, int invert, unsigned int *flags,
/* Final check; nothing. */ /* Final check; nothing. */
static void psd_mt_final_check(unsigned int flags) {} static void psd_mt_final_check(unsigned int flags) {}
/* Prints out the targinfo. */
static void psd_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_psd_info *psdinfo = (const struct xt_psd_info *)match->data;
printf(" psd ");
printf("weight-threshold: %u ", psdinfo->weight_threshold);
printf("delay-threshold: %u ", psdinfo->delay_threshold);
printf("lo-ports-weight: %u ", psdinfo->lo_ports_weight);
printf("hi-ports-weight: %u ", psdinfo->hi_ports_weight);
}
/* Saves the union ipt_targinfo in parsable form to stdout. */
static void psd_mt_save(const void *ip, const struct xt_entry_match *match) static void psd_mt_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_psd_info *psdinfo = (const struct xt_psd_info *)match->data; const struct xt_psd_info *psdinfo = (const struct xt_psd_info *)match->data;
@@ -126,12 +138,6 @@ static void psd_mt_save(const void *ip, const struct xt_entry_match *match)
printf("--psd-hi-ports-weight %u ", psdinfo->hi_ports_weight); printf("--psd-hi-ports-weight %u ", psdinfo->hi_ports_weight);
} }
static void psd_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
printf(" -m psd");
psd_mt_save(ip, match);
}
static struct xtables_match psd_mt_reg = { static struct xtables_match psd_mt_reg = {
.name = "psd", .name = "psd",
.version = XTABLES_VERSION, .version = XTABLES_VERSION,

View File

@@ -1,4 +1,3 @@
.PP
Attempt to detect TCP and UDP port scans. This match was derived from Attempt to detect TCP and UDP port scans. This match was derived from
Solar Designer's scanlogd. Solar Designer's scanlogd.
.TP .TP

View File

@@ -98,6 +98,8 @@ quota_mt2_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_quota_mtinfo2 *q = (void *)match->data; const struct xt_quota_mtinfo2 *q = (void *)match->data;
if (q->flags & XT_QUOTA_INVERT)
printf(" !");
if (q->flags & XT_QUOTA_GROW) if (q->flags & XT_QUOTA_GROW)
printf(" --grow "); printf(" --grow ");
if (q->flags & XT_QUOTA_NO_CHANGE) if (q->flags & XT_QUOTA_NO_CHANGE)
@@ -106,16 +108,29 @@ quota_mt2_save(const void *ip, const struct xt_entry_match *match)
printf(" --packets "); printf(" --packets ");
if (*q->name != '\0') if (*q->name != '\0')
printf(" --name %s ", q->name); printf(" --name %s ", q->name);
if (q->flags & XT_QUOTA_INVERT)
printf(" !");
printf(" --quota %llu ", (unsigned long long)q->quota); printf(" --quota %llu ", (unsigned long long)q->quota);
} }
static void quota_mt2_print(const void *ip, const struct xt_entry_match *match, static void quota_mt2_print(const void *ip, const struct xt_entry_match *match,
int numeric) int numeric)
{ {
printf(" -m quota"); const struct xt_quota_mtinfo2 *q = (const void *)match->data;
quota_mt2_save(ip, match);
if (q->flags & XT_QUOTA_INVERT)
printf(" !");
if (q->flags & XT_QUOTA_GROW)
printf(" counter");
else
printf(" quota");
if (*q->name != '\0')
printf(" %s:", q->name);
printf(" %llu ", (unsigned long long)q->quota);
if (q->flags & XT_QUOTA_PACKET)
printf("packets ");
else
printf("bytes ");
if (q->flags & XT_QUOTA_NO_CHANGE)
printf("(no-change mode) ");
} }
static struct xtables_match quota_mt2_reg = { static struct xtables_match quota_mt2_reg = {

View File

@@ -1,4 +1,3 @@
.PP
The "quota2" implements a named counter which can be increased or decreased The "quota2" implements a named counter which can be increased or decreased
on a per-match basis. Available modes are packet counting or byte counting. on a per-match basis. Available modes are packet counting or byte counting.
The value of the counter can be read and reset through procfs, thereby making The value of the counter can be read and reset through procfs, thereby making

View File

@@ -5,5 +5,4 @@ AM_CFLAGS = ${regular_CFLAGS} ${libxtables_CFLAGS}
include ../../Makefile.extra include ../../Makefile.extra
sbin_PROGRAMS = pknlusr noinst_PROGRAMS = pknlusr
dist_man_MANS = pknlusr.8

View File

@@ -1,17 +0,0 @@
from Crypto.Hash import SHA256
from Crypto.Hash import MD5
import sys
import hmac
import struct
import socket
from time import time
def gen_hmac(secret, ip):
epoch_mins = (long)(time()/60)
s = hmac.HMAC(secret, digestmod = SHA256)
s.update(socket.inet_aton(socket.gethostbyname(ip)))
s.update(struct.pack("i", epoch_mins)) # "i" is for integer
print s.hexdigest()
if __name__ == '__main__':
gen_hmac(sys.argv[1], sys.argv[2])

View File

@@ -1,6 +0,0 @@
#!/bin/bash
if [ "$#" -ne 4 ]; then
echo "usage: $0 <IP src> <IP dst> <PORT dst> <secret>"
exit 1
fi
python gen_hmac.py "$4" "$1" | socat - "udp-sendto:$2:$3,bind=$1"

View File

@@ -11,6 +11,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <xtables.h> #include <xtables.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
@@ -69,6 +70,7 @@ parse_ports(const char *portstring, uint16_t *ports, const char *proto)
if (cp != NULL) if (cp != NULL)
xtables_error(PARAMETER_PROBLEM, "too many ports specified"); xtables_error(PARAMETER_PROBLEM, "too many ports specified");
free(buffer); free(buffer);
return i; return i;
} }
@@ -89,11 +91,12 @@ proto_to_name(uint8_t proto)
static const char * static const char *
check_proto(uint16_t pnum, uint8_t invflags) check_proto(uint16_t pnum, uint8_t invflags)
{ {
char *proto;
if (invflags & XT_INV_PROTO) if (invflags & XT_INV_PROTO)
xtables_error(PARAMETER_PROBLEM, PKNOCK "only works with TCP and UDP."); xtables_error(PARAMETER_PROBLEM, PKNOCK "only works with TCP and UDP.");
const char *proto = proto_to_name(pnum); if ((proto = proto_to_name(pnum)) != NULL)
if (proto != NULL)
return proto; return proto;
else if (pnum == 0) else if (pnum == 0)
xtables_error(PARAMETER_PROBLEM, PKNOCK "needs `-p tcp' or `-p udp'"); xtables_error(PARAMETER_PROBLEM, PKNOCK "needs `-p tcp' or `-p udp'");
@@ -120,7 +123,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
info->ports_count = parse_ports(optarg, info->port, proto); info->ports_count = parse_ports(optarg, info->port, proto);
info->option |= XT_PKNOCK_KNOCKPORT; info->option |= XT_PKNOCK_KNOCKPORT;
*flags |= XT_PKNOCK_KNOCKPORT; *flags |= XT_PKNOCK_KNOCKPORT;
#ifdef DEBUG #if DEBUG
printf("ports_count: %d\n", info->ports_count); printf("ports_count: %d\n", info->ports_count);
#endif #endif
break; break;
@@ -159,7 +162,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
info->rule_name_len = strlen(info->rule_name); info->rule_name_len = strlen(info->rule_name);
info->option |= XT_PKNOCK_NAME; info->option |= XT_PKNOCK_NAME;
*flags |= XT_PKNOCK_NAME; *flags |= XT_PKNOCK_NAME;
#ifdef DEBUG #if DEBUG
printf("info->rule_name: %s\n", info->rule_name); printf("info->rule_name: %s\n", info->rule_name);
#endif #endif
break; break;
@@ -210,6 +213,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
if (invert) if (invert)
xtables_error(PARAMETER_PROBLEM, PKNOCK "does not support invert."); xtables_error(PARAMETER_PROBLEM, PKNOCK "does not support invert.");
return 1; return 1;
} }

View File

@@ -15,10 +15,10 @@ modprobe xt_pknock
.PP .PP
Example 1 (TCP mode, manual closing of opened port not possible): Example 1 (TCP mode, manual closing of opened port not possible):
.IP .IP
iptables \-P INPUT DROP iptables -P INPUT DROP
.IP .IP
iptables \-A INPUT \-p tcp \-m pknock \-\-knockports 4002,4001,4004 \-\-strict iptables -A INPUT -p tcp -m pknock --knockports 4002,4001,4004 --strict
\-\-name SSH \-\-time 10 \-\-autoclose 60 \-\-dport 22 \-j ACCEPT --name SSH --time 10 --autoclose 60 --dport 22 -j ACCEPT
.PP .PP
The rule will allow tcp port 22 for the attempting IP address after the successful reception of TCP SYN packets The rule will allow tcp port 22 for the attempting IP address after the successful reception of TCP SYN packets
to ports 4002, 4001 and 4004, in this order (a.k.a. port-knocking). to ports 4002, 4001 and 4004, in this order (a.k.a. port-knocking).
@@ -33,10 +33,10 @@ Example 2 (UDP mode \(em non-replayable and non-spoofable, manual closing
of opened port possible, secure, also called "SPA" = Secure Port of opened port possible, secure, also called "SPA" = Secure Port
Authorization): Authorization):
.IP .IP
iptables \-A INPUT \-p udp \-m pknock \-\-knockports 4000 \-\-name FTP iptables -A INPUT -p udp -m pknock --knockports 4000 --name FTP
\-\-opensecret foo \-\-closesecret bar \-\-autoclose 240 \-j DROP --opensecret foo --closesecret bar --autoclose 240 -j DROP
.IP .IP
iptables \-A INPUT \-p tcp \-m pknock \-\-checkip \-\-name FTP \-\-dport 21 \-j ACCEPT iptables -A INPUT -p tcp -m pknock --checkip --name FTP --dport 21 -j ACCEPT
.PP .PP
The first rule will create an "ALLOWED" record in /proc/net/xt_pknock/FTP after The first rule will create an "ALLOWED" record in /proc/net/xt_pknock/FTP after
the successful reception of an UDP packet to port 4000. The packet payload must be the successful reception of an UDP packet to port 4000. The packet payload must be
@@ -62,6 +62,8 @@ Specifying \fB--autoclose 0\fP means that no automatic close will be performed a
xt_pknock is capable of sending information about successful matches xt_pknock is capable of sending information about successful matches
via a netlink socket to userspace, should you need to implement your own via a netlink socket to userspace, should you need to implement your own
way of receiving and handling portknock notifications. way of receiving and handling portknock notifications.
Be sure to read the documentation in the doc/pknock/ directory,
or visit the original site \(em http://portknocko.berlios.de/ .
.PP .PP
\fBTCP mode\fP: \fBTCP mode\fP:
.PP .PP

View File

@@ -1,18 +0,0 @@
.TH pknlusr 8 "2020-10-22" "xtables-addons" "xtables-addons"
.SH NAME
.PP
pknlusr \(em userspace monitor for successful xt_pknock matches
.SH Synopsis
.PP
\fBpknlusr\fP [\fIgroup-id\fP]
.SH Description
\fIxt_pknock\fP is an xtables match extension that implements so-called \fIport
knocking\fP. It can be configured to send information about each successful
match via a netlink socket to userspace. \fBpknluser\fP listens for these
notifications.
.PP
By default, \fBpknlusr\fP listens for messages sent to netlink multicast group
1. Another group ID may be passed as a command-line argument.
.SH See also
.PP
xtables-addons(8)

View File

@@ -7,94 +7,85 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/connector.h> #include <linux/connector.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include "xt_pknock.h" #include "xt_pknock.h"
#define DEFAULT_GROUP_ID 1 #define GROUP 1
#define MIN_GROUP_ID DEFAULT_GROUP_ID
#define MAX_GROUP_ID \
(sizeof((struct sockaddr_nl){0}.nl_groups) * CHAR_BIT)
int main(int argc, char **argv) static struct sockaddr_nl src_addr, dest_addr;
static int sock_fd;
static unsigned char *buf;
static struct xt_pknock_nl_msg *nlmsg;
int main(void)
{ {
socklen_t addrlen;
int status; int status;
unsigned int group_id = DEFAULT_GROUP_ID; int group = GROUP;
struct sockaddr_nl local_addr = {.nl_family = AF_NETLINK};
int sock_fd;
size_t nlmsg_size;
struct nlmgrhdr *nlmsg;
struct cn_msg *cn_msg;
struct xt_pknock_nl_msg *pknock_msg;
if (argc > 2) { int buf_size;
char *prog = strdup(argv[0]);
if (prog == NULL) {
perror("strdup()");
} else {
fprintf(stderr, "%s [ group-id ]\n", basename(prog));
free(prog);
}
exit(EXIT_FAILURE);
}
if (argc == 2) { const char *ip;
long n; char ipbuf[48];
char *end;
errno = 0;
n = strtol(argv[1], &end, 10);
if (*end || (errno && (n == LONG_MIN || n == LONG_MAX)) ||
n < MIN_GROUP_ID || n > MAX_GROUP_ID) {
fputs("Group ID invalid.\n", stderr);
exit(EXIT_FAILURE);
}
group_id = n;
}
sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (sock_fd == -1) { if (sock_fd == -1) {
perror("socket()"); perror("socket()");
exit(EXIT_FAILURE); return 1;
} }
local_addr.nl_groups = 1U << (group_id - 1); memset(&src_addr, 0, sizeof(src_addr));
status = bind(sock_fd, (struct sockaddr *)&local_addr, sizeof(local_addr)); src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = group;
status = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
if (status == -1) { if (status == -1) {
close(sock_fd);
perror("bind()"); perror("bind()");
goto err_close_sock; return 1;
} }
nlmsg_size = NLMSG_SPACE(sizeof(*cn_msg) + sizeof(*pknock_msg)); memset(&dest_addr, 0, sizeof(dest_addr));
nlmsg = malloc(nlmsg_size); dest_addr.nl_family = AF_NETLINK;
if (!nlmsg) { dest_addr.nl_pid = 0;
dest_addr.nl_groups = group;
buf_size = sizeof(struct xt_pknock_nl_msg) + sizeof(struct cn_msg) + sizeof(struct nlmsghdr);
buf = malloc(buf_size);
if (!buf) {
perror("malloc()"); perror("malloc()");
goto err_close_sock; return 1;
} }
addrlen = sizeof(dest_addr);
while(1) { while(1) {
const char *ip;
char ipbuf[INET_ADDRSTRLEN];
memset(nlmsg, 0, nlmsg_size); memset(buf, 0, buf_size);
status = recv(sock_fd, nlmsg, nlmsg_size, 0);
if (status < 0) { status = recvfrom(sock_fd, buf, buf_size, 0, (struct sockaddr *)&dest_addr, &addrlen);
perror("recv()");
goto err_free_msg; if (status <= 0) {
} perror("recvfrom()");
if (status == 0) return 1;
break; }
cn_msg = NLMSG_DATA(nlmsg);
pknock_msg = (struct xt_pknock_nl_msg *)(cn_msg->data); nlmsg = (struct xt_pknock_nl_msg *) (buf + sizeof(struct cn_msg) + sizeof(struct nlmsghdr));
ip = inet_ntop(AF_INET, &pknock_msg->peer_ip, ipbuf, sizeof(ipbuf));
printf("rule_name: %s - ip %s\n", pknock_msg->rule_name, ip); ip = inet_ntop(AF_INET, &nlmsg->peer_ip, ipbuf, sizeof(ipbuf));
printf("rule_name: %s - ip %s\n", nlmsg->rule_name, ip);
} }
err_free_msg:
free(nlmsg);
err_close_sock:
close(sock_fd); close(sock_fd);
exit(status == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
free(buf);
return 0;
} }

View File

@@ -19,17 +19,23 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/jhash.h> #include <linux/jhash.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/crypto.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/connector.h> #include <linux/connector.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <crypto/hash.h>
#include "xt_pknock.h" #include "xt_pknock.h"
#include "compat_xtables.h" #include "compat_xtables.h"
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
# define PK_CRYPTO 1
#endif
enum status { enum status {
ST_INIT = 1, ST_INIT = 1,
ST_MATCHING, ST_MATCHING,
@@ -90,27 +96,35 @@ enum {
#define hashtable_for_each_safe(pos, n, head, size, i) \ #define hashtable_for_each_safe(pos, n, head, size, i) \
for ((i) = 0; (i) < (size); ++(i)) \ for ((i) = 0; (i) < (size); ++(i)) \
list_for_each_safe((pos), (n), (&head[(i)])) list_for_each_safe((pos), (n), (&head[(i)]))
#define pk_debug(msg, peer) pr_debug("(S) peer: %pI4 - %s.\n", &((peer)->ip), msg)
#define pk_debug(msg, peer) pr_debug( \
"(S) peer: " NIPQUAD_FMT " - %s.\n", \
NIPQUAD((peer)->ip), msg)
static uint32_t ipt_pknock_hash_rnd; static uint32_t ipt_pknock_hash_rnd;
static unsigned int rule_hashsize = DEFAULT_RULE_HASH_SIZE; static unsigned int rule_hashsize = DEFAULT_RULE_HASH_SIZE;
static unsigned int peer_hashsize = DEFAULT_PEER_HASH_SIZE; static unsigned int peer_hashsize = DEFAULT_PEER_HASH_SIZE;
static unsigned int gc_expir_time = DEFAULT_GC_EXPIRATION_TIME; static unsigned int gc_expir_time = DEFAULT_GC_EXPIRATION_TIME;
static int nl_multicast_group = -1; static int nl_multicast_group = -1;
static struct list_head *rule_hashtable; static struct list_head *rule_hashtable;
static struct proc_dir_entry *pde; static struct proc_dir_entry *pde;
static DEFINE_SPINLOCK(list_lock); static DEFINE_SPINLOCK(list_lock);
#ifdef PK_CRYPTO
static struct { static struct {
const char *algo; const char *algo;
struct crypto_shash *tfm; struct crypto_hash *tfm;
unsigned int size; unsigned int size;
struct shash_desc desc; struct hash_desc desc;
} crypto = { } crypto = {
.algo = "hmac(sha256)", .algo = "hmac(sha256)",
.tfm = NULL, .tfm = NULL,
.size = 0 .size = 0
}; };
#endif
module_param(rule_hashsize, int, S_IRUGO); module_param(rule_hashsize, int, S_IRUGO);
MODULE_PARM_DESC(rule_hashsize, "Buckets in rule hash table (default: 8)"); MODULE_PARM_DESC(rule_hashsize, "Buckets in rule hash table (default: 8)");
@@ -153,6 +167,7 @@ alloc_hashtable(unsigned int size)
return NULL; return NULL;
for (i = 0; i < size; ++i) for (i = 0; i < size; ++i)
INIT_LIST_HEAD(&hash[i]); INIT_LIST_HEAD(&hash[i]);
return hash; return hash;
} }
@@ -181,11 +196,14 @@ status_itoa(enum status status)
static void * static void *
pknock_seq_start(struct seq_file *s, loff_t *pos) pknock_seq_start(struct seq_file *s, loff_t *pos)
{ {
const struct xt_pknock_rule *rule = s->private; const struct proc_dir_entry *pde = s->private;
const struct xt_pknock_rule *rule = pde->data;
spin_lock_bh(&list_lock); spin_lock_bh(&list_lock);
if (*pos >= peer_hashsize) if (*pos >= peer_hashsize)
return NULL; return NULL;
return rule->peer_head + *pos; return rule->peer_head + *pos;
} }
@@ -198,11 +216,13 @@ pknock_seq_start(struct seq_file *s, loff_t *pos)
static void * static void *
pknock_seq_next(struct seq_file *s, void *v, loff_t *pos) pknock_seq_next(struct seq_file *s, void *v, loff_t *pos)
{ {
const struct xt_pknock_rule *rule = s->private; const struct proc_dir_entry *pde = s->private;
const struct xt_pknock_rule *rule = pde->data;
++*pos; ++*pos;
if (*pos >= peer_hashsize) if (*pos >= peer_hashsize)
return NULL; return NULL;
return rule->peer_head + *pos; return rule->peer_head + *pos;
} }
@@ -228,11 +248,14 @@ pknock_seq_show(struct seq_file *s, void *v)
const struct peer *peer; const struct peer *peer;
unsigned long time; unsigned long time;
const struct list_head *peer_head = v; const struct list_head *peer_head = v;
const struct xt_pknock_rule *rule = s->private;
const struct proc_dir_entry *pde = s->private;
const struct xt_pknock_rule *rule = pde->data;
list_for_each_safe(pos, n, peer_head) { list_for_each_safe(pos, n, peer_head) {
peer = list_entry(pos, struct peer, head); peer = list_entry(pos, struct peer, head);
seq_printf(s, "src=%pI4 ", &peer->ip);
seq_printf(s, "src=" NIPQUAD_FMT " ", NIPQUAD(peer->ip));
seq_printf(s, "proto=%s ", (peer->proto == IPPROTO_TCP) ? seq_printf(s, "proto=%s ", (peer->proto == IPPROTO_TCP) ?
"TCP" : "UDP"); "TCP" : "UDP");
seq_printf(s, "status=%s ", status_itoa(peer->status)); seq_printf(s, "status=%s ", status_itoa(peer->status));
@@ -278,16 +301,17 @@ pknock_proc_open(struct inode *inode, struct file *file)
int ret = seq_open(file, &pknock_seq_ops); int ret = seq_open(file, &pknock_seq_ops);
if (ret == 0) { if (ret == 0) {
struct seq_file *sf = file->private_data; struct seq_file *sf = file->private_data;
sf->private = PDE_DATA(inode); sf->private = PDE(inode);
} }
return ret; return ret;
} }
static const struct proc_ops pknock_proc_ops = { static const struct file_operations pknock_proc_ops = {
.proc_open = pknock_proc_open, .owner = THIS_MODULE,
.proc_read = seq_read, .open = pknock_proc_open,
.proc_lseek = seq_lseek, .read = seq_read,
.proc_release = seq_release, .llseek = seq_lseek,
.release = seq_release
}; };
/** /**
@@ -299,6 +323,7 @@ static void update_rule_gc_timer(struct xt_pknock_rule *rule)
{ {
if (timer_pending(&rule->timer)) if (timer_pending(&rule->timer))
del_timer(&rule->timer); del_timer(&rule->timer);
rule->timer.expires = jiffies + msecs_to_jiffies(gc_expir_time); rule->timer.expires = jiffies + msecs_to_jiffies(gc_expir_time);
add_timer(&rule->timer); add_timer(&rule->timer);
} }
@@ -343,10 +368,11 @@ has_logged_during_this_minute(const struct peer *peer)
* *
* @r: rule * @r: rule
*/ */
static void peer_gc(struct timer_list *tl) static void
peer_gc(unsigned long r)
{ {
unsigned int i; unsigned int i;
struct xt_pknock_rule *rule = from_timer(rule, tl, timer); struct xt_pknock_rule *rule = (struct xt_pknock_rule *)r;
struct peer *peer; struct peer *peer;
struct list_head *pos, *n; struct list_head *pos, *n;
@@ -420,6 +446,7 @@ add_rule(struct xt_pknock_mtinfo *info)
list_for_each_safe(pos, n, &rule_hashtable[hash]) { list_for_each_safe(pos, n, &rule_hashtable[hash]) {
rule = list_entry(pos, struct xt_pknock_rule, head); rule = list_entry(pos, struct xt_pknock_rule, head);
if (!rulecmp(info, rule)) if (!rulecmp(info, rule))
continue; continue;
++rule->ref_count; ++rule->ref_count;
@@ -428,6 +455,7 @@ add_rule(struct xt_pknock_mtinfo *info)
rule->max_time = info->max_time; rule->max_time = info->max_time;
rule->autoclose_time = info->autoclose_time; rule->autoclose_time = info->autoclose_time;
} }
if (info->option & XT_PKNOCK_CHECKIP) if (info->option & XT_PKNOCK_CHECKIP)
pr_debug("add_rule() (AC) rule found: %s - " pr_debug("add_rule() (AC) rule found: %s - "
"ref_count: %d\n", "ref_count: %d\n",
@@ -435,25 +463,34 @@ add_rule(struct xt_pknock_mtinfo *info)
return true; return true;
} }
rule = kzalloc(sizeof(*rule), GFP_KERNEL); rule = kmalloc(sizeof(*rule), GFP_KERNEL);
if (rule == NULL) if (rule == NULL)
return false; return false;
INIT_LIST_HEAD(&rule->head); INIT_LIST_HEAD(&rule->head);
memset(rule->rule_name, 0, sizeof(rule->rule_name));
strncpy(rule->rule_name, info->rule_name, info->rule_name_len); strncpy(rule->rule_name, info->rule_name, info->rule_name_len);
rule->rule_name_len = info->rule_name_len; rule->rule_name_len = info->rule_name_len;
rule->ref_count = 1; rule->ref_count = 1;
rule->max_time = info->max_time; rule->max_time = info->max_time;
rule->autoclose_time = info->autoclose_time; rule->autoclose_time = info->autoclose_time;
rule->peer_head = alloc_hashtable(peer_hashsize); rule->peer_head = alloc_hashtable(peer_hashsize);
if (rule->peer_head == NULL) if (rule->peer_head == NULL)
goto out; goto out;
timer_setup(&rule->timer, peer_gc, 0);
rule->status_proc = proc_create_data(info->rule_name, 0, pde, init_timer(&rule->timer);
&pknock_proc_ops, rule); rule->timer.function = peer_gc;
rule->timer.data = (unsigned long)rule;
rule->status_proc = create_proc_entry(info->rule_name, 0, pde);
if (rule->status_proc == NULL) if (rule->status_proc == NULL)
goto out; goto out;
rule->status_proc->proc_fops = &pknock_proc_ops;
rule->status_proc->data = rule;
list_add(&rule->head, &rule_hashtable[hash]); list_add(&rule->head, &rule_hashtable[hash]);
pr_debug("(A) rule_name: %s - created.\n", rule->rule_name); pr_debug("(A) rule_name: %s - created.\n", rule->rule_name);
return true; return true;
@@ -484,6 +521,7 @@ remove_rule(struct xt_pknock_mtinfo *info)
list_for_each_safe(pos, n, &rule_hashtable[hash]) { list_for_each_safe(pos, n, &rule_hashtable[hash]) {
rule = list_entry(pos, struct xt_pknock_rule, head); rule = list_entry(pos, struct xt_pknock_rule, head);
if (rulecmp(info, rule)) { if (rulecmp(info, rule)) {
found = 1; found = 1;
rule->ref_count--; rule->ref_count--;
@@ -509,6 +547,7 @@ remove_rule(struct xt_pknock_mtinfo *info)
pr_debug("(D) rule deleted: %s.\n", rule->rule_name); pr_debug("(D) rule deleted: %s.\n", rule->rule_name);
if (timer_pending(&rule->timer)) if (timer_pending(&rule->timer))
del_timer(&rule->timer); del_timer(&rule->timer);
list_del(&rule->head); list_del(&rule->head);
kfree(rule->peer_head); kfree(rule->peer_head);
kfree(rule); kfree(rule);
@@ -528,6 +567,7 @@ static struct peer *get_peer(struct xt_pknock_rule *rule, __be32 ip)
unsigned int hash; unsigned int hash;
hash = pknock_hash(&ip, sizeof(ip), ipt_pknock_hash_rnd, peer_hashsize); hash = pknock_hash(&ip, sizeof(ip), ipt_pknock_hash_rnd, peer_hashsize);
list_for_each_safe(pos, n, &rule->peer_head[hash]) { list_for_each_safe(pos, n, &rule->peer_head[hash]) {
peer = list_entry(pos, struct peer, head); peer = list_entry(pos, struct peer, head);
if (peer->ip == ip) if (peer->ip == ip)
@@ -561,12 +601,14 @@ static struct peer *new_peer(__be32 ip, uint8_t proto)
if (peer == NULL) if (peer == NULL)
return NULL; return NULL;
INIT_LIST_HEAD(&peer->head); INIT_LIST_HEAD(&peer->head);
peer->ip = ip; peer->ip = ip;
peer->proto = proto; peer->proto = proto;
peer->timestamp = jiffies/HZ; peer->timestamp = jiffies/HZ;
peer->login_sec = 0; peer->login_sec = 0;
reset_knock_status(peer); reset_knock_status(peer);
return peer; return peer;
} }
@@ -590,9 +632,8 @@ static void add_peer(struct peer *peer, struct xt_pknock_rule *rule)
*/ */
static void remove_peer(struct peer *peer) static void remove_peer(struct peer *peer)
{ {
if (peer == NULL)
return;
list_del(&peer->head); list_del(&peer->head);
if (peer != NULL)
kfree(peer); kfree(peer);
} }
@@ -654,24 +695,31 @@ static bool
msg_to_userspace_nl(const struct xt_pknock_mtinfo *info, msg_to_userspace_nl(const struct xt_pknock_mtinfo *info,
const struct peer *peer, int multicast_group) const struct peer *peer, int multicast_group)
{ {
#if IS_ENABLED(CONFIG_CONNECTOR) #if defined(CONFIG_CONNECTOR) || defined(CONFIG_CONNECTOR_MODULE)
struct cn_msg *m; struct cn_msg *m;
struct xt_pknock_nl_msg msg; struct xt_pknock_nl_msg msg;
m = kzalloc(sizeof(*m) + sizeof(msg), GFP_ATOMIC); m = kmalloc(sizeof(*m) + sizeof(msg), GFP_ATOMIC);
if (m == NULL) if (m == NULL)
return false; return false;
memset(m, 0, sizeof(*m) + sizeof(msg));
m->seq = 0;
m->len = sizeof(msg); m->len = sizeof(msg);
msg.peer_ip = peer->ip; msg.peer_ip = peer->ip;
scnprintf(msg.rule_name, info->rule_name_len + 1, info->rule_name); scnprintf(msg.rule_name, info->rule_name_len + 1, info->rule_name);
memcpy(m + 1, &msg, m->len); memcpy(m + 1, &msg, m->len);
cn_netlink_send(m, 0, multicast_group, GFP_ATOMIC);
cn_netlink_send(m, multicast_group, GFP_ATOMIC);
kfree(m); kfree(m);
#endif #endif
return true; return true;
} }
#ifdef PK_CRYPTO
/** /**
* Transforms a sequence of characters to hexadecimal. * Transforms a sequence of characters to hexadecimal.
* *
@@ -704,7 +752,8 @@ static bool
has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc, has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
const unsigned char *payload, unsigned int payload_len) const unsigned char *payload, unsigned int payload_len)
{ {
char result[64] = ""; // 64 bytes * 8 = 512 bits struct scatterlist sg[2];
char result[64]; // 64 bytes * 8 = 512 bits
char *hexresult; char *hexresult;
unsigned int hexa_size; unsigned int hexa_size;
int ret; int ret;
@@ -724,12 +773,23 @@ has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
/* + 1 cause we MUST add NULL in the payload */ /* + 1 cause we MUST add NULL in the payload */
if (payload_len != hexa_size + 1) if (payload_len != hexa_size + 1)
return false; return false;
hexresult = kzalloc(hexa_size, GFP_ATOMIC);
hexresult = kmalloc(hexa_size, GFP_ATOMIC);
if (hexresult == NULL) if (hexresult == NULL)
return false; return false;
memset(result, 0, sizeof(result));
memset(hexresult, 0, hexa_size);
epoch_min = get_seconds() / 60; epoch_min = get_seconds() / 60;
ret = crypto_shash_setkey(crypto.tfm, secret, secret_len); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
sg_init_table(sg, ARRAY_SIZE(sg));
#endif
sg_set_buf(&sg[0], &ipsrc, sizeof(ipsrc));
sg_set_buf(&sg[1], &epoch_min, sizeof(epoch_min));
ret = crypto_hash_setkey(crypto.tfm, secret, secret_len);
if (ret != 0) { if (ret != 0) {
printk("crypto_hash_setkey() failed ret=%d\n", ret); printk("crypto_hash_setkey() failed ret=%d\n", ret);
goto out; goto out;
@@ -740,21 +800,25 @@ has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
* 4 bytes IP (32 bits) + * 4 bytes IP (32 bits) +
* 4 bytes int epoch_min (32 bits) * 4 bytes int epoch_min (32 bits)
*/ */
if ((ret = crypto_shash_update(&crypto.desc, (const void *)&ipsrc, sizeof(ipsrc))) != 0 || ret = crypto_hash_digest(&crypto.desc, sg,
(ret = crypto_shash_update(&crypto.desc, (const void *)&epoch_min, sizeof(epoch_min))) != 0 || sizeof(ipsrc) + sizeof(epoch_min), result);
(ret = crypto_shash_final(&crypto.desc, result)) != 0) { if (ret != 0) {
printk("crypto_shash_update/final() failed ret=%d\n", ret); printk("crypto_hash_digest() failed ret=%d\n", ret);
goto out; goto out;
} }
crypt_to_hex(hexresult, result, crypto.size); crypt_to_hex(hexresult, result, crypto.size);
if (memcmp(hexresult, payload, hexa_size) != 0) if (memcmp(hexresult, payload, hexa_size) != 0)
pr_debug("secret match failed\n"); pr_debug("secret match failed\n");
else else
fret = true; fret = true;
out: out:
kfree(hexresult); kfree(hexresult);
return fret; return fret;
} }
#endif /* PK_CRYPTO */
/** /**
* If the peer pass the security policy. * If the peer pass the security policy.
@@ -777,11 +841,14 @@ pass_security(struct peer *peer, const struct xt_pknock_mtinfo *info,
pk_debug("DENIED (anti-spoof protection)", peer); pk_debug("DENIED (anti-spoof protection)", peer);
return false; return false;
} }
#ifdef PK_CRYPTO
/* Check for OPEN secret */ /* Check for OPEN secret */
if (has_secret(info->open_secret, if (has_secret(info->open_secret,
info->open_secret_len, peer->ip, info->open_secret_len, peer->ip,
payload, payload_len)) payload, payload_len))
return true; return true;
#endif
return false; return false;
} }
@@ -808,6 +875,7 @@ update_peer(struct peer *peer, const struct xt_pknock_mtinfo *info,
/* Peer must start the sequence from scratch. */ /* Peer must start the sequence from scratch. */
if (info->option & XT_PKNOCK_STRICT) if (info->option & XT_PKNOCK_STRICT)
remove_peer(peer); remove_peer(peer);
return false; return false;
} }
@@ -815,20 +883,25 @@ update_peer(struct peer *peer, const struct xt_pknock_mtinfo *info,
if (info->option & XT_PKNOCK_OPENSECRET ) { if (info->option & XT_PKNOCK_OPENSECRET ) {
if (hdr->proto != IPPROTO_UDP && hdr->proto != IPPROTO_UDPLITE) if (hdr->proto != IPPROTO_UDP && hdr->proto != IPPROTO_UDPLITE)
return false; return false;
if (!pass_security(peer, info, hdr->payload, hdr->payload_len)) if (!pass_security(peer, info, hdr->payload, hdr->payload_len))
return false; return false;
} }
/* Update the gc timer when there is a state change. */ /* Update the gc timer when there is a state change. */
update_rule_gc_timer(rule); update_rule_gc_timer(rule);
++peer->accepted_knock_count; ++peer->accepted_knock_count;
if (is_last_knock(peer, info)) { if (is_last_knock(peer, info)) {
peer->status = ST_ALLOWED; peer->status = ST_ALLOWED;
pk_debug("ALLOWED", peer); pk_debug("ALLOWED", peer);
peer->login_sec = get_seconds(); peer->login_sec = get_seconds();
if (nl_multicast_group > 0) if (nl_multicast_group > 0)
msg_to_userspace_nl(info, peer, nl_multicast_group); msg_to_userspace_nl(info, peer, nl_multicast_group);
return true; return true;
} }
@@ -866,6 +939,7 @@ static bool
is_close_knock(const struct peer *peer, const struct xt_pknock_mtinfo *info, is_close_knock(const struct peer *peer, const struct xt_pknock_mtinfo *info,
const unsigned char *payload, unsigned int payload_len) const unsigned char *payload, unsigned int payload_len)
{ {
#ifdef PK_CRYPTO
/* Check for CLOSE secret. */ /* Check for CLOSE secret. */
if (has_secret(info->close_secret, if (has_secret(info->close_secret,
info->close_secret_len, peer->ip, info->close_secret_len, peer->ip,
@@ -874,6 +948,7 @@ is_close_knock(const struct peer *peer, const struct xt_pknock_mtinfo *info,
pk_debug("BLOCKED", peer); pk_debug("BLOCKED", peer);
return true; return true;
} }
#endif
return false; return false;
} }
@@ -905,10 +980,17 @@ static bool pknock_mt(const struct sk_buff *skb,
switch (hdr.proto) { switch (hdr.proto) {
case IPPROTO_TCP: case IPPROTO_TCP:
break; break;
case IPPROTO_UDP: case IPPROTO_UDP:
case IPPROTO_UDPLITE: case IPPROTO_UDPLITE:
#ifdef PK_CRYPTO
hdr_len = (iph->ihl * 4) + sizeof(struct udphdr); hdr_len = (iph->ihl * 4) + sizeof(struct udphdr);
break; break;
#else
pr_debug("UDP protocol not supported\n");
return false;
#endif
default: default:
pr_debug("IP payload protocol is neither tcp nor udp.\n"); pr_debug("IP payload protocol is neither tcp nor udp.\n");
return false; return false;
@@ -926,10 +1008,12 @@ static bool pknock_mt(const struct sk_buff *skb,
/* Gives the peer matching status added to rule depending on ip src. */ /* Gives the peer matching status added to rule depending on ip src. */
peer = get_peer(rule, iph->saddr); peer = get_peer(rule, iph->saddr);
if (info->option & XT_PKNOCK_CHECKIP) { if (info->option & XT_PKNOCK_CHECKIP) {
ret = is_allowed(peer); ret = is_allowed(peer);
goto out; goto out;
} }
if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_UDPLITE) { if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_UDPLITE) {
hdr.payload = (void *)iph + hdr_len; hdr.payload = (void *)iph + hdr_len;
hdr.payload_len = skb->len - hdr_len; hdr.payload_len = skb->len - hdr_len;
@@ -937,8 +1021,7 @@ static bool pknock_mt(const struct sk_buff *skb,
/* Sets, updates, removes or checks the peer matching status. */ /* Sets, updates, removes or checks the peer matching status. */
if (info->option & XT_PKNOCK_KNOCKPORT) { if (info->option & XT_PKNOCK_KNOCKPORT) {
ret = is_allowed(peer); if ((ret = is_allowed(peer))) {
if (ret != 0) {
if (info->option & XT_PKNOCK_CLOSESECRET && if (info->option & XT_PKNOCK_CLOSESECRET &&
(iph->protocol == IPPROTO_UDP || (iph->protocol == IPPROTO_UDP ||
iph->protocol == IPPROTO_UDPLITE)) iph->protocol == IPPROTO_UDPLITE))
@@ -956,8 +1039,10 @@ static bool pknock_mt(const struct sk_buff *skb,
peer = new_peer(iph->saddr, iph->protocol); peer = new_peer(iph->saddr, iph->protocol);
add_peer(peer, rule); add_peer(peer, rule);
} }
if (peer == NULL) if (peer == NULL)
goto out; goto out;
update_peer(peer, info, rule, &hdr); update_peer(peer, info, rule, &hdr);
} }
@@ -977,7 +1062,7 @@ out:
return ret; return ret;
} }
#define RETURN_ERR(err) do { pr_err(err); return -EINVAL; } while (false) #define RETURN_ERR(err) do { printk(KERN_ERR PKNOCK err); return -EINVAL; } while (false)
static int pknock_mt_check(const struct xt_mtchk_param *par) static int pknock_mt_check(const struct xt_mtchk_param *par)
{ {
@@ -994,6 +1079,12 @@ static int pknock_mt_check(const struct xt_mtchk_param *par)
if (!(info->option & XT_PKNOCK_NAME)) if (!(info->option & XT_PKNOCK_NAME))
RETURN_ERR("You must specify --name option.\n"); RETURN_ERR("You must specify --name option.\n");
#ifndef PK_CRYPTO
if (info->option & (XT_PKNOCK_OPENSECRET | XT_PKNOCK_CLOSESECRET))
RETURN_ERR("No crypto support available; "
"cannot use opensecret/closescret\n");
#endif
if (info->option & XT_PKNOCK_OPENSECRET && info->ports_count != 1) if (info->option & XT_PKNOCK_OPENSECRET && info->ports_count != 1)
RETURN_ERR("--opensecret must have just one knock port\n"); RETURN_ERR("--opensecret must have just one knock port\n");
if (info->option & XT_PKNOCK_KNOCKPORT) { if (info->option & XT_PKNOCK_KNOCKPORT) {
@@ -1027,9 +1118,11 @@ static int pknock_mt_check(const struct xt_mtchk_param *par)
memcmp(info->open_secret, info->close_secret, memcmp(info->open_secret, info->close_secret,
info->open_secret_len) == 0) info->open_secret_len) == 0)
RETURN_ERR("opensecret & closesecret cannot be equal.\n"); RETURN_ERR("opensecret & closesecret cannot be equal.\n");
if (!add_rule(info)) if (!add_rule(info))
/* should ENOMEM here */ /* should ENOMEM here */
RETURN_ERR("add_rule() error in checkentry() function.\n"); RETURN_ERR("add_rule() error in checkentry() function.\n");
return 0; return 0;
} }
@@ -1053,7 +1146,7 @@ static struct xt_match xt_pknock_mt_reg __read_mostly = {
static int __init xt_pknock_mt_init(void) static int __init xt_pknock_mt_init(void)
{ {
#if !IS_ENABLED(CONFIG_CONNECTOR) #if !defined(CONFIG_CONNECTOR) && !defined(CONFIG_CONNECTOR_MODULE)
if (nl_multicast_group != -1) if (nl_multicast_group != -1)
pr_info("CONFIG_CONNECTOR not present; " pr_info("CONFIG_CONNECTOR not present; "
"netlink messages disabled\n"); "netlink messages disabled\n");
@@ -1061,25 +1154,30 @@ static int __init xt_pknock_mt_init(void)
if (gc_expir_time < DEFAULT_GC_EXPIRATION_TIME) if (gc_expir_time < DEFAULT_GC_EXPIRATION_TIME)
gc_expir_time = DEFAULT_GC_EXPIRATION_TIME; gc_expir_time = DEFAULT_GC_EXPIRATION_TIME;
#ifdef PK_CRYPTO
if (request_module(crypto.algo) < 0) { if (request_module(crypto.algo) < 0) {
pr_err("request_module('%s') error.\n", printk(KERN_ERR PKNOCK "request_module('%s') error.\n",
crypto.algo); crypto.algo);
return -ENXIO; return -ENXIO;
} }
crypto.tfm = crypto_alloc_shash(crypto.algo, 0, 0); crypto.tfm = crypto_alloc_hash(crypto.algo, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(crypto.tfm)) { if (IS_ERR(crypto.tfm)) {
pr_err("failed to load transform for %s\n", printk(KERN_ERR PKNOCK "failed to load transform for %s\n",
crypto.algo); crypto.algo);
return PTR_ERR(crypto.tfm); return PTR_ERR(crypto.tfm);
} }
crypto.size = crypto_shash_digestsize(crypto.tfm); crypto.size = crypto_hash_digestsize(crypto.tfm);
crypto.desc.tfm = crypto.tfm; crypto.desc.tfm = crypto.tfm;
crypto.desc.flags = 0;
#else
pr_info("No crypto support for < 2.6.19\n");
#endif
pde = proc_mkdir("xt_pknock", init_net.proc_net); pde = proc_mkdir("xt_pknock", init_net__proc_net);
if (pde == NULL) { if (pde == NULL) {
pr_err("proc_mkdir() error in _init().\n"); printk(KERN_ERR PKNOCK "proc_mkdir() error in _init().\n");
return -ENXIO; return -ENXIO;
} }
return xt_register_match(&xt_pknock_mt_reg); return xt_register_match(&xt_pknock_mt_reg);
@@ -1087,11 +1185,14 @@ static int __init xt_pknock_mt_init(void)
static void __exit xt_pknock_mt_exit(void) static void __exit xt_pknock_mt_exit(void)
{ {
remove_proc_entry("xt_pknock", init_net.proc_net); remove_proc_entry("xt_pknock", init_net__proc_net);
xt_unregister_match(&xt_pknock_mt_reg); xt_unregister_match(&xt_pknock_mt_reg);
kfree(rule_hashtable); kfree(rule_hashtable);
#ifdef PK_CRYPTO
if (crypto.tfm != NULL) if (crypto.tfm != NULL)
crypto_free_shash(crypto.tfm); crypto_free_hash(crypto.tfm);
#endif
} }
module_init(xt_pknock_mt_init); module_init(xt_pknock_mt_init);

View File

@@ -29,6 +29,8 @@ enum {
XT_PKNOCK_MAX_PASSWD_LEN = 31, XT_PKNOCK_MAX_PASSWD_LEN = 31,
}; };
#define DEBUG 1
struct xt_pknock_mtinfo { struct xt_pknock_mtinfo {
char rule_name[XT_PKNOCK_MAX_BUF_LEN+1]; char rule_name[XT_PKNOCK_MAX_BUF_LEN+1];
uint32_t rule_name_len; uint32_t rule_name_len;

View File

@@ -54,11 +54,33 @@ xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par)
const int fragoff = ntohs(iph->frag_off) & IP_OFFSET; const int fragoff = ntohs(iph->frag_off) & IP_OFFSET;
typeof(xt_tarpit) destiny; typeof(xt_tarpit) destiny;
bool ret; bool ret;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
int hotdrop = false;
#else
bool hotdrop = false; bool hotdrop = false;
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
ret = xm_tcp->match(skb, par->in, par->out, xm_tcp, &tcp_params,
fragoff, thoff, &hotdrop);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
{
struct xt_match_param local_par = {
.in = par->in,
.out = par->out,
.match = xm_tcp,
.matchinfo = &tcp_params,
.fragoff = fragoff,
.thoff = thoff,
.hotdrop = &hotdrop,
};
ret = xm_tcp->match(skb, &local_par);
}
#else
{ {
struct xt_action_param local_par; struct xt_action_param local_par;
local_par.state = par->state; local_par.in = par->in,
local_par.out = par->out,
local_par.match = xm_tcp; local_par.match = xm_tcp;
local_par.matchinfo = &tcp_params; local_par.matchinfo = &tcp_params;
local_par.fragoff = fragoff; local_par.fragoff = fragoff;
@@ -67,21 +89,45 @@ xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par)
ret = xm_tcp->match(skb, &local_par); ret = xm_tcp->match(skb, &local_par);
hotdrop = local_par.hotdrop; hotdrop = local_par.hotdrop;
} }
if (!ret || hotdrop || (unsigned int)prandom_u32() > delude_percentage) #endif
if (!ret || hotdrop || (unsigned int)net_random() > delude_percentage)
return; return;
destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude; destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
destiny->target(&skb, par->in, par->out, par->hooknum, destiny, NULL, NULL);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
destiny->target(&skb, par->in, par->out, par->hooknum, destiny, NULL);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
destiny->target(skb, par->in, par->out, par->hooknum, destiny, NULL);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
{ {
struct xt_action_param local_par; struct xt_target_param local_par = {
local_par.state = par->state; .in = par->in,
local_par.target = destiny; .out = par->out,
local_par.targinfo = par->targinfo; .hooknum = par->hooknum,
.target = destiny,
.targinfo = par->targinfo,
.family = par->family,
};
destiny->target(skb, &local_par); destiny->target(skb, &local_par);
} }
#else
{
struct xt_action_param local_par;
local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
local_par.target = destiny;
local_par.targinfo = par->targinfo;
local_par.family = par->family;
destiny->target(skb, &local_par);
}
#endif
} }
static unsigned int static unsigned int
chaos_tg(struct sk_buff *skb, const struct xt_action_param *par) chaos_tg(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
/* /*
* Equivalent to: * Equivalent to:
@@ -92,19 +138,43 @@ chaos_tg(struct sk_buff *skb, const struct xt_action_param *par)
* -A chaos -j DROP; * -A chaos -j DROP;
*/ */
const struct xt_chaos_tginfo *info = par->targinfo; const struct xt_chaos_tginfo *info = par->targinfo;
struct sk_buff *skb = *pskb;
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
if ((unsigned int)prandom_u32() <= reject_percentage) { if ((unsigned int)net_random() <= reject_percentage) {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
return xt_reject->target(pskb, par->in, par->out, par->hooknum,
xt_reject, &reject_params, NULL);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return xt_reject->target(pskb, par->in, par->out, par->hooknum,
xt_reject, &reject_params);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
return xt_reject->target(skb, par->in, par->out, par->hooknum,
xt_reject, &reject_params);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
struct xt_target_param local_par = {
.in = par->in,
.out = par->out,
.hooknum = par->hooknum,
.target = xt_reject,
.targinfo = &reject_params,
};
return xt_reject->target(skb, &local_par);
#else
struct xt_action_param local_par; struct xt_action_param local_par;
local_par.state = par->state; local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
local_par.target = xt_reject; local_par.target = xt_reject;
local_par.targinfo = &reject_params; local_par.targinfo = &reject_params;
return xt_reject->target(skb, &local_par); return xt_reject->target(skb, &local_par);
#endif
} }
/* TARPIT/DELUDE may not be called from the OUTPUT chain */ /* TARPIT/DELUDE may not be called from the OUTPUT chain */
if (iph->protocol == IPPROTO_TCP && info->variant != XTCHAOS_NORMAL && if (iph->protocol == IPPROTO_TCP &&
par->state->hook != NF_INET_LOCAL_OUT) info->variant != XTCHAOS_NORMAL &&
par->hooknum != NF_INET_LOCAL_OUT)
xt_chaos_total(skb, par); xt_chaos_total(skb, par);
return NF_DROP; return NF_DROP;
@@ -171,8 +241,7 @@ static int __init chaos_tg_init(void)
printk(KERN_WARNING PFX "Warning: Could not find or load " printk(KERN_WARNING PFX "Warning: Could not find or load "
"\"DELUDE\" target\n"); "\"DELUDE\" target\n");
ret = xt_register_target(&chaos_tg_reg); if ((ret = xt_register_target(&chaos_tg_reg)) != 0) {
if (ret != 0) {
printk(KERN_WARNING PFX "xt_register_target returned " printk(KERN_WARNING PFX "xt_register_target returned "
"error %d\n", ret); "error %d\n", ret);
goto out3; goto out3;

80
extensions/xt_CHECKSUM.c Normal file
View File

@@ -0,0 +1,80 @@
/*
* (C) 2002 by Harald Welte <laforge@netfilter.org>
* (C) 2010 Red Hat, Inc.
*
* Author: Michael S. Tsirkin <mst@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
# error ----------------------------------------------------------
# error This module has been merged into, and is available in the
# error mainline since Linux kernel v2.6.36. Please use that.
# error ----------------------------------------------------------
#endif
#include <linux/netfilter/x_tables.h>
#include "xt_CHECKSUM.h"
#include "compat_xtables.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael S. Tsirkin <mst@redhat.com>");
MODULE_DESCRIPTION("Xtables: checksum modification");
MODULE_ALIAS("ipt_CHECKSUM");
MODULE_ALIAS("ip6t_CHECKSUM");
static unsigned int
checksum_tg(struct sk_buff **pskb, const struct xt_action_param *par)
{
struct sk_buff *skb = *pskb;
if (skb->ip_summed == CHECKSUM_PARTIAL)
skb_checksum_help(skb);
return XT_CONTINUE;
}
static int checksum_tg_check(const struct xt_tgchk_param *par)
{
const struct xt_CHECKSUM_info *einfo = par->targinfo;
if (einfo->operation & ~XT_CHECKSUM_OP_FILL) {
pr_info("unsupported CHECKSUM operation %x\n", einfo->operation);
return -EINVAL;
}
if (!einfo->operation) {
pr_info("no CHECKSUM operation enabled\n");
return -EINVAL;
}
return 0;
}
static struct xt_target checksum_tg_reg __read_mostly = {
.name = "CHECKSUM",
.family = NFPROTO_UNSPEC,
.target = checksum_tg,
.targetsize = sizeof(struct xt_CHECKSUM_info),
.table = "mangle",
.checkentry = checksum_tg_check,
.me = THIS_MODULE,
};
static int __init checksum_tg_init(void)
{
return xt_register_target(&checksum_tg_reg);
}
static void __exit checksum_tg_exit(void)
{
xt_unregister_target(&checksum_tg_reg);
}
module_init(checksum_tg_init);
module_exit(checksum_tg_exit);

18
extensions/xt_CHECKSUM.h Normal file
View File

@@ -0,0 +1,18 @@
/* Header file for iptables ipt_CHECKSUM target
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 Red Hat Inc
* Author: Michael S. Tsirkin <mst@redhat.com>
*
* This software is distributed under GNU GPL v2, 1991
*/
#ifndef _IPT_CHECKSUM_TARGET_H
#define _IPT_CHECKSUM_TARGET_H
#define XT_CHECKSUM_OP_FILL 0x01 /* fill in checksum in IP header */
struct xt_CHECKSUM_info {
__u8 operation; /* bitset of operations */
};
#endif /* _IPT_CHECKSUM_TARGET_H */

View File

@@ -25,8 +25,7 @@
#include "compat_xtables.h" #include "compat_xtables.h"
#define PFX KBUILD_MODNAME ": " #define PFX KBUILD_MODNAME ": "
static void delude_send_reset(struct sk_buff *oldskb, static void delude_send_reset(struct sk_buff *oldskb, unsigned int hook)
const struct xt_action_param *par)
{ {
struct tcphdr _otcph, *tcph; struct tcphdr _otcph, *tcph;
const struct tcphdr *oth; const struct tcphdr *oth;
@@ -51,8 +50,7 @@ static void delude_send_reset(struct sk_buff *oldskb,
return; return;
/* Check checksum */ /* Check checksum */
if (nf_ip_checksum(oldskb, par->state->hook, ip_hdrlen(oldskb), if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
IPPROTO_TCP))
return; return;
nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
@@ -80,7 +78,7 @@ static void delude_send_reset(struct sk_buff *oldskb,
tcph->doff = sizeof(struct tcphdr) / 4; tcph->doff = sizeof(struct tcphdr) / 4;
/* DELUDE essential part */ /* DELUDE essential part */
if (oth->syn && !oth->ack && !oth->fin) { if (oth->syn && !oth->ack && !oth->rst && !oth->fin) {
tcph->syn = true; tcph->syn = true;
tcph->seq = 0; tcph->seq = 0;
tcph->ack = true; tcph->ack = true;
@@ -102,28 +100,29 @@ static void delude_send_reset(struct sk_buff *oldskb,
} }
} }
#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, tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
niph->daddr, csum_partial((char *)tcph, niph->daddr, csum_partial((char *)tcph,
sizeof(struct tcphdr), 0)); sizeof(struct tcphdr), 0));
#endif
addr_type = RTN_UNSPEC; addr_type = RTN_UNSPEC;
#ifdef CONFIG_BRIDGE_NETFILTER #ifdef CONFIG_BRIDGE_NETFILTER
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
if (par->state->hook != NF_INET_FORWARD || nskb->nf_bridge->mask & BRNF_BRIDGED))
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF) != NULL &&
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF))->physoutdev))
#else #else
if (par->state->hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL && if (hook != NF_INET_FORWARD)
nskb->nf_bridge->physoutdev))
#endif
#else
if (par->state->hook != NF_INET_FORWARD)
#endif #endif
addr_type = RTN_LOCAL; addr_type = RTN_LOCAL;
/* ip_route_me_harder expects skb->dst to be set */ /* ip_route_me_harder expects skb->dst to be set */
skb_dst_set(nskb, dst_clone(skb_dst(oldskb))); skb_dst_set(nskb, dst_clone(skb_dst(oldskb)));
if (ip_route_me_harder(par_net(par), par->state->sk, nskb, addr_type))
if (ip_route_me_harder(&nskb, addr_type))
goto free_nskb; goto free_nskb;
else else
niph = ip_hdr(nskb); niph = ip_hdr(nskb);
@@ -136,7 +135,8 @@ static void delude_send_reset(struct sk_buff *oldskb,
goto free_nskb; goto free_nskb;
nf_ct_attach(nskb, oldskb); nf_ct_attach(nskb, oldskb);
ip_local_out(par_net(par), nskb->sk, nskb);
ip_local_out(nskb);
return; return;
free_nskb: free_nskb:
@@ -144,14 +144,12 @@ static void delude_send_reset(struct sk_buff *oldskb,
} }
static unsigned int static unsigned int
delude_tg(struct sk_buff *skb, const struct xt_action_param *par) delude_tg(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
/* /* WARNING: This code causes reentry within iptables.
* Sending the reset causes reentrancy within iptables - and should not pose This means that the iptables jump stack is now crap. We
* a problem, as that is supported since Linux 2.6.35. But since we do not must return an absolute verdict. --RR */
* actually want to have a connection open, we are still going to drop it. delude_send_reset(*pskb, par->hooknum);
*/
delude_send_reset(skb, par);
return NF_DROP; return NF_DROP;
} }

View File

@@ -34,9 +34,9 @@ static void ether_set(unsigned char *addr, const unsigned char *op,
unsigned int i; unsigned int i;
for (i = 0; i < ETH_ALEN && mask > 0; ++i) { for (i = 0; i < ETH_ALEN && mask > 0; ++i) {
lo_mask = (mask >= 8) ? 8 : mask; lo_mask = mask % 8;
/* FF << 4 >> 4 = 0F */ /* FF << 4 >> 4 = 0F */
lo_mask = (uint8_t)(~0U << lo_mask) >> lo_mask; lo_mask = ~(uint8_t)0U << lo_mask >> lo_mask;
addr[i] &= lo_mask; addr[i] &= lo_mask;
addr[i] |= op[i] & ~lo_mask; addr[i] |= op[i] & ~lo_mask;
if (mask >= 8) if (mask >= 8)
@@ -55,9 +55,9 @@ static bool ether_cmp(const unsigned char *lh, const unsigned char *rh,
#define ZMACHEX(s) s[0], s[1], s[2], s[3], s[4], s[5] #define ZMACHEX(s) s[0], s[1], s[2], s[3], s[4], s[5]
for (i = 0; i < ETH_ALEN && mask > 0; ++i) { for (i = 0; i < ETH_ALEN && mask > 0; ++i) {
lo_mask = (mask >= 8) ? 8 : mask; lo_mask = mask % 8;
/* ~(0xFF << 4 >> 4) = ~0x0F = 0xF0 */ /* ~(0xFF << 4 >> 4) = ~0x0F = 0xF0 */
lo_mask = ~((uint8_t)(~0U << lo_mask) >> lo_mask); lo_mask = ~(~(uint8_t)0U << lo_mask >> lo_mask);
if ((lh[i] ^ rh[i]) & lo_mask) if ((lh[i] ^ rh[i]) & lo_mask)
return false; return false;
if (mask >= 8) if (mask >= 8)
@@ -89,15 +89,15 @@ dhcpmac_mt(const struct sk_buff *skb, struct xt_action_param *par)
} }
static unsigned int static unsigned int
dhcpmac_tg(struct sk_buff *skb, const struct xt_action_param *par) dhcpmac_tg(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
const struct dhcpmac_info *info = par->targinfo; const struct dhcpmac_info *info = par->targinfo;
struct dhcp_message dhcpbuf, *dh; struct dhcp_message dhcpbuf, *dh;
struct udphdr udpbuf, *udph; struct udphdr udpbuf, *udph;
struct sk_buff *skb = *pskb;
unsigned int i; unsigned int i;
if (skb_ensure_writable(skb, ip_hdrlen(skb) + sizeof(udpbuf) + if (!skb_make_writable(pskb, 0))
sizeof(dhcpbuf)))
return NF_DROP; return NF_DROP;
udph = skb_header_pointer(skb, ip_hdrlen(skb), udph = skb_header_pointer(skb, ip_hdrlen(skb),
@@ -111,12 +111,13 @@ dhcpmac_tg(struct sk_buff *skb, const struct xt_action_param *par)
return NF_DROP; return NF_DROP;
for (i = 0; i < sizeof(dh->chaddr); i += 2) for (i = 0; i < sizeof(dh->chaddr); i += 2)
csum_replace2(&udph->check, *(const __be16 *)(dh->chaddr + i), 0); csum_replace2(&udph->check, *(const __be16 *)dh->chaddr, 0);
memset(dh->chaddr, 0, sizeof(dh->chaddr));
ether_set(dh->chaddr, info->addr, info->mask); ether_set(dh->chaddr, info->addr, info->mask);
for (i = 0; i < sizeof(dh->chaddr); i += 2) for (i = 0; i < sizeof(dh->chaddr); i += 2)
csum_replace2(&udph->check, 0, *(const __be16 *)(dh->chaddr + i)); csum_replace2(&udph->check, 0, *(const __be16 *)dh->chaddr);
return XT_CONTINUE; return XT_CONTINUE;
} }

View File

@@ -19,24 +19,33 @@
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#ifdef CONFIG_NF_NAT
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uidgid.h>
#include <linux/version.h> #include <linux/version.h>
#include <net/netfilter/nf_nat_rule.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
#include <net/net_namespace.h> #include <net/net_namespace.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
# include <net/netfilter/nf_nat.h> # include <net/netfilter/nf_nat.h>
#else
# include <linux/netfilter/nf_nat.h>
#endif
#include "compat_xtables.h" #include "compat_xtables.h"
#include "xt_DNETMAP.h" #include "xt_DNETMAP.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Kierdelewicz <marek@piasta.pl>");
MODULE_DESCRIPTION(
"Xtables: dynamic two-way 1:1 NAT mapping of IPv4 addresses");
MODULE_ALIAS("ipt_DNETMAP");
static unsigned int default_ttl = 600; static unsigned int default_ttl = 600;
static unsigned int proc_perms = S_IRUGO | S_IWUSR; static unsigned int proc_perms = S_IRUGO | S_IWUSR;
static unsigned int proc_uid; static unsigned int proc_uid;
@@ -61,18 +70,25 @@ MODULE_PARM_DESC(whole_prefix,
static unsigned int jtimeout; static unsigned int jtimeout;
struct dnetmap_entry { struct dnetmap_entry {
struct list_head list, glist, grlist, lru_list; struct list_head list;
__be32 prenat_addr, postnat_addr; /* priv2entry */
struct list_head glist;
/* pub2entry */
struct list_head grlist;
struct list_head lru_list;
__be32 prenat_addr;
__be32 postnat_addr;
__u8 flags; __u8 flags;
unsigned long stamp; unsigned long stamp;
struct dnetmap_prefix *prefix; struct dnetmap_prefix *prefix;
}; };
struct dnetmap_prefix { struct dnetmap_prefix {
struct nf_nat_range prefix; struct nf_nat_ipv4_multi_range_compat prefix;
char prefix_str[20]; char prefix_str[16];
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
char proc_str_data[20], proc_str_stat[25]; char proc_str_data[20];
char proc_str_stat[25];
#endif #endif
struct list_head elist; // element list head struct list_head elist; // element list head
struct list_head list; // prefix list struct list_head list; // prefix list
@@ -93,19 +109,28 @@ struct dnetmap_net {
struct list_head *dnetmap_iphash; struct list_head *dnetmap_iphash;
}; };
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
static int dnetmap_net_id; static int dnetmap_net_id;
static inline struct dnetmap_net *dnetmap_pernet(struct net *net) static inline struct dnetmap_net *dnetmap_pernet(struct net *net)
{ {
return net_generic(net, dnetmap_net_id); return net_generic(net, dnetmap_net_id);
} }
#else
struct dnetmap_net *dnetmap;
#define dnetmap_pernet(x) dnetmap
#endif
static DEFINE_SPINLOCK(dnetmap_lock); static DEFINE_SPINLOCK(dnetmap_lock);
static DEFINE_MUTEX(dnetmap_mutex); static DEFINE_MUTEX(dnetmap_mutex);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static const struct proc_ops dnetmap_tg_fops, dnetmap_stat_proc_fops; static const struct file_operations dnetmap_tg_fops;
#endif #endif
static int dnetmap_stat_proc_read(char __user *buffer, char **start,
off_t offset, int length, int *eof,
void *data);
static inline unsigned int dnetmap_entry_hash(const __be32 addr) static inline unsigned int dnetmap_entry_hash(const __be32 addr)
{ {
return ntohl(addr) & (hash_size - 1); return ntohl(addr) & (hash_size - 1);
@@ -115,7 +140,9 @@ static struct dnetmap_entry *
dnetmap_entry_lookup(struct dnetmap_net *dnetmap_net, const __be32 addr) dnetmap_entry_lookup(struct dnetmap_net *dnetmap_net, const __be32 addr)
{ {
struct dnetmap_entry *e; struct dnetmap_entry *e;
unsigned int h = dnetmap_entry_hash(addr); unsigned int h;
h = dnetmap_entry_hash(addr);
list_for_each_entry(e, &dnetmap_net->dnetmap_iphash[h], glist) list_for_each_entry(e, &dnetmap_net->dnetmap_iphash[h], glist)
if (memcmp(&e->prenat_addr, &addr, sizeof(addr)) == 0) if (memcmp(&e->prenat_addr, &addr, sizeof(addr)) == 0)
@@ -127,7 +154,9 @@ static struct dnetmap_entry *
dnetmap_entry_rlookup(struct dnetmap_net *dnetmap_net, const __be32 addr) dnetmap_entry_rlookup(struct dnetmap_net *dnetmap_net, const __be32 addr)
{ {
struct dnetmap_entry *e; struct dnetmap_entry *e;
unsigned int h = dnetmap_entry_hash(addr); unsigned int h;
h = dnetmap_entry_hash(addr);
list_for_each_entry(e, &dnetmap_net->dnetmap_iphash[hash_size + h], list_for_each_entry(e, &dnetmap_net->dnetmap_iphash[hash_size + h],
grlist) grlist)
@@ -150,7 +179,7 @@ dnetmap_addr_in_prefix(struct dnetmap_net *dnetmap_net, const __be32 addr,
static struct dnetmap_prefix * static struct dnetmap_prefix *
dnetmap_prefix_lookup(struct dnetmap_net *dnetmap_net, dnetmap_prefix_lookup(struct dnetmap_net *dnetmap_net,
const struct nf_nat_range *mr) const struct nf_nat_ipv4_multi_range_compat *mr)
{ {
struct dnetmap_prefix *p; struct dnetmap_prefix *p;
@@ -229,7 +258,7 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
{ {
struct dnetmap_net *dnetmap_net = dnetmap_pernet(par->net); struct dnetmap_net *dnetmap_net = dnetmap_pernet(par->net);
const struct xt_DNETMAP_tginfo *tginfo = par->targinfo; const struct xt_DNETMAP_tginfo *tginfo = par->targinfo;
const struct nf_nat_range *mr = &tginfo->prefix; const struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
struct dnetmap_prefix *p; struct dnetmap_prefix *p;
struct dnetmap_entry *e; struct dnetmap_entry *e;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
@@ -245,10 +274,14 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
return ret; return ret;
} }
if (!(mr->flags & NF_NAT_RANGE_MAP_IPS)) { if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) {
pr_debug("DNETMAP:check: bad MAP_IPS.\n"); pr_debug("DNETMAP:check: bad MAP_IPS.\n");
return -EINVAL; return -EINVAL;
} }
if (mr->rangesize != 1) {
pr_debug("DNETMAP:check: bad rangesize %u.\n", mr->rangesize);
return -EINVAL;
}
mutex_lock(&dnetmap_mutex); mutex_lock(&dnetmap_mutex);
p = dnetmap_prefix_lookup(dnetmap_net, mr); p = dnetmap_prefix_lookup(dnetmap_net, mr);
@@ -274,15 +307,15 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
INIT_LIST_HEAD(&p->lru_list); INIT_LIST_HEAD(&p->lru_list);
INIT_LIST_HEAD(&p->elist); INIT_LIST_HEAD(&p->elist);
ip_min = ntohl(mr->min_addr.ip) + (whole_prefix == 0); ip_min = ntohl(mr->range[0].min_ip) + (whole_prefix == 0);
ip_max = ntohl(mr->max_addr.ip) - (whole_prefix == 0); ip_max = ntohl(mr->range[0].max_ip) - (whole_prefix == 0);
sprintf(p->prefix_str, "%pI4/%u", &mr->min_addr.ip, sprintf(p->prefix_str, NIPQUAD_FMT "/%u", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ip_min ^ ip_max))); 33 - ffs(~(ip_min ^ ip_max)));
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
sprintf(p->proc_str_data, "%pI4_%u", &mr->min_addr.ip, sprintf(p->proc_str_data, NIPQUAD_FMT "_%u", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ip_min ^ ip_max))); 33 - ffs(~(ip_min ^ ip_max)));
sprintf(p->proc_str_stat, "%pI4_%u_stat", &mr->min_addr.ip, sprintf(p->proc_str_stat, NIPQUAD_FMT "_%u_stat", NIPQUAD(mr->range[0].min_ip),
33 - ffs(~(ip_min ^ ip_max))); 33 - ffs(~(ip_min ^ ip_max)));
#endif #endif
printk(KERN_INFO KBUILD_MODNAME ": new prefix %s\n", p->prefix_str); printk(KERN_INFO KBUILD_MODNAME ": new prefix %s\n", p->prefix_str);
@@ -311,20 +344,21 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
proc_set_user(pde_data, make_kuid(&init_user_ns, proc_uid), pde_data->uid = proc_uid;
make_kgid(&init_user_ns, proc_gid)); pde_data->gid = proc_gid;
/* statistics */ /* statistics */
pde_stat = proc_create_data(p->proc_str_stat, proc_perms, pde_stat = create_proc_entry(p->proc_str_stat, proc_perms,
dnetmap_net->xt_dnetmap, dnetmap_net->xt_dnetmap);
&dnetmap_stat_proc_fops, p);
if (pde_stat == NULL) { if (pde_stat == NULL) {
kfree(p); kfree(p);
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
proc_set_user(pde_stat, make_kuid(&init_user_ns, proc_uid), pde_stat->data = p;
make_kgid(&init_user_ns, proc_gid)); pde_stat->read_proc = dnetmap_stat_proc_read;
pde_stat->uid = proc_uid;
pde_stat->gid = proc_gid;
#endif #endif
spin_lock_bh(&dnetmap_lock); spin_lock_bh(&dnetmap_lock);
@@ -338,27 +372,30 @@ out:
} }
static unsigned int static unsigned int
dnetmap_tg(struct sk_buff *skb, const struct xt_action_param *par) dnetmap_tg(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
struct net *net = dev_net(par->state->in ? par->state->in : par->state->out); struct sk_buff *skb = *pskb;
struct net *net = dev_net(par->in ? par->in : par->out);
struct dnetmap_net *dnetmap_net = dnetmap_pernet(net); struct dnetmap_net *dnetmap_net = dnetmap_pernet(net);
struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
__be32 prenat_ip, postnat_ip, prenat_ip_prev; __be32 prenat_ip, postnat_ip, prenat_ip_prev;
const struct xt_DNETMAP_tginfo *tginfo = par->targinfo; const struct xt_DNETMAP_tginfo *tginfo = par->targinfo;
const struct nf_nat_range *mr = &tginfo->prefix; const struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0) struct nf_nat_ipv4_range newrange;
struct nf_nat_range2 newrange;
#else
struct nf_nat_range newrange;
#endif
struct dnetmap_entry *e; struct dnetmap_entry *e;
struct dnetmap_prefix *p; struct dnetmap_prefix *p;
unsigned int hooknum = par->state->hook; __s32 jttl;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
__s32 jttl = tginfo->flags & XT_DNETMAP_TTL ? tginfo->ttl * HZ : jtimeout; NF_CT_ASSERT(par->hooknum == NF_INET_POST_ROUTING ||
par->hooknum == NF_INET_LOCAL_OUT ||
par->hooknum == NF_INET_PRE_ROUTING);
ct = nf_ct_get(skb, &ctinfo);
jttl = tginfo->flags & XT_DNETMAP_TTL ? tginfo->ttl * HZ : jtimeout;
/* in prerouting we try to map postnat-ip to prenat-ip */ /* in prerouting we try to map postnat-ip to prenat-ip */
if (hooknum == NF_INET_PRE_ROUTING) { if (par->hooknum == NF_INET_PRE_ROUTING) {
postnat_ip = ip_hdr(skb)->daddr; postnat_ip = ip_hdr(skb)->daddr;
spin_lock_bh(&dnetmap_lock); spin_lock_bh(&dnetmap_lock);
@@ -371,7 +408,7 @@ dnetmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
/* if prefix is specified, we check if /* if prefix is specified, we check if
it matches lookedup entry */ it matches lookedup entry */
if (tginfo->flags & XT_DNETMAP_PREFIX) if (tginfo->flags & XT_DNETMAP_PREFIX)
if (memcmp(mr, &e->prefix->prefix, sizeof(*mr))) if (memcmp(mr, &e->prefix, sizeof(*mr)))
goto no_rev_map; goto no_rev_map;
/* don't reset ttl if flag is set */ /* don't reset ttl if flag is set */
if (jttl >= 0 && (! (e->flags & XT_DNETMAP_STATIC) ) ) { if (jttl >= 0 && (! (e->flags & XT_DNETMAP_STATIC) ) ) {
@@ -382,14 +419,15 @@ dnetmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
spin_unlock_bh(&dnetmap_lock); spin_unlock_bh(&dnetmap_lock);
memset(&newrange, 0, sizeof(newrange)); newrange = ((struct nf_nat_ipv4_range) {
newrange.flags = mr->flags | NF_NAT_RANGE_MAP_IPS; mr->range[0].flags | NF_NAT_RANGE_MAP_IPS,
newrange.min_addr.ip = e->prenat_addr; e->prenat_addr, e->prenat_addr,
newrange.max_addr.ip = e->prenat_addr; mr->range[0].min, mr->range[0].max});
newrange.min_proto = mr->min_proto;
newrange.max_proto = mr->max_proto; /* Hand modified range to generic setup. */
return nf_nat_setup_info(ct, &newrange, return nf_nat_setup_info(ct, &newrange,
HOOK2MANIP(hooknum)); HOOK2MANIP(par->hooknum));
} }
prenat_ip = ip_hdr(skb)->saddr; prenat_ip = ip_hdr(skb)->saddr;
@@ -410,8 +448,8 @@ bind_new_prefix:
if (e->prenat_addr != 0 && time_before(jiffies, e->stamp)) { if (e->prenat_addr != 0 && time_before(jiffies, e->stamp)) {
if (!disable_log && ! (p->flags & XT_DNETMAP_FULL) ){ if (!disable_log && ! (p->flags & XT_DNETMAP_FULL) ){
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": ip %pI4 - no free adresses in prefix %s\n", ": ip " NIPQUAD_FMT " - no free adresses in prefix %s\n",
&prenat_ip, p->prefix_str); NIPQUAD(prenat_ip), p->prefix_str);
p->flags |= XT_DNETMAP_FULL; p->flags |= XT_DNETMAP_FULL;
} }
goto no_free_ip; goto no_free_ip;
@@ -424,8 +462,8 @@ bind_new_prefix:
prenat_ip_prev = e->prenat_addr; prenat_ip_prev = e->prenat_addr;
if (!disable_log) if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": timeout binding %pI4 -> %pI4\n", ": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
&prenat_ip_prev, &postnat_ip); NIPQUAD(prenat_ip_prev), NIPQUAD(postnat_ip) );
list_del(&e->glist); list_del(&e->glist);
list_del(&e->grlist); list_del(&e->grlist);
} }
@@ -442,16 +480,18 @@ bind_new_prefix:
(postnat_ip)]); (postnat_ip)]);
if (!disable_log) if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": add binding %pI4 -> %pI4\n", ": add binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
&prenat_ip, &postnat_ip); NIPQUAD(prenat_ip),NIPQUAD(postnat_ip));
} else { } else {
if (!(tginfo->flags & XT_DNETMAP_REUSE) && !(e->flags & XT_DNETMAP_STATIC)) if (!(tginfo->flags & XT_DNETMAP_REUSE) && !(e->flags & XT_DNETMAP_STATIC))
if (time_before(e->stamp, jiffies) && p != e->prefix) { if (time_before(e->stamp, jiffies) && p != e->prefix) {
if (!disable_log) if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": timeout binding %pI4 -> %pI4\n", ": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
&e->prenat_addr, &e->postnat_addr); NIPQUAD(e->prenat_addr),
NIPQUAD(e->postnat_addr));
list_del(&e->glist); list_del(&e->glist);
list_del(&e->grlist); list_del(&e->grlist);
e->prenat_addr = 0; e->prenat_addr = 0;
@@ -469,13 +509,14 @@ bind_new_prefix:
spin_unlock_bh(&dnetmap_lock); spin_unlock_bh(&dnetmap_lock);
memset(&newrange, 0, sizeof(newrange)); newrange = ((struct nf_nat_ipv4_range) {
newrange.flags = mr->flags | NF_NAT_RANGE_MAP_IPS; mr->range[0].flags | NF_NAT_RANGE_MAP_IPS,
newrange.min_addr.ip = postnat_ip; postnat_ip, postnat_ip,
newrange.max_addr.ip = postnat_ip; mr->range[0].min, mr->range[0].max});
newrange.min_proto = mr->min_proto;
newrange.max_proto = mr->max_proto; /* Hand modified range to generic setup. */
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->state->hook)); return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
no_rev_map: no_rev_map:
no_free_ip: no_free_ip:
spin_unlock_bh(&dnetmap_lock); spin_unlock_bh(&dnetmap_lock);
@@ -487,7 +528,7 @@ static void dnetmap_tg_destroy(const struct xt_tgdtor_param *par)
{ {
struct dnetmap_net *dnetmap_net = dnetmap_pernet(par->net); struct dnetmap_net *dnetmap_net = dnetmap_pernet(par->net);
const struct xt_DNETMAP_tginfo *tginfo = par->targinfo; const struct xt_DNETMAP_tginfo *tginfo = par->targinfo;
const struct nf_nat_range *mr = &tginfo->prefix; const struct nf_nat_ipv4_multi_range_compat *mr = &tginfo->prefix;
struct dnetmap_prefix *p; struct dnetmap_prefix *p;
if (!(tginfo->flags & XT_DNETMAP_PREFIX)) if (!(tginfo->flags & XT_DNETMAP_PREFIX))
@@ -550,13 +591,12 @@ static int dnetmap_seq_show(struct seq_file *seq, void *v)
const struct dnetmap_entry *e = v; const struct dnetmap_entry *e = v;
if((e->flags & XT_DNETMAP_STATIC) == 0){ if((e->flags & XT_DNETMAP_STATIC) == 0){
seq_printf(seq, "%pI4 -> %pI4 --- ttl: %d lasthit: %lu\n", seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: %d lasthit: %lu\n",
&e->prenat_addr, &e->postnat_addr, NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr),
(int)(e->stamp - jiffies) / HZ, (int)(e->stamp - jiffies) / HZ, (e->stamp - jtimeout) / HZ);
(e->stamp - jtimeout) / HZ);
}else{ }else{
seq_printf(seq, "%pI4 -> %pI4 --- ttl: S lasthit: S\n", seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: S lasthit: S\n",
&e->prenat_addr, &e->postnat_addr); NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr));
} }
return 0; return 0;
} }
@@ -570,24 +610,27 @@ static const struct seq_operations dnetmap_seq_ops = {
static int dnetmap_seq_open(struct inode *inode, struct file *file) static int dnetmap_seq_open(struct inode *inode, struct file *file)
{ {
struct proc_dir_entry *pde = PDE(inode);
struct dnetmap_iter_state *st; struct dnetmap_iter_state *st;
st = __seq_open_private(file, &dnetmap_seq_ops, sizeof(*st)); st = __seq_open_private(file, &dnetmap_seq_ops, sizeof(*st));
if (st == NULL) if (st == NULL)
return -ENOMEM; return -ENOMEM;
st->p = PDE_DATA(inode); st->p = pde->data;
return 0; return 0;
} }
static ssize_t static ssize_t
dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, loff_t *loff) dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, loff_t *loff)
{ {
struct dnetmap_prefix *p = PDE_DATA(file_inode(file)); const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
struct dnetmap_prefix *p = pde->data;
struct dnetmap_entry *e; struct dnetmap_entry *e;
char buf[sizeof("+192.168.100.100:200.200.200.200")]; char buf[sizeof("+192.168.100.100:200.200.200.200")];
const char *c = buf; const char *c = buf;
const char *c2; const char *c2;
//union nf_inet_addr addr = {};
__be32 addr1,addr2; __be32 addr1,addr2;
bool add; bool add;
char str[25]; char str[25];
@@ -678,8 +721,8 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
if(e != NULL){ if(e != NULL){
if (!disable_log) if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": timeout binding %pI4 -> %pI4\n", ": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
&e->prenat_addr, &e->postnat_addr); NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) );
list_del(&e->glist); list_del(&e->glist);
list_del(&e->grlist); list_del(&e->grlist);
}else{ }else{
@@ -701,7 +744,7 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
(e->postnat_addr)]); (e->postnat_addr)]);
list_del(&e->lru_list); list_del(&e->lru_list);
sprintf(str, "%pI4:%pI4", &addr1, &addr2); sprintf(str, NIPQUAD_FMT ":" NIPQUAD_FMT, NIPQUAD(addr1),NIPQUAD(addr2));
printk(KERN_INFO KBUILD_MODNAME ": adding static binding %s\n", str); printk(KERN_INFO KBUILD_MODNAME ": adding static binding %s\n", str);
// case of removing binding // case of removing binding
@@ -717,8 +760,8 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
if(e != NULL){ if(e != NULL){
if (!disable_log) if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": remove binding %pI4 -> %pI4\n", ": remove binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
&e->prenat_addr, &e->postnat_addr); NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) );
list_del(&e->glist); list_del(&e->glist);
list_del(&e->grlist); list_del(&e->grlist);
if(e->flags & XT_DNETMAP_STATIC){ if(e->flags & XT_DNETMAP_STATIC){
@@ -748,17 +791,20 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
} }
static const struct proc_ops dnetmap_tg_fops = { static const struct file_operations dnetmap_tg_fops = {
.proc_open = dnetmap_seq_open, .open = dnetmap_seq_open,
.proc_read = seq_read, .read = seq_read,
.proc_write = dnetmap_tg_proc_write, .write = dnetmap_tg_proc_write,
.proc_release = seq_release_private, .release = seq_release_private,
.owner = THIS_MODULE,
}; };
/* for statistics */ /* for statistics */
static int dnetmap_stat_proc_show(struct seq_file *m, void *data) static int dnetmap_stat_proc_read(char __user *buffer, char **start,
off_t offset, int length, int *eof,
void *data)
{ {
const struct dnetmap_prefix *p = m->private; const struct dnetmap_prefix *p = data;
struct dnetmap_entry *e; struct dnetmap_entry *e;
unsigned int used, used_static, all; unsigned int used, used_static, all;
long int ttl, sum_ttl; long int ttl, sum_ttl;
@@ -784,25 +830,16 @@ static int dnetmap_stat_proc_show(struct seq_file *m, void *data)
} }
sum_ttl = used > 0 ? sum_ttl / (used * HZ) : 0; sum_ttl = used > 0 ? sum_ttl / (used * HZ) : 0;
seq_printf(m, "%u %u %u %ld %s\n", used, used_static, all, sum_ttl,(p->flags & XT_DNETMAP_PERSISTENT ? "persistent" : "")); sprintf(buffer, "%u %u %u %ld %s\n", used, used_static, all, sum_ttl,(p->flags & XT_DNETMAP_PERSISTENT ? "persistent" : ""));
if (length >= strlen(buffer))
*eof = true;
spin_unlock_bh(&dnetmap_lock); spin_unlock_bh(&dnetmap_lock);
return 0; return strlen(buffer);
} }
static int dnetmap_stat_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, dnetmap_stat_proc_show, PDE_DATA(inode));
}
static const struct proc_ops dnetmap_stat_proc_fops = {
.proc_open = dnetmap_stat_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __net_init dnetmap_proc_net_init(struct net *net) static int __net_init dnetmap_proc_net_init(struct net *net)
{ {
struct dnetmap_net *dnetmap_net = dnetmap_pernet(net); struct dnetmap_net *dnetmap_net = dnetmap_pernet(net);
@@ -815,7 +852,7 @@ static int __net_init dnetmap_proc_net_init(struct net *net)
static void __net_exit dnetmap_proc_net_exit(struct net *net) static void __net_exit dnetmap_proc_net_exit(struct net *net)
{ {
remove_proc_entry("xt_DNETMAP", net->proc_net); proc_net_remove(net, "xt_DNETMAP");
} }
#else #else
@@ -834,6 +871,13 @@ static int __net_init dnetmap_net_init(struct net *net)
struct dnetmap_net *dnetmap_net = dnetmap_pernet(net); struct dnetmap_net *dnetmap_net = dnetmap_pernet(net);
int i; int i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
dnetmap = kmalloc(sizeof(struct dnetmap_net),GFP_ATOMIC);
if (dnetmap == NULL)
return -ENOMEM;
dnetmap_net = dnetmap;
#endif
dnetmap_net->dnetmap_iphash = kmalloc(sizeof(struct list_head) * dnetmap_net->dnetmap_iphash = kmalloc(sizeof(struct list_head) *
hash_size * 2, GFP_ATOMIC); hash_size * 2, GFP_ATOMIC);
if (dnetmap_net->dnetmap_iphash == NULL) if (dnetmap_net->dnetmap_iphash == NULL)
@@ -862,15 +906,20 @@ static void __net_exit dnetmap_net_exit(struct net *net)
mutex_unlock(&dnetmap_mutex); mutex_unlock(&dnetmap_mutex);
kfree(dnetmap_net->dnetmap_iphash); kfree(dnetmap_net->dnetmap_iphash);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
kfree(dnetmap_net); kfree(dnetmap_net);
#endif
dnetmap_proc_net_exit(net); dnetmap_proc_net_exit(net);
} }
static struct pernet_operations dnetmap_net_ops = { static struct pernet_operations dnetmap_net_ops = {
.init = dnetmap_net_init, .init = dnetmap_net_init,
.exit = dnetmap_net_exit, .exit = dnetmap_net_exit,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
.id = &dnetmap_net_id, .id = &dnetmap_net_id,
.size = sizeof(struct dnetmap_net), .size = sizeof(struct dnetmap_net),
#endif
}; };
static struct xt_target dnetmap_tg_reg __read_mostly = { static struct xt_target dnetmap_tg_reg __read_mostly = {
@@ -916,18 +965,6 @@ static void __exit dnetmap_tg_exit(void)
xt_unregister_target(&dnetmap_tg_reg); xt_unregister_target(&dnetmap_tg_reg);
unregister_pernet_subsys(&dnetmap_net_ops); unregister_pernet_subsys(&dnetmap_net_ops);
} }
#else /* CONFIG_NF_NAT */
static int __init dnetmap_tg_init(void)
{
pr_err("CONFIG_NF_NAT is not available in your kernel, hence this module cannot function.");
return -EINVAL;
}
static void __exit dnetmap_tg_exit(void) {}
#endif
module_init(dnetmap_tg_init); module_init(dnetmap_tg_init);
module_exit(dnetmap_tg_exit); module_exit(dnetmap_tg_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Kierdelewicz <marek@piasta.pl>");
MODULE_DESCRIPTION("Xtables: dynamic two-way 1:1 NAT mapping of IPv4 addresses");
MODULE_ALIAS("ipt_DNETMAP");

View File

@@ -13,7 +13,7 @@ enum {
}; };
struct xt_DNETMAP_tginfo { struct xt_DNETMAP_tginfo {
struct nf_nat_range prefix; struct nf_nat_ipv4_multi_range_compat prefix;
__u8 flags; __u8 flags;
__s32 ttl; __s32 ttl;
}; };

View File

@@ -24,8 +24,9 @@
#include "compat_xtables.h" #include "compat_xtables.h"
static unsigned int static unsigned int
echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par) echo_tg6(struct sk_buff **poldskb, const struct xt_action_param *par)
{ {
const struct sk_buff *oldskb = *poldskb;
const struct udphdr *oldudp; const struct udphdr *oldudp;
const struct ipv6hdr *oldip; const struct ipv6hdr *oldip;
struct udphdr *newudp, oldudp_buf; struct udphdr *newudp, oldudp_buf;
@@ -35,10 +36,10 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
void *payload; void *payload;
struct flowi6 fl; struct flowi6 fl;
struct dst_entry *dst = NULL; struct dst_entry *dst = NULL;
struct net *net = dev_net((par->state->in != NULL) ? par->state->in : par->state->out); struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
/* This allows us to do the copy operation in fewer lines of code. */ /* This allows us to do the copy operation in fewer lines of code. */
if (skb_linearize(oldskb) < 0) if (skb_linearize(*poldskb) < 0)
return NF_DROP; return NF_DROP;
oldip = ipv6_hdr(oldskb); oldip = ipv6_hdr(oldskb);
@@ -76,7 +77,6 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
payload = skb_header_pointer(oldskb, par->thoff + payload = skb_header_pointer(oldskb, par->thoff +
sizeof(*oldudp), data_len, NULL); sizeof(*oldudp), data_len, NULL);
memcpy(skb_put(newskb, data_len), payload, data_len); memcpy(skb_put(newskb, data_len), payload, data_len);
newip->payload_len = htons(newskb->len);
#if 0 #if 0
/* /*
@@ -105,15 +105,19 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
} }
skb_dst_set(newskb, dst); skb_dst_set(newskb, dst);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
newip->hop_limit = ip6_dst_hoplimit(skb_dst(newskb)); newip->hop_limit = ip6_dst_hoplimit(skb_dst(newskb));
#else
newip->hop_limit = dst_metric(skb_dst(newskb), RTAX_HOPLIMIT);
#endif
newskb->ip_summed = CHECKSUM_NONE; newskb->ip_summed = CHECKSUM_NONE;
/* "Never happens" (?) */ /* "Never happens" (?) */
if (newskb->len > dst_mtu(skb_dst(newskb))) if (newskb->len > dst_mtu(skb_dst(newskb)))
goto free_nskb; goto free_nskb;
nf_ct_attach(newskb, oldskb); nf_ct_attach(newskb, *poldskb);
ip6_local_out(par_net(par), par->state->sk, newskb); ip6_local_out(newskb);
return NF_DROP; return NF_DROP;
free_nskb: free_nskb:
@@ -122,8 +126,9 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
} }
static unsigned int static unsigned int
echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par) echo_tg4(struct sk_buff **poldskb, const struct xt_action_param *par)
{ {
const struct sk_buff *oldskb = *poldskb;
const struct udphdr *oldudp; const struct udphdr *oldudp;
const struct iphdr *oldip; const struct iphdr *oldip;
struct udphdr *newudp, oldudp_buf; struct udphdr *newudp, oldudp_buf;
@@ -133,7 +138,7 @@ echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par)
void *payload; void *payload;
/* This allows us to do the copy operation in fewer lines of code. */ /* This allows us to do the copy operation in fewer lines of code. */
if (skb_linearize(oldskb) < 0) if (skb_linearize(*poldskb) < 0)
return NF_DROP; return NF_DROP;
oldip = ip_hdr(oldskb); oldip = ip_hdr(oldskb);
@@ -157,8 +162,8 @@ echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par)
newip->version = oldip->version; newip->version = oldip->version;
newip->ihl = sizeof(*newip) / 4; newip->ihl = sizeof(*newip) / 4;
newip->tos = oldip->tos; newip->tos = oldip->tos;
newip->id = oldip->id; newip->id = 0;
newip->frag_off = 0; newip->frag_off = htons(IP_DF);
newip->protocol = oldip->protocol; newip->protocol = oldip->protocol;
newip->check = 0; newip->check = 0;
newip->saddr = oldip->daddr; newip->saddr = oldip->daddr;
@@ -174,7 +179,6 @@ echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par)
payload = skb_header_pointer(oldskb, par->thoff + payload = skb_header_pointer(oldskb, par->thoff +
sizeof(*oldudp), data_len, NULL); sizeof(*oldudp), data_len, NULL);
memcpy(skb_put(newskb, data_len), payload, data_len); memcpy(skb_put(newskb, data_len), payload, data_len);
newip->tot_len = htons(newskb->len);
#if 0 #if 0
/* /*
@@ -191,19 +195,23 @@ echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par)
/* ip_route_me_harder expects the skb's dst to be set */ /* ip_route_me_harder expects the skb's dst to be set */
skb_dst_set(newskb, dst_clone(skb_dst(oldskb))); skb_dst_set(newskb, dst_clone(skb_dst(oldskb)));
if (ip_route_me_harder(par_net(par), par->state->sk, newskb,
RTN_UNSPEC) != 0) if (ip_route_me_harder(&newskb, RTN_UNSPEC) != 0)
goto free_nskb; goto free_nskb;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
newip->ttl = ip4_dst_hoplimit(skb_dst(newskb)); newip->ttl = ip4_dst_hoplimit(skb_dst(newskb));
#else
newip->ttl = dst_metric(skb_dst(newskb), RTAX_HOPLIMIT);
#endif
newskb->ip_summed = CHECKSUM_NONE; newskb->ip_summed = CHECKSUM_NONE;
/* "Never happens" (?) */ /* "Never happens" (?) */
if (newskb->len > dst_mtu(skb_dst(newskb))) if (newskb->len > dst_mtu(skb_dst(newskb)))
goto free_nskb; goto free_nskb;
nf_ct_attach(newskb, oldskb); nf_ct_attach(newskb, *poldskb);
ip_local_out(par_net(par), newskb->sk, newskb); ip_local_out(newskb);
return NF_DROP; return NF_DROP;
free_nskb: free_nskb:

View File

@@ -25,9 +25,10 @@ MODULE_ALIAS("ipt_IPMARK");
MODULE_ALIAS("ip6t_IPMARK"); MODULE_ALIAS("ip6t_IPMARK");
static unsigned int static unsigned int
ipmark_tg4(struct sk_buff *skb, const struct xt_action_param *par) ipmark_tg4(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
const struct xt_ipmark_tginfo *ipmarkinfo = par->targinfo; const struct xt_ipmark_tginfo *ipmarkinfo = par->targinfo;
const struct sk_buff *skb = *pskb;
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
__u32 mark; __u32 mark;
@@ -60,9 +61,10 @@ static __u32 ipmark_from_ip6(const struct in6_addr *a, unsigned int s)
} }
static unsigned int static unsigned int
ipmark_tg6(struct sk_buff *skb, const struct xt_action_param *par) ipmark_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
const struct xt_ipmark_tginfo *info = par->targinfo; const struct xt_ipmark_tginfo *info = par->targinfo;
const struct sk_buff *skb = *pskb;
const struct ipv6hdr *iph = ipv6_hdr(skb); const struct ipv6hdr *iph = ipv6_hdr(skb);
__u32 mark; __u32 mark;

View File

@@ -52,24 +52,20 @@ static void logmark_ct(const struct nf_conn *ct, enum ip_conntrack_info ctinfo)
printk("EXPECTED"); printk("EXPECTED");
prev = true; prev = true;
} }
if (ct->status & IPS_SEEN_REPLY) { if (ct->status & IPS_SEEN_REPLY)
printk("%s""SEEN_REPLY", prev ? "," : ""); printk("%s""SEEN_REPLY", prev++ ? "," : "");
prev = true; if (ct->status & IPS_ASSURED)
} printk("%s""ASSURED", prev++ ? "," : "");
if (ct->status & IPS_ASSURED) { if (ct->status & IPS_CONFIRMED)
printk("%s""ASSURED", prev ? "," : ""); printk("%s""CONFIRMED", prev++ ? "," : "");
prev = true; printk(" lifetime=%lus",
} (jiffies - ct->timeout.expires) / HZ);
if (ct->status & IPS_CONFIRMED) {
printk("%s""CONFIRMED", prev ? "," : "");
prev = true;
}
printk(" lifetime=%lus", nf_ct_expires(ct) / HZ);
} }
static unsigned int static unsigned int
logmark_tg(struct sk_buff *skb, const struct xt_action_param *par) logmark_tg(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
const struct sk_buff *skb = *pskb;
const struct xt_logmark_tginfo *info = par->targinfo; const struct xt_logmark_tginfo *info = par->targinfo;
const struct nf_conn *ct; const struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
@@ -77,13 +73,20 @@ logmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
printk("<%u>%.*s""iif=%d hook=%s nfmark=0x%x " printk("<%u>%.*s""iif=%d hook=%s nfmark=0x%x "
"secmark=0x%x classify=0x%x", "secmark=0x%x classify=0x%x",
info->level, (unsigned int)sizeof(info->prefix), info->prefix, info->level, (unsigned int)sizeof(info->prefix), info->prefix,
skb_ifindex(skb), hook_names[par->state->hook], skb_ifindex(skb), hook_names[par->hooknum],
skb_nfmark(skb), skb_secmark(skb), skb->priority); skb_nfmark(skb), skb_secmark(skb), skb->priority);
ct = nf_ct_get(skb, &ctinfo); ct = nf_ct_get(skb, &ctinfo);
printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]); printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]);
if (ct == NULL) if (ct == NULL)
printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE"); printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
else if (nf_ct_is_untracked(ct))
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
#else
else if (ct == &nf_conntrack_untracked)
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
#endif
else else
logmark_ct(ct, ctinfo); logmark_ct(ct, ctinfo);

View File

@@ -1,156 +0,0 @@
/*
* Protocol modification target for IP tables
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ipv6.h>
#include <net/checksum.h>
#include <linux/netfilter/x_tables.h>
#include "xt_PROTO.h"
MODULE_AUTHOR("Shanker Wang <i@innull.com>");
MODULE_DESCRIPTION("Xtables: Protocol field modification target");
MODULE_LICENSE("GPL");
static unsigned int
proto_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
struct iphdr *iph;
const struct xt_PROTO_info *info = par->targinfo;
int new_proto;
if (skb_ensure_writable(skb, skb->len))
return NF_DROP;
iph = ip_hdr(skb);
new_proto = iph->protocol;
if (info->mode & (1 << XT_PROTO_SET))
new_proto = info->proto;
if (new_proto != iph->protocol) {
csum_replace2(&iph->check, htons(iph->protocol & 0xff),
htons(new_proto & 0xff));
iph->protocol = new_proto;
}
return XT_CONTINUE;
}
static unsigned int
proto_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
struct ipv6hdr *ip6h;
const struct xt_PROTO_info *info = par->targinfo;
u8 *nexthdr;
unsigned int hdr_offset;
__be16 *fp;
if (skb_ensure_writable(skb, skb->len))
return NF_DROP;
ip6h = ipv6_hdr(skb);
nexthdr = &ip6h->nexthdr;
hdr_offset = sizeof(struct ipv6hdr);
for (;;) {
struct ipv6_opt_hdr _opthdr, *opthp;
unsigned int hdrlen;
unsigned short _frag_off;
if (!ipv6_ext_hdr(*nexthdr) || *nexthdr == NEXTHDR_NONE)
break;
opthp = skb_header_pointer(skb, skb_network_offset(skb) + hdr_offset, sizeof(_opthdr), &_opthdr);
if (!opthp)
return NF_DROP;
if (*nexthdr == NEXTHDR_FRAGMENT) {
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
break;
fp = skb_header_pointer(skb, skb_network_offset(skb) +
hdr_offset + offsetof(struct frag_hdr, frag_off),
sizeof(_frag_off), &_frag_off);
if (!fp)
return NF_DROP;
_frag_off = ntohs(*fp) & ~0x7;
if (_frag_off) { // if the packet is not the first fragment
if (!ipv6_ext_hdr(opthp->nexthdr) || opthp->nexthdr == NEXTHDR_NONE ||
(info->mode & (1 << XT_PROTO_STOP_AT_AUTH) && opthp->nexthdr == NEXTHDR_AUTH)) {
nexthdr = &((struct ipv6_opt_hdr *)(skb_network_header(skb) + hdr_offset))->nexthdr;
break;
} else {
return XT_CONTINUE;
}
}
hdrlen = 8;
} else if(*nexthdr == NEXTHDR_AUTH) {
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
break;
hdrlen = (opthp->hdrlen + 2) << 2;
} else {
hdrlen = ipv6_optlen(opthp);
}
nexthdr = &((struct ipv6_opt_hdr *)(skb_network_header(skb) + hdr_offset))->nexthdr;
hdr_offset += hdrlen;
}
if (info->mode & (1 << XT_PROTO_SET))
*nexthdr = info->proto;
return XT_CONTINUE;
}
static int proto_tg_check(const struct xt_tgchk_param *par)
{
const struct xt_PROTO_info *info = par->targinfo;
if ((info->mode & (1 << XT_PROTO_SET)) == 0) {
pr_info_ratelimited("Did not specify any proto to set\n");
return -EINVAL;
}
if (par->family != NFPROTO_IPV6 && (info->mode & ((1 << XT_PROTO_STOP_AT_FRAG) | (1 << XT_PROTO_STOP_AT_AUTH))) != 0) {
pr_info_ratelimited("Must not specify stop-at-frag and stop-at-auth on non-ipv6 targets\n");
return -EPROTOTYPE;
}
return 0;
}
static struct xt_target proto_tg_reg[] __read_mostly = {
{
.name = "PROTO",
.revision = 0,
.family = NFPROTO_IPV4,
.target = proto_tg,
.targetsize = sizeof(struct xt_PROTO_info),
.table = "mangle",
.checkentry = proto_tg_check,
.me = THIS_MODULE,
},
{
.name = "PROTO",
.revision = 0,
.family = NFPROTO_IPV6,
.target = proto_tg6,
.targetsize = sizeof(struct xt_PROTO_info),
.table = "mangle",
.checkentry = proto_tg_check,
.me = THIS_MODULE,
},
};
static int __init proto_tg_init(void)
{
return xt_register_targets(proto_tg_reg, ARRAY_SIZE(proto_tg_reg));
}
static void __exit proto_tg_exit(void)
{
xt_unregister_targets(proto_tg_reg, ARRAY_SIZE(proto_tg_reg));
}
module_init(proto_tg_init);
module_exit(proto_tg_exit);
MODULE_ALIAS("ipt_PROTO");
MODULE_ALIAS("ip6t_PROTO");

View File

@@ -1,20 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* Protocol modification module for IP tables */
#ifndef _XT_PROTO_H
#define _XT_PROTO_H
#include <linux/types.h>
enum {
XT_PROTO_SET = 0,
XT_PROTO_STOP_AT_FRAG = 1,
XT_PROTO_STOP_AT_AUTH = 2
};
struct xt_PROTO_info {
__u8 mode;
__u8 proto;
};
#endif

View File

@@ -1,6 +1,6 @@
/* /*
* "SYSRQ" target extension for Xtables * "SYSRQ" target extension for Xtables
* Copyright Jan Engelhardt, 2016 * Copyright © Jan Engelhardt, 2008 - 2010
* *
* Based upon the ipt_SYSRQ idea by Marek Zalem <marek [at] terminus sk> * Based upon the ipt_SYSRQ idea by Marek Zalem <marek [at] terminus sk>
* *
@@ -21,12 +21,13 @@
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <crypto/hash.h> #include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <net/ip.h> #include <net/ip.h>
#include <net/ipv6.h>
#include "compat_xtables.h" #include "compat_xtables.h"
#if defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && \
(defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE))
# define WITH_CRYPTO 1 # define WITH_CRYPTO 1
#endif #endif
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
@@ -49,7 +50,7 @@ MODULE_PARM_DESC(seqno, "sequence number for remote sysrq");
MODULE_PARM_DESC(debug, "debugging: 0=off, 1=on"); MODULE_PARM_DESC(debug, "debugging: 0=off, 1=on");
#ifdef WITH_CRYPTO #ifdef WITH_CRYPTO
static struct crypto_shash *sysrq_tfm; static struct crypto_hash *sysrq_tfm;
static int sysrq_digest_size; static int sysrq_digest_size;
static unsigned char *sysrq_digest_password; static unsigned char *sysrq_digest_password;
static unsigned char *sysrq_digest; static unsigned char *sysrq_digest;
@@ -74,7 +75,8 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
{ {
const char *data = pdata; const char *data = pdata;
int i, n; int i, n;
struct shash_desc desc; struct scatterlist sg[2];
struct hash_desc desc;
int ret; int ret;
long new_seqno = 0; long new_seqno = 0;
@@ -114,15 +116,18 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
} }
desc.tfm = sysrq_tfm; desc.tfm = sysrq_tfm;
ret = crypto_shash_init(&desc); desc.flags = 0;
ret = crypto_hash_init(&desc);
if (ret != 0) if (ret != 0)
goto hash_fail; goto hash_fail;
if (crypto_shash_update(&desc, data, n) != 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
goto hash_fail; sg_init_table(sg, 2);
if (crypto_shash_update(&desc, sysrq_digest_password, #endif
strlen(sysrq_digest_password)) != 0) sg_set_buf(&sg[0], data, n);
goto hash_fail; i = strlen(sysrq_digest_password);
if (crypto_shash_final(&desc, sysrq_digest) != 0) sg_set_buf(&sg[1], sysrq_digest_password, i);
ret = crypto_hash_digest(&desc, sg, n + i, sysrq_digest);
if (ret != 0)
goto hash_fail; goto hash_fail;
for (i = 0; i < sysrq_digest_size; ++i) { for (i = 0; i < sysrq_digest_size; ++i) {
@@ -149,7 +154,13 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
sysrq_seqno = new_seqno; sysrq_seqno = new_seqno;
for (i = 0; i < len && data[i] != ','; ++i) { for (i = 0; i < len && data[i] != ','; ++i) {
printk(KERN_INFO KBUILD_MODNAME ": SysRq %c\n", data[i]); printk(KERN_INFO KBUILD_MODNAME ": SysRq %c\n", data[i]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
handle_sysrq(data[i]); handle_sysrq(data[i]);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
handle_sysrq(data[i], NULL);
#else
handle_sysrq(data[i], NULL, NULL);
#endif
} }
return NF_ACCEPT; return NF_ACCEPT;
@@ -180,14 +191,21 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
return NF_DROP; return NF_DROP;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
handle_sysrq(c); handle_sysrq(c);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
handle_sysrq(c, NULL);
#else
handle_sysrq(c, NULL, NULL);
#endif
return NF_ACCEPT; return NF_ACCEPT;
} }
#endif #endif
static unsigned int static unsigned int
sysrq_tg4(struct sk_buff *skb, const struct xt_action_param *par) sysrq_tg4(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
struct sk_buff *skb = *pskb;
const struct iphdr *iph; const struct iphdr *iph;
const struct udphdr *udph; const struct udphdr *udph;
uint16_t len; uint16_t len;
@@ -204,19 +222,21 @@ sysrq_tg4(struct sk_buff *skb, const struct xt_action_param *par)
if (sysrq_debug) if (sysrq_debug)
printk(KERN_INFO KBUILD_MODNAME printk(KERN_INFO KBUILD_MODNAME
": %pI4:%hu -> :%hu len=%u\n", ": " NIPQUAD_FMT ":%u -> :%u len=%u\n",
&iph->saddr, htons(udph->source), NIPQUAD(iph->saddr), htons(udph->source),
htons(udph->dest), len); htons(udph->dest), len);
#ifdef WITH_CRYPTO #ifdef WITH_CRYPTO
sprintf(sysrq_digest_password, "%pI4,%s", &iph->daddr, sysrq_password); sprintf(sysrq_digest_password, NIPQUAD_FMT ",%s",
NIPQUAD(iph->daddr), sysrq_password);
#endif #endif
return sysrq_tg((void *)udph + sizeof(struct udphdr), len); return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
} }
#ifdef WITH_IPV6 #ifdef WITH_IPV6
static unsigned int static unsigned int
sysrq_tg6(struct sk_buff *skb, const struct xt_action_param *par) sysrq_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
struct sk_buff *skb = *pskb;
const struct ipv6hdr *iph; const struct ipv6hdr *iph;
const struct udphdr *udph; const struct udphdr *udph;
unsigned short frag_off; unsigned short frag_off;
@@ -237,11 +257,13 @@ sysrq_tg6(struct sk_buff *skb, const struct xt_action_param *par)
len = ntohs(udph->len) - sizeof(struct udphdr); len = ntohs(udph->len) - sizeof(struct udphdr);
if (sysrq_debug) if (sysrq_debug)
printk(KERN_INFO KBUILD_MODNAME ": %pI6:%hu -> :%hu len=%u\n", printk(KERN_INFO KBUILD_MODNAME
&iph->saddr, ntohs(udph->source), ": " NIP6_FMT ":%hu -> :%hu len=%u\n",
NIP6(iph->saddr), ntohs(udph->source),
ntohs(udph->dest), len); ntohs(udph->dest), len);
#ifdef WITH_CRYPTO #ifdef WITH_CRYPTO
sprintf(sysrq_digest_password, "%pI6,%s", &iph->daddr, sysrq_password); sprintf(sysrq_digest_password, NIP6_FMT ",%s",
NIP6(iph->daddr), sysrq_password);
#endif #endif
return sysrq_tg((void *)udph + sizeof(struct udphdr), len); return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
} }
@@ -297,7 +319,7 @@ static void sysrq_crypto_exit(void)
{ {
#ifdef WITH_CRYPTO #ifdef WITH_CRYPTO
if (sysrq_tfm) if (sysrq_tfm)
crypto_free_shash(sysrq_tfm); crypto_free_hash(sysrq_tfm);
if (sysrq_digest) if (sysrq_digest)
kfree(sysrq_digest); kfree(sysrq_digest);
if (sysrq_hexdigest) if (sysrq_hexdigest)
@@ -310,10 +332,10 @@ static void sysrq_crypto_exit(void)
static int __init sysrq_crypto_init(void) static int __init sysrq_crypto_init(void)
{ {
#if defined(WITH_CRYPTO) #if defined(WITH_CRYPTO)
struct timespec64 now; struct timeval now;
int ret; int ret;
sysrq_tfm = crypto_alloc_shash(sysrq_hash, 0, 0); sysrq_tfm = crypto_alloc_hash(sysrq_hash, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(sysrq_tfm)) { if (IS_ERR(sysrq_tfm)) {
printk(KERN_WARNING KBUILD_MODNAME printk(KERN_WARNING KBUILD_MODNAME
": Error: Could not find or load %s hash\n", ": Error: Could not find or load %s hash\n",
@@ -322,7 +344,7 @@ static int __init sysrq_crypto_init(void)
sysrq_tfm = NULL; sysrq_tfm = NULL;
goto fail; goto fail;
} }
sysrq_digest_size = crypto_shash_digestsize(sysrq_tfm); sysrq_digest_size = crypto_hash_digestsize(sysrq_tfm);
sysrq_digest = kmalloc(sysrq_digest_size, GFP_KERNEL); sysrq_digest = kmalloc(sysrq_digest_size, GFP_KERNEL);
ret = -ENOMEM; ret = -ENOMEM;
if (sysrq_digest == NULL) if (sysrq_digest == NULL)
@@ -335,16 +357,15 @@ static int __init sysrq_crypto_init(void)
sizeof(sysrq_password), GFP_KERNEL); sizeof(sysrq_password), GFP_KERNEL);
if (sysrq_digest_password == NULL) if (sysrq_digest_password == NULL)
goto fail; goto fail;
ktime_get_real_ts64(&now); do_gettimeofday(&now);
sysrq_seqno = now.tv_sec; sysrq_seqno = now.tv_sec;
return 0; return 0;
fail: fail:
sysrq_crypto_exit(); sysrq_crypto_exit();
return ret; return ret;
#else #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
printk(KERN_WARNING "Kernel was compiled without crypto, " printk(KERN_WARNING "xt_SYSRQ does not provide crypto for < 2.6.19\n");
"so xt_SYSRQ won't use crypto.\n");
#endif #endif
return -EINVAL; return -EINVAL;
} }

View File

@@ -79,7 +79,7 @@ static bool xttarpit_tarpit(struct tcphdr *tcph, const struct tcphdr *oth)
#if 0 #if 0
/* Rate-limit replies to !SYN,ACKs */ /* Rate-limit replies to !SYN,ACKs */
if (!oth->syn && oth->ack) if (!oth->syn && oth->ack)
if (!xrlim_allow(&ort->dst, HZ)) if (!xrlim_allow(rt_dst(ort), HZ))
return false; return false;
#endif #endif
@@ -107,8 +107,8 @@ static bool xttarpit_honeypot(struct tcphdr *tcph, const struct tcphdr *oth,
tcph->syn = true; tcph->syn = true;
tcph->ack = true; tcph->ack = true;
tcph->window = oth->window & tcph->window = oth->window &
((prandom_u32() & 0x1f) - 0xf); ((net_random() & 0x1f) - 0xf);
tcph->seq = htonl(prandom_u32() & ~oth->seq); tcph->seq = htonl(net_random() & ~oth->seq);
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn); tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
} }
@@ -117,7 +117,7 @@ static bool xttarpit_honeypot(struct tcphdr *tcph, const struct tcphdr *oth,
tcph->syn = false; tcph->syn = false;
tcph->ack = true; tcph->ack = true;
tcph->window = oth->window & tcph->window = oth->window &
((prandom_u32() & 0x1f) - 0xf); ((net_random() & 0x1f) - 0xf);
tcph->ack_seq = payload > 100 ? tcph->ack_seq = payload > 100 ?
htonl(ntohl(oth->seq) + payload) : htonl(ntohl(oth->seq) + payload) :
oth->seq; oth->seq;
@@ -170,8 +170,8 @@ static bool tarpit_generic(struct tcphdr *tcph, const struct tcphdr *oth,
return true; return true;
} }
static void tarpit_tcp4(const struct xt_action_param *par, static void tarpit_tcp4(struct sk_buff *oldskb, unsigned int hook,
struct sk_buff *oldskb, unsigned int mode) unsigned int mode)
{ {
struct tcphdr _otcph, *tcph; struct tcphdr _otcph, *tcph;
const struct tcphdr *oth; const struct tcphdr *oth;
@@ -191,8 +191,7 @@ static void tarpit_tcp4(const struct xt_action_param *par,
return; return;
/* Check checksum. */ /* Check checksum. */
if (nf_ip_checksum(oldskb, par->state->hook, ip_hdrlen(oldskb), if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
IPPROTO_TCP))
return; return;
/* /*
@@ -206,16 +205,16 @@ static void tarpit_tcp4(const struct xt_action_param *par,
return; return;
/* This packet will not be the same as the other: clear nf fields */ /* This packet will not be the same as the other: clear nf fields */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
nf_reset_ct(nskb);
#else
nf_reset(nskb); nf_reset(nskb);
#endif
skb_nfmark(nskb) = 0; skb_nfmark(nskb) = 0;
skb_init_secmark(nskb); skb_init_secmark(nskb);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
skb_shinfo(nskb)->gso_size = 0; skb_shinfo(nskb)->gso_size = 0;
skb_shinfo(nskb)->gso_segs = 0; skb_shinfo(nskb)->gso_segs = 0;
skb_shinfo(nskb)->gso_type = 0; skb_shinfo(nskb)->gso_type = 0;
#endif
oldhdr = ip_hdr(oldskb); oldhdr = ip_hdr(oldskb);
tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb)); tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
@@ -242,9 +241,15 @@ static void tarpit_tcp4(const struct xt_action_param *par,
/* Adjust TCP checksum */ /* Adjust TCP checksum */
tcph->check = 0; 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, tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
niph->daddr, csum_partial((char *)tcph, niph->daddr, csum_partial((char *)tcph,
sizeof(struct tcphdr), 0)); sizeof(struct tcphdr), 0));
#endif
/* Set DF, id = 0 */ /* Set DF, id = 0 */
niph->frag_off = htons(IP_DF); niph->frag_off = htons(IP_DF);
@@ -254,20 +259,14 @@ static void tarpit_tcp4(const struct xt_action_param *par,
niph->id = ~oldhdr->id + 1; niph->id = ~oldhdr->id + 1;
#ifdef CONFIG_BRIDGE_NETFILTER #ifdef CONFIG_BRIDGE_NETFILTER
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
if (par->state->hook != NF_INET_FORWARD || nskb->nf_bridge->mask & BRNF_BRIDGED))
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF) != NULL &&
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF))->physoutdev))
#else #else
if (par->state->hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL && if (hook != NF_INET_FORWARD)
nskb->nf_bridge->physoutdev != NULL))
#endif
#else
if (par->state->hook != NF_INET_FORWARD)
#endif #endif
addr_type = RTN_LOCAL; addr_type = RTN_LOCAL;
if (ip_route_me_harder(par_net(par), par->state->sk, nskb, addr_type) != 0) if (ip_route_me_harder(&nskb, addr_type))
goto free_nskb; goto free_nskb;
else else
niph = ip_hdr(nskb); niph = ip_hdr(nskb);
@@ -278,7 +277,11 @@ static void tarpit_tcp4(const struct xt_action_param *par,
if (mode == XTTARPIT_HONEYPOT) if (mode == XTTARPIT_HONEYPOT)
niph->ttl = 128; niph->ttl = 128;
else else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); niph->ttl = ip4_dst_hoplimit(skb_dst(nskb));
#else
niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
#endif
/* Adjust IP checksum */ /* Adjust IP checksum */
niph->check = 0; niph->check = 0;
@@ -289,8 +292,9 @@ static void tarpit_tcp4(const struct xt_action_param *par,
goto free_nskb; goto free_nskb;
nf_ct_attach(nskb, oldskb); nf_ct_attach(nskb, oldskb);
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, par_net(par), nskb->sk, nskb,
NULL, skb_dst(nskb)->dev, dst_output); NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
return; return;
free_nskb: free_nskb:
@@ -298,8 +302,8 @@ static void tarpit_tcp4(const struct xt_action_param *par,
} }
#ifdef WITH_IPV6 #ifdef WITH_IPV6
static void tarpit_tcp6(const struct xt_action_param *par, static void tarpit_tcp6(struct sk_buff *oldskb, unsigned int hook,
struct sk_buff *oldskb, unsigned int mode) unsigned int mode)
{ {
struct sk_buff *nskb; struct sk_buff *nskb;
struct tcphdr *tcph, oth; struct tcphdr *tcph, oth;
@@ -352,16 +356,16 @@ static void tarpit_tcp6(const struct xt_action_param *par,
} }
/* This packet will not be the same as the other: clear nf fields */ /* This packet will not be the same as the other: clear nf fields */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
nf_reset_ct(nskb);
#else
nf_reset(nskb); nf_reset(nskb);
#endif
skb_nfmark(nskb) = 0; skb_nfmark(nskb) = 0;
skb_init_secmark(nskb); skb_init_secmark(nskb);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
skb_shinfo(nskb)->gso_size = 0; skb_shinfo(nskb)->gso_size = 0;
skb_shinfo(nskb)->gso_segs = 0; skb_shinfo(nskb)->gso_segs = 0;
skb_shinfo(nskb)->gso_type = 0; skb_shinfo(nskb)->gso_type = 0;
#endif
skb_put(nskb, sizeof(struct ipv6hdr)); skb_put(nskb, sizeof(struct ipv6hdr));
ip6h = ipv6_hdr(nskb); ip6h = ipv6_hdr(nskb);
*(__be32 *)ip6h = htonl(0x60000000 | (tclass << 20)); *(__be32 *)ip6h = htonl(0x60000000 | (tclass << 20));
@@ -373,7 +377,11 @@ static void tarpit_tcp6(const struct xt_action_param *par,
if (mode == XTTARPIT_HONEYPOT) { if (mode == XTTARPIT_HONEYPOT) {
ip6h->hop_limit = 128; ip6h->hop_limit = 128;
} else { } else {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
ip6h->hop_limit = ip6_dst_hoplimit(skb_dst(nskb)); ip6h->hop_limit = ip6_dst_hoplimit(skb_dst(nskb));
#else
ip6h->hop_limit = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
#endif
} }
tcph = (struct tcphdr *)(skb_network_header(nskb) + tcph = (struct tcphdr *)(skb_network_header(nskb) +
@@ -400,14 +408,16 @@ static void tarpit_tcp6(const struct xt_action_param *par,
&ipv6_hdr(nskb)->daddr, sizeof(struct tcphdr), &ipv6_hdr(nskb)->daddr, sizeof(struct tcphdr),
IPPROTO_TCP, IPPROTO_TCP,
csum_partial(tcph, sizeof(struct tcphdr), 0)); csum_partial(tcph, sizeof(struct tcphdr), 0));
if (ip6_route_me_harder(par_net(par), nskb->sk, nskb))
if (ip6_route_me_harder(nskb))
goto free_nskb; goto free_nskb;
nskb->ip_summed = CHECKSUM_NONE; nskb->ip_summed = CHECKSUM_NONE;
nf_ct_attach(nskb, oldskb); nf_ct_attach(nskb, oldskb);
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, par_net(par), nskb->sk, nskb,
NULL, skb_dst(nskb)->dev, dst_output); NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
return; return;
free_nskb: free_nskb:
@@ -416,8 +426,9 @@ static void tarpit_tcp6(const struct xt_action_param *par,
#endif #endif
static unsigned int static unsigned int
tarpit_tg4(struct sk_buff *skb, const struct xt_action_param *par) tarpit_tg4(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
const struct sk_buff *skb = *pskb;
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
const struct rtable *rt = skb_rtable(skb); const struct rtable *rt = skb_rtable(skb);
const struct xt_tarpit_tginfo *info = par->targinfo; const struct xt_tarpit_tginfo *info = par->targinfo;
@@ -445,14 +456,16 @@ tarpit_tg4(struct sk_buff *skb, const struct xt_action_param *par)
/* We are not interested in fragments */ /* We are not interested in fragments */
if (iph->frag_off & htons(IP_OFFSET)) if (iph->frag_off & htons(IP_OFFSET))
return NF_DROP; return NF_DROP;
tarpit_tcp4(par, skb, info->variant);
tarpit_tcp4(*pskb, par->hooknum, info->variant);
return NF_DROP; return NF_DROP;
} }
#ifdef WITH_IPV6 #ifdef WITH_IPV6
static unsigned int static unsigned int
tarpit_tg6(struct sk_buff *skb, const struct xt_action_param *par) tarpit_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
{ {
const struct sk_buff *skb = *pskb;
const struct ipv6hdr *iph = ipv6_hdr(skb); const struct ipv6hdr *iph = ipv6_hdr(skb);
const struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); const struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
const struct xt_tarpit_tginfo *info = par->targinfo; const struct xt_tarpit_tginfo *info = par->targinfo;
@@ -486,7 +499,8 @@ tarpit_tg6(struct sk_buff *skb, const struct xt_action_param *par)
pr_debug("addr is not unicast.\n"); pr_debug("addr is not unicast.\n");
return NF_DROP; return NF_DROP;
} }
tarpit_tcp6(par, skb, info->variant);
tarpit_tcp6(*pskb, par->hooknum, info->variant);
return NF_DROP; return NF_DROP;
} }
#endif #endif

299
extensions/xt_TEE.c Normal file
View File

@@ -0,0 +1,299 @@
/*
* "TEE" target extension for Xtables
* Copyright © Sebastian Claßen <sebastian.classen [at] freenet de>, 2007
* Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2008
*
* based on ipt_ROUTE.c from Cédric de Launois
* <delaunois [at] info ucl ac be>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2, as published by the Free Software Foundation.
*/
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/route.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <net/checksum.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/ip6_route.h>
#include <net/route.h>
#include <linux/netfilter/x_tables.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
# error ----------------------------------------------------------
# error This module has been merged into, and is available in the
# error mainline since Linux kernel v2.6.35. Please use that.
# error ----------------------------------------------------------
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
# define WITH_CONNTRACK 1
# include <net/netfilter/nf_conntrack.h>
#endif
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
# define WITH_IPV6 1
#endif
#include "compat_xtables.h"
#include "xt_TEE.h"
static bool tee_active[NR_CPUS];
static const union nf_inet_addr tee_zero_address;
static bool
tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
{
const struct iphdr *iph = ip_hdr(skb);
struct rtable *rt;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.nl_u.ip4_u.daddr = info->gw.ip;
fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE;
if (ip_route_output_key(&init_net, &rt, &fl) != 0)
return false;
dst_release(skb_dst(skb));
skb_dst_set(skb, rt_dst(rt));
skb->dev = rt_dst(rt)->dev;
skb->protocol = htons(ETH_P_IP);
return true;
}
static inline 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
* skb->dst is not NULL
* POST: the packet is sent with the link layer header pushed
* the packet is destroyed
*/
static void tee_tg_send(struct sk_buff *skb)
{
const struct dst_entry *dst = skb_dst(skb);
const struct net_device *dev = dst->dev;
unsigned int hh_len = LL_RESERVED_SPACE(dev);
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev_hh_avail(dev))) {
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
if (skb2 == NULL) {
kfree_skb(skb);
return;
}
if (skb->sk != NULL)
skb_set_owner_w(skb2, skb->sk);
kfree_skb(skb);
skb = skb2;
}
if (dst->hh != NULL)
neigh_hh_output(dst->hh, skb);
else if (dst->neighbour != NULL)
dst->neighbour->output(skb);
else
kfree_skb(skb);
}
static unsigned int
tee_tg4(struct sk_buff **pskb, const struct xt_action_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
struct sk_buff *skb = *pskb;
struct iphdr *iph;
unsigned int cpu = smp_processor_id();
if (tee_active[cpu])
return XT_CONTINUE;
/*
* Copy the skb, and route the copy. Will later return %XT_CONTINUE for
* the original skb, which should continue on its way as if nothing has
* happened. The copy should be independently delivered to the TEE
* --gateway.
*/
skb = pskb_copy(skb, GFP_ATOMIC);
if (skb == NULL)
return XT_CONTINUE;
/*
* If we are in PREROUTING/INPUT, the checksum must be recalculated
* since the length could have changed as a result of defragmentation.
*
* We also decrease the TTL to mitigate potential TEE loops
* between two hosts.
*
* Set %IP_DF so that the original source is notified of a potentially
* decreased MTU on the clone route. IPv6 does this too.
*/
iph = ip_hdr(skb);
iph->frag_off |= htons(IP_DF);
if (par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_LOCAL_IN)
--iph->ttl;
ip_send_check(iph);
#ifdef WITH_CONNTRACK
/*
* Tell conntrack to forget this packet. It may have side effects to
* see the same packet twice, as for example, accounting the original
* connection for the cloned packet.
*/
nf_conntrack_put(skb->nfct);
skb->nfct = &nf_conntrack_untracked.ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
#endif
/*
* Normally, we would just use ip_local_out. Because iph->check is
* already correct, we could take a shortcut and call dst_output
* [forwards to ip_output] directly. ip_output however will invoke
* Netfilter hooks and cause reentrancy. So we skip that too and go
* directly to ip_finish_output. Since we should not do XFRM, control
* passes to ip_finish_output2. That function is not exported, so it is
* copied here as tee_ip_direct_send.
*
* We do no XFRM on the cloned packet on purpose! The choice of
* iptables match options will control whether the raw packet or the
* transformed version is cloned.
*
* Also on purpose, no fragmentation is done, to preserve the
* packet as best as possible.
*/
if (tee_tg_route4(skb, info)) {
tee_active[cpu] = true;
tee_tg_send(skb);
tee_active[cpu] = false;
} else {
kfree_skb(skb);
}
return XT_CONTINUE;
}
#ifdef WITH_IPV6
static bool
tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info)
{
const struct ipv6hdr *iph = ipv6_hdr(skb);
struct dst_entry *dst;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.nl_u.ip6_u.daddr = info->gw.in6;
fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) |
(iph->flow_lbl[1] << 8) | iph->flow_lbl[2];
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 25)
dst = ip6_route_output(NULL, &fl);
#else
dst = ip6_route_output(dev_net(skb->dev), NULL, &fl);
#endif
if (dst == NULL)
return false;
dst_release(skb_dst(skb));
skb_dst_set(skb, dst);
skb->dev = dst->dev;
skb->protocol = htons(ETH_P_IPV6);
return true;
}
static unsigned int
tee_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
struct sk_buff *skb = *pskb;
unsigned int cpu = smp_processor_id();
if (tee_active[cpu])
return XT_CONTINUE;
skb = pskb_copy(skb, GFP_ATOMIC);
if (skb == NULL)
return XT_CONTINUE;
#ifdef WITH_CONNTRACK
nf_conntrack_put(skb->nfct);
skb->nfct = &nf_conntrack_untracked.ct_general;
skb->nfctinfo = IP_CT_NEW;
nf_conntrack_get(skb->nfct);
#endif
if (par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_LOCAL_IN) {
struct ipv6hdr *iph = ipv6_hdr(skb);
--iph->hop_limit;
}
if (tee_tg_route6(skb, info)) {
tee_active[cpu] = true;
tee_tg_send(skb);
tee_active[cpu] = false;
} else {
kfree_skb(skb);
}
return XT_CONTINUE;
}
#endif /* WITH_IPV6 */
static int tee_tg_check(const struct xt_tgchk_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
/* 0.0.0.0 and :: not allowed */
return (memcmp(&info->gw, &tee_zero_address,
sizeof(tee_zero_address)) == 0) ? -EINVAL : 0;
}
static struct xt_target tee_tg_reg[] __read_mostly = {
{
.name = "TEE",
.revision = 0,
.family = NFPROTO_IPV4,
.target = tee_tg4,
.targetsize = sizeof(struct xt_tee_tginfo),
.checkentry = tee_tg_check,
.me = THIS_MODULE,
},
#ifdef WITH_IPV6
{
.name = "TEE",
.revision = 0,
.family = NFPROTO_IPV6,
.target = tee_tg6,
.targetsize = sizeof(struct xt_tee_tginfo),
.checkentry = tee_tg_check,
.me = THIS_MODULE,
},
#endif
};
static int __init tee_tg_init(void)
{
return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
}
static void __exit tee_tg_exit(void)
{
xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg));
}
module_init(tee_tg_init);
module_exit(tee_tg_exit);
MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>");
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_DESCRIPTION("Xtables: Reroute packet copy");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_TEE");
MODULE_ALIAS("ip6t_TEE");

8
extensions/xt_TEE.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef _XT_TEE_TARGET_H
#define _XT_TEE_TARGET_H
struct xt_tee_tginfo {
union nf_inet_addr gw;
};
#endif /* _XT_TEE_TARGET_H */

View File

@@ -7,7 +7,6 @@
* Authors: * Authors:
* Stephane Ouellette <ouellettes [at] videotron ca>, 2002-10-22 * Stephane Ouellette <ouellettes [at] videotron ca>, 2002-10-22
* Massimiliano Hofer <max [at] nucleus it>, 2006-05-15 * Massimiliano Hofer <max [at] nucleus it>, 2006-05-15
* Grzegorz Kuczyński <grzegorz.kuczynski [at] koba pl>, 2017-02-27
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License; either version 2 * under the terms of the GNU General Public License; either version 2
@@ -22,8 +21,6 @@
#include <linux/version.h> #include <linux/version.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include "xt_condition.h" #include "xt_condition.h"
#include "compat_xtables.h" #include "compat_xtables.h"
@@ -55,44 +52,31 @@ struct condition_variable {
struct proc_dir_entry *status_proc; struct proc_dir_entry *status_proc;
unsigned int refcount; unsigned int refcount;
bool enabled; bool enabled;
char name[sizeof(((struct xt_condition_mtinfo *)NULL)->name)];
}; };
/* proc_lock is a user context only semaphore used for write access */ /* proc_lock is a user context only semaphore used for write access */
/* to the conditions' list. */ /* to the conditions' list. */
static DEFINE_MUTEX(proc_lock); static DEFINE_MUTEX(proc_lock);
struct condition_net { static LIST_HEAD(conditions_list);
struct list_head conditions_list; static struct proc_dir_entry *proc_net_condition;
struct proc_dir_entry *proc_net_condition;
bool after_clear;
};
static int condition_net_id; static int condition_proc_read(char __user *buffer, char **start, off_t offset,
int length, int *eof, void *data)
static inline struct condition_net *condition_pernet(struct net *net)
{ {
return net_generic(net, condition_net_id); 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_show(struct seq_file *m, void *data) static int condition_proc_write(struct file *file, const char __user *buffer,
unsigned long length, void *data)
{ {
const struct condition_variable *var = m->private; struct condition_variable *var = data;
seq_printf(m, var->enabled ? "1\n" : "0\n");
return 0;
}
static int condition_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, condition_proc_show, PDE_DATA(inode));
}
static ssize_t
condition_proc_write(struct file *file, const char __user *buffer,
size_t length, loff_t *loff)
{
struct condition_variable *var = PDE_DATA(file_inode(file));
char newval; char newval;
if (length > 0) { if (length > 0) {
@@ -111,14 +95,6 @@ condition_proc_write(struct file *file, const char __user *buffer,
return length; return length;
} }
static const struct proc_ops condition_proc_fops = {
.proc_open = condition_proc_open,
.proc_read = seq_read,
.proc_write = condition_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static bool static bool
condition_mt(const struct sk_buff *skb, struct xt_action_param *par) condition_mt(const struct sk_buff *skb, struct xt_action_param *par)
{ {
@@ -132,7 +108,6 @@ static int condition_mt_check(const struct xt_mtchk_param *par)
{ {
struct xt_condition_mtinfo *info = par->matchinfo; struct xt_condition_mtinfo *info = par->matchinfo;
struct condition_variable *var; struct condition_variable *var;
struct condition_net *condition_net = condition_pernet(par->net);
/* Forbid certain names */ /* Forbid certain names */
if (*info->name == '\0' || *info->name == '.' || if (*info->name == '\0' || *info->name == '.' ||
@@ -148,8 +123,8 @@ static int condition_mt_check(const struct xt_mtchk_param *par)
* or increase the reference counter. * or increase the reference counter.
*/ */
mutex_lock(&proc_lock); mutex_lock(&proc_lock);
list_for_each_entry(var, &condition_net->conditions_list, list) { list_for_each_entry(var, &conditions_list, list) {
if (strcmp(info->name, var->name) == 0) { if (strcmp(info->name, var->status_proc->name) == 0) {
var->refcount++; var->refcount++;
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
info->condvar = var; info->condvar = var;
@@ -164,23 +139,27 @@ static int condition_mt_check(const struct xt_mtchk_param *par)
return -ENOMEM; return -ENOMEM;
} }
memcpy(var->name, info->name, sizeof(info->name));
/* Create the condition variable's proc file entry. */ /* Create the condition variable's proc file entry. */
var->status_proc = proc_create_data(info->name, condition_list_perms, var->status_proc = create_proc_entry(info->name, condition_list_perms,
condition_net->proc_net_condition, &condition_proc_fops, var); proc_net_condition);
if (var->status_proc == NULL) { if (var->status_proc == NULL) {
kfree(var); kfree(var);
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
return -ENOMEM; return -ENOMEM;
} }
proc_set_user(var->status_proc,
make_kuid(&init_user_ns, condition_uid_perms),
make_kgid(&init_user_ns, condition_gid_perms));
var->refcount = 1; var->refcount = 1;
var->enabled = false; var->enabled = false;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
var->status_proc->owner = THIS_MODULE;
#endif
var->status_proc->data = var;
wmb(); wmb();
list_add(&var->list, &condition_net->conditions_list); var->status_proc->read_proc = condition_proc_read;
var->status_proc->write_proc = condition_proc_write;
list_add(&var->list, &conditions_list);
var->status_proc->uid = condition_uid_perms;
var->status_proc->gid = condition_gid_perms;
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
info->condvar = var; info->condvar = var;
return 0; return 0;
@@ -190,15 +169,11 @@ static void condition_mt_destroy(const struct xt_mtdtor_param *par)
{ {
const struct xt_condition_mtinfo *info = par->matchinfo; const struct xt_condition_mtinfo *info = par->matchinfo;
struct condition_variable *var = info->condvar; struct condition_variable *var = info->condvar;
struct condition_net *cnet = condition_pernet(par->net);
if (cnet->after_clear)
return;
mutex_lock(&proc_lock); mutex_lock(&proc_lock);
if (--var->refcount == 0) { if (--var->refcount == 0) {
list_del(&var->list); list_del(&var->list);
remove_proc_entry(var->name, cnet->proc_net_condition); remove_proc_entry(var->status_proc->name, proc_net_condition);
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
kfree(var); kfree(var);
return; return;
@@ -231,54 +206,18 @@ static struct xt_match condition_mt_reg[] __read_mostly = {
static const char *const dir_name = "nf_condition"; static const char *const dir_name = "nf_condition";
static int __net_init condition_net_init(struct net *net)
{
struct condition_net *condition_net = condition_pernet(net);
INIT_LIST_HEAD(&condition_net->conditions_list);
condition_net->proc_net_condition = proc_mkdir(dir_name, net->proc_net);
if (condition_net->proc_net_condition == NULL)
return -EACCES;
condition_net->after_clear = 0;
return 0;
}
static void __net_exit condition_net_exit(struct net *net)
{
struct condition_net *condition_net = condition_pernet(net);
struct list_head *pos, *q;
struct condition_variable *var = NULL;
remove_proc_subtree(dir_name, net->proc_net);
mutex_lock(&proc_lock);
list_for_each_safe(pos, q, &condition_net->conditions_list) {
var = list_entry(pos, struct condition_variable, list);
list_del(pos);
kfree(var);
}
mutex_unlock(&proc_lock);
condition_net->after_clear = true;
}
static struct pernet_operations condition_net_ops = {
.init = condition_net_init,
.exit = condition_net_exit,
.id = &condition_net_id,
.size = sizeof(struct condition_net),
};
static int __init condition_mt_init(void) static int __init condition_mt_init(void)
{ {
int ret; int ret;
mutex_init(&proc_lock); mutex_init(&proc_lock);
ret = register_pernet_subsys(&condition_net_ops); proc_net_condition = proc_mkdir(dir_name, init_net__proc_net);
if (ret != 0) if (proc_net_condition == NULL)
return ret; return -EACCES;
ret = xt_register_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg)); ret = xt_register_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg));
if (ret < 0) { if (ret < 0) {
unregister_pernet_subsys(&condition_net_ops); remove_proc_entry(dir_name, init_net__proc_net);
return ret; return ret;
} }
@@ -288,7 +227,7 @@ static int __init condition_mt_init(void)
static void __exit condition_mt_exit(void) static void __exit condition_mt_exit(void)
{ {
xt_unregister_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg)); xt_unregister_matches(condition_mt_reg, ARRAY_SIZE(condition_mt_reg));
unregister_pernet_subsys(&condition_net_ops); remove_proc_entry(dir_name, init_net__proc_net);
} }
module_init(condition_mt_init); module_init(condition_mt_init);

View File

@@ -75,8 +75,7 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr,
if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0) if (copy_from_user(&umem, umem_ptr, sizeof(umem)) != 0)
return ERR_PTR(-EFAULT); return ERR_PTR(-EFAULT);
if (umem.count > SIZE_MAX / geoproto_size[proto])
return ERR_PTR(-E2BIG);
p = kmalloc(sizeof(struct geoip_country_kernel), GFP_KERNEL); p = kmalloc(sizeof(struct geoip_country_kernel), GFP_KERNEL);
if (p == NULL) if (p == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
@@ -84,19 +83,11 @@ geoip_add_node(const struct geoip_country_user __user *umem_ptr,
p->count = umem.count; p->count = umem.count;
p->cc = umem.cc; p->cc = umem.cc;
size = p->count * geoproto_size[proto]; size = p->count * geoproto_size[proto];
if (size == 0) {
/*
* Believe it or not, vmalloc prints a warning to dmesg for
* zero-sized allocations :-/
*/
subnet = NULL;
} else {
subnet = vmalloc(size); subnet = vmalloc(size);
if (subnet == NULL) { if (subnet == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto free_p; goto free_p;
} }
}
if (copy_from_user(subnet, if (copy_from_user(subnet,
(const void __user *)(unsigned long)umem.subnets, size) != 0) { (const void __user *)(unsigned long)umem.subnets, size) != 0) {
ret = -EFAULT; ret = -EFAULT;

View File

@@ -45,10 +45,14 @@ static const struct net_device *iface_get(const struct xt_iface_mtinfo *info,
const struct xt_action_param *par, struct net_device **put) const struct xt_action_param *par, struct net_device **put)
{ {
if (info->flags & XT_IFACE_DEV_IN) if (info->flags & XT_IFACE_DEV_IN)
return par->state->in; return par->in;
else if (info->flags & XT_IFACE_DEV_OUT) else if (info->flags & XT_IFACE_DEV_OUT)
return par->state->out; return par->out;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
return *put = dev_get_by_name(&init_net, info->ifname); return *put = dev_get_by_name(&init_net, info->ifname);
#else
return *put = dev_get_by_name(info->ifname);
#endif
} }
static bool iface_flagtest(unsigned int devflags, unsigned int flags, static bool iface_flagtest(unsigned int devflags, unsigned int flags,

View File

@@ -511,7 +511,7 @@ search_bittorrent(const unsigned char *payload, const unsigned int plen)
* but *must have* one (or more) of strings listed below (true for scrape and announce) * but *must have* one (or more) of strings listed below (true for scrape and announce)
*/ */
if (memcmp(payload, "GET /", 5) == 0) { if (memcmp(payload, "GET /", 5) == 0) {
if (HX_memmem(payload, plen, "info_hash=", 10) != NULL) if (HX_memmem(payload, plen, "info_hash=", 9) != NULL)
return IPP2P_BIT * 100 + 1; return IPP2P_BIT * 100 + 1;
if (HX_memmem(payload, plen, "peer_id=", 8) != NULL) if (HX_memmem(payload, plen, "peer_id=", 8) != NULL)
return IPP2P_BIT * 100 + 2; return IPP2P_BIT * 100 + 2;
@@ -857,11 +857,8 @@ ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
p2p_result = matchlist[i].function_name(haystack, hlen); p2p_result = matchlist[i].function_name(haystack, hlen);
if (p2p_result) { if (p2p_result) {
if (info->debug) if (info->debug)
printk("IPP2P.debug:TCP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %d\n", printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
p2p_result, &ip->saddr, p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
ntohs(tcph->source),
&ip->daddr,
ntohs(tcph->dest), hlen);
return p2p_result; return p2p_result;
} }
} }
@@ -891,11 +888,8 @@ ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
p2p_result = udp_list[i].function_name(haystack, hlen); p2p_result = udp_list[i].function_name(haystack, hlen);
if (p2p_result) { if (p2p_result) {
if (info->debug) if (info->debug)
printk("IPP2P.debug:UDP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %d\n", printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
p2p_result, &ip->saddr, p2p_result, NIPQUAD(ip->saddr), ntohs(udph->source), NIPQUAD(ip->daddr), ntohs(udph->dest), hlen);
ntohs(udph->source),
&ip->daddr,
ntohs(udph->dest), hlen);
return p2p_result; return p2p_result;
} }
} }

View File

@@ -184,8 +184,7 @@ lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
return false; return false;
/* Check for invalid packets: -m conntrack --ctstate INVALID */ /* Check for invalid packets: -m conntrack --ctstate INVALID */
ctdata = nf_ct_get(skb, &ctstate); if ((ctdata = nf_ct_get(skb, &ctstate)) == NULL) {
if (ctdata == NULL) {
if (info->match_stealth) if (info->match_stealth)
return lscan_mt_stealth(tcph); return lscan_mt_stealth(tcph);
/* /*
@@ -205,7 +204,7 @@ lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
unsigned int n; unsigned int n;
n = lscan_mt_full(ctdata->mark & connmark_mask, ctstate, n = lscan_mt_full(ctdata->mark & connmark_mask, ctstate,
par->state->in == init_net.loopback_dev, tcph, par->in == init_net__loopback_dev, tcph,
skb->len - par->thoff - 4 * tcph->doff); skb->len - par->thoff - 4 * tcph->doff);
ctdata->mark = (ctdata->mark & ~connmark_mask) | n; ctdata->mark = (ctdata->mark & ~connmark_mask) | n;

View File

@@ -45,12 +45,12 @@ MODULE_ALIAS("ip6t_psd");
/* /*
* Keep track of up to LIST_SIZE source addresses, using a hash table of * Keep track of up to LIST_SIZE source addresses, using a hash table of
* PSD_HASH_SIZE entries for faster lookups, but limiting hash collisions to * HASH_SIZE entries for faster lookups, but limiting hash collisions to
* HASH_MAX source addresses per the same hash value. * HASH_MAX source addresses per the same hash value.
*/ */
#define LIST_SIZE 0x100 #define LIST_SIZE 0x100
#define HASH_LOG 9 #define HASH_LOG 9
#define PSD_HASH_SIZE (1 << HASH_LOG) #define HASH_SIZE (1 << HASH_LOG)
#define HASH_MAX 0x10 #define HASH_MAX 0x10
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
@@ -108,7 +108,7 @@ struct host6 {
static struct { static struct {
spinlock_t lock; spinlock_t lock;
struct host4 list[LIST_SIZE]; struct host4 list[LIST_SIZE];
struct host *hash[PSD_HASH_SIZE]; struct host *hash[HASH_SIZE];
int index; int index;
} state; } state;
@@ -143,12 +143,13 @@ static bool state6_alloc_mem(void)
if (state6.list == NULL) if (state6.list == NULL)
return false; return false;
memset(state6.list, 0, LIST_SIZE * sizeof(struct host6)); memset(state6.list, 0, LIST_SIZE * sizeof(struct host6));
state6.hash = vmalloc(PSD_HASH_SIZE * sizeof(struct host *));
state6.hash = vmalloc(HASH_SIZE * sizeof(struct host*));
if (state6.hash == NULL) { if (state6.hash == NULL) {
vfree(state6.list); vfree(state6.list);
return false; return false;
} }
memset(state6.hash, 0, PSD_HASH_SIZE * sizeof(struct host *)); memset(state6.hash, 0, HASH_SIZE * sizeof(struct host *));
return true; return true;
} }
#endif #endif
@@ -166,7 +167,8 @@ static unsigned int hashfunc(__be32 addr)
do { do {
hash ^= value; hash ^= value;
} while ((value >>= HASH_LOG) != 0); } while ((value >>= HASH_LOG) != 0);
return hash & (PSD_HASH_SIZE - 1);
return hash & (HASH_SIZE - 1);
} }
static inline unsigned int hashfunc6(const struct in6_addr *addr) static inline unsigned int hashfunc6(const struct in6_addr *addr)

Some files were not shown because too many files have changed in this diff Show More