Compare commits

...

166 Commits

Author SHA1 Message Date
Jan Engelhardt
e3ae438e2e Merge branch 'master' of ssh://git.code.sf.net/u/jeffcarlson72/xtables-addons 2021-08-16 08:49:55 +02:00
Jeff Carlson
c90ecf4320 pknock: added UDP options to help and made whitespace consistent 2021-08-15 18:59:25 -07:00
Jeremy Sowden
1abcd731c0 libxt_ACCOUNT_cl: correct LDFLAGS variable name
The LT library name is libxt_ACCOUNT_cl.la, so the variable should be
`libxt_ACCOUNT_cl_la_LDFLAGS`.

Fixes: 81ab0b9586 ("libxt_ACCOUNT_cl: drop padding holes from struct ipt_ACCOUNT_context")
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2021-08-15 13:29:15 +02:00
Jan Engelhardt
af10045c75 doc: add incompatibility notice with transmogrified kernels 2021-07-17 11:37:50 +02:00
Jan Engelhardt
6d74a85f70 extensions: remove unused code from compat_xtnu.h 2021-07-17 11:34:34 +02:00
Jan Engelhardt
b9893b9505 xt_ipp2p: use fixed-size integers for struct ipt_p2p_info 2021-07-17 11:33:20 +02:00
Jan Engelhardt
714998176a extensions: syntactically compact struct definitions 2021-07-17 11:32:19 +02:00
Jan Engelhardt
81ab0b9586 libxt_ACCOUNT_cl: drop padding holes from struct ipt_ACCOUNT_context 2021-07-17 11:31:10 +02:00
Jan Engelhardt
1f308c7262 extensions: use simpler header guards 2021-07-17 11:24:47 +02:00
Jan Engelhardt
87189b0051 Xtables-addons 3.18 2021-03-11 17:13:17 +01:00
Jan Engelhardt
d3fb275c03 xt_pknock: fix build failure under platforms like ARM 32-bit
./arch/arm/include/asm/div64.h:24:45: note: expected "uint64_t *"
{aka "long long unsigned int *"} but argument is of type
"long unsigned int *"
   24 | static inline uint32_t __div64_32(uint64_t *n, uint32_t base)
2021-03-11 17:11:47 +01:00
Jan Engelhardt
9faa3085bb Xtables-addons 3.17 2021-02-28 17:54:20 +01:00
Jan Engelhardt
947a677ddb xt_pknock: reduce indent in the two most-recently touched functions 2021-02-28 17:53:19 +01:00
Andrew S. Johnson
42a9b5c6c3 xt_pknock: cure NULL dereference
The original patch for long division on x86 didn't take into account
the use of short circuit logic for checking if peer is NULL before
testing it. Here is a revised patch to v3.16.
2021-02-28 17:50:36 +01:00
Jan Engelhardt
3233a0ed2c Xtables-addons 3.16 2021-02-24 01:16:22 +01:00
Jan Engelhardt
97808473f9 xt_quota2: silence a compiler warning
libxt_quota2.c:73:3: warning: ‘strncpy’ specified bound 15 equals destination size [-Wstringop-truncation]
   73 |   strncpy(info->name, optarg, sizeof(info->name));
2021-02-24 01:12:28 +01:00
Andrew S. Johnson
3aa4ca3eaf xt_pknock: use do_div for long division 2021-02-24 01:10:18 +01:00
Jan Engelhardt
5104269605 Xtables-addons 3.15 2021-02-05 21:56:26 +01:00
Jan Engelhardt
4ee209416f xt_pknock: replace obsolete function get_seconds
get_seconds is removed in 5.11; its replacement ktime_get_real_seconds
is available since 3.19. The timestamps should not be affected by clock
resets, so will be switched to ktime_get_seconds.
2021-02-05 21:55:46 +01:00
Jan Engelhardt
43df040e05 xt_lscan: add --mirai option 2021-02-05 18:58:55 +01:00
Jan Engelhardt
f59a4eb9d9 xt_lscan: extend info struct to support more flags (without size change) 2021-01-20 02:50:01 +01:00
Jan Engelhardt
a238253509 xt_ECHO: support new function signature of security_skb_classify_flow 2021-01-20 02:44:25 +01:00
Jan Engelhardt
4547e4c5cc Xtables-addons 3.14 2020-11-24 18:41:52 +01:00
Jeremy Sowden
5d94a36d22 geoip: use correct download URL for MaxMind DBs
The download URL for the GeoLite2 DBs has changed and includes a
licence key. Update the download script to read the key from file or
stdin and use the correct URL.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-11-24 18:39:00 +01:00
Jan Engelhardt
9d5b2e2e0e extensions: reduce number of arguments to send_reset functions 2020-11-23 23:14:46 +01:00
Jan Engelhardt
f973577ec0 extensions: call send_reset with xtables state socket
Reported-by: Minqiang Chen <ptpt52@gmail.com>
2020-11-23 23:06:25 +01:00
Jan Engelhardt
a35feefa0f build: cure overall build failure when CONFIG_NF_NAT=n 2020-11-22 17:45:37 +01:00
Jan Engelhardt
a1b3d81ccb geoip: rename xt_geoip_fetch to xt_geoip_query
"fetch" sounds a bit like "download", but that is not what this
utility does. Calling it "query" seems more appropriate.
2020-11-22 17:44:51 +01:00
Jeremy Sowden
6504f251c6 geoip: add man pages for MaxMind scripts
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-11-22 17:27:51 +01:00
Jeremy Sowden
1c67775d10 doc: fix man page typos
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-11-22 17:27:40 +01:00
Jeremy Sowden
7327cd725b geoip: remove superfluous xt_geoip_fetch_maxmind script
xt_geoip_fetch and xt_geoip_fetch_maxmind are identical. Remove the
latter.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-11-22 17:27:31 +01:00
Jan Engelhardt
5c8aecdd56 Xtables-addons 3.13 2020-11-20 13:13:52 +01:00
Jan Engelhardt
5ad9de75d4 compat_xtables: employ route_me_harder define for 4.19 and 5.4 too
The API change found its way into some more Linux stable series.
2020-11-20 13:11:38 +01:00
Jan Engelhardt
9e84e8f13d Xtables-addons 3.12 2020-11-19 22:11:19 +01:00
Jan Engelhardt
50153ffdb9 compat_xtables: fix a spello near route_me_harder 2020-11-19 22:11:19 +01:00
Jan Engelhardt
9c4aeea422 xt_DNETMAP: compaction of variable declarations 2020-11-19 21:53:15 +01:00
Philip Prindeville
c09d0704af geoip: re-add Maxmind scripts 2020-11-19 13:03:42 +01:00
Jan Engelhardt
0021003dc7 extensions: abolish NIPQUAD/NIP6
Support for Linux 2.6.28 is long gone.
2020-11-19 12:54:36 +01:00
Jan Engelhardt
0ab3247900 build: adjust for changed signature of ip_route_me_harder
(Cf. commit 46d6c5ae953cc0be38efd0e469284df7c4328cf8 in Linux.)
2020-11-19 12:28:55 +01:00
Jeremy Sowden
d3f7dc1f55 pknlusr: mention the group ID command-line paramater in the man page
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-26 11:08:20 +01:00
Jan Engelhardt
87d3aab175 pknock: trim some blank lines 2020-10-26 11:06:57 +01:00
Jan Engelhardt
bfb0516c79 extensions: split assignments and if-exprs 2020-10-25 15:41:24 +01:00
Jeremy Sowden
939d3ee0d3 xt_pknock: remove DEBUG definition and disable debug output
The DEBUG definition in xt_pknock.h causes a compiler warning if one
adds a DEBUG define to xt_pknock.c to enable pr_debug. Since it only
controls some debugging output in libxt_pknock.c, it would make sense to
move the definition there, but let's just disable the debugging instead.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:17:40 +01:00
Jeremy Sowden
5df71f8741 xt_pknock: use pr_err
Replace some instances of `printk(KERN_ERR PKNOCK ...)`. We define
`pr_fmt`, so `pr_err` is equivalent.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:14:31 +01:00
Jeremy Sowden
82379e8ec1 xt_pknock: use kzalloc
Replace some instances of kmalloc + memset.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:14:27 +01:00
Jeremy Sowden
b3a3f2e91b xt_pknock: use IS_ENABLED
It is more succinct than checking whether CONFIG_BLAH or
CONFIG_BLAH_MODULE are defined.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:06:11 +01:00
Jeremy Sowden
63fb5d3490 pknlusr: fix hard-coded netlink multicast group ID
The group ID used by xt_pknock is configurable, but pknlusr hard-codes
it. Modify pknlusr to accept an optional ID from the command line.
Group IDs range from 1 to 32 and each ID appears in the group bitmask
at position `group_id - 1`.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:06:10 +01:00
Jeremy Sowden
05cacbe84c pknlusr: always close socket
On some error paths, the socket was not being closed before exit.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:02:39 +01:00
Jeremy Sowden
3c120ef5f1 pknlusr: do not treat recv return value of zero as an error
A return-value of zero is not an error, so there is no point calling
perror, but since we have not requested and do not expect a zero-length
datagram, we treat it as EOF and exit.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:01:50 +01:00
Jeremy Sowden
b0a1aacd4b pknlusr: use macro to define inet_ntop buffer size
POSIX provides a macro to define the minimum length required, so let's
use it.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:01:18 +01:00
Jeremy Sowden
c3bd1c61d1 pknlusr: use NLMSG macros and proper types, rather than arithmetic on char pointers
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 15:00:45 +01:00
Jeremy Sowden
9cd0b44c81 pknlusr: tidy up initialization of local address
Use struct initialization and drop memset. We do not need to set the port
ID, since the kernel will do it for us.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 14:54:40 +01:00
Jeremy Sowden
b4faa4de65 pknock: pknlusr: tighten up variable scopes
Make global variables local, and move variables local to while-loop into
the loop.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 14:54:10 +01:00
Jeremy Sowden
b05ea5644c pknock: pknlusr: remove dest_addr and rename src_addr
We only need to specify the address at our end, and given that we are
receiving messages, not sending them, calling it `src_addr` is
misleading.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 14:53:34 +01:00
Jeremy Sowden
b052ec0f7d pknock: pknlusr: ensure man-page is included by make dist
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-10-25 14:50:17 +01:00
Jeremy Sowden
249df831b0 pknlusr: add man page
Since pknlusr is now being installed, let's give it a man page.
2020-10-23 11:22:41 +02:00
Jeremy Sowden
86112194da pknlusr: fix formatting of a line 2020-10-22 19:59:06 +02:00
Jan Engelhardt
20e1b669fc Xtables-addons 3.11 2020-09-06 16:35:13 +02:00
Jeremy Sowden
e4784832ed build: bump supported kernel version to 5.9
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-08-31 15:04:54 +02:00
Jeremy Sowden
48e30a0990 xt_ACCOUNT: update prototype of nf_sockopt_ops::set callback
In 5.9, the `void __user` parameter has been replaced by a `sockptr`.
Update `ipt_acc_set_ctl` appropriately.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-08-31 15:04:43 +02:00
Helmut Grohne
ea588d0b9c build: do not hard-code pkg-config
Use $PKG_CONFIG in configure.ac in order to allow it to be overridden.
Fixes cross-compilation.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-08-31 13:03:48 +02:00
Jeremy Sowden
96460646e9 build: clean some extra build artifacts.
Makefile.mans creates .manpages.lst, but does not remove it. Add
it to the `clean` target.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-08-30 13:39:53 +02:00
Jan Engelhardt
2cb4b2bec6 build: do build & install userspace programs for xt_ACCOUNT and xt_pknock 2020-08-30 13:36:10 +02:00
Jan Engelhardt
37f19c6b96 Xtables-addons 3.10 2020-07-28 10:02:34 +02:00
Jeremy Sowden
73b96e25e4 doc: fix quoted string in libxt_DNETMAP manpage
In roff, lines beginning with a single quote are control lines.  In the
libxt_DNETMAP man-page there is a single-quoted string at the beginning
of a line, which troff tries and fails to interpret as a macro:

	troff: <standard input>:49: warning: macro 'S'' not defined

This means that the line is not output.

Replace the single quotes with the appropriate escape-sequences.

Fixes: v2.3~9 ("doc: spelling and grammar corrections to DNETMAP")
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2020-07-28 10:02:26 +02:00
Philip Prindeville
ca84ee8e15 geoip: add quiet flag to xt_geoip_build
Conceivably someone might want to run a refresh of the geoip database
from within a script, particularly an unattended script such as a cron
job. Do not generate output in that case.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2020-05-26 14:58:04 +02:00
Jan Engelhardt
c9ba3507fc geoip: add -s option to xt_geoip_build 2020-05-12 22:49:37 +02:00
Jan Engelhardt
b87366bb83 geoip: replace xt_geoip_build's -S option by new option -i
The Maxmind DB came with potentially multiple files, but DBIP is
currently just one. Drop the -S argument and instead introduce -i.
2020-05-12 22:47:00 +02:00
Jan Engelhardt
8bbb0cb3eb geoip: set +x again on xt_geoip_build 2020-05-12 22:38:32 +02:00
Jan Engelhardt
b4629f46c6 build: do install xt_geoip_fetch.1 2020-05-01 23:07:16 +02:00
Philip Prindeville
f7f18f0c4f geoip: install and document xt_geoip_fetch
Add a man page for xt_geoip_fetch.1 and include it as part of
the installed scripts.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2020-05-01 23:04:55 +02:00
Jan Engelhardt
9193adc835 geoip: pipe wget right into gzip
Skip over creating temporary files.
2020-04-21 12:01:52 +02:00
Philip Prindeville
74fcd4a2ae geoip: simplify unpacking start/end tuples from database
Use unpack() to separate start/end instead of substr().

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2020-04-21 12:00:54 +02:00
Philip Prindeville
4b43df69f5 geoip: update download script for DBIP database
Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2020-04-21 12:00:50 +02:00
Jan Engelhardt
4c68c774c8 Xtables-addons 3.9 2020-02-25 07:35:08 +01:00
Jan Engelhardt
0888357642 build: avoid configure warning for Linux 4.15
Commit 4603d3e0f4 and others
erroneously changed the acceptance range from >=4.15 to >=4.17.
Return to previous state.
2020-02-25 07:30:01 +01:00
Jan Engelhardt
d31067b32e Support for Linux 5.6 procfs API 2020-02-25 07:28:23 +01:00
Jan Engelhardt
fc44fcb94f Xtables-addons 3.8 2020-02-03 12:02:34 +01:00
Arjen de Korte
26f5bcbdbb geoip: adjust builder script for DBIP service
Maxmind databases are no longer libre.
2020-02-01 15:51:54 +01:00
Jan Engelhardt
061fc794b5 Xtables-addons 3.7 2019-12-01 11:30:53 +01:00
Jeremy Sowden
bf1ca298ae xt_geoip: fix in6_addr little-endian byte swapping
The Perl script that builds the GeoIP DBs uses inet_pton(3) to convert
the addresses to network byte order. This converts

  "1234:5678::90ab:cdef"

to:

  0x12 0x34 0x56 0x78 .. 0xcd 0xef, interpreted by an LE machine
  accessing this in uint32_t-sized chunks as
  8765:4321::fedc:ba09

The kernel module compares the addresses in packets with the ranges from
the DB in host byte order using binary search. It uses 32-bit swaps
when converting the addresses.

libxt_geoip, however, which the module uses to load the ranges from the
DB and convert them from NBO to HBO, uses 16-bit swaps to do so, and
this means that:

  1234:5678::90ab:cdef

becomes:

  4321:8765::ba09:fedc

Obviously, this is inconsistent with the kernel module and DB build
script and breaks the binary search.

Fixes: b91dbd03c7 ("geoip: store database in network byte order")
Reported-by: "Thomas B. Clark" <kernel@clark.bz>
Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2019-12-01 11:29:40 +01:00
Jeremy Sowden
6e5edc8372 build: update max. supported kernel version
The maximum supported version is reported as 5.3. Bump to 5.4.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2019-12-01 11:02:38 +01:00
Jan Engelhardt
7ad14b7150 Xtables-addons 3.6 2019-11-20 22:50:04 +01:00
Paolo Pisati
0cc51e6b35 build: add support for Linux 5.4 2019-11-20 22:45:18 +01:00
Jan Engelhardt
fa7bcbfb9b Xtables-addons 3.5 2019-09-10 11:14:13 +02:00
Jan Engelhardt
d86101e470 Merge MR-14 2019-09-10 11:12:30 +02:00
Jan Engelhardt
00114dea3d Xtables-addons 3.4 2019-09-06 10:43:58 +02:00
Jeremy Sowden
d4c2aac5f8 xt_pknock, xt_SYSRQ: do not set shash_desc::flags.
shash_desc::flags was removed from the kernel in 5.1.

That assignment was actually superfluous anyway, because crypto.desc
is zero-initialized when crypto is initialized (xt_pknock.c, ll.
110ff.).

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2019-09-06 10:34:36 +02:00
Jan Engelhardt
5622c5f024 treewide: replace skb_make_writable
skb_make_writable was removed in v5.3-rc1~140^2~370^2~1 .
Replace it with skb_ensure_writable that was introduced in
v3.19-rc1~118^2~153^2~2 .
2019-09-06 10:34:36 +02:00
Jan Engelhardt
358991306c xt_PROTO: style fixes 2019-09-06 10:34:35 +02:00
Jan Engelhardt
2bbdcb1d58 Merge MR-11 2019-09-06 10:34:29 +02:00
Jeremy Sowden
b14728691d xt_DHCPMAC: replace skb_make_writable with skb_ensure_writable
skb_make_writable was removed from the kernel in
v5.3-rc1~140^2~370^2~1 , and its callers were converted to use
skb_ensure_writable. Updated dhcpmac_tg() accordingly.

Signed-off-by: Jeremy Sowden <jeremy@azazel.net>
2019-09-06 10:28:37 +02:00
rantal
708f883635 add support for Linux 5.0 for DELUDE and TARPIT 2019-08-14 18:40:07 +00:00
Aron Xu
f822b8bc1b Add man page items for xt_PROTO
Signed-off-by: Aron Xu <happyaron.xu@gmail.com>
2019-05-07 03:31:24 +08:00
Aron Xu
4205900d9b Enable xt_PROTO in build system
Signed-off-by: Aron Xu <happyaron.xu@gmail.com>
2019-05-07 03:24:43 +08:00
Miao Wang
266638e41e Add xt_PROTO extension
Signed-off-by: Aron Xu <happyaron.xu@gmail.com>
2019-05-07 03:24:43 +08:00
Jan Engelhardt
ebcd176822 Xtables-addons 3.3 2019-03-07 10:24:08 +01:00
Jan Engelhardt
6b47d09a36 build: remove xa-download-more script
This mechanism has not seen any use in recent years (the "sources"
file is still the same) — drop it.
2019-03-07 10:20:05 +01:00
Jan Engelhardt
1849c47ae8 doc: update README and changelog 2019-03-07 10:18:43 +01:00
PGNet Dev
68d895f75c xt_SYSRQ: replace do_gettimeofday
Linux kernel commit v4.20-rc1-18-ge4b92b108c6c removed
do_gettimeofday in favor of ktime_get_real_ts64 introduced in
v3.16-rc5-59-gd6d29896c665 .
2019-03-07 10:07:28 +01:00
Jan Engelhardt
53b6b862cc Merge MR-10 2018-11-17 12:32:56 +01:00
Nataniel Santos
ed10cb9c17 xt_ACCOUNT: make table limit configurable
Add parameter option in module xt_ACCOUNT.ko to accept. Change in the
ACCOUN_MAX_TABLES table without the need to recompile the module.

References: MR-8
2018-11-17 12:13:00 +01:00
Jan Engelhardt
5903f4bcfc Xtables-addons 3.2 2018-09-07 15:04:28 +02:00
Jan Engelhardt
5e19871613 geoip: build tool should not rely on directory name
Fix this:

	GeoLite2-Country-CSV_20180905$ /usr/lib/xtables-addons/xt_geoip_build

	Use of uninitialized value $dir in concatenation (.) or string at
	/usr/lib/xtables-addons/xt_geoip_build line 59.
	Couldn't open list country names

Do not rely on any directory names (they change). Use the current
directory as the default source directory, similar to the older
xt_geoip_build (well, *.csv was passed as arguments).
2018-09-07 15:03:20 +02:00
Jan Engelhardt
30fb410003 Xtables-addons 3.1 2018-08-14 14:31:10 +02:00
Jan Engelhardt
3ea761a1ed build: add support for Linux 4.18 2018-08-14 14:29:30 +02:00
Jan Engelhardt
4603d3e0f4 build: add support for Linux 4.17 2018-08-14 14:23:04 +02:00
Jan Engelhardt
b0b2b5a74c build: fix 4.16 warning 2018-08-14 14:22:40 +02:00
Jan Engelhardt
082d42fb21 build: match documented and coded build requirements 2018-08-14 14:22:17 +02:00
Jan Engelhardt
b1f0e118a0 doc: add 3.0 headline in changelog 2018-08-14 14:15:07 +02:00
Philip Prindeville
56fba3ecff geoip: simplify handling table column names
Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2018-04-30 09:41:29 +02:00
Philip Prindeville
9057fb48f3 geoip: add database query tool for use with ipsets
Add a tool for retrieiving the IPv4 or IPv6 (or both!) CIDR ranges
for a given country, which can then be injected into an ipset if
one doesn't want to use (or have available) the xt_geoip extension.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2018-04-30 09:41:21 +02:00
Philip Prindeville
e19f91ddb4 geoip: update man page for xt_geoip_build
Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2018-04-30 09:40:54 +02:00
Philip Prindeville
256ac1a4f6 geoip: adapt to GeoLite2 database
Requires Net::CIDR::Lite for manipulating CIDR blocks, aggregation, etc.
since database is stored as subnet/mask pairs and may require compaction
into ranges (which can combine adjacent subnets).

We don't use Net::CIDR because it's a clunkier interface.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2018-04-30 09:40:51 +02:00
Philip Prindeville
b91dbd03c7 geoip: store database in network byte order
This allows a single database to be built and distributed as a
package that is accepted by both big- and little-endian hosts.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2018-02-19 01:42:29 +01:00
Jan Engelhardt
254c6926d3 Xtables-addons 3.0 2018-02-12 15:17:10 +01:00
Jan Engelhardt
2e78cf03a4 build: support for Linux 4.16 2018-02-12 15:10:47 +01:00
Jan Engelhardt
bf63a25a64 build: remove support for Linux 4.14 2018-02-12 15:09:52 +01:00
Jan Engelhardt
94656621ed build: remove support for Linux 4.13 2018-02-12 15:09:41 +01:00
Jan Engelhardt
95d4f9e113 build: remove support for Linux 4.12 2018-02-12 15:09:32 +01:00
Jan Engelhardt
123e1a14e9 build: remove support for Linux 4.11 2018-02-12 15:09:25 +01:00
Jan Engelhardt
f4f3f98609 build: remove support for Linux 4.10 2018-02-12 15:09:15 +01:00
Jan Engelhardt
9b1c7c1c04 build: remove support for Linux 4.9 2018-02-12 14:59:44 +01:00
Jan Engelhardt
ed8e496750 build: remove support for Linux 4.8 2018-02-12 14:57:21 +01:00
Jan Engelhardt
5339fcc65b build: remove support for Linux 4.7 2018-02-12 14:56:57 +01:00
Jan Engelhardt
2265c1b854 build: remove support for Linux 4.6 2018-02-12 14:56:40 +01:00
Jan Engelhardt
2c574f992d build: remove support for Linux 4.5 2018-02-12 14:56:24 +01:00
Jan Engelhardt
3a24468a68 build: remove support for Linux 4.4 2018-02-12 14:56:05 +01:00
Jan Engelhardt
7682cc8c34 build: remove support for Linux 4.3 2018-02-12 14:55:45 +01:00
Jan Engelhardt
215b3c5b12 build: remove support for Linux 4.2 2018-02-12 14:54:26 +01:00
Jan Engelhardt
4dbb36b723 build: remove support for Linux 4.1 2018-02-12 14:53:25 +01:00
Jan Engelhardt
10f951e61d build: remove support for Linux 4.0 2018-02-12 14:53:01 +01:00
Jan Engelhardt
a4c50ae405 build: remove support for Linux 3.19 2018-02-12 14:50:33 +01:00
Jan Engelhardt
38d89983ca build: remove support for Linux 3.18 2018-02-12 14:49:20 +01:00
Jan Engelhardt
25985650a9 build: remove support for Linux 3.17 2018-02-12 14:48:53 +01:00
Jan Engelhardt
4de9ff1505 build: remove support for Linux 3.16 2018-02-12 14:48:34 +01:00
Jan Engelhardt
46b7cf206b build: remove support for Linux 3.15 2018-02-12 14:47:58 +01:00
Jan Engelhardt
29d10e11fa build: remove support for Linux 3.14 2018-02-12 14:46:50 +01:00
Jan Engelhardt
60a26f1dea build: remove support for Linux 3.13 2018-02-12 14:45:55 +01:00
Jan Engelhardt
cdf90737be build: remove support for Linux 3.12 2018-02-12 14:45:41 +01:00
Jan Engelhardt
5713415014 build: remove support for Linux 3.11 2018-02-12 14:45:30 +01:00
Jan Engelhardt
230bc1f327 build: remove support for Linux 3.10 2018-02-12 14:45:14 +01:00
Jan Engelhardt
d360f5578c build: remove support for Linux 3.9 2018-02-12 14:45:00 +01:00
Jan Engelhardt
dd32060f6a build: remove support for Linux 3.8 2018-02-12 14:40:30 +01:00
Jan Engelhardt
d5eb4e586c build: remove support for Linux 3.7 2018-02-12 14:39:36 +01:00
Jan Engelhardt
1b4b4347c5 geoip: apply consistent style to xt_geoip_build 2018-02-12 13:58:18 +01:00
Philip Prindeville
2f37af43c5 geoip: selective endianness catalog generation 2018-02-12 13:56:48 +01:00
Jan Engelhardt
56e5970c64 xt_pknock: don't split function heads 2018-01-05 01:36:12 +01:00
Marcelo Henrique Cerri
2b76b68c65 build: support for Linux 4.15
Signed-off-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com>
2018-01-05 01:35:12 +01:00
Seth Forshee
d2eeac4c32 build: (additional) support for Linux 4.14
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
2018-01-05 01:35:07 +01:00
Jan Engelhardt
0e9037b000 Xtables-addons 2.14 2017-11-22 18:29:25 +01:00
Jan Engelhardt
0a6091b64a DNETMAP: remove NF_CT_ASSERT use
The hooks are already checked by the xtables core (due to struct
xt_target::hooks).
2017-11-22 18:27:36 +01:00
Jan Engelhardt
b565a85fb6 DNETMAP: fix write past end of buffer 2017-11-22 18:24:10 +01:00
Philip Prindeville
425a035959 xt_geoip: fix typo in error message
Make both instances of the same message (about invalid country codes)
be consistent with each other.  If you have scripts which capture and
collate error messages, then having consistent strings to match against
is a win.

Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
2017-11-02 21:14:00 -06:00
Jan Engelhardt
89c80f5981 DELUDE: fix PVSStudio reports
V560 A part of conditional expression is always true: !oth->rst.
2017-07-23 19:59:36 +02:00
Jan Engelhardt
8579fd2b3b ipp2p: fix PVSStudio reports
V666 Consider inspecting fourth argument of the function 'HX_memmem'.
It is possible that the value does not correspond with the length of
a string which was passed with the third argument.
2017-07-23 19:56:42 +02:00
Jan Engelhardt
0a836e9677 pknock: fix PVSStudio static analyzer reports
V595 The 'peer' pointer was utilized before it was verified against
nullptr.
2017-07-23 19:55:06 +02:00
Jan Engelhardt
90b0f3a51f Xtables-addons 2.13 2017-06-29 14:46:37 +02:00
Grzegorz Kuczyński
89d1b808b9 xt_condition: namespace support #2 2017-06-27 13:36:03 +02:00
Jan Engelhardt
c839e87bbb xt_geoip: check for allocation overflow 2017-06-26 22:03:53 +02:00
Jan Engelhardt
a587f9526d compat_xtables: use more accurate printf format for NIPQUAD
We never expect to emit values greater than 255 here, so use %hhu to
address more sprintf warnings.
2017-06-15 12:18:41 +02:00
Jan Engelhardt
1874fcd519 xt_DNETMAP: fix a buffer overflow
prefix_str was only 16 bytes, but the largest emitted string could be
"255.255.255.255/32" (19 bytes).

xt_DNETMAP.c: In function "dnetmap_tg_check":
compat_xtables.h:46:22: warning: "%u" directive writing between 1 and 10
bytes into a region of size between 0 and 8 [-Wformat-overflow=]
 # define NIPQUAD_FMT "%u.%u.%u.%u"
xt_DNETMAP.c:296:2: note: "sprintf" output between 10 and 27 bytes into
a destination of size 16
  sprintf(p->prefix_str, NIPQUAD_FMT "/%u", NIPQUAD(mr->min_addr.ip),
   33 - ffs(~(ip_min ^ ip_max)));
2017-06-15 12:15:48 +02:00
Jan Engelhardt
21ea7b76ec xt_LOGMARK: resolve new gcc7 warnings
xt_LOGMARK.c:56:32: warning: increment of a boolean expression [-Wbool-operation]
   printk("%s""SEEN_REPLY", prev++ ? "," : "");
xt_LOGMARK.c:58:29: warning: increment of a boolean expression [-Wbool-operation]
   printk("%s""ASSURED", prev++ ? "," : "");
xt_LOGMARK.c:60:31: warning: increment of a boolean expression [-Wbool-operation]
   printk("%s""CONFIRMED", prev++ ? "," : "");
2017-06-15 12:00:09 +02:00
Ralph Sennhauser
ee8da2b1ac build: support for Linux 4.12
As a result of commit cc41c84b7e7f ("netfilter: kill the fake untracked
conntrack objects") the helper nf_ct_is_untracked always returns false
and commit ab8bc7ed864b ("netfilter: remove nf_ct_is_untracked") removes
it all together.

Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
2017-06-15 11:57:23 +02:00
Grzegorz Kuczyński
19a4359368 xt_condition: add support for namespaces 2017-06-15 10:45:37 +02:00
Jan Engelhardt
1b379667d3 xt_psd: resolve compiler warning
xt_psd.c:53:0: warning: "HASH_SIZE" redefined
 #define HASH_SIZE   (1 << HASH_LOG)
linux-4.10.10/include/linux/hashtable.h:26:0:
note: this is the location of the previous definition
 #define HASH_SIZE(name) (ARRAY_SIZE(name))
2017-04-13 11:38:00 +02:00
81 changed files with 1630 additions and 1047 deletions

2
.gitignore vendored
View File

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

10
INSTALL
View File

@@ -12,16 +12,20 @@ in combination with the kernel's Kbuild system.
Supported configurations for this release Supported configurations for this release
========================================= =========================================
* iptables >= 1.4.5 * iptables >= 1.6.0
* kernel-devel >= 3.7 * kernel-devel >= 4.15
with prepared build/output directory with prepared build/output directory
- CONFIG_NF_CONNTRACK - CONFIG_NF_CONNTRACK
- CONFIG_NF_CONNTRACK_MARK enabled =y or as module (=m) - CONFIG_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-1.x if you need support for Linux < 3.7.
Use xtables-addons-2.x if you need support for Linux < 4.15.)
Note: xtables-addons regularly fails to build with patched-to-death
kernels like on RHEL or SLES because the API does not match
LINUX_KERNEL_VERSION anymore.
Selecting extensions Selecting extensions

View File

@@ -1,7 +1,7 @@
# -*- Makefile -*- # -*- Makefile -*-
ACLOCAL_AMFLAGS = -I m4 ACLOCAL_AMFLAGS = -I m4
SUBDIRS = extensions geoip SUBDIRS = extensions extensions/ACCOUNT extensions/pknock geoip
man_MANS := xtables-addons.8 man_MANS := xtables-addons.8

View File

@@ -40,4 +40,4 @@ targets.man: .manpages.lst ${wcman_targets}
$(call man_run,${wlist_targets}) $(call man_run,${wlist_targets})
clean: clean:
rm -f xtables-addons.8 matches.man targets.man rm -f xtables-addons.8 matches.man targets.man .manpages.lst

54
README
View File

@@ -1,57 +1,15 @@
Xtables-addons Xtables-addons
============== ==============
Xtables-addons is the proclaimed successor to patch-o-matic(-ng). It Xtables-addons is a set of extensions that were not accepted in the
contains extensions that were not accepted in the main Xtables Linux kernel and/or main Xtables/iptables package.
package.
Xtables-addons is different from patch-o-matic in that you do not It superseded the earlier patch-o-matic(-ng) package in that no
have to patch or recompile either kernel or Xtables(iptables). But patching and/or recompilation of either the kernel or
please see the INSTALL file for the minimum requirements of this Xtables/iptables is required. However, do see the INSTALL file for
package. the minimum requirements of Xtables-addons.
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], [2.12]) AC_INIT([xtables-addons], [3.18])
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.4.5]) PKG_CHECK_MODULES([libxtables], [xtables >= 1.6.0])
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],
@@ -57,12 +57,12 @@ if test -n "$kbuilddir"; 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 4 -o "$kmajor" -eq 4 -a "$kminor" -gt 10; then if test "$kmajor" -gt 5 -o "$kmajor" -eq 5 -a "$kminor" -gt 11; then
echo "WARNING: That kernel version is not officially supported yet. Continue at own luck."; echo "WARNING: That kernel version is not officially supported yet. Continue at own luck.";
elif test "$kmajor" -eq 4 -a "$kminor" -le 10; then elif test "$kmajor" -eq 5 -a "$kminor" -ge 0; then
:; :
elif test "$kmajor" -eq 3 -a "$kminor" -ge 7; then elif test "$kmajor" -eq 4 -a "$kminor" -ge 15; then
:; :
else else
echo "WARNING: That kernel version is not officially supported."; echo "WARNING: That kernel version is not officially supported.";
fi; fi;

View File

@@ -1,6 +1,135 @@
v3.18 (2021-03-11)
==================
- xt_pknock: fix a build failure on ARM 32-bit
HEAD
==== v3.17 (2021-02-28)
==================
- xt_pknock: cure a NULL deref
v3.16 (2021-02-24)
==================
- xt_pknock: build fix for ILP32 targets
v3.15 (2021-02-05)
==================
- xt_ECHO: support new function signature of security_skb_classify_flow
- xt_lscan: add --mirai option
- Support for Linux 5.11
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.
v3.13 (2020-11-20)
==================
- 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) v2.12 (2017-01-11)
@@ -109,5 +238,5 @@ Changes:
Enhancements: Enhancements:
- Support for Linux 3.7 - Support for Linux 3.7
If you want to use Xtables-addons with kernels older than 3.7, If you want to use Xtables-addons with kernels older than 4.15,
use the addons 1.x series (maintained but without new features). use the addons 2.x series.

View File

@@ -9,5 +9,6 @@ sbin_PROGRAMS = iptaccount
iptaccount_LDADD = libxt_ACCOUNT_cl.la iptaccount_LDADD = libxt_ACCOUNT_cl.la
lib_LTLIBRARIES = libxt_ACCOUNT_cl.la lib_LTLIBRARIES = libxt_ACCOUNT_cl.la
libxt_ACCOUNT_cl_la_LDFLAGS = -version-info 1:0:0
man_MANS = iptaccount.8 man_MANS = iptaccount.8

View File

@@ -34,7 +34,8 @@ 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
if ((ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE)) == NULL) { ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE);
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

@@ -7,10 +7,7 @@
* version 2.1 as published by the Free Software Foundation; * * version 2.1 as published by the Free Software Foundation; *
* * * *
***************************************************************************/ ***************************************************************************/
#pragma once
#ifndef _xt_ACCOUNT_cl_H
#define _xt_ACCOUNT_cl_H
#include <xt_ACCOUNT.h> #include <xt_ACCOUNT.h>
#define LIBXT_ACCOUNT_VERSION "1.3" #define LIBXT_ACCOUNT_VERSION "1.3"
@@ -23,9 +20,8 @@ struct ipt_ACCOUNT_context
int sockfd; int sockfd;
struct ipt_acc_handle_sockopt handle; struct ipt_acc_handle_sockopt handle;
unsigned int data_size; unsigned int data_size, pos;
void *data; void *data;
unsigned int pos;
char *error_str; char *error_str;
}; };
@@ -55,6 +51,3 @@ const char *ipt_ACCOUNT_get_next_name(struct ipt_ACCOUNT_context *ctx);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif

View File

@@ -28,6 +28,9 @@
#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/netns/generic.h>
@@ -40,6 +43,9 @@
#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
@@ -181,24 +187,22 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
{ {
unsigned int i; unsigned int i;
pr_debug("ACCOUNT: ipt_acc_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n", pr_debug("ACCOUNT: ipt_acc_table_insert: %s, %pI4/%pI4\n",
name, NIPQUAD(ip), NIPQUAD(netmask)); name, &ip, &netmask);
/* Look for existing table */ /* Look for existing table */
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) { for (i = 0; i < max_tables_limit; 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 - " pr_debug("ACCOUNT: Found existing slot: %d - %pI4/%pI4\n",
"%u.%u.%u.%u/%u.%u.%u.%u\n", i, i, &ipt_acc_tables[i].ip, &ipt_acc_tables[i].netmask);
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: %u.%u.%u.%u/%u.%u.%u.%u\n", "IP/netmask found: %pI4/%pI4\n",
name, NIPQUAD(ipt_acc_tables[i].ip), name, &ipt_acc_tables[i].ip,
NIPQUAD(ipt_acc_tables[i].netmask)); &ipt_acc_tables[i].netmask);
return -1; return -1;
} }
@@ -209,7 +213,7 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
} }
/* Insert new table */ /* Insert new table */
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) { for (i = 0; i < max_tables_limit; 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;
@@ -258,7 +262,7 @@ 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 ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES); "Please increase the \"max_tables_limit\" module parameter.\n", max_tables_limit);
return -1; return -1;
} }
@@ -299,7 +303,7 @@ 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 < ACCOUNT_MAX_TABLES; i++) { for (i = 0; i < max_tables_limit; i++) {
if (strncmp(ian->ipt_acc_tables[i].name, info->table_name, if (strncmp(ian->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);
@@ -337,9 +341,8 @@ 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: %u.%u.%u.%u/%u.%u.%u.%u " pr_debug("ACCOUNT: ipt_acc_depth0_insert: %pI4/%pI4 for net %pI4/%pI4,"
"for net %u.%u.%u.%u/%u.%u.%u.%u, size: %u\n", NIPQUAD(src_ip), " size: %u\n", &src_ip, &dst_ip, &net_ip, &netmask, size);
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 */
@@ -351,9 +354,8 @@ 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 %u.%u.%u.%u/%u.%u.%u.%u " pr_debug("ACCOUNT: Skipping packet %pI4/%pI4 for net %pI4/%pI4\n",
"for net %u.%u.%u.%u/%u.%u.%u.%u\n", NIPQUAD(src_ip), &src_ip, &dst_ip, &net_ip, &netmask);
NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask));
return; return;
} }
@@ -392,11 +394,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: %u.%u.%u.%u\n", NIPQUAD(src_ip)); pr_debug("ACCOUNT: New src_ip: %pI4\n", &src_ip);
++*itemcount; ++*itemcount;
} }
if (is_dst_new_ip) { if (is_dst_new_ip) {
pr_debug("ACCOUNT: New dst_ip: %u.%u.%u.%u\n", NIPQUAD(dst_ip)); pr_debug("ACCOUNT: New dst_ip: %pI4\n", &dst_ip);
++*itemcount; ++*itemcount;
} }
} }
@@ -482,16 +484,7 @@ 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 *skb, const struct xt_action_param *par) ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
{ {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
struct ipt_acc_net *ian = net_generic(par->state->net, ipt_acc_net_id); struct ipt_acc_net *ian = net_generic(par->state->net, ipt_acc_net_id);
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
struct ipt_acc_net *ian = net_generic(par->net, ipt_acc_net_id);
#else
struct net *net = dev_net(par->in ? par->in : par->out);
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
#endif
#endif
struct ipt_acc_table *ipt_acc_tables = ian->ipt_acc_tables; 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;
@@ -504,8 +497,7 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
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 %u.%u.%u.%u/%u.%u.%u.%u\n", info->table_nr, "IPs %pI4/%pI4\n", info->table_nr, &src_ip, &dst_ip);
NIPQUAD(src_ip), NIPQUAD(dst_ip));
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ian->ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
@@ -544,10 +536,8 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
return XT_CONTINUE; return XT_CONTINUE;
} }
printk("ACCOUNT: ipt_acc_target: Unable to process packet. " printk("ACCOUNT: ipt_acc_target: Unable to process packet. Table id "
"Table id %u. IPs %u.%u.%u.%u/%u.%u.%u.%u\n", "%u. IPs %pI4/%pI4\n", info->table_nr, &src_ip, &dst_ip);
info->table_nr, NIPQUAD(src_ip), NIPQUAD(dst_ip));
spin_unlock_bh(&ian->ipt_acc_lock); spin_unlock_bh(&ian->ipt_acc_lock);
return XT_CONTINUE; return XT_CONTINUE;
} }
@@ -613,12 +603,12 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
int table_nr = -1; int table_nr = -1;
uint8_t depth; uint8_t depth;
for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++) for (table_nr = 0; table_nr < max_tables_limit; 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 == ACCOUNT_MAX_TABLES) { if (table_nr == max_tables_limit) {
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;
@@ -630,7 +620,8 @@ 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 */
if ((dest->data = ipt_acc_zalloc_page()) == NULL) { dest->data = ipt_acc_zalloc_page();
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;
@@ -716,19 +707,20 @@ static int ipt_acc_handle_prepare_read_flush(struct ipt_acc_table *ipt_acc_table
int table_nr; int table_nr;
void *new_data_page; void *new_data_page;
for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++) for (table_nr = 0; table_nr < max_tables_limit; 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 == ACCOUNT_MAX_TABLES) { if (table_nr == max_tables_limit) {
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 */
if (!(new_data_page = ipt_acc_zalloc_page())) { 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;
@@ -885,7 +877,12 @@ 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,
void *user, unsigned int len) #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
void *user,
#else
sockptr_t arg,
#endif
unsigned int len)
{ {
struct net *net = sock_net(sk); struct net *net = sock_net(sk);
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id); struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
@@ -904,7 +901,12 @@ static int ipt_acc_set_ctl(struct sock *sk, int cmd,
break; break;
} }
if (copy_from_user(&handle, user, len)) { #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
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;
@@ -972,7 +974,8 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
/* Allocate a userspace handle */ /* Allocate a userspace handle */
down(&ian->ipt_acc_userspace_mutex); down(&ian->ipt_acc_userspace_mutex);
if ((handle.handle_nr = ipt_acc_handle_find_slot(ian->ipt_acc_handles)) == -1) { handle.handle_nr = ipt_acc_handle_find_slot(ian->ipt_acc_handles);
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(&ian->ipt_acc_userspace_mutex);
return -EINVAL; return -EINVAL;
@@ -1061,7 +1064,7 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
spin_lock_bh(&ian->ipt_acc_lock); spin_lock_bh(&ian->ipt_acc_lock);
/* Determine size of table names */ /* Determine size of table names */
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) { for (i = 0; i < max_tables_limit; i++) {
if (ian->ipt_acc_tables[i].name[0] != 0) if (ian->ipt_acc_tables[i].name[0] != 0)
size += strlen(ian->ipt_acc_tables[i].name) + 1; size += strlen(ian->ipt_acc_tables[i].name) + 1;
} }
@@ -1076,7 +1079,7 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
} }
/* Copy table names to userspace */ /* Copy table names to userspace */
tnames = ian->ipt_acc_tmpbuf; tnames = ian->ipt_acc_tmpbuf;
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) { for (i = 0; i < max_tables_limit; i++) {
if (ian->ipt_acc_tables[i].name[0] != 0) { if (ian->ipt_acc_tables[i].name[0] != 0) {
name_len = strlen(ian->ipt_acc_tables[i].name) + 1; name_len = strlen(ian->ipt_acc_tables[i].name) + 1;
memcpy(tnames, ian->ipt_acc_tables[i].name, name_len); memcpy(tnames, ian->ipt_acc_tables[i].name, name_len);
@@ -1109,7 +1112,7 @@ static int __net_init ipt_acc_net_init(struct net *net)
memset(ian, 0, sizeof(*ian)); memset(ian, 0, sizeof(*ian));
sema_init(&ian->ipt_acc_userspace_mutex, 1); sema_init(&ian->ipt_acc_userspace_mutex, 1);
ian->ipt_acc_tables = kcalloc(ACCOUNT_MAX_TABLES, ian->ipt_acc_tables = kcalloc(max_tables_limit,
sizeof(struct ipt_acc_table), GFP_KERNEL); sizeof(struct ipt_acc_table), GFP_KERNEL);
if (ian->ipt_acc_tables == NULL) { if (ian->ipt_acc_tables == NULL) {
printk("ACCOUNT: Out of memory allocating account_tables structure"); printk("ACCOUNT: Out of memory allocating account_tables structure");

View File

@@ -7,9 +7,7 @@
* version 2 as published by the Free Software Foundation; * * version 2 as published by the Free Software Foundation; *
* * * *
***************************************************************************/ ***************************************************************************/
#pragma once
#ifndef _IPT_ACCOUNT_H
#define _IPT_ACCOUNT_H
/* /*
* Socket option interface shared between kernel (xt_ACCOUNT) and userspace * Socket option interface shared between kernel (xt_ACCOUNT) and userspace
@@ -34,14 +32,12 @@
#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
/* Structure for the userspace part of ipt_ACCOUNT */ /* Structure for the userspace part of ipt_ACCOUNT */
struct ipt_acc_info { struct ipt_acc_info {
__be32 net_ip; __be32 net_ip, net_mask;
__be32 net_mask;
char table_name[ACCOUNT_TABLE_NAME_LEN]; char table_name[ACCOUNT_TABLE_NAME_LEN];
int32_t table_nr; int32_t table_nr;
}; };
@@ -60,10 +56,5 @@ struct ipt_acc_handle_sockopt {
*/ */
struct ipt_acc_handle_ip { struct ipt_acc_handle_ip {
__be32 ip, __dummy; __be32 ip, __dummy;
uint64_t src_packets; uint64_t src_packets, src_bytes, dst_packets, dst_bytes;
uint64_t src_bytes;
uint64_t dst_packets;
uint64_t dst_bytes;
}; };
#endif /* _IPT_ACCOUNT_H */

View File

@@ -13,6 +13,7 @@ obj-${build_DNETMAP} += xt_DNETMAP.o
obj-${build_ECHO} += xt_ECHO.o obj-${build_ECHO} += xt_ECHO.o
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_condition} += xt_condition.o obj-${build_condition} += xt_condition.o

View File

@@ -8,6 +8,7 @@ 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_condition} += libxt_condition.so obj-${build_condition} += libxt_condition.so

View File

@@ -1,6 +1,4 @@
#ifndef COMPAT_SKBUFF_H #pragma once
#define COMPAT_SKBUFF_H 1
struct tcphdr; struct tcphdr;
struct udphdr; struct udphdr;
@@ -12,5 +10,3 @@ struct udphdr;
#else #else
# define skb_secmark(skb) 0 # define skb_secmark(skb) 0
#endif #endif
#endif /* COMPAT_SKBUFF_H */

View File

@@ -1,12 +1,8 @@
/* /*
* Userspace-level compat hacks * Userspace-level compat hacks
*/ */
#ifndef _XTABLES_COMPAT_USER_H #pragma once
#define _XTABLES_COMPAT_USER_H 1
/* linux-glibc-devel 2.6.34 header screwup */ /* linux-glibc-devel 2.6.34 header screwup */
#ifndef ALIGN #ifndef ALIGN
# define ALIGN(s, n) (((s) + ((n) - 1)) & ~((n) - 1)) # define ALIGN(s, n) (((s) + ((n) - 1)) & ~((n) - 1))
#endif #endif
#endif /* _XTABLES_COMPAT_USER_H */

View File

@@ -23,7 +23,6 @@
#include <net/route.h> #include <net/route.h>
#include <linux/export.h> #include <linux/export.h>
#include "compat_skbuff.h" #include "compat_skbuff.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

View File

@@ -1,19 +1,12 @@
#ifndef _XTABLES_COMPAT_H #pragma once
#define _XTABLES_COMPAT_H 1
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/version.h> #include <linux/version.h>
#include "compat_skbuff.h" #include "compat_skbuff.h"
#include "compat_xtnu.h"
#define DEBUGP Use__pr_debug__instead #define DEBUGP Use__pr_debug__instead
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
# warning Kernels below 3.7 not supported. # warning Kernels below 4.15 not supported.
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
# define prandom_u32() random32()
#endif #endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -25,72 +18,31 @@
# warning You need CONFIG_NF_CONNTRACK. # warning You need CONFIG_NF_CONNTRACK.
#endif #endif
#if !defined(NIP6) && !defined(NIP6_FMT) #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \
# define NIP6(addr) \ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 9) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) || \
ntohs((addr).s6_addr16[0]), \ LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 78) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) || \
ntohs((addr).s6_addr16[1]), \ LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 158) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
ntohs((addr).s6_addr16[2]), \ #else
ntohs((addr).s6_addr16[3]), \ # define ip_route_me_harder(xnet, xsk, xskb, xaddrtype) ip_route_me_harder((xnet), (xskb), (xaddrtype))
ntohs((addr).s6_addr16[4]), \ # define ip6_route_me_harder(xnet, xsk, xskb) ip6_route_me_harder((xnet), (xskb))
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, 9, 0)
static inline struct inode *file_inode(struct file *f)
{
return f->f_path.dentry->d_inode;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
static inline void proc_set_user(struct proc_dir_entry *de,
typeof(de->uid) uid, typeof(de->gid) gid)
{
de->uid = uid;
de->gid = gid;
}
static inline void *PDE_DATA(struct inode *inode)
{
return PDE(inode)->data;
}
static inline void proc_remove(struct proc_dir_entry *de)
{
if (de != NULL)
remove_proc_entry(de->name, de->parent);
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
# define ip6_local_out(xnet, xsk, xskb) ip6_local_out(xskb)
# define ip6_route_me_harder(xnet, xskb) ip6_route_me_harder(xskb)
# define ip_local_out(xnet, xsk, xskb) ip_local_out(xskb)
# define ip_route_me_harder(xnet, xskb, xaddrtype) ip_route_me_harder((xskb), (xaddrtype))
#endif #endif
static inline struct net *par_net(const struct xt_action_param *par) static inline struct net *par_net(const struct xt_action_param *par)
{ {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
return par->state->net; return par->state->net;
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
return par->net;
#else
return dev_net((par->in != NULL) ? par->in : par->out);
#endif
#endif
} }
#endif /* _XTABLES_COMPAT_H */ #ifndef NF_CT_ASSERT
# define NF_CT_ASSERT(x) WARN_ON(!(x))
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
# define proc_ops file_operations
# define proc_open open
# define proc_read read
# define proc_write write
# define proc_lseek llseek
# define proc_release release
#endif
extern void *HX_memmem(const void *, size_t, const void *, size_t);

View File

@@ -1,67 +0,0 @@
#ifndef _COMPAT_XTNU_H
#define _COMPAT_XTNU_H 1
#include <linux/netfilter/x_tables.h>
struct module;
struct sk_buff;
struct xtnu_match {
/*
* Making it smaller by sizeof(void *) on purpose to catch
* lossy translation, if any.
*/
char name[sizeof(((struct xt_match *)NULL)->name) - 1 - sizeof(void *)];
uint8_t revision;
bool (*match)(const struct sk_buff *, struct xt_action_param *);
int (*checkentry)(const struct xt_mtchk_param *);
void (*destroy)(const struct xt_mtdtor_param *);
struct module *me;
const char *table;
unsigned int matchsize, hooks;
unsigned short proto, family;
void *__compat_match;
};
struct xtnu_target {
char name[sizeof(((struct xt_target *)NULL)->name) - 1 - sizeof(void *)];
uint8_t revision;
unsigned int (*target)(struct sk_buff **,
const struct xt_action_param *);
int (*checkentry)(const struct xt_tgchk_param *);
void (*destroy)(const struct xt_tgdtor_param *);
struct module *me;
const char *table;
unsigned int targetsize, hooks;
unsigned short proto, family;
void *__compat_target;
};
static inline struct xtnu_match *xtcompat_numatch(const struct xt_match *m)
{
void *q;
memcpy(&q, m->name + sizeof(m->name) - sizeof(void *), sizeof(void *));
return q;
}
static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
{
void *q;
memcpy(&q, t->name + sizeof(t->name) - sizeof(void *), sizeof(void *));
return q;
}
extern int xtnu_register_match(struct xtnu_match *);
extern void xtnu_unregister_match(struct xtnu_match *);
extern int xtnu_register_matches(struct xtnu_match *, unsigned int);
extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int);
extern int xtnu_register_target(struct xtnu_target *);
extern void xtnu_unregister_target(struct xtnu_target *);
extern int xtnu_register_targets(struct xtnu_target *, unsigned int);
extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int);
extern void *HX_memmem(const void *, size_t, const void *, size_t);
#endif /* _COMPAT_XTNU_H */

View File

@@ -46,7 +46,7 @@ Contains the binding table for the given \fIsubnet/mask\fP. Each line contains
\fBprenat address\fR, \fBpostnat address\fR, \fBttl\fR (seconds until the entry \fBprenat address\fR, \fBpostnat address\fR, \fBttl\fR (seconds until the entry
times out), \fBlasthit\fR (last hit to the entry in seconds relative to system times out), \fBlasthit\fR (last hit to the entry in seconds relative to system
boot time). Please note that the \fBttl\fR and \fBlasthit\fR entries contain an boot time). Please note that the \fBttl\fR and \fBlasthit\fR entries contain an
'\fBS\fR' in case of a 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 a given \fIsubnet/mask\fP. The line contains four

105
extensions/libxt_PROTO.c Normal file
View File

@@ -0,0 +1,105 @@
/*
* 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

@@ -0,0 +1,30 @@
.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

@@ -49,30 +49,44 @@ 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];
int fd; #if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int n;
#endif
/* Use simple integer vector files */ /* Use simple integer vector files */
if (nfproto == NFPROTO_IPV6) { if (nfproto == NFPROTO_IPV6)
#if __BYTE_ORDER == _BIG_ENDIAN snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/%s.iv6", code);
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv6", code); else
#else snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/%s.iv4", code);
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
}
if ((fd = open(buf, O_RDONLY)) < 0) { int fd = open(buf, O_RDONLY);
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");
} }
@@ -98,6 +112,25 @@ 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;
} }
@@ -135,7 +168,7 @@ check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
cc[i] = toupper(cc[i]); cc[i] = toupper(cc[i]);
else else
xtables_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: invalid country code '%s'", cc); "geoip: invalid country code '%s'", cc);
/* Convert chars into a single 16 bit integer. /* Convert chars into a single 16 bit integer.
* FIXME: This assumes that a country code is * FIXME: This assumes that a country code is
@@ -170,7 +203,8 @@ 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';
if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) { cctmp = check_geoip_cc(cp, cc, count);
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,

View File

@@ -24,6 +24,7 @@ static const struct option lscan_mt_opts[] = {
{.name = "synscan", .has_arg = false, .val = 's'}, {.name = "synscan", .has_arg = false, .val = 's'},
{.name = "cnscan", .has_arg = false, .val = 'c'}, {.name = "cnscan", .has_arg = false, .val = 'c'},
{.name = "grscan", .has_arg = false, .val = 'g'}, {.name = "grscan", .has_arg = false, .val = 'g'},
{.name = "mirai", .has_arg = false, .val = 'm'},
{NULL}, {NULL},
}; };
@@ -35,7 +36,8 @@ static void lscan_mt_help(void)
" --stealth Match TCP Stealth packets\n" " --stealth Match TCP Stealth packets\n"
" --synscan Match TCP SYN scans\n" " --synscan Match TCP SYN scans\n"
" --cnscan Match TCP Connect scans\n" " --cnscan Match TCP Connect scans\n"
" --grscan Match Banner Grabbing scans\n"); " --grscan Match Banner Grabbing scans\n"
" --mirai Match TCP scan with ISN = dest. IP\n");
} }
static int lscan_mt_parse(int c, char **argv, int invert, static int lscan_mt_parse(int c, char **argv, int invert,
@@ -45,16 +47,19 @@ static int lscan_mt_parse(int c, char **argv, int invert,
switch (c) { switch (c) {
case 'c': case 'c':
info->match_cn = true; info->match_fl3 |= LSCAN_FL3_CN;
return true; return true;
case 'g': case 'g':
info->match_gr = true; info->match_fl4 |= LSCAN_FL4_GR;
return true;
case 'm':
info->match_fl1 |= LSCAN_FL1_MIRAI;
return true; return true;
case 's': case 's':
info->match_syn = true; info->match_fl2 |= LSCAN_FL2_SYN;
return true; return true;
case 'x': case 'x':
info->match_stealth = true; info->match_fl1 |= LSCAN_FL1_STEALTH;
return true; return true;
} }
return false; return false;
@@ -68,14 +73,16 @@ 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);
if (info->match_stealth) if (info->match_fl1 & LSCAN_FL1_STEALTH)
printf(" --stealth "); printf(" --stealth ");
if (info->match_syn) if (info->match_fl2 & LSCAN_FL2_SYN)
printf(" --synscan "); printf(" --synscan ");
if (info->match_cn) if (info->match_fl3 & LSCAN_FL3_CN)
printf(" --cnscan "); printf(" --cnscan ");
if (info->match_gr) if (info->match_fl4 & LSCAN_FL4_GR)
printf(" --grscan "); printf(" --grscan ");
if (info->match_fl1 & LSCAN_FL1_MIRAI)
printf(" --mirai ");
} }
static void lscan_mt_print(const void *ip, static void lscan_mt_print(const void *ip,

View File

@@ -27,6 +27,11 @@ warranted single-direction data flows, usually bulk data transfers such as
FTP DATA connections or IRC DCC. Grab Scan Detection should only be used on FTP DATA connections or IRC DCC. Grab Scan Detection should only be used on
ports where a protocol runs that is guaranteed to do a bidirectional exchange ports where a protocol runs that is guaranteed to do a bidirectional exchange
of bytes. of bytes.
.TP
\fB\-\-mirai\fP
Match if the TCP ISN is equal to the IPv4 destination address; this is used
by the devices in the Mirai botnet as a form of TCP SYN scan, so you will
have to explicitly specify --syn for the rule.
.PP .PP
NOTE: Some clients (Windows XP for example) may do what looks like a SYN scan, NOTE: Some clients (Windows XP for example) may do what looks like a SYN scan,
so be advised to carefully use xt_lscan in conjunction with blocking rules, so be advised to carefully use xt_lscan in conjunction with blocking rules,

View File

@@ -70,7 +70,7 @@ quota_mt2_parse(int c, char **argv, int invert, unsigned int *flags,
/* zero termination done on behalf of the kernel module */ /* zero termination done on behalf of the kernel module */
xtables_param_act(XTF_ONLY_ONCE, "quota", "--name", *flags & FL_NAME); xtables_param_act(XTF_ONLY_ONCE, "quota", "--name", *flags & FL_NAME);
xtables_param_act(XTF_NO_INVERT, "quota", "--name", invert); xtables_param_act(XTF_NO_INVERT, "quota", "--name", invert);
strncpy(info->name, optarg, sizeof(info->name)); snprintf(info->name, sizeof(info->name), "%s", optarg);
*flags |= FL_NAME; *flags |= FL_NAME;
return true; return true;
case 'p': case 'p':

View File

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

View File

@@ -11,7 +11,6 @@
#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>
@@ -34,18 +33,23 @@ static const struct option pknock_mt_opts[] = {
static void pknock_mt_help(void) static void pknock_mt_help(void)
{ {
printf("pknock match options:\n" printf("pknock match options:\n"
" --knockports port[,port,port,...] " " --knockports port[,port[,port[,...]]]\n"
"Matches destination port(s).\n" "\t\t\t\tMatches destination port(s).\n"
" --time seconds\n" " --time seconds "
"Max allowed time between knocks.\n" "Max allowed time between knocks.\n"
" --autoclose minutes\n" " --autoclose minutes "
"Time after which to automatically close opened\n" "Time after which to automatically close opened\n"
"\t\t\t\t\tport(s).\n" "\t\t\t\tport(s).\n"
" --strict " " --name rule_name "
"Knocks sequence must be exact.\n"
" --name rule_name "
"Rule name.\n" "Rule name.\n"
" --checkip " " --opensecret secret "
"(UDP only) Secret to activate the rule.\n"
" --closesecret secret "
"(UDP only) Secret to deactivate the\n"
"\t\t\t\trule.\n"
" --strict "
"Knocks sequence must be exact.\n"
" --checkip "
"Matches if the source ip is in the list.\n" "Matches if the source ip is in the list.\n"
); );
} }
@@ -70,7 +74,6 @@ 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;
} }
@@ -91,12 +94,11 @@ 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.");
if ((proto = proto_to_name(pnum)) != NULL) const char *proto = proto_to_name(pnum);
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'");
@@ -123,7 +125,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;
#if DEBUG #ifdef DEBUG
printf("ports_count: %d\n", info->ports_count); printf("ports_count: %d\n", info->ports_count);
#endif #endif
break; break;
@@ -162,7 +164,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;
#if DEBUG #ifdef DEBUG
printf("info->rule_name: %s\n", info->rule_name); printf("info->rule_name: %s\n", info->rule_name);
#endif #endif
break; break;
@@ -213,7 +215,6 @@ __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;
} }
@@ -267,7 +268,7 @@ static void pknock_mt_check(unsigned int flags)
} }
static void pknock_mt_print(const void *ip, static void pknock_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric) const struct xt_entry_match *match, int numeric)
{ {
const struct xt_pknock_mtinfo *info = (void *)match->data; const struct xt_pknock_mtinfo *info = (void *)match->data;
int i; int i;

View File

@@ -0,0 +1,18 @@
.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,85 +7,94 @@
#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 GROUP 1 #define DEFAULT_GROUP_ID 1
#define MIN_GROUP_ID DEFAULT_GROUP_ID
#define MAX_GROUP_ID \
(sizeof((struct sockaddr_nl){0}.nl_groups) * CHAR_BIT)
static struct sockaddr_nl src_addr, dest_addr; int main(int argc, char **argv)
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;
int group = GROUP; unsigned int group_id = DEFAULT_GROUP_ID;
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;
int buf_size; if (argc > 2) {
char *prog = strdup(argv[0]);
if (prog == NULL) {
perror("strdup()");
} else {
fprintf(stderr, "%s [ group-id ]\n", basename(prog));
free(prog);
}
exit(EXIT_FAILURE);
}
const char *ip; if (argc == 2) {
char ipbuf[48]; long n;
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()");
return 1; exit(EXIT_FAILURE);
} }
memset(&src_addr, 0, sizeof(src_addr)); local_addr.nl_groups = 1U << (group_id - 1);
src_addr.nl_family = AF_NETLINK; status = bind(sock_fd, (struct sockaddr *)&local_addr, sizeof(local_addr));
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()");
return 1; goto err_close_sock;
} }
memset(&dest_addr, 0, sizeof(dest_addr)); nlmsg_size = NLMSG_SPACE(sizeof(*cn_msg) + sizeof(*pknock_msg));
dest_addr.nl_family = AF_NETLINK; nlmsg = malloc(nlmsg_size);
dest_addr.nl_pid = 0; if (!nlmsg) {
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()");
return 1; goto err_close_sock;
} }
addrlen = sizeof(dest_addr);
while(1) { while(1) {
const char *ip;
char ipbuf[INET_ADDRSTRLEN];
memset(buf, 0, buf_size); memset(nlmsg, 0, nlmsg_size);
status = recv(sock_fd, nlmsg, nlmsg_size, 0);
status = recvfrom(sock_fd, buf, buf_size, 0, (struct sockaddr *)&dest_addr, &addrlen); if (status < 0) {
perror("recv()");
if (status <= 0) { goto err_free_msg;
perror("recvfrom()");
return 1;
} }
if (status == 0)
nlmsg = (struct xt_pknock_nl_msg *) (buf + sizeof(struct cn_msg) + sizeof(struct nlmsghdr)); break;
cn_msg = NLMSG_DATA(nlmsg);
ip = inet_ntop(AF_INET, &nlmsg->peer_ip, ipbuf, sizeof(ipbuf)); pknock_msg = (struct xt_pknock_nl_msg *)(cn_msg->data);
printf("rule_name: %s - ip %s\n", nlmsg->rule_name, ip); ip = inet_ntop(AF_INET, &pknock_msg->peer_ip, ipbuf, sizeof(ipbuf));
printf("rule_name: %s - ip %s\n", pknock_msg->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

@@ -90,21 +90,15 @@ 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);
static struct { static struct {
@@ -159,7 +153,6 @@ 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;
} }
@@ -191,10 +184,8 @@ pknock_seq_start(struct seq_file *s, loff_t *pos)
const struct xt_pknock_rule *rule = s->private; const struct xt_pknock_rule *rule = s->private;
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;
} }
@@ -212,7 +203,6 @@ pknock_seq_next(struct seq_file *s, void *v, loff_t *pos)
++*pos; ++*pos;
if (*pos >= peer_hashsize) if (*pos >= peer_hashsize)
return NULL; return NULL;
return rule->peer_head + *pos; return rule->peer_head + *pos;
} }
@@ -238,13 +228,11 @@ 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 xt_pknock_rule *rule = s->private;
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));
@@ -259,12 +247,11 @@ pknock_seq_show(struct seq_file *s, void *v)
seq_printf(s, "expir_time=%lu [secs] ", time); seq_printf(s, "expir_time=%lu [secs] ", time);
} }
if (peer->status == ST_ALLOWED && rule->autoclose_time != 0) { if (peer->status == ST_ALLOWED && rule->autoclose_time != 0) {
unsigned long x = ktime_get_seconds();
unsigned long y = peer->login_sec + rule->autoclose_time * 60;
time = 0; time = 0;
if (time_before(get_seconds(), peer->login_sec + if (time_before(x, y))
rule->autoclose_time * 60)) time = y - x;
time = peer->login_sec +
rule->autoclose_time * 60 -
get_seconds();
seq_printf(s, "autoclose_time=%lu [secs] ", time); seq_printf(s, "autoclose_time=%lu [secs] ", time);
} }
seq_printf(s, "\n"); seq_printf(s, "\n");
@@ -295,12 +282,11 @@ pknock_proc_open(struct inode *inode, struct file *file)
return ret; return ret;
} }
static const struct file_operations pknock_proc_ops = { static const struct proc_ops pknock_proc_ops = {
.owner = THIS_MODULE, .proc_open = pknock_proc_open,
.open = pknock_proc_open, .proc_read = seq_read,
.read = seq_read, .proc_lseek = seq_lseek,
.llseek = seq_lseek, .proc_release = seq_release,
.release = seq_release
}; };
/** /**
@@ -312,7 +298,6 @@ 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);
} }
@@ -326,8 +311,12 @@ static void update_rule_gc_timer(struct xt_pknock_rule *rule)
static inline bool static inline bool
autoclose_time_passed(const struct peer *peer, unsigned int autoclose_time) autoclose_time_passed(const struct peer *peer, unsigned int autoclose_time)
{ {
return peer != NULL && autoclose_time != 0 && time_after(get_seconds(), unsigned long x, y;
peer->login_sec + autoclose_time * 60); if (peer == NULL || autoclose_time == 0)
return false;
x = ktime_get_seconds();
y = peer->login_sec + autoclose_time * 60;
return time_after(x, y);
} }
/** /**
@@ -349,7 +338,12 @@ is_interknock_time_exceeded(const struct peer *peer, unsigned int max_time)
static inline bool static inline bool
has_logged_during_this_minute(const struct peer *peer) has_logged_during_this_minute(const struct peer *peer)
{ {
return peer != NULL && peer->login_sec / 60 == get_seconds() / 60; uint64_t x, y;
if (peer == NULL)
return 0;
x = ktime_get_seconds();
y = peer->login_sec;
return do_div(y, 60) == do_div(x, 60);
} }
/** /**
@@ -357,11 +351,10 @@ has_logged_during_this_minute(const struct peer *peer)
* *
* @r: rule * @r: rule
*/ */
static void static void peer_gc(struct timer_list *tl)
peer_gc(unsigned long r)
{ {
unsigned int i; unsigned int i;
struct xt_pknock_rule *rule = (struct xt_pknock_rule *)r; struct xt_pknock_rule *rule = from_timer(rule, tl, timer);
struct peer *peer; struct peer *peer;
struct list_head *pos, *n; struct list_head *pos, *n;
@@ -435,7 +428,6 @@ 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;
@@ -444,7 +436,6 @@ 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",
@@ -452,27 +443,20 @@ add_rule(struct xt_pknock_mtinfo *info)
return true; return true;
} }
rule = kmalloc(sizeof(*rule), GFP_KERNEL); rule = kzalloc(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);
init_timer(&rule->timer);
rule->timer.function = peer_gc;
rule->timer.data = (unsigned long)rule;
rule->status_proc = proc_create_data(info->rule_name, 0, pde, rule->status_proc = proc_create_data(info->rule_name, 0, pde,
&pknock_proc_ops, rule); &pknock_proc_ops, rule);
if (rule->status_proc == NULL) if (rule->status_proc == NULL)
@@ -508,7 +492,6 @@ 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--;
@@ -534,7 +517,6 @@ 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);
@@ -554,7 +536,6 @@ 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)
@@ -588,14 +569,12 @@ 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;
} }
@@ -619,9 +598,10 @@ 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);
} }
/** /**
@@ -682,29 +662,19 @@ 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 defined(CONFIG_CONNECTOR) || defined(CONFIG_CONNECTOR_MODULE) #if IS_ENABLED(CONFIG_CONNECTOR)
struct cn_msg *m; struct cn_msg *m;
struct xt_pknock_nl_msg msg; struct xt_pknock_nl_msg msg;
m = kmalloc(sizeof(*m) + sizeof(msg), GFP_ATOMIC); m = kzalloc(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);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
cn_netlink_send(m, 0, multicast_group, GFP_ATOMIC); cn_netlink_send(m, 0, multicast_group, GFP_ATOMIC);
#else
cn_netlink_send(m, multicast_group, GFP_ATOMIC);
#endif
kfree(m); kfree(m);
#endif #endif
return true; return true;
@@ -742,11 +712,12 @@ 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 char result[64] = ""; // 64 bytes * 8 = 512 bits
char *hexresult; char *hexresult;
unsigned int hexa_size; unsigned int hexa_size;
int ret; int ret;
bool fret = false; bool fret = false;
uint64_t x;
unsigned int epoch_min; unsigned int epoch_min;
if (payload_len == 0) if (payload_len == 0)
@@ -762,15 +733,11 @@ 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;
x = ktime_get_seconds();
memset(result, 0, sizeof(result)); epoch_min = do_div(x, 60);
memset(hexresult, 0, hexa_size);
epoch_min = get_seconds() / 60;
ret = crypto_shash_setkey(crypto.tfm, secret, secret_len); ret = crypto_shash_setkey(crypto.tfm, secret, secret_len);
if (ret != 0) { if (ret != 0) {
@@ -789,14 +756,11 @@ has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
printk("crypto_shash_update/final() failed ret=%d\n", ret); printk("crypto_shash_update/final() 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;
@@ -828,7 +792,6 @@ pass_security(struct peer *peer, const struct xt_pknock_mtinfo *info,
info->open_secret_len, peer->ip, info->open_secret_len, peer->ip,
payload, payload_len)) payload, payload_len))
return true; return true;
return false; return false;
} }
@@ -855,7 +818,6 @@ 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;
} }
@@ -863,25 +825,20 @@ 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 = ktime_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;
} }
@@ -958,7 +915,6 @@ 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:
hdr_len = (iph->ihl * 4) + sizeof(struct udphdr); hdr_len = (iph->ihl * 4) + sizeof(struct udphdr);
@@ -980,12 +936,10 @@ 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;
@@ -993,7 +947,8 @@ 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) {
if ((ret = is_allowed(peer))) { 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))
@@ -1011,10 +966,8 @@ 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);
} }
@@ -1034,7 +987,7 @@ out:
return ret; return ret;
} }
#define RETURN_ERR(err) do { printk(KERN_ERR PKNOCK err); return -EINVAL; } while (false) #define RETURN_ERR(err) do { pr_err(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)
{ {
@@ -1084,11 +1037,9 @@ 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;
} }
@@ -1112,7 +1063,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 !defined(CONFIG_CONNECTOR) && !defined(CONFIG_CONNECTOR_MODULE) #if !IS_ENABLED(CONFIG_CONNECTOR)
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");
@@ -1121,25 +1072,24 @@ 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;
if (request_module(crypto.algo) < 0) { if (request_module(crypto.algo) < 0) {
printk(KERN_ERR PKNOCK "request_module('%s') error.\n", pr_err("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_shash(crypto.algo, 0, 0);
if (IS_ERR(crypto.tfm)) { if (IS_ERR(crypto.tfm)) {
printk(KERN_ERR PKNOCK "failed to load transform for %s\n", pr_err("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_shash_digestsize(crypto.tfm);
crypto.desc.tfm = crypto.tfm; crypto.desc.tfm = crypto.tfm;
crypto.desc.flags = 0;
pde = proc_mkdir("xt_pknock", init_net.proc_net); pde = proc_mkdir("xt_pknock", init_net.proc_net);
if (pde == NULL) { if (pde == NULL) {
printk(KERN_ERR PKNOCK "proc_mkdir() error in _init().\n"); pr_err("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);

View File

@@ -8,9 +8,7 @@
* *
* This program is released under the terms of GNU GPL version 2. * This program is released under the terms of GNU GPL version 2.
*/ */
#ifndef _XT_PKNOCK_H #pragma once
#define _XT_PKNOCK_H
#define PKNOCK "xt_pknock: " #define PKNOCK "xt_pknock: "
enum { enum {
@@ -29,8 +27,6 @@ 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;
@@ -49,5 +45,3 @@ struct xt_pknock_nl_msg {
char rule_name[XT_PKNOCK_MAX_BUF_LEN+1]; char rule_name[XT_PKNOCK_MAX_BUF_LEN+1];
__be32 peer_ip; __be32 peer_ip;
}; };
#endif /* _XT_PKNOCK_H */

View File

@@ -58,12 +58,7 @@ xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par)
{ {
struct xt_action_param local_par; struct xt_action_param local_par;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
local_par.state = par->state; local_par.state = par->state;
#else
local_par.in = par->in,
local_par.out = par->out,
#endif
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;
@@ -78,14 +73,7 @@ xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par)
destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude; destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude;
{ {
struct xt_action_param local_par; struct xt_action_param local_par;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
local_par.state = par->state; local_par.state = par->state;
#else
local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
local_par.family = par->family;
#endif
local_par.target = destiny; local_par.target = destiny;
local_par.targinfo = par->targinfo; local_par.targinfo = par->targinfo;
destiny->target(skb, &local_par); destiny->target(skb, &local_par);
@@ -108,27 +96,15 @@ chaos_tg(struct sk_buff *skb, const struct xt_action_param *par)
if ((unsigned int)prandom_u32() <= reject_percentage) { if ((unsigned int)prandom_u32() <= reject_percentage) {
struct xt_action_param local_par; struct xt_action_param local_par;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
local_par.state = par->state; local_par.state = par->state;
#else
local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
#endif
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);
} }
/* 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 && if (iph->protocol == IPPROTO_TCP && info->variant != XTCHAOS_NORMAL &&
info->variant != XTCHAOS_NORMAL && par->state->hook != NF_INET_LOCAL_OUT)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
par->state->hook
#else
par->hooknum
#endif
!= NF_INET_LOCAL_OUT)
xt_chaos_total(skb, par); xt_chaos_total(skb, par);
return NF_DROP; return NF_DROP;
@@ -195,7 +171,8 @@ 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");
if ((ret = xt_register_target(&chaos_tg_reg)) != 0) { ret = xt_register_target(&chaos_tg_reg);
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;

View File

@@ -1,6 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_CHAOS_H #pragma once
#define _LINUX_NETFILTER_XT_CHAOS_H 1
enum xt_chaos_target_variant { enum xt_chaos_target_variant {
XTCHAOS_NORMAL, XTCHAOS_NORMAL,
XTCHAOS_TARPIT, XTCHAOS_TARPIT,
@@ -10,5 +8,3 @@ enum xt_chaos_target_variant {
struct xt_chaos_tginfo { struct xt_chaos_tginfo {
uint8_t variant; uint8_t variant;
}; };
#endif /* _LINUX_NETFILTER_XT_CHAOS_H */

View File

@@ -25,8 +25,8 @@
#include "compat_xtables.h" #include "compat_xtables.h"
#define PFX KBUILD_MODNAME ": " #define PFX KBUILD_MODNAME ": "
static void delude_send_reset(struct net *net, 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,7 +51,8 @@ static void delude_send_reset(struct net *net, struct sk_buff *oldskb,
return; return;
/* Check checksum */ /* Check checksum */
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) if (nf_ip_checksum(oldskb, par->state->hook, ip_hdrlen(oldskb),
IPPROTO_TCP))
return; return;
nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
@@ -79,7 +80,7 @@ static void delude_send_reset(struct net *net, 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->rst && !oth->fin) { if (oth->syn && !oth->ack && !oth->fin) {
tcph->syn = true; tcph->syn = true;
tcph->seq = 0; tcph->seq = 0;
tcph->ack = true; tcph->ack = true;
@@ -107,22 +108,22 @@ static void delude_send_reset(struct net *net, struct sk_buff *oldskb,
addr_type = RTN_UNSPEC; addr_type = RTN_UNSPEC;
#ifdef CONFIG_BRIDGE_NETFILTER #ifdef CONFIG_BRIDGE_NETFILTER
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) #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->physoutdev)) ((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 (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL && if (par->state->hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
nskb->nf_bridge->mask & BRNF_BRIDGED)) nskb->nf_bridge->physoutdev))
#endif #endif
#else #else
if (hook != NF_INET_FORWARD) 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(net, nskb, addr_type))
goto free_nskb; goto free_nskb;
else else
niph = ip_hdr(nskb); niph = ip_hdr(nskb);
@@ -135,8 +136,7 @@ static void delude_send_reset(struct net *net, 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(net, nskb->sk, nskb);
return; return;
free_nskb: free_nskb:
@@ -151,13 +151,7 @@ delude_tg(struct sk_buff *skb, const struct xt_action_param *par)
* a problem, as that is supported since Linux 2.6.35. But since we do not * a problem, as that is supported since Linux 2.6.35. But since we do not
* actually want to have a connection open, we are still going to drop it. * actually want to have a connection open, we are still going to drop it.
*/ */
delude_send_reset(par_net(par), skb, delude_send_reset(skb, par);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
par->state->hook
#else
par->hooknum
#endif
);
return NF_DROP; return NF_DROP;
} }

View File

@@ -96,7 +96,8 @@ dhcpmac_tg(struct sk_buff *skb, const struct xt_action_param *par)
struct udphdr udpbuf, *udph; struct udphdr udpbuf, *udph;
unsigned int i; unsigned int i;
if (!skb_make_writable(skb, 0)) if (skb_ensure_writable(skb, ip_hdrlen(skb) + sizeof(udpbuf) +
sizeof(dhcpbuf)))
return NF_DROP; return NF_DROP;
udph = skb_header_pointer(skb, ip_hdrlen(skb), udph = skb_header_pointer(skb, ip_hdrlen(skb),

View File

@@ -1,6 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_DHCPMAC_H #pragma once
#define _LINUX_NETFILTER_XT_DHCPMAC_H 1
#define DH_MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X" #define DH_MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
#define DH_MAC_HEX(z) z[0], z[1], z[2], z[3], z[4], z[5] #define DH_MAC_HEX(z) z[0], z[1], z[2], z[3], z[4], z[5]
@@ -8,5 +6,3 @@ struct dhcpmac_info {
unsigned char addr[ETH_ALEN]; unsigned char addr[ETH_ALEN];
uint8_t mask, invert; uint8_t mask, invert;
}; };
#endif /* _LINUX_NETFILTER_XT_DHCPMAC_H */

View File

@@ -19,9 +19,10 @@
*/ */
#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>
@@ -36,12 +37,6 @@
#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;
@@ -66,14 +61,8 @@ MODULE_PARM_DESC(whole_prefix,
static unsigned int jtimeout; static unsigned int jtimeout;
struct dnetmap_entry { struct dnetmap_entry {
struct list_head list; struct list_head list, glist, grlist, lru_list;
/* priv2entry */ __be32 prenat_addr, postnat_addr;
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;
@@ -81,10 +70,9 @@ struct dnetmap_entry {
struct dnetmap_prefix { struct dnetmap_prefix {
struct nf_nat_range prefix; struct nf_nat_range prefix;
char prefix_str[16]; char prefix_str[20];
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
char proc_str_data[20]; char proc_str_data[20], proc_str_stat[25];
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
@@ -115,7 +103,7 @@ 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 file_operations dnetmap_tg_fops, dnetmap_stat_proc_fops; static const struct proc_ops dnetmap_tg_fops, dnetmap_stat_proc_fops;
#endif #endif
static inline unsigned int dnetmap_entry_hash(const __be32 addr) static inline unsigned int dnetmap_entry_hash(const __be32 addr)
@@ -127,9 +115,7 @@ 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; unsigned int h = dnetmap_entry_hash(addr);
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)
@@ -141,9 +127,7 @@ 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; unsigned int h = dnetmap_entry_hash(addr);
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)
@@ -293,12 +277,12 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
ip_min = ntohl(mr->min_addr.ip) + (whole_prefix == 0); ip_min = ntohl(mr->min_addr.ip) + (whole_prefix == 0);
ip_max = ntohl(mr->max_addr.ip) - (whole_prefix == 0); ip_max = ntohl(mr->max_addr.ip) - (whole_prefix == 0);
sprintf(p->prefix_str, NIPQUAD_FMT "/%u", NIPQUAD(mr->min_addr.ip), sprintf(p->prefix_str, "%pI4/%u", &mr->min_addr.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, NIPQUAD_FMT "_%u", NIPQUAD(mr->min_addr.ip), sprintf(p->proc_str_data, "%pI4_%u", &mr->min_addr.ip,
33 - ffs(~(ip_min ^ ip_max))); 33 - ffs(~(ip_min ^ ip_max)));
sprintf(p->proc_str_stat, NIPQUAD_FMT "_%u_stat", NIPQUAD(mr->min_addr.ip), sprintf(p->proc_str_stat, "%pI4_%u_stat", &mr->min_addr.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);
@@ -356,33 +340,22 @@ out:
static unsigned int static unsigned int
dnetmap_tg(struct sk_buff *skb, const struct xt_action_param *par) dnetmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
{ {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
struct net *net = dev_net(par->state->in ? par->state->in : par->state->out); struct net *net = dev_net(par->state->in ? par->state->in : par->state->out);
#else
struct net *net = dev_net(par->in ? par->in : par->out);
#endif
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_range *mr = &tginfo->prefix;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 newrange;
#else
struct nf_nat_range newrange; struct nf_nat_range newrange;
#endif
struct dnetmap_entry *e; struct dnetmap_entry *e;
struct dnetmap_prefix *p; struct dnetmap_prefix *p;
__s32 jttl;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
unsigned int hooknum = par->state->hook; unsigned int hooknum = par->state->hook;
#else struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int hooknum = par->hooknum; __s32 jttl = tginfo->flags & XT_DNETMAP_TTL ? tginfo->ttl * HZ : jtimeout;
#endif
NF_CT_ASSERT(hooknum == NF_INET_POST_ROUTING ||
hooknum == NF_INET_LOCAL_OUT ||
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 (hooknum == NF_INET_PRE_ROUTING) {
@@ -398,7 +371,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, sizeof(*mr))) if (memcmp(mr, &e->prefix->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) ) ) {
@@ -437,8 +410,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 " NIPQUAD_FMT " - no free adresses in prefix %s\n", ": ip %pI4 - no free adresses in prefix %s\n",
NIPQUAD(prenat_ip), p->prefix_str); &prenat_ip, p->prefix_str);
p->flags |= XT_DNETMAP_FULL; p->flags |= XT_DNETMAP_FULL;
} }
goto no_free_ip; goto no_free_ip;
@@ -451,8 +424,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 " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", ": timeout binding %pI4 -> %pI4\n",
NIPQUAD(prenat_ip_prev), NIPQUAD(postnat_ip) ); &prenat_ip_prev, &postnat_ip);
list_del(&e->glist); list_del(&e->glist);
list_del(&e->grlist); list_del(&e->grlist);
} }
@@ -469,18 +442,16 @@ 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 " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", ": add binding %pI4 -> %pI4\n",
NIPQUAD(prenat_ip),NIPQUAD(postnat_ip)); &prenat_ip, &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 " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", ": timeout binding %pI4 -> %pI4\n",
NIPQUAD(e->prenat_addr), &e->prenat_addr, &e->postnat_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;
@@ -504,12 +475,7 @@ bind_new_prefix:
newrange.max_addr.ip = postnat_ip; newrange.max_addr.ip = postnat_ip;
newrange.min_proto = mr->min_proto; newrange.min_proto = mr->min_proto;
newrange.max_proto = mr->max_proto; newrange.max_proto = mr->max_proto;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->state->hook)); return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->state->hook));
#else
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
#endif
no_rev_map: no_rev_map:
no_free_ip: no_free_ip:
spin_unlock_bh(&dnetmap_lock); spin_unlock_bh(&dnetmap_lock);
@@ -584,12 +550,13 @@ 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, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: %d lasthit: %lu\n", seq_printf(seq, "%pI4 -> %pI4 --- ttl: %d lasthit: %lu\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr), &e->prenat_addr, &e->postnat_addr,
(int)(e->stamp - jiffies) / HZ, (e->stamp - jtimeout) / HZ); (int)(e->stamp - jiffies) / HZ,
(e->stamp - jtimeout) / HZ);
}else{ }else{
seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: S lasthit: S\n", seq_printf(seq, "%pI4 -> %pI4 --- ttl: S lasthit: S\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr)); &e->prenat_addr, &e->postnat_addr);
} }
return 0; return 0;
} }
@@ -711,8 +678,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 " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", ": timeout binding %pI4 -> %pI4\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) ); &e->prenat_addr, &e->postnat_addr);
list_del(&e->glist); list_del(&e->glist);
list_del(&e->grlist); list_del(&e->grlist);
}else{ }else{
@@ -734,7 +701,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, NIPQUAD_FMT ":" NIPQUAD_FMT, NIPQUAD(addr1),NIPQUAD(addr2)); sprintf(str, "%pI4:%pI4", &addr1, &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
@@ -750,8 +717,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 " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", ": remove binding %pI4 -> %pI4\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) ); &e->prenat_addr, &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){
@@ -781,12 +748,11 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
} }
static const struct file_operations dnetmap_tg_fops = { static const struct proc_ops dnetmap_tg_fops = {
.open = dnetmap_seq_open, .proc_open = dnetmap_seq_open,
.read = seq_read, .proc_read = seq_read,
.write = dnetmap_tg_proc_write, .proc_write = dnetmap_tg_proc_write,
.release = seq_release_private, .proc_release = seq_release_private,
.owner = THIS_MODULE,
}; };
/* for statistics */ /* for statistics */
@@ -830,11 +796,11 @@ static int dnetmap_stat_proc_open(struct inode *inode, struct file *file)
return single_open(file, dnetmap_stat_proc_show, PDE_DATA(inode)); return single_open(file, dnetmap_stat_proc_show, PDE_DATA(inode));
} }
static const struct file_operations dnetmap_stat_proc_fops = { static const struct proc_ops dnetmap_stat_proc_fops = {
.open = dnetmap_stat_proc_open, .proc_open = dnetmap_stat_proc_open,
.read = seq_read, .proc_read = seq_read,
.llseek = seq_lseek, .proc_lseek = seq_lseek,
.release = single_release, .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)
@@ -950,6 +916,18 @@ 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

@@ -1,6 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_DNETMAP_H #pragma once
#define _LINUX_NETFILTER_XT_DNETMAP_H 1
#define DNETMAP_VERSION 2 #define DNETMAP_VERSION 2
enum { enum {
@@ -17,5 +15,3 @@ struct xt_DNETMAP_tginfo {
__u8 flags; __u8 flags;
__s32 ttl; __s32 ttl;
}; };
#endif

View File

@@ -35,11 +35,7 @@ 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;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
struct net *net = dev_net((par->state->in != NULL) ? par->state->in : par->state->out); struct net *net = dev_net((par->state->in != NULL) ? par->state->in : par->state->out);
#else
struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
#endif
/* 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(oldskb) < 0)
@@ -101,7 +97,11 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
memcpy(&fl.daddr, &newip->daddr, sizeof(fl.daddr)); memcpy(&fl.daddr, &newip->daddr, sizeof(fl.daddr));
fl.fl6_sport = newudp->source; fl.fl6_sport = newudp->source;
fl.fl6_dport = newudp->dest; fl.fl6_dport = newudp->dest;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi_common(&fl));
#else
security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi(&fl)); security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi(&fl));
#endif
dst = ip6_route_output(net, NULL, &fl); dst = ip6_route_output(net, NULL, &fl);
if (dst == NULL || dst->error != 0) { if (dst == NULL || dst->error != 0) {
dst_release(dst); dst_release(dst);
@@ -117,7 +117,7 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
goto free_nskb; goto free_nskb;
nf_ct_attach(newskb, oldskb); nf_ct_attach(newskb, oldskb);
ip6_local_out(par_net(par), newskb->sk, newskb); ip6_local_out(par_net(par), par->state->sk, newskb);
return NF_DROP; return NF_DROP;
free_nskb: free_nskb:
@@ -195,8 +195,8 @@ 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,
if (ip_route_me_harder(par_net(par), newskb, RTN_UNSPEC) != 0) RTN_UNSPEC) != 0)
goto free_nskb; goto free_nskb;
newip->ttl = ip4_dst_hoplimit(skb_dst(newskb)); newip->ttl = ip4_dst_hoplimit(skb_dst(newskb));

View File

@@ -1,5 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_IPMARK_H #pragma once
#define _LINUX_NETFILTER_XT_IPMARK_H 1
enum { enum {
XT_IPMARK_SRC, XT_IPMARK_SRC,
@@ -7,10 +6,6 @@ enum {
}; };
struct xt_ipmark_tginfo { struct xt_ipmark_tginfo {
__u32 andmask; __u32 andmask, ormask;
__u32 ormask; __u8 selector, shift;
__u8 selector;
__u8 shift;
}; };
#endif /* _LINUX_NETFILTER_XT_IPMARK_H */

View File

@@ -52,18 +52,19 @@ 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 ? "," : "");
if (ct->status & IPS_ASSURED) prev = true;
printk("%s""ASSURED", prev++ ? "," : ""); }
if (ct->status & IPS_CONFIRMED) if (ct->status & IPS_ASSURED) {
printk("%s""CONFIRMED", prev++ ? "," : ""); printk("%s""ASSURED", prev ? "," : "");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) prev = true;
}
if (ct->status & IPS_CONFIRMED) {
printk("%s""CONFIRMED", prev ? "," : "");
prev = true;
}
printk(" lifetime=%lus", nf_ct_expires(ct) / HZ); printk(" lifetime=%lus", nf_ct_expires(ct) / HZ);
#else
printk(" lifetime=%lus",
(jiffies - ct->timeout.expires) / HZ);
#endif
} }
static unsigned int static unsigned int
@@ -76,19 +77,13 @@ 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,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
skb_ifindex(skb), hook_names[par->state->hook], skb_ifindex(skb), hook_names[par->state->hook],
#else
skb_ifindex(skb), hook_names[par->hooknum],
#endif
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");
else if (nf_ct_is_untracked(ct))
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
else else
logmark_ct(ct, ctinfo); logmark_ct(ct, ctinfo);

View File

@@ -1,9 +1,5 @@
#ifndef _LINUX_NETFILTER_XT_LOGMARK_TARGET_H #pragma once
#define _LINUX_NETFILTER_XT_LOGMARK_TARGET_H 1
struct xt_logmark_tginfo { struct xt_logmark_tginfo {
char prefix[14]; char prefix[14];
u_int8_t level; u_int8_t level;
}; };
#endif /* _LINUX_NETFILTER_XT_LOGMARK_TARGET_H */

156
extensions/xt_PROTO.c Normal file
View File

@@ -0,0 +1,156 @@
/*
* 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");

14
extensions/xt_PROTO.h Normal file
View File

@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* Protocol modification module for IP tables */
#pragma once
#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, proto;
};

View File

@@ -114,7 +114,6 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
} }
desc.tfm = sysrq_tfm; desc.tfm = sysrq_tfm;
desc.flags = 0;
ret = crypto_shash_init(&desc); ret = crypto_shash_init(&desc);
if (ret != 0) if (ret != 0)
goto hash_fail; goto hash_fail;
@@ -205,12 +204,11 @@ 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
": " NIPQUAD_FMT ":%u -> :%u len=%u\n", ": %pI4:%hu -> :%hu len=%u\n",
NIPQUAD(iph->saddr), htons(udph->source), &iph->saddr, htons(udph->source),
htons(udph->dest), len); htons(udph->dest), len);
#ifdef WITH_CRYPTO #ifdef WITH_CRYPTO
sprintf(sysrq_digest_password, NIPQUAD_FMT ",%s", sprintf(sysrq_digest_password, "%pI4,%s", &iph->daddr, sysrq_password);
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);
} }
@@ -239,13 +237,11 @@ 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 printk(KERN_INFO KBUILD_MODNAME ": %pI6:%hu -> :%hu len=%u\n",
": " NIP6_FMT ":%hu -> :%hu len=%u\n", &iph->saddr, ntohs(udph->source),
NIP6(iph->saddr), ntohs(udph->source),
ntohs(udph->dest), len); ntohs(udph->dest), len);
#ifdef WITH_CRYPTO #ifdef WITH_CRYPTO
sprintf(sysrq_digest_password, NIP6_FMT ",%s", sprintf(sysrq_digest_password, "%pI6,%s", &iph->daddr, sysrq_password);
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);
} }
@@ -314,7 +310,7 @@ 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 timeval now; struct timespec64 now;
int ret; int ret;
sysrq_tfm = crypto_alloc_shash(sysrq_hash, 0, 0); sysrq_tfm = crypto_alloc_shash(sysrq_hash, 0, 0);
@@ -339,7 +335,7 @@ 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;
do_gettimeofday(&now); ktime_get_real_ts64(&now);
sysrq_seqno = now.tv_sec; sysrq_seqno = now.tv_sec;
return 0; return 0;

View File

@@ -170,8 +170,8 @@ static bool tarpit_generic(struct tcphdr *tcph, const struct tcphdr *oth,
return true; return true;
} }
static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb, static void tarpit_tcp4(const struct xt_action_param *par,
unsigned int hook, unsigned int mode) struct sk_buff *oldskb, unsigned int mode)
{ {
struct tcphdr _otcph, *tcph; struct tcphdr _otcph, *tcph;
const struct tcphdr *oth; const struct tcphdr *oth;
@@ -191,7 +191,8 @@ static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
return; return;
/* Check checksum. */ /* Check checksum. */
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) if (nf_ip_checksum(oldskb, par->state->hook, ip_hdrlen(oldskb),
IPPROTO_TCP))
return; return;
/* /*
@@ -205,7 +206,11 @@ static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
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);
skb_shinfo(nskb)->gso_size = 0; skb_shinfo(nskb)->gso_size = 0;
@@ -249,19 +254,20 @@ static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
niph->id = ~oldhdr->id + 1; niph->id = ~oldhdr->id + 1;
#ifdef CONFIG_BRIDGE_NETFILTER #ifdef CONFIG_BRIDGE_NETFILTER
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) #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->physoutdev != NULL)) ((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 (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL && if (par->state->hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
nskb->nf_bridge->mask & BRNF_BRIDGED)) nskb->nf_bridge->physoutdev != NULL))
#endif #endif
#else #else
if (hook != NF_INET_FORWARD) if (par->state->hook != NF_INET_FORWARD)
#endif #endif
addr_type = RTN_LOCAL; addr_type = RTN_LOCAL;
if (ip_route_me_harder(net, nskb, addr_type)) if (ip_route_me_harder(par_net(par), par->state->sk, nskb, addr_type) != 0)
goto free_nskb; goto free_nskb;
else else
niph = ip_hdr(nskb); niph = ip_hdr(nskb);
@@ -283,17 +289,8 @@ static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
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,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) NULL, skb_dst(nskb)->dev, dst_output);
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output_sk);
#else
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#endif
return; return;
free_nskb: free_nskb:
@@ -301,8 +298,8 @@ static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
} }
#ifdef WITH_IPV6 #ifdef WITH_IPV6
static void tarpit_tcp6(struct net *net, struct sk_buff *oldskb, static void tarpit_tcp6(const struct xt_action_param *par,
unsigned int hook, unsigned int mode) struct sk_buff *oldskb, unsigned int mode)
{ {
struct sk_buff *nskb; struct sk_buff *nskb;
struct tcphdr *tcph, oth; struct tcphdr *tcph, oth;
@@ -355,7 +352,11 @@ static void tarpit_tcp6(struct net *net, struct sk_buff *oldskb,
} }
/* 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);
skb_shinfo(nskb)->gso_size = 0; skb_shinfo(nskb)->gso_size = 0;
@@ -399,24 +400,14 @@ static void tarpit_tcp6(struct net *net, struct sk_buff *oldskb,
&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(net, 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,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0) NULL, skb_dst(nskb)->dev, dst_output);
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output_sk);
#else
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#endif
return; return;
free_nskb: free_nskb:
@@ -454,12 +445,7 @@ 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);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
tarpit_tcp4(par_net(par), skb, par->state->hook, info->variant);
#else
tarpit_tcp4(par_net(par), skb, par->hooknum, info->variant);
#endif
return NF_DROP; return NF_DROP;
} }
@@ -500,12 +486,7 @@ 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);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
tarpit_tcp6(par_net(par), skb, par->state->hook, info->variant);
#else
tarpit_tcp6(par_net(par), skb, par->hooknum, info->variant);
#endif
return NF_DROP; return NF_DROP;
} }
#endif #endif

View File

@@ -1,5 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_TARPIT_H #pragma once
#define _LINUX_NETFILTER_XT_TARPIT_H 1
enum xt_tarpit_target_variant { enum xt_tarpit_target_variant {
XTTARPIT_TARPIT, XTTARPIT_TARPIT,
@@ -10,5 +9,3 @@ enum xt_tarpit_target_variant {
struct xt_tarpit_tginfo { struct xt_tarpit_tginfo {
uint8_t variant; uint8_t variant;
}; };
#endif /* _LINUX_NETFILTER_XT_TARPIT_H */

View File

@@ -7,6 +7,7 @@
* 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
@@ -21,6 +22,8 @@
#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"
@@ -59,8 +62,18 @@ struct condition_variable {
/* to the conditions' list. */ /* to the conditions' list. */
static DEFINE_MUTEX(proc_lock); static DEFINE_MUTEX(proc_lock);
static LIST_HEAD(conditions_list); struct condition_net {
static struct proc_dir_entry *proc_net_condition; struct list_head conditions_list;
struct proc_dir_entry *proc_net_condition;
bool after_clear;
};
static int condition_net_id;
static inline struct condition_net *condition_pernet(struct net *net)
{
return net_generic(net, condition_net_id);
}
static int condition_proc_show(struct seq_file *m, void *data) static int condition_proc_show(struct seq_file *m, void *data)
{ {
@@ -98,12 +111,12 @@ condition_proc_write(struct file *file, const char __user *buffer,
return length; return length;
} }
static const struct file_operations condition_proc_fops = { static const struct proc_ops condition_proc_fops = {
.open = condition_proc_open, .proc_open = condition_proc_open,
.read = seq_read, .proc_read = seq_read,
.llseek = seq_lseek, .proc_write = condition_proc_write,
.write = condition_proc_write, .proc_lseek = seq_lseek,
.release = single_release, .proc_release = single_release,
}; };
static bool static bool
@@ -119,6 +132,7 @@ 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 == '.' ||
@@ -134,7 +148,7 @@ 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, &conditions_list, list) { list_for_each_entry(var, &condition_net->conditions_list, list) {
if (strcmp(info->name, var->name) == 0) { if (strcmp(info->name, var->name) == 0) {
var->refcount++; var->refcount++;
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
@@ -153,7 +167,7 @@ static int condition_mt_check(const struct xt_mtchk_param *par)
memcpy(var->name, info->name, sizeof(info->name)); 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 = proc_create_data(info->name, condition_list_perms,
proc_net_condition, &condition_proc_fops, var); condition_net->proc_net_condition, &condition_proc_fops, var);
if (var->status_proc == NULL) { if (var->status_proc == NULL) {
kfree(var); kfree(var);
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
@@ -166,7 +180,7 @@ static int condition_mt_check(const struct xt_mtchk_param *par)
var->refcount = 1; var->refcount = 1;
var->enabled = false; var->enabled = false;
wmb(); wmb();
list_add(&var->list, &conditions_list); list_add(&var->list, &condition_net->conditions_list);
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
info->condvar = var; info->condvar = var;
return 0; return 0;
@@ -176,11 +190,15 @@ 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);
proc_remove(var->status_proc); remove_proc_entry(var->name, cnet->proc_net_condition);
mutex_unlock(&proc_lock); mutex_unlock(&proc_lock);
kfree(var); kfree(var);
return; return;
@@ -213,18 +231,54 @@ 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);
proc_net_condition = proc_mkdir(dir_name, init_net.proc_net); ret = register_pernet_subsys(&condition_net_ops);
if (proc_net_condition == NULL) if (ret != 0)
return -EACCES; return ret;
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) {
remove_proc_entry(dir_name, init_net.proc_net); unregister_pernet_subsys(&condition_net_ops);
return ret; return ret;
} }
@@ -234,7 +288,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));
remove_proc_entry(dir_name, init_net.proc_net); unregister_pernet_subsys(&condition_net_ops);
} }
module_init(condition_mt_init); module_init(condition_mt_init);

View File

@@ -1,5 +1,4 @@
#ifndef _XT_CONDITION_H #pragma once
#define _XT_CONDITION_H
enum { enum {
CONDITION_NAME_LEN = 31, CONDITION_NAME_LEN = 31,
@@ -12,5 +11,3 @@ struct xt_condition_mtinfo {
/* Used internally by the kernel */ /* Used internally by the kernel */
void *condvar __attribute__((aligned(8))); void *condvar __attribute__((aligned(8)));
}; };
#endif /* _XT_CONDITION_H */

View File

@@ -1,5 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_FUZZY_H #pragma once
#define _LINUX_NETFILTER_XT_FUZZY_H 1
enum { enum {
FUZZY_MIN_RATE = 3, FUZZY_MIN_RATE = 3,
@@ -7,14 +6,9 @@ enum {
}; };
struct xt_fuzzy_mtinfo { struct xt_fuzzy_mtinfo {
uint32_t minimum_rate; uint32_t minimum_rate, maximum_rate;
uint32_t maximum_rate; uint32_t packets_total, bytes_total;
uint32_t packets_total; uint32_t previous_time, present_time;
uint32_t bytes_total;
uint32_t previous_time;
uint32_t present_time;
uint32_t mean_rate; uint32_t mean_rate;
uint8_t acceptance_rate; uint8_t acceptance_rate;
}; };
#endif /* _LINUX_NETFILTER_XT_FUZZY_H */

View File

@@ -75,7 +75,8 @@ 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);

View File

@@ -10,8 +10,7 @@
* Samuel Jean * Samuel Jean
* Nicolas Bouliane * Nicolas Bouliane
*/ */
#ifndef _LINUX_NETFILTER_XT_GEOIP_H #pragma once
#define _LINUX_NETFILTER_XT_GEOIP_H 1
enum { enum {
XT_GEOIP_SRC = 1 << 0, /* Perform check on Source IP */ XT_GEOIP_SRC = 1 << 0, /* Perform check on Source IP */
@@ -23,8 +22,7 @@ enum {
/* Yup, an address range will be passed in with host-order */ /* Yup, an address range will be passed in with host-order */
struct geoip_subnet4 { struct geoip_subnet4 {
__u32 begin; __u32 begin, end;
__u32 end;
}; };
struct geoip_subnet6 { struct geoip_subnet6 {
@@ -45,8 +43,7 @@ union geoip_country_group {
}; };
struct xt_geoip_match_info { struct xt_geoip_match_info {
__u8 flags; __u8 flags, count;
__u8 count;
__u16 cc[XT_GEOIP_MAX]; __u16 cc[XT_GEOIP_MAX];
/* Used internally by the kernel */ /* Used internally by the kernel */
@@ -54,5 +51,3 @@ struct xt_geoip_match_info {
}; };
#define COUNTRY(cc) ((cc) >> 8), ((cc) & 0x00FF) #define COUNTRY(cc) ((cc) >> 8), ((cc) & 0x00FF)
#endif /* _LINUX_NETFILTER_XT_GEOIP_H */

View File

@@ -1,9 +1,4 @@
#ifndef _XT_GRADM_H #pragma once
#define _XT_GRADM_H
struct xt_gradm_mtinfo { struct xt_gradm_mtinfo {
__u16 flags; __u16 flags, invflags;
__u16 invflags;
}; };
#endif

View File

@@ -45,17 +45,9 @@ 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)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
return par->state->in; return par->state->in;
#else
return par->in;
#endif
else if (info->flags & XT_IFACE_DEV_OUT) else if (info->flags & XT_IFACE_DEV_OUT)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
return par->state->out; return par->state->out;
#else
return par->out;
#endif
return *put = dev_get_by_name(&init_net, info->ifname); return *put = dev_get_by_name(&init_net, info->ifname);
} }

View File

@@ -1,5 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_IFACE_H #pragma once
#define _LINUX_NETFILTER_XT_IFACE_H 1
enum { enum {
XT_IFACE_UP = 1 << 0, XT_IFACE_UP = 1 << 0,
@@ -19,8 +18,5 @@ enum {
struct xt_iface_mtinfo { struct xt_iface_mtinfo {
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
__u16 flags; __u16 flags, invflags;
__u16 invflags;
}; };
#endif

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=", 9) != NULL) if (HX_memmem(payload, plen, "info_hash=", 10) != 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,8 +857,11 @@ 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: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", printk("IPP2P.debug:TCP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %d\n",
p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen); p2p_result, &ip->saddr,
ntohs(tcph->source),
&ip->daddr,
ntohs(tcph->dest), hlen);
return p2p_result; return p2p_result;
} }
} }
@@ -888,8 +891,11 @@ 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: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n", printk("IPP2P.debug:UDP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %d\n",
p2p_result, NIPQUAD(ip->saddr), ntohs(udph->source), NIPQUAD(ip->daddr), ntohs(udph->dest), hlen); p2p_result, &ip->saddr,
ntohs(udph->source),
&ip->daddr,
ntohs(udph->dest), hlen);
return p2p_result; return p2p_result;
} }
} }

View File

@@ -1,5 +1,4 @@
#ifndef __IPT_IPP2P_H #pragma once
#define __IPT_IPP2P_H
#define IPP2P_VERSION "0.10" #define IPP2P_VERSION "0.10"
enum { enum {
@@ -39,8 +38,5 @@ enum {
}; };
struct ipt_p2p_info { struct ipt_p2p_info {
int cmd; int32_t cmd, debug;
int debug;
}; };
#endif //__IPT_IPP2P_H

View File

@@ -1,5 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_IPV4OPTIONS_H #pragma once
#define _LINUX_NETFILTER_XT_IPV4OPTIONS_H 1
/* IPv4 allows for a 5-bit option number - 32 options */ /* IPv4 allows for a 5-bit option number - 32 options */
@@ -18,9 +17,6 @@ enum xt_ipv4options_flags {
* @flags: see above * @flags: see above
*/ */
struct xt_ipv4options_mtinfo1 { struct xt_ipv4options_mtinfo1 {
__u32 map; __u32 map, invert;
__u32 invert;
__u8 flags; __u8 flags;
}; };
#endif /* _LINUX_NETFILTER_XT_IPV4OPTIONS_H */

View File

@@ -1,5 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_LENGTH2_H #pragma once
#define _LINUX_NETFILTER_XT_LENGTH2_H
enum { enum {
XT_LENGTH_INVERT = 1 << 0, XT_LENGTH_INVERT = 1 << 0,
@@ -18,5 +17,3 @@ struct xt_length_mtinfo2 {
u_int32_t min, max; u_int32_t min, max;
u_int16_t flags; u_int16_t flags;
}; };
#endif /* _LINUX_NETFILTER_XT_LENGTH2_H */

View File

@@ -175,6 +175,7 @@ lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
{ {
const struct xt_lscan_mtinfo *info = par->matchinfo; const struct xt_lscan_mtinfo *info = par->matchinfo;
enum ip_conntrack_info ctstate; enum ip_conntrack_info ctstate;
const struct iphdr *iph = ip_hdr(skb);
const struct tcphdr *tcph; const struct tcphdr *tcph;
struct nf_conn *ctdata; struct nf_conn *ctdata;
struct tcphdr tcph_buf; struct tcphdr tcph_buf;
@@ -182,10 +183,14 @@ lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
tcph = skb_header_pointer(skb, par->thoff, sizeof(tcph_buf), &tcph_buf); tcph = skb_header_pointer(skb, par->thoff, sizeof(tcph_buf), &tcph_buf);
if (tcph == NULL) if (tcph == NULL)
return false; return false;
if (info->match_fl1 & LSCAN_FL1_MIRAI && iph != NULL &&
iph->version == 4 && iph->daddr == tcph->seq)
return true;
/* Check for invalid packets: -m conntrack --ctstate INVALID */ /* Check for invalid packets: -m conntrack --ctstate INVALID */
if ((ctdata = nf_ct_get(skb, &ctstate)) == NULL) { ctdata = nf_ct_get(skb, &ctstate);
if (info->match_stealth) if (ctdata == NULL) {
if (info->match_fl1 & LSCAN_FL1_STEALTH)
return lscan_mt_stealth(tcph); return lscan_mt_stealth(tcph);
/* /*
* If @ctdata is NULL, we cannot match the other scan * If @ctdata is NULL, we cannot match the other scan
@@ -204,28 +209,26 @@ 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,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
par->state->in == init_net.loopback_dev, tcph, par->state->in == init_net.loopback_dev, tcph,
#else
par->in == init_net.loopback_dev, tcph,
#endif
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;
skb_nfmark(skb) = (skb_nfmark(skb) & ~packet_mask) ^ mark_seen; skb_nfmark(skb) = (skb_nfmark(skb) & ~packet_mask) ^ mark_seen;
} }
return (info->match_syn && ctdata->mark == mark_synscan) || return (info->match_fl1 & LSCAN_FL1_STEALTH && ctdata->mark == mark_synscan) ||
(info->match_cn && ctdata->mark == mark_cnscan) || (info->match_fl3 & LSCAN_FL3_CN && ctdata->mark == mark_cnscan) ||
(info->match_gr && ctdata->mark == mark_grscan); (info->match_fl4 & LSCAN_FL4_GR && ctdata->mark == mark_grscan);
} }
static int lscan_mt_check(const struct xt_mtchk_param *par) static int lscan_mt_check(const struct xt_mtchk_param *par)
{ {
const struct xt_lscan_mtinfo *info = par->matchinfo; const struct xt_lscan_mtinfo *info = par->matchinfo;
if ((info->match_stealth & ~1) || (info->match_syn & ~1) || if ((info->match_fl1 & ~(LSCAN_FL1_STEALTH | LSCAN_FL1_MIRAI)) ||
(info->match_cn & ~1) || (info->match_gr & ~1)) { (info->match_fl2 & ~LSCAN_FL2_SYN) ||
(info->match_fl3 & ~LSCAN_FL3_CN) ||
(info->match_fl4 & ~LSCAN_FL4_GR)) {
printk(KERN_WARNING PFX "Invalid flags\n"); printk(KERN_WARNING PFX "Invalid flags\n");
return -EINVAL; return -EINVAL;
} }

View File

@@ -1,8 +1,13 @@
#ifndef _LINUX_NETFILTER_XT_LSCAN_H #pragma once
#define _LINUX_NETFILTER_XT_LSCAN_H 1
struct xt_lscan_mtinfo { enum {
uint8_t match_stealth, match_syn, match_cn, match_gr; LSCAN_FL1_STEALTH = 1 << 0,
LSCAN_FL1_MIRAI = 1 << 1,
LSCAN_FL2_SYN = 1 << 0,
LSCAN_FL3_CN = 1 << 0,
LSCAN_FL4_GR = 1 << 0,
}; };
#endif /* _LINUX_NETFILTER_XT_LSCAN_H */ struct xt_lscan_mtinfo {
uint8_t match_fl1, match_fl2, match_fl3, match_fl4;
};

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
* HASH_SIZE entries for faster lookups, but limiting hash collisions to * PSD_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 HASH_SIZE (1 << HASH_LOG) #define PSD_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[HASH_SIZE]; struct host *hash[PSD_HASH_SIZE];
int index; int index;
} state; } state;
@@ -143,13 +143,12 @@ 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, HASH_SIZE * sizeof(struct host *)); memset(state6.hash, 0, PSD_HASH_SIZE * sizeof(struct host *));
return true; return true;
} }
#endif #endif
@@ -167,8 +166,7 @@ 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)

View File

@@ -1,6 +1,4 @@
#ifndef _LINUX_NETFILTER_XT_PSD_H #pragma once
#define _LINUX_NETFILTER_XT_PSD_H 1
#include <linux/param.h> #include <linux/param.h>
#include <linux/types.h> #include <linux/types.h>
@@ -21,10 +19,6 @@
#define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT #define SCAN_WEIGHT_THRESHOLD SCAN_MAX_COUNT
struct xt_psd_info { struct xt_psd_info {
__u32 weight_threshold; __u32 weight_threshold, delay_threshold;
__u32 delay_threshold; __u16 lo_ports_weight, hi_ports_weight;
__u16 lo_ports_weight;
__u16 hi_ports_weight;
}; };
#endif /*_LINUX_NETFILTER_XT_PSD_H*/

View File

@@ -117,12 +117,12 @@ quota_proc_write(struct file *file, const char __user *input,
return size; return size;
} }
static const struct file_operations quota_proc_fops = { static const struct proc_ops quota_proc_fops = {
.open = quota_proc_open, .proc_open = quota_proc_open,
.read = seq_read, .proc_read = seq_read,
.llseek = seq_lseek, .proc_write = quota_proc_write,
.write = quota_proc_write, .proc_lseek = seq_lseek,
.release = single_release, .proc_release = single_release,
}; };
static struct xt_quota_counter * static struct xt_quota_counter *

View File

@@ -1,5 +1,4 @@
#ifndef _XT_QUOTA_H #pragma once
#define _XT_QUOTA_H
enum xt_quota_flags { enum xt_quota_flags {
XT_QUOTA_INVERT = 1 << 0, XT_QUOTA_INVERT = 1 << 0,
@@ -21,5 +20,3 @@ struct xt_quota_mtinfo2 {
/* Used internally by the kernel */ /* Used internally by the kernel */
struct xt_quota_counter *master __attribute__((aligned(8))); struct xt_quota_counter *master __attribute__((aligned(8)));
}; };
#endif /* _XT_QUOTA_H */

View File

@@ -1,5 +1,9 @@
# -*- Makefile -*- # -*- Makefile -*-
pkglibexec_SCRIPTS = xt_geoip_build xt_geoip_dl bin_SCRIPTS = xt_geoip_query
man1_MANS = xt_geoip_build.1 xt_geoip_dl.1 pkglibexec_SCRIPTS = xt_geoip_build xt_geoip_build_maxmind xt_geoip_dl xt_geoip_dl_maxmind
man1_MANS = xt_geoip_build.1 xt_geoip_dl.1 \
xt_geoip_build_maxmind.1 xt_geoip_dl_maxmind.1 \
xt_geoip_query.1

View File

@@ -1,10 +1,14 @@
#!/usr/bin/perl #!/usr/bin/perl
# #
# Converter for MaxMind CSV database to binary, for xt_geoip # Converter for DBIP (Country Lite) CSV database to binary, for xt_geoip
# Copyright © Jan Engelhardt, 2008-2011 # Copyright Jan Engelhardt, 2008-2011
# Copyright Philip Prindeville, 2018
# Copyright Arjen de Korte, 2020
# #
use Getopt::Long; use Getopt::Long;
use IO::Handle; use Net::CIDR::Lite;
use Socket qw(AF_INET AF_INET6 inet_pton);
use warnings;
use Text::CSV_XS; # or trade for Text::CSV use Text::CSV_XS; # or trade for Text::CSV
use strict; use strict;
@@ -13,52 +17,62 @@ my $csv = Text::CSV_XS->new({
binary => 1, binary => 1,
eol => $/, eol => $/,
}); # or Text::CSV }); # or Text::CSV
my $quiet = 0;
my $input_file = "dbip-country-lite.csv";
my $target_dir = "."; my $target_dir = ".";
&Getopt::Long::Configure(qw(bundling)); &Getopt::Long::Configure(qw(bundling));
&GetOptions( &GetOptions(
"D=s" => \$target_dir, "D=s" => \$target_dir,
"i=s" => \$input_file,
"q" => \$quiet,
"s" => sub { $target_dir = "/usr/share/xt_geoip"; },
); );
if (!-d $target_dir) { if (!-d $target_dir) {
print STDERR "Target directory $target_dir does not exist.\n"; print STDERR "Target directory \"$target_dir\" does not exist.\n";
exit 1; exit 1;
} }
foreach (qw(LE BE)) {
my $dir = "$target_dir/$_";
if (!-e $dir && !mkdir($dir)) {
print STDERR "Could not mkdir $dir: $!\n";
exit 1;
}
}
&dump(&collect()); &dump(&collect());
sub collect sub collect
{ {
my %country; my ($file, $fh, $row);
my (%country);
if ($input_file eq "-") {
open($fh, "<&STDIN");
} else {
open($fh, "<", $input_file) || die "Cannot open $input_file: $!\n";
}
while (my $row = $csv->getline(*ARGV)) { while ($row = $csv->getline($fh)) {
if (!defined($country{$row->[4]})) { my ($cc, $range);
$country{$row->[4]} = {
name => $row->[5], $cc = $row->[2];
pool_v4 => [], $range = $row->[0] . "-" . $row->[1];
pool_v6 => [],
}; if (!exists($country{$cc})) {
$country{$cc} = { pool_v4 => Net::CIDR::Lite->new(), pool_v6 => Net::CIDR::Lite->new() };
} }
my $c = $country{$row->[4]};
if ($row->[0] =~ /:/) { if (index($range, '.') > 0) {
push(@{$c->{pool_v6}}, $country{$cc}->{pool_v4}->add_range($range);
[&ip6_pack($row->[0]), &ip6_pack($row->[1])]);
} else {
push(@{$c->{pool_v4}}, [$row->[2], $row->[3]]);
} }
if ($. % 4096 == 0) {
if (index($range, ':') > 0) {
$country{$cc}->{pool_v6}->add_range($range);
}
if (!$quiet && $. % 4096 == 0) {
print STDERR "\r\e[2K$. entries"; print STDERR "\r\e[2K$. entries";
} }
} }
print STDERR "\r\e[2K$. entries total\n"; print STDERR "\r\e[2K$. entries total\n" unless ($quiet);
close($fh);
return \%country; return \%country;
} }
@@ -66,7 +80,7 @@ sub dump
{ {
my $country = shift @_; my $country = shift @_;
foreach my $iso_code (sort keys %$country) { foreach my $iso_code (sort keys %{$country}) {
&dump_one($iso_code, $country->{$iso_code}); &dump_one($iso_code, $country->{$iso_code});
} }
} }
@@ -74,68 +88,40 @@ sub dump
sub dump_one sub dump_one
{ {
my($iso_code, $country) = @_; my($iso_code, $country) = @_;
my($file, $fh_le, $fh_be); my @ranges;
printf "%5u IPv6 ranges for %s %s\n", @ranges = $country->{pool_v4}->list_range();
scalar(@{$country->{pool_v6}}),
$iso_code, $country->{name};
$file = "$target_dir/LE/".uc($iso_code).".iv6"; writeCountry($iso_code, AF_INET, @ranges);
if (!open($fh_le, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
$file = "$target_dir/BE/".uc($iso_code).".iv6";
if (!open($fh_be, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
foreach my $range (@{$country->{pool_v6}}) {
print $fh_be $range->[0], $range->[1];
print $fh_le &ip6_swap($range->[0]), &ip6_swap($range->[1]);
}
close $fh_le;
close $fh_be;
printf "%5u IPv4 ranges for %s %s\n", @ranges = $country->{pool_v6}->list_range();
scalar(@{$country->{pool_v4}}),
$iso_code, $country->{name};
$file = "$target_dir/LE/".uc($iso_code).".iv4"; writeCountry($iso_code, AF_INET6, @ranges);
if (!open($fh_le, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
$file = "$target_dir/BE/".uc($iso_code).".iv4";
if (!open($fh_be, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
foreach my $range (@{$country->{pool_v4}}) {
print $fh_le pack("VV", $range->[0], $range->[1]);
print $fh_be pack("NN", $range->[0], $range->[1]);
}
close $fh_le;
close $fh_be;
} }
sub ip6_pack sub writeCountry
{ {
my $addr = shift @_; my ($iso_code, $family, @ranges) = @_;
$addr =~ s{::}{:!:}; my $fh;
my @addr = split(/:/, $addr);
my @e = (0) x 8;
foreach (@addr) {
if ($_ eq "!") {
$_ = join(':', @e[0..(8-scalar(@addr))]);
}
}
@addr = split(/:/, join(':', @addr));
$_ = hex($_) foreach @addr;
return pack("n*", @addr);
}
sub ip6_swap printf "%5u IPv%s ranges for %s\n",
{ scalar(@ranges),
return pack("V*", unpack("N*", shift @_)); ($family == AF_INET ? '4' : '6'),
$iso_code unless ($quiet);
my $file = "$target_dir/".uc($iso_code).".iv".($family == AF_INET ? '4' : '6');
if (!open($fh, '>', $file)) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
binmode($fh);
foreach my $range (@ranges) {
my ($start, $end) = split('-', $range);
$start = inet_pton($family, $start);
$end = inet_pton($family, $end);
print $fh $start, $end;
}
close $fh;
} }

View File

@@ -5,7 +5,7 @@ xt_geoip_build \(em convert GeoIP.csv to packed format for xt_geoip
.SH Syntax .SH Syntax
.PP .PP
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build\fP [\fB\-D\fP \fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build\fP [\fB\-D\fP
\fItarget_dir\fP] [\fIfile\fP...] \fItarget_dir\fP] [\fB\-i\fP \fIinput_file\fP]
.SH Description .SH Description
.PP .PP
xt_geoip_build is used to build packed raw representations of the range xt_geoip_build is used to build packed raw representations of the range
@@ -16,20 +16,26 @@ required to be loaded into memory. The ranges in the packed database files are
also ordered, as xt_geoip relies on this property for its bisection approach to also ordered, as xt_geoip relies on this property for its bisection approach to
work. work.
.PP .PP
Input is processed from the listed files, or if none is given, from stdin.
.PP
Since the script is usually installed to the libexec directory of the Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the xtables-addons package and this is outside $PATH (on purpose), invoking the
script requires it to be called with a path. script requires it to be called with a path.
.PP Options .PP Options
.TP .TP
\fB\-D\fP \fItarget_dir\fP \fB\-D\fP \fItarget_dir\fP
Specify a target directory into which the files are to be put. Specifies the target directory into which the files are to be put. Defaults to ".".
.TP
\fB\-i\fP \fIinput_file\fP
Specifies the source location of the DBIP CSV file. Defaults to
"dbip-country-lite.csv". Use "-" to read from stdin.
.TP
\fB\-s\fP
"System mode". Equivalent to \fB\-D /usr/share/xt_geoip\fP.
.SH Application .SH Application
.PP .PP
Shell commands to build the databases and put them to where they are expected: Shell commands to build the databases and put them to where they are expected
(usually run as root):
.PP .PP
xt_geoip_build \-D /usr/share/xt_geoip xt_geoip_build \-s
.SH See also .SH See also
.PP .PP
xt_geoip_dl(1) xt_geoip_dl(1)

268
geoip/xt_geoip_build_maxmind Executable file
View File

@@ -0,0 +1,268 @@
#!/usr/bin/perl
#
# Converter for MaxMind (GeoLite2) CSV database to binary, for xt_geoip
# Copyright Jan Engelhardt, 2008-2011
# Copyright Philip Prindeville, 2018
#
use Getopt::Long;
use Net::CIDR::Lite;
use Socket qw(AF_INET AF_INET6 inet_pton);
use warnings;
use Text::CSV_XS; # or trade for Text::CSV
use strict;
my $csv = Text::CSV_XS->new({
allow_whitespace => 1,
binary => 1,
eol => $/,
}); # or Text::CSV
my $source_dir = ".";
my $quiet = 0;
my $target_dir = ".";
&Getopt::Long::Configure(qw(bundling));
&GetOptions(
"D=s" => \$target_dir,
"S=s" => \$source_dir,
"q" => \$quiet,
"s" => sub { $target_dir = "/usr/share/xt_geoip"; },
);
if (!-d $source_dir) {
print STDERR "Source directory \"$source_dir\" does not exist.\n";
exit 1;
}
if (!-d $target_dir) {
print STDERR "Target directory \"$target_dir\" does not exist.\n";
exit 1;
}
my %countryId;
my %countryName;
&loadCountries();
&dump(&collect());
sub loadCountries
{
sub id; sub cc; sub long; sub ct; sub cn;
%countryId = ();
%countryName = ();
my $file = "$source_dir/GeoLite2-Country-Locations-en.csv";
open(my $fh, '<', $file) || die "Couldn't open list country names\n";
# first line is headers
my $row = $csv->getline($fh);
my %header = map { ($row->[$_], $_); } (0..$#{$row});
my %pairs = (
country_iso_code => 'ISO Country Code',
geoname_id => 'ID',
country_name => 'Country Name',
continent_code => 'Continent Code',
continent_name => 'Continent Name',
);
# verify that the columns we need are present
map { die "Table has no $pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;
my %remapping = (
id => 'geoname_id',
cc => 'country_iso_code',
long => 'country_name',
ct => 'continent_code',
cn => 'continent_name',
);
# now create a function which returns the value of that column #
map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;
while (my $row = $csv->getline($fh)) {
if ($row->[cc] eq '' && $row->[long] eq '') {
$countryId{$row->[id]} = $row->[ct];
$countryName{$row->[ct]} = $row->[cn];
} else {
$countryId{$row->[id]} = $row->[cc];
$countryName{$row->[cc]} = $row->[long];
}
}
$countryName{A1} = 'Anonymous Proxy';
$countryName{A2} = 'Satellite Provider';
$countryName{O1} = 'Other Country';
close($fh);
# clean up the namespace
undef &id; undef &cc; undef &long; undef &ct; undef &cn;
}
sub lookupCountry
{
my ($id, $rid, $proxy, $sat) = @_;
if ($proxy) {
return 'A1';
} elsif ($sat) {
return 'A2';
}
$id ||= $rid;
if ($id eq '') {
return 'O1';
}
die "Unknown id: $id line $.\n" unless (exists $countryId{$id});
return $countryId{$id};
}
sub collect
{
my ($file, $fh, $row);
my (%country, %header);
sub net; sub id; sub rid; sub proxy; sub sat;
my %pairs = (
network => 'Network',
registered_country_geoname_id => 'Registered Country ID',
geoname_id => 'Country ID',
is_anonymous_proxy => 'Anonymous Proxy',
is_satellite_provider => 'Satellite',
);
foreach (sort keys %countryName) {
$country{$_} = {
name => $countryName{$_},
pool_v4 => Net::CIDR::Lite->new(),
pool_v6 => Net::CIDR::Lite->new(),
};
}
$file = "$source_dir/GeoLite2-Country-Blocks-IPv4.csv";
open($fh, '<', $file) || die "Can't open IPv4 database\n";
# first line is headers
$row = $csv->getline($fh);
%header = map { ($row->[$_], $_); } (0..$#{$row});
# verify that the columns we need are present
map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;
my %remapping = (
net => 'network',
id => 'geoname_id',
rid => 'registered_country_geoname_id',
proxy => 'is_anonymous_proxy',
sat => 'is_satellite_provider',
);
# now create a function which returns the value of that column #
map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;
while ($row = $csv->getline($fh)) {
my ($cc, $cidr);
$cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]);
$cidr = $row->[net];
$country{$cc}->{pool_v4}->add($cidr);
if ($. % 4096 == 0) {
print STDERR "\r\e[2K$. entries";
}
}
print STDERR "\r\e[2K$. entries total\n";
close($fh);
# clean up the namespace
undef &net; undef &id; undef &rid; undef &proxy; undef &sat;
$file = "$source_dir/GeoLite2-Country-Blocks-IPv6.csv";
open($fh, '<', $file) || die "Can't open IPv6 database\n";
# first line is headers
$row = $csv->getline($fh);
%header = map { ($row->[$_], $_); } (0..$#{$row});
# verify that the columns we need are present
map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;
# unlikely the IPv6 table has different columns, but just to be sure
# create a function which returns the value of that column #
map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;
while ($row = $csv->getline($fh)) {
my ($cc, $cidr);
$cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]);
$cidr = $row->[net];
$country{$cc}->{pool_v6}->add($cidr);
if (!$quiet && $. % 4096 == 0) {
print STDERR "\r\e[2K$. entries";
}
}
print STDERR "\r\e[2K$. entries total\n" unless ($quiet);
close($fh);
# clean up the namespace
undef &net; undef &id; undef &rid; undef &proxy; undef &sat;
return \%country;
}
sub dump
{
my $country = shift @_;
foreach my $iso_code (sort keys %{$country}) {
&dump_one($iso_code, $country->{$iso_code});
}
}
sub dump_one
{
my($iso_code, $country) = @_;
my @ranges;
@ranges = $country->{pool_v4}->list_range();
writeCountry($iso_code, $country->{name}, AF_INET, @ranges);
@ranges = $country->{pool_v6}->list_range();
writeCountry($iso_code, $country->{name}, AF_INET6, @ranges);
}
sub writeCountry
{
my ($iso_code, $name, $family, @ranges) = @_;
my $fh;
printf "%5u IPv%s ranges for %s %s\n",
scalar(@ranges),
($family == AF_INET ? '4' : '6'),
$iso_code, $name unless ($quiet);
my $file = "$target_dir/".uc($iso_code).".iv".($family == AF_INET ? '4' : '6');
if (!open($fh, '>', $file)) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
binmode($fh);
foreach my $range (@ranges) {
my ($start, $end) = split('-', $range);
$start = inet_pton($family, $start);
$end = inet_pton($family, $end);
print $fh $start, $end;
}
close $fh;
}

View File

@@ -0,0 +1,40 @@
.TH xt_geoip_build_maxmind 1 "2010-12-17" "xtables-addons" "xtables-addons"
.SH Name
.PP
xt_geoip_build_maxmind \(em convert GeoIP.csv to packed format for xt_geoip
.SH Syntax
.PP
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build_maxmind\fP [\fB\-D\fP
\fItarget_dir\fP] [\fB\-S\fP \fIsource_dir\fP]
.SH Description
.PP
xt_geoip_build_maxmind is used to build packed raw representations of the range
database that the xt_geoip module relies on. Since kernel memory is precious,
much of the preprocessing is done in userspace by this very building tool. One
file is produced for each country, so that no more addresses than needed are
required to be loaded into memory. The ranges in the packed database files are
also ordered, as xt_geoip relies on this property for its bisection approach to
work.
.PP
Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the
script requires it to be called with a path.
.PP Options
.TP
\fB\-D\fP \fItarget_dir\fP
Specifies the target directory into which the files are to be put. Defaults to ".".
.TP
\fB\-S\fP \fIsource_dir\fP
Specifies the source directory of the MaxMind CSV files. Defaults to ".".
.TP
\fB\-s\fP
"System mode". Equivalent to \fB\-D /usr/share/xt_geoip\fP.
.SH Application
.PP
Shell commands to build the databases and put them to where they are expected
(usually run as root):
.PP
xt_geoip_build_maxmind \-s
.SH See also
.PP
xt_geoip_dl_maxmind(1)

View File

@@ -1,8 +1,5 @@
#!/bin/sh #!/bin/sh
rm -f GeoIPv6.csv GeoIPv6.csv.gz GeoIPCountryCSV.zip GeoIPCountryWhois.csv; timestamp=$(date "+%Y-%m")
wget \ wget -q "https://download.db-ip.com/free/dbip-country-lite-$timestamp.csv.gz" -O- | \
http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz \ gzip -cd >dbip-country-lite.csv
http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip;
gzip -d GeoIPv6.csv.gz;
unzip GeoIPCountryCSV.zip;

View File

@@ -7,8 +7,9 @@ xt_geoip_dl \(em download GeoIP database files
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_dl\fP \fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_dl\fP
.SH Description .SH Description
.PP .PP
Downloads and unpacks the MaxMind GeoIP Country Lite databases for IPv4 and Downloads the DB-IP Country Lite databases for IPv4 and IPv6 and unpacks them
IPv6 and unpacks them to the current directory. to the current directory. The alternate \fBxt_geoip_dl_maxmind\fP script can be
used for MaxMind formatted CSV databases.
.PP .PP
Since the script is usually installed to the libexec directory of the Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the xtables-addons package and this is outside $PATH (on purpose), invoking the

16
geoip/xt_geoip_dl_maxmind Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
if [ $# -eq 1 ]; then
exec <$1
elif [ $# -ne 0 ]; then
echo $(basename $0) [ licence_key_file ] 1>&2
exit 1
fi
read licence_key
rm -rf GeoLite2-Country-CSV_*
wget -q -OGeoLite2-Country-CSV.zip "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=${licence_key}&suffix=zip"
unzip -q GeoLite2-Country-CSV.zip
rm -f GeoLite2-Country-CSV.zip

View File

@@ -0,0 +1,22 @@
.TH xt_geoip_dl_maxmind 1 "2010-12-17" "xtables-addons" "xtables-addons"
.SH Name
.PP
xt_geoip_dl_maxmind \(em download MaxMind GeoIP database files
.SH Syntax
.PP
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_dl_maxmind\fP [\fI licence-key file\fP]
.SH Description
.PP
Downloads the MaxMind GeoLite2 databases for IPv4 and IPv6 and unpacks them to
the current directory. The alternate \fBxt_geoip_dl\fP script can be
used for the DB-IP Country Lite databases.
.PP
Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the
script requires it to be called with a path.
.SH Options
.PP
None.
.SH See also
.PP
xt_geoip_build_maxmind(1)

95
geoip/xt_geoip_query Executable file
View File

@@ -0,0 +1,95 @@
#!/usr/bin/perl
#
# Utility to query GeoIP database (.iv4/.iv6 files)
# Copyright Philip Prindeville, 2018
#
use Getopt::Long;
use Socket qw(AF_INET AF_INET6 inet_ntop);
use warnings;
use strict;
sub AF_INET_SIZE() { 4 }
sub AF_INET6_SIZE() { 16 }
my $target_dir = ".";
my $ipv4 = 0;
my $ipv6 = 0;
&Getopt::Long::Configure(qw(bundling));
&GetOptions(
"D=s" => \$target_dir,
"4" => \$ipv4,
"6" => \$ipv6,
);
if (!-d $target_dir) {
print STDERR "Target directory $target_dir does not exit.\n";
exit 1;
}
# if neither specified, assume both
if (! $ipv4 && ! $ipv6) {
$ipv4 = $ipv6 = 1;
}
foreach my $cc (@ARGV) {
if ($cc !~ m/^([a-z]{2}|a[12]|o1)$/i) {
print STDERR "Invalid country code '$cc'\n";
exit 1;
}
my $file = $target_dir . '/' . uc($cc) . '.iv4';
if (! -f $file) {
printf STDERR "Can't find data for country '$cc'\n";
exit 1;
}
my ($contents, $buffer, $bytes, $fh);
if ($ipv4) {
open($fh, '<', $file) || die "Couldn't open file for '$cc'\n";
binmode($fh);
while (($bytes = read($fh, $buffer, AF_INET_SIZE * 2)) == AF_INET_SIZE * 2) {
my ($start, $end) = unpack('a4a4', $buffer);
$start = inet_ntop(AF_INET, $start);
$end = inet_ntop(AF_INET, $end);
print $start, '-', $end, "\n";
}
close($fh);
if (! defined $bytes) {
printf STDERR "Error reading file for '$cc'\n";
exit 1;
} elsif ($bytes != 0) {
printf STDERR "Short read on file for '$cc'\n";
exit 1;
}
}
substr($file, -1) = '6';
if ($ipv6) {
open($fh, '<', $file) || die "Couldn't open file for '$cc'\n";
binmode($fh);
while (($bytes = read($fh, $buffer, AF_INET6_SIZE * 2)) == AF_INET6_SIZE * 2) {
my ($start, $end) = unpack('a16a16', $buffer);
$start = inet_ntop(AF_INET6, $start);
$end = inet_ntop(AF_INET6, $end);
print $start, '-', $end, "\n";
}
close($fh);
if (! defined $bytes) {
printf STDERR "Error reading file for '$cc'\n";
exit 1;
} elsif ($bytes != 0) {
printf STDERR "Short read on file for '$cc'\n";
exit 1;
}
}
}
exit 0;

35
geoip/xt_geoip_query.1 Normal file
View File

@@ -0,0 +1,35 @@
.TH xt_geoip_query 1 "2020-04-30" "xtables-addons" "xtables-addons"
.SH Name
.PP
xt_geoip_query \(em dump a country database to stdout
.SH Syntax
.PP
\fBxt_geoip_query\fP [\fB\-D\fP
\fIdatabase_dir\fP] [\fB-4\fP] [\fB-6\fP] \fIcc\fP [ \fIcc\fP ... ]
.SH Description
.PP
xt_geoip_query reads a country's IPv4 or IPv6 databases and dumps
them to standard output as a sorted, non-overlapping list of ranges (which
is how they are represented in the database), suitable for browsing or
further processing.
.PP Options
.TP
\fB\-D\fP \fIdatabase_dir\fP
Specifies the directory into which the files have been put. Defaults to ".".
.TP
\fB-4\fP
Specifies IPv4 data only.
.TP
\fB-6\fP
Specifies IPv6 data only.
.TP
\fIcc\fP [ \fIcc\fP ... ]
The ISO-3166 country code names of the desired countries' databases.
.SH Application
.PP
Shell command to dump the list of Swiss IPv6 address ranges:
.PP
xt_geoip_query \-D /usr/share/xt_geoip \-6 ch
.SH See also
.PP
xt_geoip_build(1)

View File

@@ -8,6 +8,7 @@ build_DNETMAP=m
build_ECHO=m build_ECHO=m
build_IPMARK=m build_IPMARK=m
build_LOGMARK=m build_LOGMARK=m
build_PROTO=m
build_SYSRQ=m build_SYSRQ=m
build_TARPIT=m build_TARPIT=m
build_condition=m build_condition=m

View File

@@ -1,3 +0,0 @@
#
# Source URLs for external patchlets
#

View File

@@ -1,83 +0,0 @@
#!/usr/bin/perl -w
use HTTP::Request;
use LWP::UserAgent;
use strict;
&main(\@ARGV);
sub main
{
local *FH;
if (!-d "downloads") {
if (!mkdir("downloads")) {
die "Could not create downloads/ directory";
}
}
open(FH, "<sources");
while (defined($_ = <FH>)) {
chomp $_;
$_ =~ s/#.*//gs;
$_ =~ s/^\s+|\s+$//gs;
if (length($_) == 0) {
next;
}
&process_index($_);
}
close FH;
}
sub process_index
{
my $top = shift @_;
my($agent, $res, $url);
local *FH;
$agent = LWP::UserAgent->new();
$agent->env_proxy();
$url = &slash_remove("$top/xa-index.txt");
print " GET $url\n";
$res = $agent->get($url);
if (!$res->is_success()) {
print STDERR " `-> ", $res->status_line(), "\n";
return;
}
foreach my $ext (split(/\s+/, $res->content())) {
my($ex_url, $ex_res);
$ex_url = &slash_remove("$top/$ext");
print " GET $ex_url\n";
$ex_res = $agent->mirror($ex_url, "downloads/$ext");
if ($ex_res->code() == 304) {
# "Not modified" = up to date
next;
}
if (!$ex_res->is_success()) {
print STDERR " `-> ", $ex_res->status_line(), "\n";
next;
}
print " UNPACK downloads/$ext\n";
system "tar", "-xjf", "downloads/$ext";
}
}
sub slash_remove
{
my $s = shift @_;
$s =~ s{(\w+://)(.*)}{$1.&slash_remove2($2)}eg;
return $s;
}
sub slash_remove2
{
my $s = shift @_;
$s =~ s{/+}{/}g;
return $s;
}

View File

@@ -1,4 +1,4 @@
.TH xtables-addons 8 "Not For Workgroups" "" "v2.12 (2017-01-11)" .TH xtables-addons 8 "" "" "v3.18 (2021-03-11)"
.SH Name .SH Name
Xtables-addons \(em additional extensions for iptables, ip6tables, etc. Xtables-addons \(em additional extensions for iptables, ip6tables, etc.
.SH Targets .SH Targets