Compare commits

..

184 Commits

Author SHA1 Message Date
Jan Engelhardt
26f25a43a9 Xtables-addons 1.18 2009-09-09 17:37:07 +02:00
Jan Engelhardt
bcda21a2b0 Merge branch 'psd' 2009-09-09 17:27:28 +02:00
Jan Engelhardt
4e6bc8af95 Merge branch 'ACCOUNT' 2009-09-09 17:26:00 +02:00
Jan Engelhardt
bd4be0d991 ACCOUNT: remove pointless casts 2009-09-05 04:39:00 +02:00
Jan Engelhardt
1f736c8203 ACCOUNT: remove static initializers to zero
These are not needed, .bss is zeroed.
2009-09-05 04:39:00 +02:00
Jan Rafaj
90fa3ab9e2 ACCOUNT: tweak base ctl number for setsockopts
IPT_BASE_CTL+3 is already used IPT_SO_GET_REVISION_TARGET and
therefore must not be used by extensions.
2009-09-05 04:38:57 +02:00
Jan Engelhardt
fd82a312d6 Merge branch 'ipset' 2009-09-05 03:49:47 +02:00
Jan Engelhardt
27c1676821 ipset: fix compile error with 2.6.20
$e/ipset/ip_set_iptree.c: In function "iptree_test":
$e/ipset/ip_set_iptree.c:84:6: warning: implicit declaration of
function "time_after"
$e/ipset/ip_set_iptree.c:84:39: error: "jiffies" undeclared (first
use in this function)
$e/ipset/ip_set_iptree.c:84:39: error: (Each undeclared identifier is
reported only once
$e/ipset/ip_set_iptree.c:84:39: error: for each function it appears
in.)
$e/ipset/ip_set_iptree.c: In function "iptree_add":
$e/ipset/ip_set_iptree.c:130:57: error: "jiffies" undeclared (first
use in this function)
$e/ipset/ip_set_iptree.c:134:48: error: "HZ" undeclared (first use in
this function)
$e/ipset/ip_set_iptree.c: In function "ip_tree_gc":
$e/ipset/ip_set_iptree.c:214:8: warning: implicit declaration of
function "time_before"
$e/ipset/ip_set_iptree.c:214:42: error: "jiffies" undeclared (first
use in this function)
$e/ipset/ip_set_iptree.c:258:49: error: "HZ" undeclared (first use in
this function)
$e/ipset/ip_set_iptree.c: In function "init_gc_timer":
$e/ipset/ip_set_iptree.c:274:20: error: "jiffies" undeclared (first
use in this function)
$e/ipset/ip_set_iptree.c:274:49: error: "HZ" undeclared (first use in
this function)
$e/ipset/ip_set_iptree.c: In function "iptree_list_members_size":
$e/ipset/ip_set_iptree.c:380:58: error: "jiffies" undeclared (first
use in this function)
$e/ipset/ip_set_iptree.c: In function "iptree_list_members":
$e/ipset/ip_set_iptree.c:407:58: error: "jiffies" undeclared (first
use in this function)
$e/ipset/ip_set_iptree.c:411:37: error: "HZ" undeclared (first use in
this function)

$e/ipset/ip_set_iptreemap.c: In function "gc":
$e/ipset/ip_set_iptreemap.c:456:20: error: "jiffies" undeclared
(first use in this function)
$e/ipset/ip_set_iptreemap.c:456:20: error: (Each undeclared
identifier is reported only once
$e/ipset/ip_set_iptreemap.c:456:20: error: for each function it
appears in.)
$e/ipset/ip_set_iptreemap.c:456:49: error: "HZ" undeclared (first use
in this function)
$e/ipset/ip_set_iptreemap.c: In function "init_gc_timer":
$e/ipset/ip_set_iptreemap.c:468:20: error: "jiffies" undeclared
(first use in this function)
$e/ipset/ip_set_iptreemap.c:468:49: error: "HZ" undeclared (first use
in this function)
2009-09-05 03:49:37 +02:00
Jan Engelhardt
3e26335cbd ipset: fast forward to v3.2 2009-09-05 03:49:37 +02:00
Jan Rafaj
f4b96672ef ACCOUNT: add kernel module metadata and alias 2009-09-05 03:40:47 +02:00
Jan Engelhardt
c3d080f21a ACCOUNT: manpage updates
- expand "f.e."
- escape dashes where appropriate
- fB/fI formatting
2009-09-05 03:40:47 +02:00
Jan Rafaj
cb268031b7 ACCOUNT: supply manpage 2009-09-05 03:40:47 +02:00
Jan Engelhardt
ac44a5a1fe ACCOUNT: direct-inline two short functions 2009-09-05 03:40:47 +02:00
Jan Rafaj
a3baa78ae2 ACCOUNT: remove compat glue from libxt_ACCOUNT 2009-09-05 03:40:47 +02:00
Jan Rafaj
47e002127c ACCOUNT: use non-clashing function names
[jengelh: It is just impossible to set a breakpoint right on functions
if all modules call or/use the same symbol name.]
2009-09-05 03:40:47 +02:00
Jan Rafaj
03363a528a ACCOUNT: utilize compat_xtables.h for backwards compatibility 2009-09-05 03:40:47 +02:00
Jan Rafaj
58b016f0af ACCOUNT: replace own DEBUGP by kernel's pr_debug 2009-09-05 03:40:47 +02:00
Jan Rafaj
8d64e7bd50 ACCOUNT: remove manual compat support 2009-09-05 03:40:47 +02:00
Jan Engelhardt
dd6cb27da4 ACCOUNT: simple reformat, use tabs instead of spaces
The result is not perfect, but at more manageable.
2009-09-05 03:40:46 +02:00
Jan Engelhardt
06c01131e8 ACCOUNT: remove trailing whitespace 2009-09-05 03:38:58 +02:00
Jan Engelhardt
a44c4e4b1d Import ACCOUNT kernel and iptables modules
Reference: git://developer.intra2net.com/ipt_ACCOUNT # v1.15-1-gfb4dd1a
2009-09-05 03:38:31 +02:00
Jan Engelhardt
1fb6f187d3 build: enable fully parallel builds
Make make happy by using ${MAKE} instead of make.
2009-08-28 12:32:52 +02:00
Jan Engelhardt
83e474f9ab psd: move pr_ prefix into pr_fmt 2009-08-28 12:32:23 +02:00
Jan Engelhardt
efd4c91557 psd: style: remove braces for single statements in ifs 2009-08-16 12:40:44 +02:00
Jan Engelhardt
65a257a67d psd: style: add explicit comparisons where not used in bool context 2009-08-14 20:26:37 +02:00
Jan Engelhardt
5b07e04600 psd: style: break double statements 2009-08-14 20:24:36 +02:00
Jan Engelhardt
6b175b40cb psd: jiffies is an unsigned long, fix compiler warning
"jiffies" has always been unsigned long, not clock_t.

xt_psd.c:176:7: warning: comparison of distinct pointer types lacks a cast
2009-08-14 20:19:13 +02:00
Jan Engelhardt
0887365f8b psd: remove whitespace at EOL 2009-08-14 20:15:00 +02:00
Jan Engelhardt
cebadbfcd7 psd: merge into main configuration files
When psd is included in the main tree, it can use the main
configuration files.
2009-08-14 20:12:43 +02:00
Mohd Nawawi Mohamad Jamili
380b1b6997 psd: fix revision mismatch 2009-08-13 13:11:18 +02:00
Jan Engelhardt
8e5219636a psd: tag match reg struct as __read_mostly 2009-08-13 01:04:26 +02:00
Jan Engelhardt
760edd3db6 psd: use fixated types in info struct 2009-08-13 00:52:46 +02:00
Jan Engelhardt
502c1c05aa psd: return correct status from init 2009-08-13 00:46:33 +02:00
Jan Engelhardt
a7ceccc0f4 psd: bss is always zero-initialized 2009-08-13 00:45:52 +02:00
Jan Engelhardt
10bd08d0f3 psd: remove empty checkentry function 2009-08-13 00:44:39 +02:00
Jan Engelhardt
1e5315d338 psd: replace open-coded access by skb handling functions
pskb->network_header would not even compile under older kernels.

This also fixes the compile warning:
xt_psd.c:116:18: warning: cast to pointer from integer of different size
2009-08-13 00:42:01 +02:00
Jan Engelhardt
579484ed70 psd: avoid shadowing of function
ip_hdr and tcp_hdr are actually functions. Because we need them means
they must not be shadowed by variables.
2009-08-13 00:38:39 +02:00
Mohd Nawawi Mohamad Jamili
2aa32d4bce psd: import 20090807 code base 2009-08-12 21:59:33 +02:00
Jan Engelhardt
5aee8738ed quota2: fix invalid page access in cleanup function 2009-08-07 10:35:52 +02:00
Jan Engelhardt
1111edfd85 quota2: change max name length from 31 to 15 2009-07-10 17:21:27 +02:00
Jan Engelhardt
0d47cb8b37 quota2: direct-code XT_QUOTA_COUNTER_NAME_LENGTH 2009-07-10 17:21:12 +02:00
Jan Engelhardt
1c55aec64a quota2: use strtoull instead of strtoul 2009-07-10 17:18:48 +02:00
Jan Engelhardt
dd26ab476c quota2: extend locked period during cleanup 2009-07-04 02:11:25 +02:00
Jan Engelhardt
4bf667d8eb quota2: reduce memory footprint for anonymous counters
48/64 bytes (32/64-bit arch, resp.) per counter.
2009-07-04 01:53:35 +02:00
Jan Engelhardt
0a88bd3435 quota2: consolidate spinlocking calls 2009-07-04 01:31:13 +02:00
Jan Engelhardt
62fb261265 quota2: prefix internal struct name with xt_ 2009-07-04 01:29:32 +02:00
Jan Engelhardt
d97f77a8f5 TEE: spello fix 2009-07-02 04:16:14 +02:00
Jan Engelhardt
822c6bebe2 quota2: support nameless counters 2009-07-02 02:21:11 +02:00
Jan Engelhardt
fdf42a3a50 build: support for Linux 2.6.31-rc1 2009-07-02 01:51:40 +02:00
Jan Engelhardt
6b2ca78af7 build: fix kernel version info 2009-07-02 01:04:48 +02:00
Jan Engelhardt
ee24cd1ac1 Xtables-addons 1.17 2009-06-16 16:25:53 +02:00
kd6lvw
71812a2053 build: support for Linux 2.6.30
Fix a compile error with xt_quota2. Linux kernel commit
v2.6.29-7544-g3ba113d removed the "owner" member.
2009-06-12 03:41:00 +02:00
kd6lvw
31e4e18998 build: use readlink -f in extensions/ipset/
Supplement to v1.5.7-5-gf373750.
2009-06-12 03:37:18 +02:00
Marek Michalkiewicz
9fb2ffe1d3 IPMARK: print missing --shift parameter 2009-06-12 03:33:54 +02:00
Jan Engelhardt
23e83aa04c Xtables-addons 1.16 2009-05-27 14:55:51 +02:00
Jan Engelhardt
77ee63ba8b ipset: fast forward to 3.0 2009-05-27 14:51:15 +02:00
Jan Engelhardt
49e59a6dce RAWNAT: make iptable_rawpost compile with 2.6.30-rc5 2009-05-15 18:35:53 +02:00
Jan Engelhardt
137ecb9814 extensions: bump revision number to avoid possible POM clash
Users still using a kernel with POM modules may have problems due to
differing binary structures. Bump the revision numbers of the
Xtables-addons modules, to make them distinct from POM.
2009-05-14 21:42:05 +02:00
Jan Engelhardt
7e25254e93 SYSRQ: enable userspace module for multiprotocol 2009-05-14 21:39:48 +02:00
Jan Engelhardt
0c9ae3cb1b iface: enable for multiprotocol 2009-05-14 21:38:09 +02:00
Jan Engelhardt
471e747fc0 STEAL: enable for multiprotocol 2009-05-14 21:38:08 +02:00
Jan Engelhardt
fe7a66f3cb Xtables-addons 1.15 2009-04-30 20:58:23 +02:00
Jan Engelhardt
a13650f94d Merge branch 'RAWNAT' 2009-04-30 20:35:59 +02:00
Jan Engelhardt
73e7b5ead1 compat_xtables: fix compilation with <= 2.6.19
Once upon a time there was no such checksumming...
2009-04-30 20:35:48 +02:00
Jan Engelhardt
e5920cc577 Merge branch 'iface' 2009-04-30 19:41:56 +02:00
Jan Engelhardt
39655fe83b iface: fix compilation with <= 2.6.27
Need to include compat_xtables.h to get all the definitions for older
kernels.
Also, net namespaces are not available before 2.6.24.
2009-04-30 19:41:31 +02:00
Jan Engelhardt
9df309a14a iface: remove unused .data field
Neither is it anywhere used, but compat_xtables does not provide it
either.
2009-04-28 10:04:36 +02:00
Jan Engelhardt
5e2085a45f build: reword RH5-unsupported warning 2009-04-28 01:41:57 +02:00
Jan Engelhardt
4bcb7077c0 Merge branch 'iface' 2009-04-27 20:50:05 +02:00
Jan Engelhardt
000c2d73fd iface: must use __u types in header files 2009-04-27 20:46:25 +02:00
Jan Engelhardt
e89c5d976a iface: move private struct xt_iface_flag_pairs to .c file 2009-04-27 20:46:09 +02:00
Jan Engelhardt
f5ed98fbf5 iface: update documentation
For one, the tabs must go as they cause alignment problems. Also
update the manpage with proper markup.
2009-04-26 23:20:38 +02:00
Jan Engelhardt
60c4162087 iface: replace --lower_up by --lower-up 2009-04-26 22:22:20 +02:00
Jan Engelhardt
074a7d6cb7 iface: remove --promiscous flag
The spelling is difficult (actually it is "promiscuous"), and one
option should be enough. Keeping --promisc.
2009-04-26 22:21:27 +02:00
Jan Engelhardt
a6ba463c43 iface: remove redundant fields and use bool 2009-04-26 22:13:06 +02:00
Jan Engelhardt
be2061c520 iface: constify data arrays 2009-04-26 22:13:05 +02:00
Jan Engelhardt
3f96deb0f0 iface: remove define for internal array size
The macro was only used inside kernel code and not relevant to
user-space anyway.
2009-04-26 22:07:53 +02:00
Jan Engelhardt
6d8ce3acae iface: dissolve module name/revision macros
The module name will unlikely be changing anytime soon. And if the
revision increases, we cannot just bump the number (well, in
Xtables-addons we can, but it would not be the case for the core
kernel). So let's not get into bad habits.
2009-04-26 22:07:43 +02:00
Jan Engelhardt
f6c317710f iface: remove version/revision from helptext
XTABLES_VERSION does not contain anything meaningful to display.
Printing the revision is not of value too, I think.
2009-04-26 22:01:30 +02:00
Jan Engelhardt
6799806300 iface: use NFPROTO_* 2009-04-26 21:59:41 +02:00
Jan Engelhardt
0d36136f54 iface: some command decoupling 2009-04-26 21:56:53 +02:00
Jan Engelhardt
e1fc5f2086 iface: remove redundant parentheses 2009-04-26 21:56:25 +02:00
Jan Engelhardt
9d5f4bf468 Merge branch 'RAWNAT' 2009-04-26 21:47:43 +02:00
Jan Engelhardt
637516f2d4 RAWNAT: add extension's kernel and userspace modules
RAWNAT provides stateless 1:1 network address translation.
2009-04-26 21:44:54 +02:00
Jan Engelhardt
b427c930f2 build: add kernel version check to configure 2009-04-26 20:22:40 +02:00
Roman Hoog Antink
34f39756ec condition: fix intrapositional negation sign 2009-04-17 16:12:30 +02:00
Bryan Duff
e36c7575fc condition: compile fix for 2.6.30-rc 2009-04-17 16:01:45 +02:00
Jan Engelhardt
0a23bd2580 doc: update changelog 2009-04-14 21:43:13 +02:00
Jan Engelhardt
03aeed615d RAWNAT: add the rawpost tables for IPv4/IPv6 2009-04-11 00:35:58 +02:00
Jan Engelhardt
49018e2ff7 Merge branch 'sf/master' 2009-04-11 00:33:28 +02:00
Jan Engelhardt
50d14a33c0 ipp2p: fix typo in error message
Reference: http://bugs.gentoo.org/show_bug.cgi?id=250407
Reported-by: Mike <empx@gmx.de>
2009-04-10 19:42:59 +02:00
Jan Engelhardt
c64a78ffcc ipp2p: fix bogus varargs call
Reference: http://bugs.gentoo.org/show_bug.cgi?id=250407
Reported-by: Mike <empx@gmx.de>
2009-04-10 19:34:56 +02:00
Jan Engelhardt
1aae519356 iface: remove DEBUGP 2009-04-05 10:59:12 +02:00
Jan Engelhardt
af5823b407 iface: remove redundant functions 2009-04-05 10:50:45 +02:00
Jan Engelhardt
9b198fe6e7 iface: import version 20081029 2009-04-05 10:37:05 +02:00
Jan Engelhardt
4997b326f6 fuzzy: fix bogus comparison logic leftover from move to new 1.4.3 API 2009-04-05 10:36:16 +02:00
Jriri Moravec
c288ecdb9c dhcpmac: fix rename leftover from typo 2009-04-04 01:14:32 +02:00
Jan Engelhardt
f21e372402 ipp2p: print ipp2p module name when run from iptables -L 2009-04-04 00:45:20 +02:00
Eray Aslan
927dd88dc4 SYSRQ: fix manpage typo 2009-04-02 10:37:55 +02:00
Jan Engelhardt
7dd96ec357 Xtables-addons 1.14 2009-03-31 22:55:29 +02:00
Jan Engelhardt
ba6aa51f91 SYSRQ: do proper L4 header access in IPv6 code 2009-03-27 21:06:26 +01:00
Jan Engelhardt
beb7546e20 SYSRQ: ignore non-UDP packets 2009-03-27 20:27:03 +01:00
Jan Engelhardt
67579079e0 layer: block use of DEBUGP
As per "Writing Netfilter Modules" e-book 20090326 section 4.8, one
should use pr_debug instead.
2009-03-27 00:00:44 +01:00
Jan Engelhardt
3a632a9bc5 dhcpmac: rename from dhcpaddr 2009-03-26 21:55:10 +01:00
Jan Engelhardt
45b2e64d82 desc: add informational Kconfig descriptions 2009-03-26 21:32:44 +01:00
Jan Engelhardt
538d74b5d8 Update my email address 2009-03-25 22:10:42 +01:00
Jan Engelhardt
e3988b50b5 Add the "STEAL" target from the "demos" branch 2009-03-25 19:54:25 +01:00
Jan Engelhardt
f4b8440fba libxt_geoip: geoip: remove XT_ALIGN from .userspacesize when used with offsetof
XT_ALIGN rounds up to the nearest multiple of 64 bits, but that is wrong
for .userspacesize if it is less than .matchsize/.targetsize.
2009-03-24 08:27:41 +01:00
Changli Gao
d3ee3a0c3c libxt_fuzzy: need to account for kernel-level modified variables in .userspacesize
When reviewing the code, I found there maybe a bug in libxt_fuzzy.c.
If a user wants to delete this match, he will get an error reported,
and the command fails. As the fields after maximum_rate in
xt_fuzzy_mtinfo will be altered in kernel space, we should assign the
userspacesize with the value offsetof(struct xt_fuzzy_mtinfo,
packets_total) instead.
2009-03-24 08:26:24 +01:00
Jan Engelhardt
f96bc08f35 Xtables-addons 1.13 2009-03-23 15:50:42 +01:00
Jan Engelhardt
a0c791dc88 Upgrade to iptables 1.4.3 API 2009-03-19 11:05:26 +01:00
Jan Engelhardt
f717a91bc5 Merge branch 'ipv4options' 2009-03-19 11:03:26 +01:00
Jan Engelhardt
8bd5fc14ba libxt_ipv4options: add manpage 2009-03-19 10:34:27 +01:00
Jan Engelhardt
a51b16097b Add a reworked IPv4 options match - xt_ipv4options
This revision 1 of ipv4options makes it possible to match the
presence or absence of any of the 32 possible IP options, either all
or any of the options the user specified.
2009-03-08 23:38:12 +01:00
Jan Engelhardt
0bb538ba69 Xtables-addons 1.12 2009-03-07 03:24:21 +01:00
Jan Engelhardt
e11a07b230 build: fix compile issues with <= 2.6.19
Resolve compile breakage from commits
36f80be2f7 and
7b9ca945d4.
2009-03-07 02:58:36 +01:00
Jan Engelhardt
d263cfbd50 ipset: fast forward to 2.5.0 2009-03-07 01:33:31 +01:00
Jan Engelhardt
36f80be2f7 xt_TEE: enable routing by iif, nfmark and flowlabel
Patrick McHardy suggests in
http://marc.info/?l=netfilter-devel&m=123564267330117&w=2 that
routing should handle the clone more like its original.
2009-03-07 01:27:08 +01:00
Jan Engelhardt
7b9ca945d4 xt_LOGMARK: print incoming interface index 2009-03-07 01:15:48 +01:00
Jan Engelhardt
ffeb1da7d7 build: silence warning about ignored variable
The warning was:

	config.status: WARNING: 'extensions/ipset/GNUmakefile.in'
	seems to ignore the --datarootdir setting
2009-03-07 00:59:05 +01:00
Florian Westphal
d2d8712980 xt_TEE: resolve unknown symbol error with CONFIG_IPV6=n
WARNING: xt_TEE.ko needs unknown symbol ip6_route_output

Signed-off-by: Florian Westphal <fwestphal@astaro.com>
2009-03-07 00:48:16 +01:00
Jan Engelhardt
621cef39f5 revert "TEE: do not use TOS for routing"
Revert commit f77a8e2eda.

Patrick McHardy suggests in
http://marc.info/?l=netfilter-devel&m=123564267330117&w=2 that
routing should handle the clone more like its original.
2009-03-05 02:03:06 +01:00
Jan Engelhardt
08e6f23655 xt_lscan: rename from xt_portscan 2009-03-05 01:43:29 +01:00
Jan Engelhardt
4a25321191 doc: ipset: replace RW_LOCK_UNLOCKED
ipset uses RW_LOCK_UNLOCKED directly, but this is not quite right,
and causes compilation errors with 2.6.29-rt.
2009-03-05 01:30:02 +01:00
Jan Engelhardt
8c322a0119 ipset: replace RW_LOCK_UNLOCKED
ipset uses RW_LOCK_UNLOCKED directly, but this is not quite right,
and causes compilation errors with 2.6.29-rt.
2009-03-05 01:25:17 +01:00
Jan Engelhardt
bd39e4671e doc: remove old path examples 2009-02-24 19:14:10 +01:00
Jan Engelhardt
3d6bb5f86f doc: add changelog 2009-02-21 17:21:39 +01:00
Jan Engelhardt
ce03d0ee8e build: make kbuild call obey V 2009-02-21 16:54:49 +01:00
Jan Engelhardt
bca90ca2a7 build: trigger configure when GNUmakefile.in changed 2009-02-21 16:54:30 +01:00
Jan Engelhardt
08cb9e5584 Xtables-addons 1.10 2009-02-18 00:31:26 +01:00
Jan Engelhardt
1a8cc305af doc: add precise version information to INSTALL document 2009-02-11 16:56:35 +01:00
Jan Engelhardt
47a34e0ccf ipset: upgrade to ipset 2.4.9 2009-02-11 16:51:40 +01:00
Jan Engelhardt
36dab67658 Update .gitignore 2009-02-11 15:57:10 +01:00
Jan Engelhardt
7bb2957e47 compat: compile fixes for 2.6.29
2.6.29 removes at least NIP6, and NIPQUAD is scheduled to follow.
2009-02-11 15:56:33 +01:00
Jan Engelhardt
c168a2f142 Xtables-addons 1.9 2009-01-30 06:34:07 +01:00
Jan Engelhardt
68af6989b1 ipset: bump version to 2.4.7
Moving from ipset 2.4.5 to 2.4.7. Upstream changed, but
the Xtables-addons copy did not (issues were not present):

>2.4.7
>  - Typo which broke compilation with kernels < 2.6.28
>    fixed (reported by Richard Lucassen, Danny Rawlins)
>
>2.4.6
>   - Compatibility fix for kernels >= 2.6.28
2009-01-30 06:33:21 +01:00
Jan Engelhardt
446c67018a TEE: remove calls to check_inverse 2009-01-30 06:19:22 +01:00
Jan Engelhardt
0fe8e180c4 ipp2p: version bump
For cosmetics, or so. The recent bugfix warrants this I'd say.
2009-01-30 06:02:10 +01:00
Jan Engelhardt
7cdfc0ac3d Add xt_length2
xt_length2 provides exact layer-4,-5 and -7 length matching
besides the preexisting layer-3 length match.
2009-01-30 06:01:12 +01:00
Jan Engelhardt
85cab10371 Xtables-addons 1.8 2009-01-10 14:05:46 +01:00
Jan Engelhardt
61d8425cb6 Merge branch 'TEE6' 2009-01-10 14:03:04 +01:00
Jan Engelhardt
d49b6244c1 Merge branch 'TEE' 2009-01-10 14:03:03 +01:00
Jan Engelhardt
10c2b97786 Merge branch 'ipp2p' 2009-01-10 13:59:43 +01:00
Jan Engelhardt
9ed364ed36 TEE: collapse tee_tg_send{4,6} 2009-01-10 13:58:19 +01:00
Jan Engelhardt
b95e5f6417 TEE: IPv6 support for iptables module 2009-01-10 10:19:21 +01:00
Jan Engelhardt
4afebf88eb Merge branch 'TEE' into TEE6 2009-01-10 10:01:31 +01:00
Jan Engelhardt
d523158e92 TEE: iptables -nL and -L produced conversely output 2009-01-10 10:01:27 +01:00
Jan Engelhardt
1fd1787a1c TEE: limit iptables module to NFPROTO_IPV4
The code here is only usable with IPv4.
2009-01-10 09:57:44 +01:00
Jan Engelhardt
fbbca68790 ipp2p: partial revert of 3c8131b9
Revert part of 3c8131b976.

The transport header offset is not (yet) set by the time Netfilter
is invoked so using tcp_hdr/udp_hdr has undefined behavior.
2009-01-10 08:25:42 +01:00
Jan Engelhardt
4cdfd49637 ipp2p: add boundary check in search_all_kazaa
To avoid underflow on "end - 18", we must check for plen >= 18.
2009-01-10 06:11:13 +01:00
Jan Engelhardt
31c01cf107 portscan: update manpage about --grscan caveats 2009-01-10 05:23:43 +01:00
Jan Engelhardt
879e964f60 ipp2p: remove log flooding
Syslog was flooded by lots of messages due to if (plen >= 5) firing
on any packet, when it should have been plen < 5. Incidentally, this
turned up that plen also takes on huge nonsense values, assuming
underflow - yet to be investigated.
2009-01-10 04:47:14 +01:00
Jan Engelhardt
019c9de291 ipp2p: update help text
More suggestions from Stanley Pinchak.
2009-01-10 04:42:27 +01:00
Jan Engelhardt
af370f81f0 ipp2p: update manpage
(With suggestions from Stanley Pinchak.)
2009-01-09 20:24:41 +01:00
Jan Engelhardt
598c7ede37 Xtables-addons 1.7 2008-12-25 20:10:38 +01:00
Jan Engelhardt
2f66755226 Merge branch 'ipp2p' 2008-12-10 16:51:34 +01:00
Jan Engelhardt
d01a5f3d17 ipp2p: ensure better array bounds checking 2008-12-10 16:50:45 +01:00
Jan Engelhardt
bbda3e53da Merge branch 'SYSRQ' 2008-12-10 16:03:13 +01:00
Jan Engelhardt
22e73ea31f xt_SYSRQ: src: prefix variables 2008-12-10 16:02:21 +01:00
Jan Engelhardt
6b37f201d7 xt_SYSRQ: make new code compile for kernel <= 2.6.23 2008-12-10 15:45:43 +01:00
John Haxby
94ecf3847b xt_SYSRQ: improve security
I want to be able to use SYSRQ to reboot, crash or partially diagnose
machines that become unresponsive for one reason or another. These
machines, typically, are blades or rack mounted machines that do not
have a PS/2 connection for a keyboard and the old method of wheeling
round a "crash trolley" that has a monitor and a keyboard on it no
longer works: USB keyboards rarely, if ever, work because by the time
the machine is responding only to a ping, udev is incapable of
setting up a new keyboard.

This patch extends the xt_SYSRQ module to avoid both disclosing the
sysrq password and preventing replay. This is done by changing the
request packet from the simple "<key><password>" to a slightly more
complex "<key>,<seqno>,<salt>,<hash>". The hash is the sha1 checksum
of "<key>,<seqno>,<salt>,<password>". A request can be constructed in
a small shell script (see manpage).

Verification of the hash in xt_SYSRQ follows much the same process.
The sequence number, seqno, is initialised to the current time (in
seconds) when the xt_SYSRQ module is loaded and is updated each time
a valid request is received. A request with a sequence number less
than the current sequence number or a wrong hash is silently ignored.
(Using the time for the sequence number assumes (requires) that time
doesn't go backwards on a reboot and that the requester and victim
have reasonably synchronized clocks.)

The random salt is there to prevent pre-computed dictionary attacks
difficult: dictionary attacks are still feasible if you capture a
packet because the hash is computed quickly -- taking perhaps several
milliseconds to compute a more complex hash in xt_SYSRQ when the
machine is unresponsive is probably not the best thing you could do.
However, cracking, say, a random 32 character password would take
some time and is probably beyond what the people in the target
untrustworthy environment are prepared to do or have the resources
for. It almost goes without saying that no two victim machines should
use the same password.

Finally, the module allocates all the resources it need at module
initialisation time on the assumption that if things are going badly
resource allocation is going to be troublesome.
2008-12-02 19:45:22 +01:00
Jan Engelhardt
ee968691d7 ipp2p: fix newline inspection in kazaa
LFCR looks suspect, it should most likely be CRLF.
2008-11-26 00:47:36 +01:00
Jan Engelhardt
22db3bcb9c ipp2p: kazaa code cleanup 2008-11-26 00:46:44 +01:00
Jan Engelhardt
7da803e908 doc: add manpages for xt_ECHO and xt_TEE 2008-11-24 17:42:32 +01:00
Jan Engelhardt
4aad07bdc4 TEE: IPv6 support 2008-11-21 01:15:21 +01:00
Jan Engelhardt
7a3f874753 TEE: various cleanups, add comments
Normalize function names in light of upcoming IPv6 support.
Reformat other lines.
Add comment note about tee_send4.
2008-11-21 01:15:03 +01:00
Jan Engelhardt
f77a8e2eda TEE: do not use TOS for routing
Otherwise the cloned packet may be subject to more policy routing
rules than expected.
2008-11-21 01:15:02 +01:00
Jan Engelhardt
bd99e950f5 ipset: enable building of new modules
Whoops, modules need to be listed in GNUmakefile.in!
(Needed for out-of-srcdir builds.)
2008-11-20 23:08:33 +01:00
Jan Engelhardt
fdb7f34bc8 build: use new vars from automake-tranquility-3 2008-11-20 21:17:42 +01:00
Jan Engelhardt
85e3c24167 build: do not unconditionally install ipset
build_ipset=n was not completely respected and the ipset userspace
parts were still installed. This is now fixed.
2008-11-20 20:19:55 +01:00
Jan Engelhardt
aab8dd360f src: avoid use of _init
Xtables-addons's extensions will always be built as modules, so it is
safe to use __attribute__((constructor)).
2008-11-20 20:00:26 +01:00
Jan Engelhardt
a8f60d0d4b xt_ECHO: compile fix 2008-11-19 17:38:45 +01:00
Jan Engelhardt
5b1bfedb82 Xtables-addons 1.6 2008-11-18 18:16:34 +01:00
Jan Engelhardt
ee7e4f5a42 Update for Linux 2.6.28 2008-11-18 12:51:25 +01:00
Jan Engelhardt
d20d1922db ipset: upgrade to ipset 2.4.5 2008-11-18 12:01:59 +01:00
Jan Engelhardt
be6fbee56a src: use NFPROTO_ constants 2008-11-18 11:57:14 +01:00
Jan Engelhardt
3c0b26c4b9 src: add NULL to sentinel struct option 2008-11-18 11:29:57 +01:00
Jan Engelhardt
25e2fbdf7d ipset: upgrade to ipset 2.4.4 2008-11-13 17:46:11 +01:00
Jan Engelhardt
5bd67db123 ipset: upgrade to ipset 2.4.3 2008-11-11 19:36:33 +01:00
Jan Engelhardt
f3737502bd build: use readlink -f
Coreutils 5.x does not know `readlink -e`; we can also use
`readlink -f` instead which is supported by 5.x.
2008-10-16 20:49:21 -04:00
Jan Engelhardt
74e7eb283a ipp2p: parenthesize unaligned-access macros 2008-09-24 12:29:21 -04:00
Jan Engelhardt
f3f0741469 Support for Linux 2.6.17 2008-09-22 13:40:25 -04:00
Jan Engelhardt
9c43965a86 Resolve compiler warnings in xt_ECHO
Reported-by: Jiri Moravec <jim.lkml@gmail.com>
2008-09-19 17:10:23 -04:00
Jan Engelhardt
3a4e719b8c src: compile fixes for 2.6.18 and 2.6.19
I did not test f30793f591 on all
supported kernel versions and noticed too late.
2008-09-01 18:41:45 -04:00
149 changed files with 10373 additions and 4056 deletions

39
INSTALL
View File

@@ -9,20 +9,23 @@ in combination with the kernel's Kbuild system.
# make install # make install
Prerequirements Supported configurations for this release
=============== =========================================
* a recent iptables snapshot * iptables >= 1.4.3
- from the "xtables" git repository at dev.medozas.de
(minimum as per git-describe: v1.4.0-77)
- or the subversion repository at netfilter.org (minimum: r7502)
- or the xtables-combined tarball that is currently distributed
* kernel-source >= 2.6.18.5 with prepared build/output directory * kernel-source >= 2.6.17, no upper bound known
with prepared build/output directory
- CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK - CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK
- CONFIG_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_MARK - CONFIG_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_MARK
enabled =y or as module (=m) enabled =y or as module (=m)
Extra notes:
* in the kernel 2.6.18.x series, >= 2.6.18.5 is required
* requires that no vendor backports interfere
Selecting extensions Selecting extensions
==================== ====================
@@ -49,11 +52,8 @@ Configuring and compiling
xtables.h, should it not be within the standard C compiler xtables.h, should it not be within the standard C compiler
include path (/usr/include), or if you want to override it. include path (/usr/include), or if you want to override it.
The directory will be checked for xtables.h and The directory will be checked for xtables.h and
include/xtables.h. (This is to support the following specs:) include/xtables.h. (The latter to support both standard
/usr/include and the iptables source root.)
--with-xtables=/usr/src/xtables
--with-xtables=/usr/src/xtables/include
--with-xtables=/opt/xtables/include
--with-libxtdir= --with-libxtdir=
@@ -69,6 +69,19 @@ If you want to enable debugging, use
much easier.) much easier.)
Build-time options
==================
V= controls the kernel's make verbosity.
V=0 "silent" (output filename)
V=1 "verbose" (entire gcc command line)
VU= controls the Xt-a make verbosity.
VU=0 output filename
VU=1 output filename and source file
VU=2 entire gcc command line
Note to distribution packagers Note to distribution packagers
============================== ==============================

View File

@@ -1,12 +1,12 @@
# -*- Makefile -*- # -*- Makefile -*-
AUTOMAKE_OPTIONS = foreign subdir-objects ACLOCAL_AMFLAGS = -I m4
SUBDIRS = extensions extensions/ipset SUBDIRS = extensions
man_MANS := xtables-addons.8 man_MANS := xtables-addons.8
xtables-addons.8: ${srcdir}/xtables-addons.8.in extensions/matches.man extensions/targets.man xtables-addons.8: ${srcdir}/xtables-addons.8.in extensions/matches.man extensions/targets.man
${AM_VERBOSE_GEN} sed -e '/@MATCHES@/ r extensions/matches.man' -e '/@TARGET@/ r extensions/targets.man' $< >$@; ${am__verbose_GEN}sed -e '/@MATCHES@/ r extensions/matches.man' -e '/@TARGET@/ r extensions/targets.man' $< >$@;
extensions/%: extensions/%:
${MAKE} ${AM_MAKEFLAGS} -C $(@D) $(@F) ${MAKE} ${AM_MAKEFLAGS} -C $(@D) $(@F)
@@ -14,6 +14,8 @@ extensions/%:
install-exec-local: install-exec-local:
depmod -a || :; depmod -a || :;
config.status: extensions/GNUmakefile.in
.PHONY: tarball .PHONY: tarball
tarball: tarball:
rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION}; rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION};

View File

@@ -1,8 +1,9 @@
AC_INIT([xtables-addons], [1.5.7]) AC_INIT([xtables-addons], [1.18])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_INSTALL AC_PROG_INSTALL
AM_INIT_AUTOMAKE AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
AC_DISABLE_STATIC AC_DISABLE_STATIC
@@ -27,8 +28,11 @@ AC_ARG_WITH([xtlibdir],
[xtlibdir="$withval"], [xtlibdir="$withval"],
[xtlibdir='${libexecdir}/xtables']) [xtlibdir='${libexecdir}/xtables'])
AC_MSG_CHECKING([xtables.h presence]) #
# --with-xtables= overrides a possibly installed pkgconfig file.
#
if [[ -n "$xtables_location" ]]; then if [[ -n "$xtables_location" ]]; then
AC_MSG_CHECKING([xtables.h presence])
if [[ -f "$xtables_location/xtables.h" ]]; then if [[ -f "$xtables_location/xtables.h" ]]; then
AC_MSG_RESULT([$xtables_location/xtables.h]) AC_MSG_RESULT([$xtables_location/xtables.h])
xtables_CFLAGS="-I $xtables_location"; xtables_CFLAGS="-I $xtables_location";
@@ -36,7 +40,6 @@ if [[ -n "$xtables_location" ]]; then
AC_MSG_RESULT([$xtables_location/include/xtables.h]) AC_MSG_RESULT([$xtables_location/include/xtables.h])
xtables_CFLAGS="-I $xtables_location/include"; xtables_CFLAGS="-I $xtables_location/include";
fi; fi;
fi;
if [[ -z "$xtables_CFLAGS" ]]; then if [[ -z "$xtables_CFLAGS" ]]; then
if [[ -f "$includedir/xtables.h" ]]; then if [[ -f "$includedir/xtables.h" ]]; then
AC_MSG_RESULT([$includedir/xtables.h]) AC_MSG_RESULT([$includedir/xtables.h])
@@ -44,6 +47,9 @@ if [[ -z "$xtables_CFLAGS" ]]; then
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
fi; fi;
fi; fi;
else
PKG_CHECK_MODULES([libxtables], [xtables >= 1.4.3])
fi;
regular_CFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \ regular_CFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \
-D_REENTRANT -Wall -Waggregate-return -Wmissing-declarations \ -D_REENTRANT -Wall -Waggregate-return -Wmissing-declarations \
@@ -57,10 +63,46 @@ if [[ -n "$ksourcedir" ]]; then
kinclude_CFLAGS="$kinclude_CFLAGS -I $ksourcedir/include"; kinclude_CFLAGS="$kinclude_CFLAGS -I $ksourcedir/include";
fi; fi;
#
# check kernel version
#
if grep -q "CentOS release 5\." /etc/redhat-release 2>/dev/null ||
grep -q "Red Hat Enterprise Linux Server release 5" /etc/redhat-release 2>/dev/null; then
# しまった!
# Well, just a warning. Maybe the admin updated the kernel.
echo "WARNING: This distribution's shipped kernel is not supported.";
fi;
krel="$(make -sC ${kbuilddir} kernelrelease)";
krel="${krel%%-*}";
kmajor="${krel%%.*}";
krel="${krel#*.}";
kminor="${krel%%.*}";
krel="${krel#*.}";
kmicro="${krel%%.*}";
krel2="${krel#*.}";
if test "$krel" = "$krel2"; then
kstable=0;
else
kstable="${krel%%.*}";
if test -z "$kstable"; then
kstable=0;
fi;
fi;
echo "Found kernel version $kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
if test "$kmajor" -gt 2 -o "$kminor" -gt 6 -o "$kmicro" -gt 31; then
echo "WARNING: You are trying a newer kernel. Results may vary. :-)";
elif test \( "$kmajor" -lt 2 -o "$kminor" -lt 6 -o "$kmicro" -lt 17 \) -o \
\( "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -eq 18 -a \
"$kstable" -lt 5 \); then
echo "ERROR: That kernel version is not supported. Please see INSTALL for minimum configuration.";
exit 1;
fi;
AC_SUBST([regular_CFLAGS]) AC_SUBST([regular_CFLAGS])
AC_SUBST([xtables_CFLAGS]) AC_SUBST([xtables_CFLAGS])
AC_SUBST([kinclude_CFLAGS]) AC_SUBST([kinclude_CFLAGS])
AC_SUBST([kbuilddir]) AC_SUBST([kbuilddir])
AC_SUBST([ksourcedir]) AC_SUBST([ksourcedir])
AC_SUBST([xtlibdir]) AC_SUBST([xtlibdir])
AC_OUTPUT([Makefile extensions/GNUmakefile extensions/ipset/GNUmakefile]) AC_CONFIG_FILES([Makefile extensions/GNUmakefile extensions/ipset/GNUmakefile])
AC_OUTPUT

4
doc/README.psd Normal file
View File

@@ -0,0 +1,4 @@
PSD (Portscan Detection) External extensions for Xtables-addons
Example:
iptables -A INPUT -m psd --psd-weight-threshold 21 --psd-delay-threshold 300 --psd-lo-ports-weight 1 --psd-hi-ports-weight 10 -j LOG --log-prefix "PSD: "

180
doc/changelog.txt Normal file
View File

@@ -0,0 +1,180 @@
Xtables-addons 1.18 (September 09 2009)
=======================================
- build: support for Linux 2.6.31
- ipset: fast forward to v3.2
- quota2: support anonymous counters
- quota2: reduce memory footprint for anonymous counters
- quota2: extend locked period during cleanup (locking bugfix)
- quota2: use strtoull instead of strtoul
- merged xt_ACCOUNT module
- merged xt_psd module
Xtables-addons 1.17 (June 16 2009)
==================================
- IPMARK: print missing --shift parameter
- build: use readlink -f in extensions/ipset/
- build: support for Linux 2.6.30
Xtables-addons 1.16 (May 27 2009)
=================================
- RAWNAT: make iptable_rawpost compile with 2.6.30-rc5
- ipset: fast forward to 3.0
Xtables-addons 1.15 (April 30 2009)
===================================
- build: add kernel version check to configure
- condition: compile fix for 2.6.30-rc
- condition: fix intrapositional negation sign
- fuzzy: fix bogus comparison logic leftover from move to new 1.4.3 API
- ipp2p: fix bogus varargs call
- ipp2p: fix typo in error message
- added "iface" match
- added rawpost table (for use with RAWNAT)
- added RAWSNAT/RAWDNAT targets
Xtables-addons 1.14 (March 31 2009)
===================================
- fuzzy: need to account for kernel-level modified variables in .userspacesize
- geoip: remove XT_ALIGN from .userspacesize when used with offsetof
- SYSRQ: ignore non-UDP packets
- SYSRQ: do proper L4 header access in IPv6 code
(must not use tcp/udp_hdr in input path)
- add "STEAL" target
- dhcpmac: rename from dhcpaddr
Xtables-addons 1.13 (March 23 2009)
===================================
- added a reworked ipv4options match
- upgrade to iptables 1.4.3 API
Xtables-addons 1.12 (March 07 2009)
===================================
- ipset: fix for compilation with 2.6.29-rt
- ipset: fast forward to 2.5.0
- rename xt_portscan to xt_lscan ("low-level scan") because
"portscan" as a word caused confusion
- xt_LOGMARK: print incoming interface index
- revert "TEE: do not use TOS for routing"
- xt_TEE: resolve unknown symbol error with CONFIG_IPV6=n
- xt_TEE: enable routing by iif, nfmark and flowlabel
Xtables-addons 1.10 (February 18 2009)
======================================
- compat: compile fixes for 2.6.29
- ipset: upgrade to ipset 2.4.9
Xtables-addons 1.9 (January 30 2009)
====================================
- add the xt_length2 extension
- xt_TEE: remove intrapositional '!' support
- ipset: upgrade to ipset 2.4.7
Xtables-addons 1.8 (January 10 2009)
====================================
- xt_TEE: IPv6 support
- xt_TEE: do not include TOS value in routing decision
- xt_TEE: fix switch-case inversion for name/IP display
- xt_ipp2p: update manpages and help text
- xt_ipp2p: remove log flooding
- xt_portscan: update manpage about --grscan option caveats
Xtables-addons 1.7 (December 25 2008)
=====================================
- xt_ECHO: compile fix
- avoid the use of "_init" which led to compile errors on some installations
- build: do not unconditionally install ipset
- doc: add manpages for xt_ECHO and xt_TEE
- xt_ipp2p: kazaa detection code cleanup
- xt_ipp2p: fix newline inspection in kazaa detection
- xt_ipp2p: ensure better array bounds checking
- xt_SYSRQ: improve security by hashing password
Xtables-addons 1.6 (November 18 2008)
=====================================
- build: support for Linux 2.6.17
- build: compile fixes for 2.6.18 and 2.6.19
- xt_ECHO: resolve compile errors in xt_ECHO
- xt_ipp2p: parenthesize unaligned-access macros
Xtables-addons 1.5.7 (September 01 2008)
========================================
- API layer: fix use of uninitialized 'hotdrop' variable
- API layer: move to pskb-based signatures
- xt_SYSRQ: compile fixes for Linux <= 2.6.19
- ipset: adjust semaphore.h include for Linux >= 2.6.27
- build: automatically run `depmod -a` on installation
- add reworked xt_fuzzy module
- add DHCP address match and mangle module
- xt_portscan: IPv6 support
- xt_SYSRQ: add missing module aliases
Xtables-addons 1.5.5 (August 03 2008)
=====================================
- manpage updates for xt_CHAOS, xt_IPMARK; README updates
- build: properly recognize external Kbuild/Mbuild files
- build: remove dependency on CONFIG_NETWORK_SECMARK
- add the xt_SYSRQ target
- add the xt_quota2 extension
- import ipset extension group
Xtables-addons 1.5.4.1 (April 26 2008)
======================================
- build: fix compile error for 2.6.18-stable
Xtables-addons 1.5.4 (April 09 2008)
====================================
- build: support building multiple files with one config option
- API layer: add check for pskb relocation
- doc: generate manpages
- xt_ECHO: catch skb_linearize out-of-memory condition
- xt_LOGMARK: add hook= and ctdir= fields in dump
- xt_LOGMARK: fix comma output in ctstatus= list
- xt_TEE: fix address copying bug
- xt_TEE: make skb writable before attempting checksum update
- add reworked xt_condition match
- add reworked xt_ipp2p match
- add reworked xt_IPMARK target
Xtables-addons 1.5.3 (March 22 2008)
====================================
- support for Linux 2.6.18
- add xt_ECHO sample target
- add reworked xt_geoip match
Xtables-addons 1.5.2 (March 04 2008)
====================================
- build: support for GNU make < 3.81 which does not have $(realpath)
Xtables-addons 1.5.1 (February 21 2008)
=======================================
- build: allow user to select what extensions to compile and install
- build: allow external proejcts to be downloaded into the tree
- xt_LOGMARK: dump classify mark, ctstate and ctstatus
- add xt_CHAOS, xt_DELUDE and xt_portscan from Chaostables
Xtables-addons 1.5.0 (February 11 2008)
=======================================
Initial release with:
- extensions: xt_LOGMARK, xt_TARPIT, xt_TEE
- support for Linux >= 2.6.19

View File

@@ -3,7 +3,9 @@
.tmp_versions .tmp_versions
*.ko *.ko
*.mod.c *.mod.c
Module.markers
Module.symvers Module.symvers
Modules.symvers
modules.order modules.order
/*.so /*.so

View File

@@ -2,8 +2,8 @@
top_srcdir := @top_srcdir@ top_srcdir := @top_srcdir@
srcdir := @srcdir@ srcdir := @srcdir@
abstop_srcdir := $(shell readlink -e ${top_srcdir}) abstop_srcdir := $(shell readlink -f ${top_srcdir})
abssrcdir := $(shell readlink -e ${srcdir}) abssrcdir := $(shell readlink -f ${srcdir})
ifeq (${abstop_srcdir},) ifeq (${abstop_srcdir},)
$(error Path resolution of ${top_srcdir} failed) $(error Path resolution of ${top_srcdir} failed)
@@ -30,15 +30,16 @@ xtables_CFLAGS := @xtables_CFLAGS@
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS} AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS}
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
ifeq (${V},) VU := 0
AM_LIBTOOL_SILENT = --silent am__v_CC_0 = @echo " CC " $@;
AM_VERBOSE_CC = @echo " CC " $@; am__v_CCLD_0 = @echo " CCLD " $@;
AM_VERBOSE_CCLD = @echo " CCLD " $@; am__v_GEN_0 = @echo " GEN " $@;
AM_VERBOSE_CXX = @echo " CXX " $@; am__v_SILENT_0 = @
AM_VERBOSE_CXXLD = @echo " CXXLD " $@; AM_V_CC = ${am__v_CC_${VU}}
AM_VERBOSE_AR = @echo " AR " $@; AM_V_CCLD = ${am__v_CCLD_${VU}}
AM_VERBOSE_GEN = @echo " GEN " $@; AM_V_GEN = ${am__v_GEN_${VU}}
endif AM_V_silent = ${am__v_GEN_${VU}}
# #
# Wildcard module list # Wildcard module list
@@ -53,22 +54,30 @@ include ${srcdir}/Mbuild
# #
# Building blocks # Building blocks
# #
targets := ${obj-m} targets := $(filter-out %/,${obj-m})
targets_install := ${obj-m} targets_install := ${targets}
subdirs_list := $(filter %/,${obj-m})
.SECONDARY: .SECONDARY:
.PHONY: all install clean distclean FORCE .PHONY: all install clean distclean FORCE
all: modules user matches.man targets.man all: subdirs modules user matches.man targets.man
subdirs:
@for i in ${subdirs_list}; do ${MAKE} -C $$i; done;
subdirs-install:
@for i in ${subdirs_list}; do ${MAKE} -C $$i install; done;
user: ${targets} user: ${targets}
install: modules_install ${targets_install} install: modules_install subdirs-install ${targets_install}
@mkdir -p "${DESTDIR}${xtlibdir}"; @mkdir -p "${DESTDIR}${xtlibdir}";
install -pm0755 ${targets_install} "${DESTDIR}${xtlibdir}/"; install -pm0755 ${targets_install} "${DESTDIR}${xtlibdir}/";
clean: clean_modules clean: clean_modules
@for i in ${subdirs_list}; do ${MAKE} -C $$i clean; done;
rm -f *.oo *.so; rm -f *.oo *.so;
distclean: clean distclean: clean
@@ -83,23 +92,23 @@ distclean: clean
.PHONY: modules modules_install clean_modules .PHONY: modules modules_install clean_modules
modules: modules:
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} modules; ${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} modules; fi;
modules_install: modules_install:
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} INSTALL_MOD_PATH=${DESTDIR} modules_install; ${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} INSTALL_MOD_PATH=${DESTDIR} modules_install; fi;
clean_modules: clean_modules:
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} clean; ${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} clean; fi;
# #
# Shared libraries # Shared libraries
# #
lib%.so: lib%.oo lib%.so: lib%.oo
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<; ${AM_V_CCLD}${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
lib%.oo: ${srcdir}/lib%.c lib%.oo: ${srcdir}/lib%.c
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<; ${AM_V_CC}${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
# #
@@ -116,8 +125,7 @@ wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
rm -f $@.tmp; rm -f $@.tmp;
man_run = \ man_run = \
${AM_VERBOSE_GEN} \ ${AM_V_GEN}for ext in $(1); do \
for ext in $(1); do \
f="${srcdir}/libxt_$$ext.man"; \ f="${srcdir}/libxt_$$ext.man"; \
if [ -f "$$f" ]; then \ if [ -f "$$f" ]; then \
echo ".SS $$ext"; \ echo ".SS $$ext"; \

View File

@@ -5,21 +5,28 @@ include ${XA_TOPSRCDIR}/mconfig
obj-m += compat_xtables.o obj-m += compat_xtables.o
obj-${build_ACCOUNT} += xt_ACCOUNT.o
obj-${build_CHAOS} += xt_CHAOS.o obj-${build_CHAOS} += xt_CHAOS.o
obj-${build_DELUDE} += xt_DELUDE.o obj-${build_DELUDE} += xt_DELUDE.o
obj-${build_DHCPADDR} += xt_DHCPADDR.o obj-${build_DHCPMAC} += xt_DHCPMAC.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_RAWNAT} += xt_RAWNAT.o iptable_rawpost.o ip6table_rawpost.o
obj-${build_SYSRQ} += xt_SYSRQ.o obj-${build_SYSRQ} += xt_SYSRQ.o
obj-${build_STEAL} += xt_STEAL.o
obj-${build_TARPIT} += xt_TARPIT.o obj-${build_TARPIT} += xt_TARPIT.o
obj-${build_TEE} += xt_TEE.o obj-${build_TEE} += xt_TEE.o
obj-${build_condition} += xt_condition.o obj-${build_condition} += xt_condition.o
obj-${build_fuzzy} += xt_fuzzy.o obj-${build_fuzzy} += xt_fuzzy.o
obj-${build_geoip} += xt_geoip.o obj-${build_geoip} += xt_geoip.o
obj-${build_iface} += xt_iface.o
obj-${build_ipp2p} += xt_ipp2p.o obj-${build_ipp2p} += xt_ipp2p.o
obj-${build_ipset} += ipset/ obj-${build_ipset} += ipset/
obj-${build_portscan} += xt_portscan.o obj-${build_ipv4options} += xt_ipv4options.o
obj-${build_length2} += xt_length2.o
obj-${build_lscan} += xt_lscan.o
obj-${build_psd} += xt_psd.o
obj-${build_quota2} += xt_quota2.o obj-${build_quota2} += xt_quota2.o
-include ${M}/*.Kbuild -include ${M}/*.Kbuild

View File

@@ -1,15 +1,23 @@
obj-${build_ACCOUNT} += libxt_ACCOUNT.so
obj-${build_CHAOS} += libxt_CHAOS.so obj-${build_CHAOS} += libxt_CHAOS.so
obj-${build_DELUDE} += libxt_DELUDE.so obj-${build_DELUDE} += libxt_DELUDE.so
obj-${build_DHCPADDR} += libxt_DHCPADDR.so libxt_dhcpaddr.so obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.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_RAWNAT} += libxt_RAWDNAT.so libxt_RAWSNAT.so
obj-${build_STEAL} += libxt_STEAL.so
obj-${build_SYSRQ} += libxt_SYSRQ.so obj-${build_SYSRQ} += libxt_SYSRQ.so
obj-${build_TARPIT} += libxt_TARPIT.so obj-${build_TARPIT} += libxt_TARPIT.so
obj-${build_TEE} += libxt_TEE.so obj-${build_TEE} += libxt_TEE.so
obj-${build_condition} += libxt_condition.so obj-${build_condition} += libxt_condition.so
obj-${build_fuzzy} += libxt_fuzzy.so obj-${build_fuzzy} += libxt_fuzzy.so
obj-${build_geoip} += libxt_geoip.so obj-${build_geoip} += libxt_geoip.so
obj-${build_iface} += libxt_iface.so
obj-${build_ipp2p} += libxt_ipp2p.so obj-${build_ipp2p} += libxt_ipp2p.so
obj-${build_portscan} += libxt_portscan.so obj-${build_ipset} += ipset/
obj-${build_ipv4options} += libxt_ipv4options.so
obj-${build_length2} += libxt_length2.so
obj-${build_lscan} += libxt_lscan.so
obj-${build_psd} += libxt_psd.so
obj-${build_quota2} += libxt_quota2.so obj-${build_quota2} += libxt_quota2.so

View File

@@ -0,0 +1,87 @@
#ifndef XTA_COMPAT_RAWPOST_H
#define XTA_COMPAT_RAWPOST_H 1
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
typedef struct sk_buff sk_buff_t;
#else
typedef struct sk_buff *sk_buff_t;
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21)
#define XT_TARGET_INIT(__name, __size) \
{ \
.target.u.user = { \
.target_size = XT_ALIGN(__size), \
.name = __name, \
}, \
}
#define IPT_ENTRY_INIT(__size) \
{ \
.target_offset = sizeof(struct ipt_entry), \
.next_offset = (__size), \
}
#define IPT_STANDARD_INIT(__verdict) \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \
.target = XT_TARGET_INIT(IPT_STANDARD_TARGET, \
sizeof(struct xt_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define IPT_ERROR_INIT \
{ \
.entry = IPT_ENTRY_INIT(sizeof(struct ipt_error)), \
.target = XT_TARGET_INIT(IPT_ERROR_TARGET, \
sizeof(struct ipt_error_target)), \
.target.errorname = "ERROR", \
}
#define IP6T_ENTRY_INIT(__size) \
{ \
.target_offset = sizeof(struct ip6t_entry), \
.next_offset = (__size), \
}
#define IP6T_STANDARD_INIT(__verdict) \
{ \
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
.target = XT_TARGET_INIT(IP6T_STANDARD_TARGET, \
sizeof(struct ip6t_standard_target)), \
.target.verdict = -(__verdict) - 1, \
}
#define IP6T_ERROR_INIT \
{ \
.entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
.target = XT_TARGET_INIT(IP6T_ERROR_TARGET, \
sizeof(struct ip6t_error_target)), \
.target.errorname = "ERROR", \
}
#endif /* 2.6.21 */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 20)
# include <linux/netfilter_ipv6/ip6_tables.h>
/* Standard entry */
struct ip6t_standard
{
struct ip6t_entry entry;
struct ip6t_standard_target target;
};
struct ip6t_error_target
{
struct ip6t_entry_target target;
char errorname[IP6T_FUNCTION_MAXNAMELEN];
};
struct ip6t_error
{
struct ip6t_entry entry;
struct ip6t_error_target target;
};
#endif /* 2.6.20 */
#endif /* XTA_COMPAT_RAWPOST_H */

View File

@@ -4,9 +4,29 @@
struct tcphdr; struct tcphdr;
struct udphdr; struct udphdr;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 30)
static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
skb->dst = dst;
}
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
{
return skb->dst;
}
static inline struct rtable *skb_rtable(const struct sk_buff *skb)
{
return (void *)skb->dst;
}
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define skb_ifindex(skb) \
(((skb)->input_dev != NULL) ? (skb)->input_dev->ifindex : 0)
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->nfmark) # define skb_nfmark(skb) (((struct sk_buff *)(skb))->nfmark)
#else #else
# define skb_ifindex(skb) (skb)->iif
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark) # define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
#endif #endif

View File

@@ -25,14 +25,30 @@ static int xtnu_match_run(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, const struct net_device *in, const struct net_device *out,
const struct xt_match *cm, const void *matchinfo, int offset, const struct xt_match *cm, const void *matchinfo, int offset,
unsigned int protoff, int *hotdrop) unsigned int protoff, int *hotdrop)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static bool xtnu_match_run(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
const struct xt_match *cm, const void *matchinfo, int offset,
unsigned int protoff, bool *hotdrop)
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{ {
struct xtnu_match *nm = xtcompat_numatch(cm); struct xtnu_match *nm = xtcompat_numatch(cm);
bool lo_drop = false, lo_ret; bool lo_drop = false, lo_ret;
struct xt_match_param local_par = {
.in = in,
.out = out,
.match = cm,
.matchinfo = matchinfo,
.fragoff = offset,
.thoff = protoff,
.hotdrop = &lo_drop,
.family = NFPROTO_UNSPEC, /* don't have that info */
};
if (nm == NULL || nm->match == NULL) if (nm == NULL || nm->match == NULL)
return false; return false;
lo_ret = nm->match(skb, in, out, nm, matchinfo, lo_ret = nm->match(skb, &local_par);
offset, protoff, &lo_drop);
*hotdrop = lo_drop; *hotdrop = lo_drop;
return lo_ret; return lo_ret;
} }
@@ -45,35 +61,51 @@ static int xtnu_match_check(const char *table, const void *entry,
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
static int xtnu_match_check(const char *table, const void *entry, static int xtnu_match_check(const char *table, const void *entry,
const struct xt_match *cm, void *matchinfo, unsigned int hook_mask) const struct xt_match *cm, void *matchinfo, unsigned int hook_mask)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static bool xtnu_match_check(const char *table, const void *entry,
const struct xt_match *cm, void *matchinfo, unsigned int hook_mask)
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{ {
struct xtnu_match *nm = xtcompat_numatch(cm); struct xtnu_match *nm = xtcompat_numatch(cm);
struct xt_mtchk_param local_par = {
.table = table,
.entryinfo = entry,
.match = cm,
.matchinfo = matchinfo,
.hook_mask = hook_mask,
.family = NFPROTO_UNSPEC,
};
if (nm == NULL) if (nm == NULL)
return false; return false;
if (nm->checkentry == NULL) if (nm->checkentry == NULL)
return true; return true;
return nm->checkentry(table, entry, nm, matchinfo, hook_mask); return nm->checkentry(&local_par);
} }
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo, static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo,
unsigned int matchinfosize) unsigned int matchinfosize)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo) static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo)
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{ {
struct xtnu_match *nm = xtcompat_numatch(cm); struct xtnu_match *nm = xtcompat_numatch(cm);
struct xt_mtdtor_param local_par = {
.match = cm,
.matchinfo = matchinfo,
.family = NFPROTO_UNSPEC,
};
if (nm != NULL && nm->destroy != NULL) if (nm != NULL && nm->destroy != NULL)
nm->destroy(nm, matchinfo); nm->destroy(&local_par);
} }
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
int xtnu_register_match(struct xtnu_match *nt) int xtnu_register_match(struct xtnu_match *nt)
{ {
struct xt_match *ct; struct xt_match *ct;
@@ -152,18 +184,36 @@ static unsigned int xtnu_target_run(struct sk_buff **pskb,
static unsigned int xtnu_target_run(struct sk_buff **pskb, static unsigned int xtnu_target_run(struct sk_buff **pskb,
const struct net_device *in, const struct net_device *out, const struct net_device *in, const struct net_device *out,
unsigned int hooknum, const struct xt_target *ct, const void *targinfo) unsigned int hooknum, const struct xt_target *ct, const void *targinfo)
#else #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static unsigned int xtnu_target_run(struct sk_buff *skb, static unsigned int xtnu_target_run(struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, const struct net_device *in, const struct net_device *out,
unsigned int hooknum, const struct xt_target *ct, const void *targinfo) unsigned int hooknum, const struct xt_target *ct, const void *targinfo)
#else
static unsigned int
xtnu_target_run(struct sk_buff *skb, const struct xt_target_param *par)
#endif #endif
{ {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
struct xtnu_target *nt = xtcompat_nutarget(ct); struct xtnu_target *nt = xtcompat_nutarget(ct);
struct xt_target_param local_par = {
.in = in,
.out = out,
.hooknum = hooknum,
.target = ct,
.targinfo = targinfo,
.family = NFPROTO_UNSPEC,
};
#else
struct xtnu_target *nt = xtcompat_nutarget(par->target);
#endif
if (nt != NULL && nt->target != NULL) if (nt != NULL && nt->target != NULL)
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
return nt->target(pskb, in, out, hooknum, nt, targinfo); return nt->target(pskb, &local_par);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
return nt->target(&skb, &local_par);
#else #else
return nt->target(&skb, in, out, hooknum, nt, targinfo); return nt->target(&skb, par);
#endif #endif
return XT_CONTINUE; return XT_CONTINUE;
} }
@@ -175,31 +225,50 @@ static int xtnu_target_check(const char *table, const void *entry,
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
static int xtnu_target_check(const char *table, const void *entry, static int xtnu_target_check(const char *table, const void *entry,
const struct xt_target *ct, void *targinfo, unsigned int hook_mask) const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
#else #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static bool xtnu_target_check(const char *table, const void *entry, static bool xtnu_target_check(const char *table, const void *entry,
const struct xt_target *ct, void *targinfo, unsigned int hook_mask) const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{ {
struct xtnu_target *nt = xtcompat_nutarget(ct); struct xtnu_target *nt = xtcompat_nutarget(ct);
struct xt_tgchk_param local_par = {
.table = table,
.entryinfo = entry,
.target = ct,
.targinfo = targinfo,
.hook_mask = hook_mask,
.family = NFPROTO_UNSPEC,
};
if (nt == NULL) if (nt == NULL)
return false; return false;
if (nt->checkentry == NULL) if (nt->checkentry == NULL)
/* this is valid, just like if there was no function */ /* this is valid, just like if there was no function */
return true; return true;
return nt->checkentry(table, entry, nt, targinfo, hook_mask); return nt->checkentry(&local_par);
} }
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo, static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo,
unsigned int targinfosize) unsigned int targinfosize)
#else #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo) static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo)
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
{ {
struct xtnu_target *nt = xtcompat_nutarget(ct); struct xtnu_target *nt = xtcompat_nutarget(ct);
struct xt_tgdtor_param local_par = {
.target = ct,
.targinfo = targinfo,
.family = NFPROTO_UNSPEC,
};
if (nt != NULL && nt->destroy != NULL) if (nt != NULL && nt->destroy != NULL)
nt->destroy(nt, targinfo); nt->destroy(&local_par);
} }
#endif
int xtnu_register_target(struct xtnu_target *nt) int xtnu_register_target(struct xtnu_target *nt)
{ {
@@ -223,8 +292,13 @@ int xtnu_register_target(struct xtnu_target *nt)
ct->hooks = nt->hooks; ct->hooks = nt->hooks;
ct->proto = nt->proto; ct->proto = nt->proto;
ct->target = xtnu_target_run; ct->target = xtnu_target_run;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
ct->checkentry = xtnu_target_check; ct->checkentry = xtnu_target_check;
ct->destroy = xtnu_target_destroy; ct->destroy = xtnu_target_destroy;
#else
ct->checkentry = nt->checkentry;
ct->destroy = nt->destroy;
#endif
ct->targetsize = nt->targetsize; ct->targetsize = nt->targetsize;
ct->me = nt->me; ct->me = nt->me;
@@ -368,6 +442,30 @@ int xtnu_ip_route_output_key(void *net, struct rtable **rp, struct flowi *flp)
return ip_route_output_flow(rp, flp, NULL, 0); return ip_route_output_flow(rp, flp, NULL, 0);
} }
EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key); EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key);
void xtnu_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
__be32 from, __be32 to, bool pseudohdr)
{
__be32 diff[] = {~from, to};
const void *dv = diff; /* kludge for < v2.6.19-555-g72685fc */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
if (skb->ip_summed != CHECKSUM_PARTIAL) {
*sum = csum_fold(csum_partial(dv, sizeof(diff),
~csum_unfold(*sum)));
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
skb->csum = ~csum_partial(dv, sizeof(diff),
~skb->csum);
} else if (pseudohdr) {
*sum = ~csum_fold(csum_partial(dv, sizeof(diff),
csum_unfold(*sum)));
}
#else
*sum = csum_fold(csum_partial(dv, sizeof(diff),
~csum_unfold(*sum)));
#endif
}
EXPORT_SYMBOL_GPL(xtnu_proto_csum_replace4);
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
@@ -384,18 +482,31 @@ int xtnu_neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
} }
EXPORT_SYMBOL_GPL(xtnu_neigh_hh_output); EXPORT_SYMBOL_GPL(xtnu_neigh_hh_output);
static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to) static inline __wsum xtnu_csum_unfold(__sum16 n)
{
return (__force __wsum)n;
}
void xtnu_csum_replace4(__sum16 *sum, __be32 from, __be32 to)
{ {
__be32 diff[] = {~from, to}; __be32 diff[] = {~from, to};
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff), *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
~csum_unfold(*sum))); ~xtnu_csum_unfold(*sum)));
} }
void xtnu_csum_replace2(__sum16 *sum, __be16 from, __be16 to) void xtnu_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
{ {
csum_replace4(sum, (__force __be32)from, (__force __be32)to); xtnu_csum_replace4(sum, (__force __be32)from, (__force __be32)to);
} }
EXPORT_SYMBOL_GPL(xtnu_csum_replace2); EXPORT_SYMBOL_GPL(xtnu_csum_replace2);
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
int xtnu_skb_linearize(struct sk_buff *skb)
{
return skb_linearize(skb, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(xtnu_skb_linearize);
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@@ -1,12 +1,15 @@
#ifndef _XTABLES_COMPAT_H #ifndef _XTABLES_COMPAT_H
#define _XTABLES_COMPAT_H 1 #define _XTABLES_COMPAT_H 1
#include <linux/kernel.h>
#include <linux/version.h> #include <linux/version.h>
#include "compat_skbuff.h" #include "compat_skbuff.h"
#include "compat_xtnu.h" #include "compat_xtnu.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18) #define DEBUGP Use__pr_debug__instead
# warning Kernels below 2.6.18.5 not supported.
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
# warning Kernels below 2.6.17 not supported.
#endif #endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -26,9 +29,15 @@
# warning You need either CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK. # warning You need either CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK.
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
# define skb_init_secmark(skb)
# define skb_linearize xtnu_skb_linearize
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define neigh_hh_output xtnu_neigh_hh_output # define neigh_hh_output xtnu_neigh_hh_output
# define IPPROTO_UDPLITE 136 # define IPPROTO_UDPLITE 136
# define CSUM_MANGLED_0 ((__force __sum16)0xffff)
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
@@ -51,7 +60,7 @@
# define init_net__proc_net init_net.proc_net # define init_net__proc_net init_net.proc_net
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
# define xt_match xtnu_match # define xt_match xtnu_match
# define xt_register_match xtnu_register_match # define xt_register_match xtnu_register_match
# define xt_unregister_match xtnu_unregister_match # define xt_unregister_match xtnu_unregister_match
@@ -61,8 +70,33 @@
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
# define csum_replace2 xtnu_csum_replace2 # define csum_replace2 xtnu_csum_replace2
# define csum_replace4 xtnu_csum_replace4
# define inet_proto_csum_replace4 xtnu_proto_csum_replace4
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24) #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
# define csum_replace2 nf_csum_replace2 # define csum_replace2 nf_csum_replace2
# define csum_replace4 nf_csum_replace4
# define inet_proto_csum_replace4 xtnu_proto_csum_replace4
#endif
#if !defined(NIP6) && !defined(NIP6_FMT)
# define NIP6(addr) \
ntohs((addr).s6_addr16[0]), \
ntohs((addr).s6_addr16[1]), \
ntohs((addr).s6_addr16[2]), \
ntohs((addr).s6_addr16[3]), \
ntohs((addr).s6_addr16[4]), \
ntohs((addr).s6_addr16[5]), \
ntohs((addr).s6_addr16[6]), \
ntohs((addr).s6_addr16[7])
# define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
#endif
#if !defined(NIPQUAD) && !defined(NIPQUAD_FMT)
# define NIPQUAD(addr) \
((const unsigned char *)&addr)[0], \
((const unsigned char *)&addr)[1], \
((const unsigned char *)&addr)[2], \
((const unsigned char *)&addr)[3]
# define NIPQUAD_FMT "%u.%u.%u.%u"
#endif #endif
#define ip_route_me_harder xtnu_ip_route_me_harder #define ip_route_me_harder xtnu_ip_route_me_harder

View File

@@ -9,6 +9,10 @@
typedef _Bool bool; typedef _Bool bool;
enum { false = 0, true = 1, }; enum { false = 0, true = 1, };
#endif #endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
typedef __u16 __bitwise __sum16;
typedef __u32 __bitwise __wsum;
#endif
struct flowi; struct flowi;
struct hh_cache; struct hh_cache;
@@ -17,15 +21,72 @@ struct net_device;
struct rtable; struct rtable;
struct sk_buff; struct sk_buff;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 27)
enum {
NFPROTO_UNSPEC = 0,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3,
NFPROTO_BRIDGE = 7,
NFPROTO_IPV6 = 10,
NFPROTO_DECNET = 12,
NFPROTO_NUMPROTO,
};
struct xt_match_param {
const struct net_device *in, *out;
const struct xt_match *match;
const void *matchinfo;
int fragoff;
unsigned int thoff;
bool *hotdrop;
u_int8_t family;
};
struct xt_mtchk_param {
const char *table;
const void *entryinfo;
const struct xt_match *match;
void *matchinfo;
unsigned int hook_mask;
u_int8_t family;
};
struct xt_mtdtor_param {
const struct xt_match *match;
void *matchinfo;
u_int8_t family;
};
struct xt_target_param {
const struct net_device *in, *out;
unsigned int hooknum;
const struct xt_target *target;
const void *targinfo;
u_int8_t family;
};
struct xt_tgchk_param {
const char *table;
const void *entryinfo;
const struct xt_target *target;
void *targinfo;
unsigned int hook_mask;
u_int8_t family;
};
struct xt_tgdtor_param {
const struct xt_target *target;
void *targinfo;
u_int8_t family;
};
#endif
struct xtnu_match { struct xtnu_match {
struct list_head list; struct list_head list;
char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)]; char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)];
bool (*match)(const struct sk_buff *, const struct net_device *, bool (*match)(const struct sk_buff *, const struct xt_match_param *);
const struct net_device *, const struct xtnu_match *, bool (*checkentry)(const struct xt_mtchk_param *);
const void *, int, unsigned int, bool *); void (*destroy)(const struct xt_mtdtor_param *);
bool (*checkentry)(const char *, const void *,
const struct xtnu_match *, void *, unsigned int);
void (*destroy)(const struct xtnu_match *, void *);
struct module *me; struct module *me;
const char *table; const char *table;
unsigned int matchsize, hooks; unsigned int matchsize, hooks;
@@ -38,12 +99,10 @@ struct xtnu_match {
struct xtnu_target { struct xtnu_target {
struct list_head list; struct list_head list;
char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)]; char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)];
unsigned int (*target)(struct sk_buff **, const struct net_device *, unsigned int (*target)(struct sk_buff **,
const struct net_device *, unsigned int, const struct xt_target_param *);
const struct xtnu_target *, const void *); bool (*checkentry)(const struct xt_tgchk_param *);
bool (*checkentry)(const char *, const void *, void (*destroy)(const struct xt_tgdtor_param *);
const struct xtnu_target *, void *, unsigned int);
void (*destroy)(const struct xtnu_target *, void *);
struct module *me; struct module *me;
const char *table; const char *table;
unsigned int targetsize, hooks; unsigned int targetsize, hooks;
@@ -67,6 +126,13 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
return q; return q;
} }
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
static inline __wsum csum_unfold(__sum16 n)
{
return (__force __wsum)n;
}
#endif
extern int xtnu_ip_local_out(struct sk_buff *); extern int xtnu_ip_local_out(struct sk_buff *);
extern int xtnu_ip_route_me_harder(struct sk_buff **, unsigned int); extern int xtnu_ip_route_me_harder(struct sk_buff **, unsigned int);
extern int xtnu_skb_make_writable(struct sk_buff **, unsigned int); extern int xtnu_skb_make_writable(struct sk_buff **, unsigned int);
@@ -82,5 +148,10 @@ extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int);
extern struct xt_match *xtnu_request_find_match(unsigned int, extern struct xt_match *xtnu_request_find_match(unsigned int,
const char *, uint8_t); const char *, uint8_t);
extern int xtnu_neigh_hh_output(struct hh_cache *, struct sk_buff *); extern int xtnu_neigh_hh_output(struct hh_cache *, struct sk_buff *);
extern void xtnu_csum_replace2(__u16 __bitwise *, __be16, __be16);
extern void xtnu_csum_replace4(__u16 __bitwise *, __be32, __be32);
extern void xtnu_proto_csum_replace4(__u16 __bitwise *, struct sk_buff *,
__be32, __be32, bool);
extern int xtnu_skb_linearize(struct sk_buff *);
#endif /* _COMPAT_XTNU_H */ #endif /* _COMPAT_XTNU_H */

View File

@@ -0,0 +1,107 @@
/*
* rawpost table for ip6_tables
* written by Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2009
* placed in the Public Domain
*/
#include <linux/module.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/ip.h>
#include "compat_xtables.h"
#include "compat_rawpost.h"
enum {
RAWPOST_VALID_HOOKS = 1 << NF_INET_POST_ROUTING,
};
static struct {
struct ip6t_replace repl;
struct ip6t_standard entries[1];
struct ip6t_error term;
} rawpost6_initial __initdata = {
.repl = {
.name = "rawpost",
.valid_hooks = RAWPOST_VALID_HOOKS,
.num_entries = 2,
.size = sizeof(struct ip6t_standard) +
sizeof(struct ip6t_error),
.hook_entry = {
[NF_INET_POST_ROUTING] = 0,
},
.underflow = {
[NF_INET_POST_ROUTING] = 0,
},
},
.entries = {
IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IP6T_ERROR_INIT, /* ERROR */
};
static struct xt_table *rawpost6_ptable;
static struct xt_table rawpost6_itable = {
.name = "rawpost",
.af = NFPROTO_IPV6,
.valid_hooks = RAWPOST_VALID_HOOKS,
.me = THIS_MODULE,
};
static unsigned int rawpost6_hook_fn(unsigned int hook, sk_buff_t *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
return ip6t_do_table(skb, hook, in, out, rawpost6_ptable);
#else
return ip6t_do_table(skb, hook, in, out, rawpost6_ptable, NULL);
#endif
}
static struct nf_hook_ops rawpost6_hook_ops __read_mostly = {
.hook = rawpost6_hook_fn,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_LAST,
.owner = THIS_MODULE,
};
static int __init rawpost6_table_init(void)
{
int ret;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
rwlock_init(&rawpost6_itable.lock);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
rawpost6_ptable = ip6t_register_table(&init_net, &rawpost6_itable,
&rawpost6_initial.repl);
if (IS_ERR(rawpost6_ptable))
return PTR_ERR(rawpost6_ptable);
#else
ret = ip6t_register_table(&rawpost6_itable, &rawpost6_initial.repl);
if (ret < 0)
return ret;
rawpost6_ptable = &rawpost6_itable;
#endif
ret = nf_register_hook(&rawpost6_hook_ops);
if (ret < 0)
goto out;
return ret;
out:
ip6t_unregister_table(rawpost6_ptable);
return ret;
}
static void __exit rawpost6_table_exit(void)
{
nf_unregister_hook(&rawpost6_hook_ops);
ip6t_unregister_table(rawpost6_ptable);
}
module_init(rawpost6_table_init);
module_exit(rawpost6_table_exit);
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_LICENSE("GPL");

View File

@@ -2,8 +2,9 @@
top_srcdir := @top_srcdir@ top_srcdir := @top_srcdir@
srcdir := @srcdir@ srcdir := @srcdir@
abstop_srcdir := $(shell readlink -e ${top_srcdir}) datarootdir := @datarootdir@
abssrcdir := $(shell readlink -e ${srcdir}) abstop_srcdir := $(shell readlink -f ${top_srcdir})
abssrcdir := $(shell readlink -f ${srcdir})
ifeq (${abstop_srcdir},) ifeq (${abstop_srcdir},)
$(error Path resolution of ${top_srcdir} failed) $(error Path resolution of ${top_srcdir} failed)
@@ -29,23 +30,23 @@ regular_CFLAGS := @regular_CFLAGS@
kinclude_CFLAGS := @kinclude_CFLAGS@ kinclude_CFLAGS := @kinclude_CFLAGS@
xtables_CFLAGS := @xtables_CFLAGS@ xtables_CFLAGS := @xtables_CFLAGS@
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS} -DXTABLES_LIBDIR=\"${xtlibdir}\" AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS} -DIPSET_LIB_DIR=\"${xtlibdir}\"
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
ifeq (${V},) VU := 0
AM_LIBTOOL_SILENT = --silent am__1verbose_CC_0 = @echo " CC " $@;
AM_VERBOSE_CC = @echo " CC " $@; am__1verbose_CCLD_0 = @echo " CCLD " $@;
AM_VERBOSE_CCLD = @echo " CCLD " $@; am__1verbose_CC_1 = @echo " CC " $@ "<-" $<;
AM_VERBOSE_CXX = @echo " CXX " $@; am__1verbose_CCLD_1 = @echo " CCLD " $@ "<-" $^;
AM_VERBOSE_CXXLD = @echo " CXXLD " $@; am__verbose_CC = ${am__1verbose_CC_${VU}}
AM_VERBOSE_AR = @echo " AR " $@; am__verbose_CCLD = ${am__1verbose_CCLD_${VU}}
AM_VERBOSE_GEN = @echo " GEN " $@;
endif
# #
# Building blocks # Building blocks
# #
targets := $(addsuffix .so,$(addprefix libipset_,iphash ipmap ipporthash iptree iptreemap macipmap nethash portmap)) targets := $(addsuffix .so,$(addprefix libipset_, \
iphash ipmap ipporthash ipportiphash ipportnethash iptree \
iptreemap macipmap nethash portmap setlist))
.SECONDARY: .SECONDARY:
@@ -69,16 +70,16 @@ distclean: clean
ipset: ipset.o ipset: ipset.o
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -o $@ $< -ldl -rdynamic; ${am__verbose_CCLD}${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -o $@ $< -ldl -rdynamic;
# #
# Shared libraries # Shared libraries
# #
lib%.so: lib%.oo lib%.so: lib%.oo
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<; ${am__verbose_CCLD}${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
libipset_%.oo: ${srcdir}/ipset_%.c libipset_%.oo: ${srcdir}/ipset_%.c
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DPIC -fPIC ${CFLAGS} -o $@ -c $<; ${am__verbose_CC}${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
%.o: %.c %.o: %.c
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} ${CFLAGS} -o $@ -c $<; ${am__verbose_CC}${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} ${CFLAGS} -o $@ -c $<;

View File

@@ -19,21 +19,21 @@
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/jhash.h> #include "ip_set_jhash.h"
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/capability.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
# include <linux/semaphore.h>
#else
#include <asm/semaphore.h> #include <asm/semaphore.h>
#else
#include <linux/semaphore.h>
#endif #endif
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/vmalloc.h>
#define ASSERT_READ_LOCK(x) #define ASSERT_READ_LOCK(x)
#define ASSERT_WRITE_LOCK(x) #define ASSERT_WRITE_LOCK(x)
#include <linux/netfilter.h>
#include "ip_set.h" #include "ip_set.h"
static struct list_head set_type_list; /* all registered sets */ static struct list_head set_type_list; /* all registered sets */
@@ -235,10 +235,10 @@ ip_set_testip_kernel(ip_set_id_t index,
&& follow_bindings(index, set, ip)); && follow_bindings(index, set, ip));
read_unlock_bh(&ip_set_lock); read_unlock_bh(&ip_set_lock);
return res; return (res < 0 ? 0 : res);
} }
void int
ip_set_addip_kernel(ip_set_id_t index, ip_set_addip_kernel(ip_set_id_t index,
const struct sk_buff *skb, const struct sk_buff *skb,
const u_int32_t *flags) const u_int32_t *flags)
@@ -268,9 +268,11 @@ ip_set_addip_kernel(ip_set_id_t index,
&& set->type->retry && set->type->retry
&& (res = set->type->retry(set)) == 0) && (res = set->type->retry(set)) == 0)
goto retry; goto retry;
return res;
} }
void int
ip_set_delip_kernel(ip_set_id_t index, ip_set_delip_kernel(ip_set_id_t index,
const struct sk_buff *skb, const struct sk_buff *skb,
const u_int32_t *flags) const u_int32_t *flags)
@@ -294,6 +296,8 @@ ip_set_delip_kernel(ip_set_id_t index,
&& flags[i] && flags[i]
&& follow_bindings(index, set, ip)); && follow_bindings(index, set, ip));
read_unlock_bh(&ip_set_lock); read_unlock_bh(&ip_set_lock);
return res;
} }
/* Register and deregister settype */ /* Register and deregister settype */
@@ -358,6 +362,29 @@ ip_set_unregister_set_type(struct ip_set_type *set_type)
} }
ip_set_id_t
__ip_set_get_byname(const char *name, struct ip_set **set)
{
ip_set_id_t i, index = IP_SET_INVALID_ID;
for (i = 0; i < ip_set_max; i++) {
if (ip_set_list[i] != NULL
&& SETNAME_EQ(ip_set_list[i]->name, name)) {
__ip_set_get(i);
index = i;
*set = ip_set_list[i];
break;
}
}
return index;
}
void __ip_set_put_byindex(ip_set_id_t index)
{
if (ip_set_list[index])
__ip_set_put(index);
}
/* /*
* Userspace routines * Userspace routines
*/ */
@@ -407,12 +434,26 @@ ip_set_get_byindex(ip_set_id_t index)
return index; return index;
} }
/*
* Find the set id belonging to the index.
* We are protected by the mutex, so we do not need to use
* ip_set_lock. There is no need to reference the sets either.
*/
ip_set_id_t
ip_set_id(ip_set_id_t index)
{
if (index >= ip_set_max || !ip_set_list[index])
return IP_SET_INVALID_ID;
return ip_set_list[index]->id;
}
/* /*
* If the given set pointer points to a valid set, decrement * If the given set pointer points to a valid set, decrement
* reference count by 1. The caller shall not assume the index * reference count by 1. The caller shall not assume the index
* to be valid, after calling this function. * to be valid, after calling this function.
*/ */
void ip_set_put(ip_set_id_t index) void ip_set_put_byindex(ip_set_id_t index)
{ {
down(&ip_set_app_mutex); down(&ip_set_app_mutex);
if (ip_set_list[index]) if (ip_set_list[index])
@@ -452,7 +493,7 @@ ip_set_find_byindex(ip_set_id_t index)
static inline int static inline int
__ip_set_testip(struct ip_set *set, __ip_set_testip(struct ip_set *set,
const void *data, const void *data,
size_t size, u_int32_t size,
ip_set_ip_t *ip) ip_set_ip_t *ip)
{ {
int res; int res;
@@ -467,7 +508,7 @@ __ip_set_testip(struct ip_set *set,
static int static int
__ip_set_addip(ip_set_id_t index, __ip_set_addip(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set = ip_set_list[index]; struct ip_set *set = ip_set_list[index];
ip_set_ip_t ip; ip_set_ip_t ip;
@@ -488,9 +529,18 @@ __ip_set_addip(ip_set_id_t index,
static int static int
ip_set_addip(ip_set_id_t index, ip_set_addip(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set = ip_set_list[index];
IP_SET_ASSERT(set);
if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) {
ip_set_printk("data length wrong (want %lu, have %zu)",
(long unsigned)set->type->reqsize,
size - sizeof(struct ip_set_req_adt));
return -EINVAL;
}
return __ip_set_addip(index, return __ip_set_addip(index,
data + sizeof(struct ip_set_req_adt), data + sizeof(struct ip_set_req_adt),
size - sizeof(struct ip_set_req_adt)); size - sizeof(struct ip_set_req_adt));
@@ -499,13 +549,20 @@ ip_set_addip(ip_set_id_t index,
static int static int
ip_set_delip(ip_set_id_t index, ip_set_delip(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set = ip_set_list[index]; struct ip_set *set = ip_set_list[index];
ip_set_ip_t ip; ip_set_ip_t ip;
int res; int res;
IP_SET_ASSERT(set); IP_SET_ASSERT(set);
if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) {
ip_set_printk("data length wrong (want %lu, have %zu)",
(long unsigned)set->type->reqsize,
size - sizeof(struct ip_set_req_adt));
return -EINVAL;
}
write_lock_bh(&set->lock); write_lock_bh(&set->lock);
res = set->type->delip(set, res = set->type->delip(set,
data + sizeof(struct ip_set_req_adt), data + sizeof(struct ip_set_req_adt),
@@ -519,13 +576,20 @@ ip_set_delip(ip_set_id_t index,
static int static int
ip_set_testip(ip_set_id_t index, ip_set_testip(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set = ip_set_list[index]; struct ip_set *set = ip_set_list[index];
ip_set_ip_t ip; ip_set_ip_t ip;
int res; int res;
IP_SET_ASSERT(set); IP_SET_ASSERT(set);
if (size - sizeof(struct ip_set_req_adt) != set->type->reqsize) {
ip_set_printk("data length wrong (want %lu, have %zu)",
(long unsigned)set->type->reqsize,
size - sizeof(struct ip_set_req_adt));
return -EINVAL;
}
res = __ip_set_testip(set, res = __ip_set_testip(set,
data + sizeof(struct ip_set_req_adt), data + sizeof(struct ip_set_req_adt),
size - sizeof(struct ip_set_req_adt), size - sizeof(struct ip_set_req_adt),
@@ -537,7 +601,7 @@ ip_set_testip(ip_set_id_t index,
static int static int
ip_set_bindip(ip_set_id_t index, ip_set_bindip(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set = ip_set_list[index]; struct ip_set *set = ip_set_list[index];
const struct ip_set_req_bind *req_bind; const struct ip_set_req_bind *req_bind;
@@ -623,7 +687,7 @@ __unbind_default(struct ip_set *set)
static int static int
ip_set_unbindip(ip_set_id_t index, ip_set_unbindip(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set; struct ip_set *set;
const struct ip_set_req_bind *req_bind; const struct ip_set_req_bind *req_bind;
@@ -696,7 +760,7 @@ ip_set_unbindip(ip_set_id_t index,
static int static int
ip_set_testbind(ip_set_id_t index, ip_set_testbind(ip_set_id_t index,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set = ip_set_list[index]; struct ip_set *set = ip_set_list[index];
const struct ip_set_req_bind *req_bind; const struct ip_set_req_bind *req_bind;
@@ -798,13 +862,14 @@ ip_set_create(const char *name,
const char *typename, const char *typename,
ip_set_id_t restore, ip_set_id_t restore,
const void *data, const void *data,
size_t size) u_int32_t size)
{ {
struct ip_set *set; struct ip_set *set;
ip_set_id_t index = 0, id; ip_set_id_t index = 0, id;
int res = 0; int res = 0;
DP("setname: %s, typename: %s, id: %u", name, typename, restore); DP("setname: %s, typename: %s, id: %u", name, typename, restore);
/* /*
* First, and without any locks, allocate and initialize * First, and without any locks, allocate and initialize
* a normal base set structure. * a normal base set structure.
@@ -812,7 +877,7 @@ ip_set_create(const char *name,
set = kmalloc(sizeof(struct ip_set), GFP_KERNEL); set = kmalloc(sizeof(struct ip_set), GFP_KERNEL);
if (!set) if (!set)
return -ENOMEM; return -ENOMEM;
set->lock = RW_LOCK_UNLOCKED; rwlock_init(&set->lock);
strncpy(set->name, name, IP_SET_MAXNAMELEN); strncpy(set->name, name, IP_SET_MAXNAMELEN);
set->binding = IP_SET_INVALID_ID; set->binding = IP_SET_INVALID_ID;
atomic_set(&set->ref, 0); atomic_set(&set->ref, 0);
@@ -848,6 +913,14 @@ ip_set_create(const char *name,
} }
read_unlock_bh(&ip_set_lock); read_unlock_bh(&ip_set_lock);
/* Check request size */
if (size != set->type->header_size) {
ip_set_printk("data length wrong (want %lu, have %lu)",
(long unsigned)set->type->header_size,
(long unsigned)size);
goto put_out;
}
/* /*
* Without holding any locks, create private part. * Without holding any locks, create private part.
*/ */
@@ -1007,7 +1080,9 @@ ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
u_int32_t from_ref; u_int32_t from_ref;
DP("set: %s to %s", from->name, to->name); DP("set: %s to %s", from->name, to->name);
/* Features must not change. Artifical restriction. */ /* Features must not change.
* Not an artifical restriction anymore, as we must prevent
* possible loops created by swapping in setlist type of sets. */
if (from->type->features != to->type->features) if (from->type->features != to->type->features)
return -ENOEXEC; return -ENOEXEC;
@@ -1034,7 +1109,7 @@ ip_set_swap(ip_set_id_t from_index, ip_set_id_t to_index)
static inline void static inline void
__set_hash_bindings_size_list(struct ip_set_hash *set_hash, __set_hash_bindings_size_list(struct ip_set_hash *set_hash,
ip_set_id_t id, size_t *size) ip_set_id_t id, u_int32_t *size)
{ {
if (set_hash->id == id) if (set_hash->id == id)
*size += sizeof(struct ip_set_hash_list); *size += sizeof(struct ip_set_hash_list);
@@ -1042,7 +1117,7 @@ __set_hash_bindings_size_list(struct ip_set_hash *set_hash,
static inline void static inline void
__set_hash_bindings_size_save(struct ip_set_hash *set_hash, __set_hash_bindings_size_save(struct ip_set_hash *set_hash,
ip_set_id_t id, size_t *size) ip_set_id_t id, u_int32_t *size)
{ {
if (set_hash->id == id) if (set_hash->id == id)
*size += sizeof(struct ip_set_hash_save); *size += sizeof(struct ip_set_hash_save);
@@ -1145,7 +1220,7 @@ static int ip_set_save_set(ip_set_id_t index,
*used += sizeof(struct ip_set_save); *used += sizeof(struct ip_set_save);
set = ip_set_list[index]; set = ip_set_list[index];
DP("set: %s, used: %u(%u) %p %p", set->name, *used, len, DP("set: %s, used: %d(%d) %p %p", set->name, *used, len,
data, data + *used); data, data + *used);
read_lock_bh(&set->lock); read_lock_bh(&set->lock);
@@ -1162,8 +1237,8 @@ static int ip_set_save_set(ip_set_id_t index,
set->type->list_header(set, data + *used); set->type->list_header(set, data + *used);
*used += set_save->header_size; *used += set_save->header_size;
DP("set header filled: %s, used: %u(%u) %p %p", set->name, *used, DP("set header filled: %s, used: %d(%lu) %p %p", set->name, *used,
set_save->header_size, data, data + *used); (unsigned long)set_save->header_size, data, data + *used);
/* Get and ensure set specific members size */ /* Get and ensure set specific members size */
set_save->members_size = set->type->list_members_size(set); set_save->members_size = set->type->list_members_size(set);
if (*used + set_save->members_size > len) if (*used + set_save->members_size > len)
@@ -1173,8 +1248,8 @@ static int ip_set_save_set(ip_set_id_t index,
set->type->list_members(set, data + *used); set->type->list_members(set, data + *used);
*used += set_save->members_size; *used += set_save->members_size;
read_unlock_bh(&set->lock); read_unlock_bh(&set->lock);
DP("set members filled: %s, used: %u(%u) %p %p", set->name, *used, DP("set members filled: %s, used: %d(%lu) %p %p", set->name, *used,
set_save->members_size, data, data + *used); (unsigned long)set_save->members_size, data, data + *used);
return 0; return 0;
unlock_set: unlock_set:
@@ -1254,7 +1329,7 @@ static int ip_set_restore(void *data,
while (1) { while (1) {
line++; line++;
DP("%u %u %u", used, sizeof(struct ip_set_restore), len); DP("%d %zu %d", used, sizeof(struct ip_set_restore), len);
/* Get and ensure header size */ /* Get and ensure header size */
if (used + sizeof(struct ip_set_restore) > len) if (used + sizeof(struct ip_set_restore) > len)
return line; return line;
@@ -1292,12 +1367,13 @@ static int ip_set_restore(void *data,
/* Try to restore members data */ /* Try to restore members data */
set = ip_set_list[index]; set = ip_set_list[index];
members_size = 0; members_size = 0;
DP("members_size %u reqsize %u", DP("members_size %lu reqsize %lu",
set_restore->members_size, set->type->reqsize); (unsigned long)set_restore->members_size,
(unsigned long)set->type->reqsize);
while (members_size + set->type->reqsize <= while (members_size + set->type->reqsize <=
set_restore->members_size) { set_restore->members_size) {
line++; line++;
DP("members: %u, line %u", members_size, line); DP("members: %d, line %d", members_size, line);
res = __ip_set_addip(index, res = __ip_set_addip(index,
data + used + members_size, data + used + members_size,
set->type->reqsize); set->type->reqsize);
@@ -1306,8 +1382,8 @@ static int ip_set_restore(void *data,
members_size += set->type->reqsize; members_size += set->type->reqsize;
} }
DP("members_size %u %u", DP("members_size %lu %d",
set_restore->members_size, members_size); (unsigned long)set_restore->members_size, members_size);
if (members_size != set_restore->members_size) if (members_size != set_restore->members_size)
return line++; return line++;
used += set_restore->members_size; used += set_restore->members_size;
@@ -1367,10 +1443,10 @@ ip_set_sockfn_set(struct sock *sk, int optval, void *user, unsigned int len)
struct ip_set_req_adt *req_adt; struct ip_set_req_adt *req_adt;
ip_set_id_t index = IP_SET_INVALID_ID; ip_set_id_t index = IP_SET_INVALID_ID;
int (*adtfn)(ip_set_id_t index, int (*adtfn)(ip_set_id_t index,
const void *data, size_t size); const void *data, u_int32_t size);
struct fn_table { struct fn_table {
int (*fn)(ip_set_id_t index, int (*fn)(ip_set_id_t index,
const void *data, size_t size); const void *data, u_int32_t size);
} adtfn_table[] = } adtfn_table[] =
{ { ip_set_addip }, { ip_set_delip }, { ip_set_testip}, { { ip_set_addip }, { ip_set_delip }, { ip_set_testip},
{ ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind }, { ip_set_bindip}, { ip_set_unbindip }, { ip_set_testbind },
@@ -1835,13 +1911,23 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
res = -ENOENT; res = -ENOENT;
goto done; goto done;
} }
#define SETLIST(set) (strcmp(set->type->typename, "setlist") == 0)
used = 0; used = 0;
if (index == IP_SET_INVALID_ID) { if (index == IP_SET_INVALID_ID) {
/* Save all sets */ /* Save all sets: ugly setlist type dependency */
int setlist = 0;
setlists:
for (i = 0; i < ip_set_max && res == 0; i++) { for (i = 0; i < ip_set_max && res == 0; i++) {
if (ip_set_list[i] != NULL) if (ip_set_list[i] != NULL
&& !(setlist ^ SETLIST(ip_set_list[i])))
res = ip_set_save_set(i, data, &used, *len); res = ip_set_save_set(i, data, &used, *len);
} }
if (!setlist) {
setlist = 1;
goto setlists;
}
} else { } else {
/* Save an individual set */ /* Save an individual set */
res = ip_set_save_set(index, data, &used, *len); res = ip_set_save_set(index, data, &used, *len);
@@ -1863,14 +1949,14 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
if (*len < sizeof(struct ip_set_req_setnames) if (*len < sizeof(struct ip_set_req_setnames)
|| *len != req_restore->size) { || *len != req_restore->size) {
ip_set_printk("invalid RESTORE (want =%zu, got %d)", ip_set_printk("invalid RESTORE (want =%lu, got %d)",
req_restore->size, *len); (long unsigned)req_restore->size, *len);
res = -EINVAL; res = -EINVAL;
goto done; goto done;
} }
line = ip_set_restore(data + sizeof(struct ip_set_req_setnames), line = ip_set_restore(data + sizeof(struct ip_set_req_setnames),
req_restore->size - sizeof(struct ip_set_req_setnames)); req_restore->size - sizeof(struct ip_set_req_setnames));
DP("ip_set_restore: %u", line); DP("ip_set_restore: %d", line);
if (line != 0) { if (line != 0) {
res = -EAGAIN; res = -EAGAIN;
req_restore->size = line; req_restore->size = line;
@@ -1885,7 +1971,7 @@ ip_set_sockfn_get(struct sock *sk, int optval, void *user, int *len)
} /* end of switch(op) */ } /* end of switch(op) */
copy: copy:
DP("set %s, copylen %u", index != IP_SET_INVALID_ID DP("set %s, copylen %d", index != IP_SET_INVALID_ID
&& ip_set_list[index] && ip_set_list[index]
? ip_set_list[index]->name ? ip_set_list[index]->name
: ":all:", copylen); : ":all:", copylen);
@@ -1916,6 +2002,7 @@ static struct nf_sockopt_ops so_set = {
}; };
static int max_sets, hash_size; static int max_sets, hash_size;
module_param(max_sets, int, 0600); module_param(max_sets, int, 0600);
MODULE_PARM_DESC(max_sets, "maximal number of sets"); MODULE_PARM_DESC(max_sets, "maximal number of sets");
module_param(hash_size, int, 0600); module_param(hash_size, int, 0600);
@@ -1958,6 +2045,7 @@ static int __init ip_set_init(void)
vfree(ip_set_hash); vfree(ip_set_hash);
return res; return res;
} }
return 0; return 0;
} }
@@ -1975,7 +2063,10 @@ EXPORT_SYMBOL(ip_set_unregister_set_type);
EXPORT_SYMBOL(ip_set_get_byname); EXPORT_SYMBOL(ip_set_get_byname);
EXPORT_SYMBOL(ip_set_get_byindex); EXPORT_SYMBOL(ip_set_get_byindex);
EXPORT_SYMBOL(ip_set_put); EXPORT_SYMBOL(ip_set_put_byindex);
EXPORT_SYMBOL(ip_set_id);
EXPORT_SYMBOL(__ip_set_get_byname);
EXPORT_SYMBOL(__ip_set_put_byindex);
EXPORT_SYMBOL(ip_set_addip_kernel); EXPORT_SYMBOL(ip_set_addip_kernel);
EXPORT_SYMBOL(ip_set_delip_kernel); EXPORT_SYMBOL(ip_set_delip_kernel);

View File

@@ -48,7 +48,7 @@
/* /*
* Used so that the kernel module and ipset-binary can match their versions * Used so that the kernel module and ipset-binary can match their versions
*/ */
#define IP_SET_PROTOCOL_VERSION 2 #define IP_SET_PROTOCOL_VERSION 3
#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */ #define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
@@ -95,6 +95,9 @@ typedef uint16_t ip_set_id_t;
#define IPSET_TYPE_PORT 0x02 /* Port type of set */ #define IPSET_TYPE_PORT 0x02 /* Port type of set */
#define IPSET_DATA_SINGLE 0x04 /* Single data storage */ #define IPSET_DATA_SINGLE 0x04 /* Single data storage */
#define IPSET_DATA_DOUBLE 0x08 /* Double data storage */ #define IPSET_DATA_DOUBLE 0x08 /* Double data storage */
#define IPSET_DATA_TRIPLE 0x10 /* Triple data storage */
#define IPSET_TYPE_IP1 0x20 /* IP address type of set */
#define IPSET_TYPE_SETNAME 0x40 /* setname type of set */
/* Reserved keywords */ /* Reserved keywords */
#define IPSET_TOKEN_DEFAULT ":default:" #define IPSET_TOKEN_DEFAULT ":default:"
@@ -233,7 +236,7 @@ struct ip_set_req_max_sets {
struct ip_set_req_setnames { struct ip_set_req_setnames {
unsigned op; unsigned op;
ip_set_id_t index; /* set to list/save */ ip_set_id_t index; /* set to list/save */
size_t size; /* size to get setdata/bindings */ u_int32_t size; /* size to get setdata/bindings */
/* followed by sets number of struct ip_set_name_list */ /* followed by sets number of struct ip_set_name_list */
}; };
@@ -255,9 +258,9 @@ struct ip_set_list {
ip_set_id_t index; ip_set_id_t index;
ip_set_id_t binding; ip_set_id_t binding;
u_int32_t ref; u_int32_t ref;
size_t header_size; /* Set header data of header_size */ u_int32_t header_size; /* Set header data of header_size */
size_t members_size; /* Set members data of members_size */ u_int32_t members_size; /* Set members data of members_size */
size_t bindings_size; /* Set bindings data of bindings_size */ u_int32_t bindings_size;/* Set bindings data of bindings_size */
}; };
struct ip_set_hash_list { struct ip_set_hash_list {
@@ -274,8 +277,8 @@ struct ip_set_hash_list {
struct ip_set_save { struct ip_set_save {
ip_set_id_t index; ip_set_id_t index;
ip_set_id_t binding; ip_set_id_t binding;
size_t header_size; /* Set header data of header_size */ u_int32_t header_size; /* Set header data of header_size */
size_t members_size; /* Set members data of members_size */ u_int32_t members_size; /* Set members data of members_size */
}; };
/* At restoring, ip == 0 means default binding for the given set: */ /* At restoring, ip == 0 means default binding for the given set: */
@@ -295,8 +298,8 @@ struct ip_set_restore {
char name[IP_SET_MAXNAMELEN]; char name[IP_SET_MAXNAMELEN];
char typename[IP_SET_MAXNAMELEN]; char typename[IP_SET_MAXNAMELEN];
ip_set_id_t index; ip_set_id_t index;
size_t header_size; /* Create data of header_size */ u_int32_t header_size; /* Create data of header_size */
size_t members_size; /* Set members data of members_size */ u_int32_t members_size; /* Set members data of members_size */
}; };
static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b) static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
@@ -304,7 +307,12 @@ static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
return 4 * ((((b - a + 8) / 8) + 3) / 4); return 4 * ((((b - a + 8) / 8) + 3) / 4);
} }
/* General limit for the elements in a set */
#define MAX_RANGE 0x0000FFFF
#ifdef __KERNEL__ #ifdef __KERNEL__
#include "ip_set_compat.h"
#include "ip_set_malloc.h"
#define ip_set_printk(format, args...) \ #define ip_set_printk(format, args...) \
do { \ do { \
@@ -358,14 +366,14 @@ struct ip_set_type {
* return 0 if not in set, 1 if in set. * return 0 if not in set, 1 if in set.
*/ */
int (*testip) (struct ip_set *set, int (*testip) (struct ip_set *set,
const void *data, size_t size, const void *data, u_int32_t size,
ip_set_ip_t *ip); ip_set_ip_t *ip);
/* /*
* Size of the data structure passed by when * Size of the data structure passed by when
* adding/deletin/testing an entry. * adding/deletin/testing an entry.
*/ */
size_t reqsize; u_int32_t reqsize;
/* Add IP into set (userspace: ipset -A set IP) /* Add IP into set (userspace: ipset -A set IP)
* Return -EEXIST if the address is already in the set, * Return -EEXIST if the address is already in the set,
@@ -373,7 +381,7 @@ struct ip_set_type {
* If the address was not already in the set, 0 is returned. * If the address was not already in the set, 0 is returned.
*/ */
int (*addip) (struct ip_set *set, int (*addip) (struct ip_set *set,
const void *data, size_t size, const void *data, u_int32_t size,
ip_set_ip_t *ip); ip_set_ip_t *ip);
/* Add IP into set (kernel: iptables ... -j SET set src|dst) /* Add IP into set (kernel: iptables ... -j SET set src|dst)
@@ -393,7 +401,7 @@ struct ip_set_type {
* If the address really was in the set, 0 is returned. * If the address really was in the set, 0 is returned.
*/ */
int (*delip) (struct ip_set *set, int (*delip) (struct ip_set *set,
const void *data, size_t size, const void *data, u_int32_t size,
ip_set_ip_t *ip); ip_set_ip_t *ip);
/* remove IP from set (kernel: iptables ... -j SET --entry x) /* remove IP from set (kernel: iptables ... -j SET --entry x)
@@ -410,7 +418,7 @@ struct ip_set_type {
/* new set creation - allocated type specific items /* new set creation - allocated type specific items
*/ */
int (*create) (struct ip_set *set, int (*create) (struct ip_set *set,
const void *data, size_t size); const void *data, u_int32_t size);
/* retry the operation after successfully tweaking the set /* retry the operation after successfully tweaking the set
*/ */
@@ -429,7 +437,7 @@ struct ip_set_type {
/* Listing: size needed for header /* Listing: size needed for header
*/ */
size_t header_size; u_int32_t header_size;
/* Listing: Get the header /* Listing: Get the header
* *
@@ -487,20 +495,88 @@ struct ip_set_hash {
/* register and unregister set references */ /* register and unregister set references */
extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]); extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id); extern ip_set_id_t ip_set_get_byindex(ip_set_id_t index);
extern void ip_set_put(ip_set_id_t id); extern void ip_set_put_byindex(ip_set_id_t index);
extern ip_set_id_t ip_set_id(ip_set_id_t index);
extern ip_set_id_t __ip_set_get_byname(const char name[IP_SET_MAXNAMELEN],
struct ip_set **set);
extern void __ip_set_put_byindex(ip_set_id_t index);
/* API for iptables set match, and SET target */ /* API for iptables set match, and SET target */
extern void ip_set_addip_kernel(ip_set_id_t id, extern int ip_set_addip_kernel(ip_set_id_t id,
const struct sk_buff *skb, const struct sk_buff *skb,
const u_int32_t *flags); const u_int32_t *flags);
extern void ip_set_delip_kernel(ip_set_id_t id, extern int ip_set_delip_kernel(ip_set_id_t id,
const struct sk_buff *skb, const struct sk_buff *skb,
const u_int32_t *flags); const u_int32_t *flags);
extern int ip_set_testip_kernel(ip_set_id_t id, extern int ip_set_testip_kernel(ip_set_id_t id,
const struct sk_buff *skb, const struct sk_buff *skb,
const u_int32_t *flags); const u_int32_t *flags);
/* Macros to generate functions */
#define STRUCT(pre, type) CONCAT2(pre, type)
#define CONCAT2(pre, type) struct pre##type
#define FNAME(pre, mid, post) CONCAT3(pre, mid, post)
#define CONCAT3(pre, mid, post) pre##mid##post
#define UADT0(type, adt, args...) \
static int \
FNAME(type,_u,adt)(struct ip_set *set, const void *data, u_int32_t size,\
ip_set_ip_t *hash_ip) \
{ \
const STRUCT(ip_set_req_,type) *req = data; \
\
return FNAME(type,_,adt)(set, hash_ip , ## args); \
}
#define UADT(type, adt, args...) \
UADT0(type, adt, req->ip , ## args)
#define KADT(type, adt, getfn, args...) \
static int \
FNAME(type,_k,adt)(struct ip_set *set, \
const struct sk_buff *skb, \
ip_set_ip_t *hash_ip, \
const u_int32_t *flags, \
unsigned char index) \
{ \
ip_set_ip_t ip = getfn(skb, flags[index]); \
\
KADT_CONDITION \
return FNAME(type,_,adt)(set, hash_ip, ip , ##args); \
}
#define REGISTER_MODULE(type) \
static int __init ip_set_##type##_init(void) \
{ \
init_max_page_size(); \
return ip_set_register_set_type(&ip_set_##type); \
} \
\
static void __exit ip_set_##type##_fini(void) \
{ \
/* FIXME: possible race with ip_set_create() */ \
ip_set_unregister_set_type(&ip_set_##type); \
} \
\
module_init(ip_set_##type##_init); \
module_exit(ip_set_##type##_fini);
/* Common functions */
static inline ip_set_ip_t
ipaddr(const struct sk_buff *skb, u_int32_t flag)
{
return ntohl(flag & IPSET_SRC ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr);
}
#define jhash_ip(map, i, ip) jhash_1word(ip, *(map->initval + i))
#define pack_ip_port(map, ip, port) \
(port + ((ip - ((map)->first_ip)) << 16))
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /*_IP_SET_H*/ #endif /*_IP_SET_H*/

View File

@@ -0,0 +1,121 @@
#ifndef __IP_SET_BITMAPS_H
#define __IP_SET_BITMAPS_H
/* Macros to generate functions */
#ifdef __KERNEL__
#define BITMAP_CREATE(type) \
static int \
type##_create(struct ip_set *set, const void *data, u_int32_t size) \
{ \
int newbytes; \
const struct ip_set_req_##type##_create *req = data; \
struct ip_set_##type *map; \
\
if (req->from > req->to) { \
DP("bad range"); \
return -ENOEXEC; \
} \
\
map = kmalloc(sizeof(struct ip_set_##type), GFP_KERNEL); \
if (!map) { \
DP("out of memory for %zu bytes", \
sizeof(struct ip_set_##type)); \
return -ENOMEM; \
} \
map->first_ip = req->from; \
map->last_ip = req->to; \
\
newbytes = __##type##_create(req, map); \
if (newbytes < 0) { \
kfree(map); \
return newbytes; \
} \
\
map->size = newbytes; \
map->members = ip_set_malloc(newbytes); \
if (!map->members) { \
DP("out of memory for %i bytes", newbytes); \
kfree(map); \
return -ENOMEM; \
} \
memset(map->members, 0, newbytes); \
\
set->data = map; \
return 0; \
}
#define BITMAP_DESTROY(type) \
static void \
type##_destroy(struct ip_set *set) \
{ \
struct ip_set_##type *map = set->data; \
\
ip_set_free(map->members, map->size); \
kfree(map); \
\
set->data = NULL; \
}
#define BITMAP_FLUSH(type) \
static void \
type##_flush(struct ip_set *set) \
{ \
struct ip_set_##type *map = set->data; \
memset(map->members, 0, map->size); \
}
#define BITMAP_LIST_HEADER(type) \
static void \
type##_list_header(const struct ip_set *set, void *data) \
{ \
const struct ip_set_##type *map = set->data; \
struct ip_set_req_##type##_create *header = data; \
\
header->from = map->first_ip; \
header->to = map->last_ip; \
__##type##_list_header(map, header); \
}
#define BITMAP_LIST_MEMBERS_SIZE(type) \
static int \
type##_list_members_size(const struct ip_set *set) \
{ \
const struct ip_set_##type *map = set->data; \
\
return map->size; \
}
#define BITMAP_LIST_MEMBERS(type) \
static void \
type##_list_members(const struct ip_set *set, void *data) \
{ \
const struct ip_set_##type *map = set->data; \
\
memcpy(data, map->members, map->size); \
}
#define IP_SET_TYPE(type, __features) \
struct ip_set_type ip_set_##type = { \
.typename = #type, \
.features = __features, \
.protocol_version = IP_SET_PROTOCOL_VERSION, \
.create = &type##_create, \
.destroy = &type##_destroy, \
.flush = &type##_flush, \
.reqsize = sizeof(struct ip_set_req_##type), \
.addip = &type##_uadd, \
.addip_kernel = &type##_kadd, \
.delip = &type##_udel, \
.delip_kernel = &type##_kdel, \
.testip = &type##_utest, \
.testip_kernel = &type##_ktest, \
.header_size = sizeof(struct ip_set_req_##type##_create),\
.list_header = &type##_list_header, \
.list_members_size = &type##_list_members_size, \
.list_members = &type##_list_members, \
.me = THIS_MODULE, \
};
#endif /* __KERNEL */
#endif /* __IP_SET_BITMAPS_H */

View File

@@ -0,0 +1,71 @@
#ifndef _IP_SET_COMPAT_H
#define _IP_SET_COMPAT_H
#ifdef __KERNEL__
#include <linux/version.h>
/* Arrgh */
#ifdef MODULE
#define __MOD_INC(foo) __MOD_INC_USE_COUNT(foo)
#define __MOD_DEC(foo) __MOD_DEC_USE_COUNT(foo)
#else
#define __MOD_INC(foo) 1
#define __MOD_DEC(foo)
#endif
/* Backward compatibility */
#ifndef __nocast
#define __nocast
#endif
#ifndef __bitwise__
#define __bitwise__
#endif
/* Compatibility glue code */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#include <linux/interrupt.h>
#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED
#define try_module_get(x) __MOD_INC(x)
#define module_put(x) __MOD_DEC(x)
#define __clear_bit(nr, addr) clear_bit(nr, addr)
#define __set_bit(nr, addr) set_bit(nr, addr)
#define __test_and_set_bit(nr, addr) test_and_set_bit(nr, addr)
#define __test_and_clear_bit(nr, addr) test_and_clear_bit(nr, addr)
typedef unsigned __bitwise__ gfp_t;
static inline void *kzalloc(size_t size, gfp_t flags)
{
void *data = kmalloc(size, flags);
if (data)
memset(data, 0, size);
return data;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#define __KMEM_CACHE_T__ kmem_cache_t
#else
#define __KMEM_CACHE_T__ struct kmem_cache
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
#define ip_hdr(skb) ((skb)->nh.iph)
#define skb_mac_header(skb) ((skb)->mac.raw)
#define eth_hdr(skb) ((struct ethhdr *)skb_mac_header(skb))
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
#include <linux/netfilter.h>
#define KMEM_CACHE_CREATE(name, size) \
kmem_cache_create(name, size, 0, 0, NULL, NULL)
#else
#define KMEM_CACHE_CREATE(name, size) \
kmem_cache_create(name, size, 0, 0, NULL)
#endif
#endif /* __KERNEL__ */
#endif /* _IP_SET_COMPAT_H */

View File

@@ -0,0 +1,48 @@
#ifndef _IP_SET_GETPORT_H
#define _IP_SET_GETPORT_H
#ifdef __KERNEL__
#define INVALID_PORT (MAX_RANGE + 1)
/* We must handle non-linear skbs */
static inline ip_set_ip_t
get_port(const struct sk_buff *skb, u_int32_t flags)
{
struct iphdr *iph = ip_hdr(skb);
u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
switch (iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr tcph;
/* See comments at tcp_match in ip_tables.c */
if (offset)
return INVALID_PORT;
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
/* No choice either */
return INVALID_PORT;
return ntohs(flags & IPSET_SRC ?
tcph.source : tcph.dest);
}
case IPPROTO_UDP: {
struct udphdr udph;
if (offset)
return INVALID_PORT;
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
/* No choice either */
return INVALID_PORT;
return ntohs(flags & IPSET_SRC ?
udph.source : udph.dest);
}
default:
return INVALID_PORT;
}
}
#endif /* __KERNEL__ */
#endif /*_IP_SET_GETPORT_H*/

View File

@@ -0,0 +1,306 @@
#ifndef __IP_SET_HASHES_H
#define __IP_SET_HASHES_H
#define initval_t uint32_t
/* Macros to generate functions */
#ifdef __KERNEL__
#define HASH_RETRY0(type, dtype, cond) \
static int \
type##_retry(struct ip_set *set) \
{ \
struct ip_set_##type *map = set->data, *tmp; \
dtype *elem; \
void *members; \
u_int32_t i, hashsize = map->hashsize; \
int res; \
\
if (map->resize == 0) \
return -ERANGE; \
\
again: \
res = 0; \
\
/* Calculate new hash size */ \
hashsize += (hashsize * map->resize)/100; \
if (hashsize == map->hashsize) \
hashsize++; \
\
ip_set_printk("rehashing of set %s triggered: " \
"hashsize grows from %lu to %lu", \
set->name, \
(long unsigned)map->hashsize, \
(long unsigned)hashsize); \
\
tmp = kmalloc(sizeof(struct ip_set_##type) \
+ map->probes * sizeof(initval_t), GFP_ATOMIC); \
if (!tmp) { \
DP("out of memory for %zu bytes", \
sizeof(struct ip_set_##type) \
+ map->probes * sizeof(initval_t)); \
return -ENOMEM; \
} \
tmp->members = harray_malloc(hashsize, sizeof(dtype), GFP_ATOMIC);\
if (!tmp->members) { \
DP("out of memory for %zu bytes", hashsize * sizeof(dtype));\
kfree(tmp); \
return -ENOMEM; \
} \
tmp->hashsize = hashsize; \
tmp->elements = 0; \
tmp->probes = map->probes; \
tmp->resize = map->resize; \
memcpy(tmp->initval, map->initval, map->probes * sizeof(initval_t));\
__##type##_retry(tmp, map); \
\
write_lock_bh(&set->lock); \
map = set->data; /* Play safe */ \
for (i = 0; i < map->hashsize && res == 0; i++) { \
elem = HARRAY_ELEM(map->members, dtype *, i); \
if (cond) \
res = __##type##_add(tmp, elem); \
} \
if (res) { \
/* Failure, try again */ \
write_unlock_bh(&set->lock); \
harray_free(tmp->members); \
kfree(tmp); \
goto again; \
} \
\
/* Success at resizing! */ \
members = map->members; \
\
map->hashsize = tmp->hashsize; \
map->members = tmp->members; \
write_unlock_bh(&set->lock); \
\
harray_free(members); \
kfree(tmp); \
\
return 0; \
}
#define HASH_RETRY(type, dtype) \
HASH_RETRY0(type, dtype, *elem)
#define HASH_RETRY2(type, dtype) \
HASH_RETRY0(type, dtype, elem->ip || elem->ip1)
#define HASH_CREATE(type, dtype) \
static int \
type##_create(struct ip_set *set, const void *data, u_int32_t size) \
{ \
const struct ip_set_req_##type##_create *req = data; \
struct ip_set_##type *map; \
uint16_t i; \
\
if (req->hashsize < 1) { \
ip_set_printk("hashsize too small"); \
return -ENOEXEC; \
} \
\
if (req->probes < 1) { \
ip_set_printk("probes too small"); \
return -ENOEXEC; \
} \
\
map = kmalloc(sizeof(struct ip_set_##type) \
+ req->probes * sizeof(initval_t), GFP_KERNEL); \
if (!map) { \
DP("out of memory for %zu bytes", \
sizeof(struct ip_set_##type) \
+ req->probes * sizeof(initval_t)); \
return -ENOMEM; \
} \
for (i = 0; i < req->probes; i++) \
get_random_bytes(((initval_t *) map->initval)+i, 4); \
map->elements = 0; \
map->hashsize = req->hashsize; \
map->probes = req->probes; \
map->resize = req->resize; \
if (__##type##_create(req, map)) { \
kfree(map); \
return -ENOEXEC; \
} \
map->members = harray_malloc(map->hashsize, sizeof(dtype), GFP_KERNEL);\
if (!map->members) { \
DP("out of memory for %zu bytes", map->hashsize * sizeof(dtype));\
kfree(map); \
return -ENOMEM; \
} \
\
set->data = map; \
return 0; \
}
#define HASH_DESTROY(type) \
static void \
type##_destroy(struct ip_set *set) \
{ \
struct ip_set_##type *map = set->data; \
\
harray_free(map->members); \
kfree(map); \
\
set->data = NULL; \
}
#define HASH_FLUSH(type, dtype) \
static void \
type##_flush(struct ip_set *set) \
{ \
struct ip_set_##type *map = set->data; \
harray_flush(map->members, map->hashsize, sizeof(dtype)); \
map->elements = 0; \
}
#define HASH_FLUSH_CIDR(type, dtype) \
static void \
type##_flush(struct ip_set *set) \
{ \
struct ip_set_##type *map = set->data; \
harray_flush(map->members, map->hashsize, sizeof(dtype)); \
memset(map->cidr, 0, sizeof(map->cidr)); \
memset(map->nets, 0, sizeof(map->nets)); \
map->elements = 0; \
}
#define HASH_LIST_HEADER(type) \
static void \
type##_list_header(const struct ip_set *set, void *data) \
{ \
const struct ip_set_##type *map = set->data; \
struct ip_set_req_##type##_create *header = data; \
\
header->hashsize = map->hashsize; \
header->probes = map->probes; \
header->resize = map->resize; \
__##type##_list_header(map, header); \
}
#define HASH_LIST_MEMBERS_SIZE(type, dtype) \
static int \
type##_list_members_size(const struct ip_set *set) \
{ \
const struct ip_set_##type *map = set->data; \
\
return (map->hashsize * sizeof(dtype)); \
}
#define HASH_LIST_MEMBERS(type, dtype) \
static void \
type##_list_members(const struct ip_set *set, void *data) \
{ \
const struct ip_set_##type *map = set->data; \
dtype *elem; \
uint32_t i; \
\
for (i = 0; i < map->hashsize; i++) { \
elem = HARRAY_ELEM(map->members, dtype *, i); \
((dtype *)data)[i] = *elem; \
} \
}
#define HASH_LIST_MEMBERS_MEMCPY(type, dtype) \
static void \
type##_list_members(const struct ip_set *set, void *data) \
{ \
const struct ip_set_##type *map = set->data; \
dtype *elem; \
uint32_t i; \
\
for (i = 0; i < map->hashsize; i++) { \
elem = HARRAY_ELEM(map->members, dtype *, i); \
memcpy((((dtype *)data)+i), elem, sizeof(dtype)); \
} \
}
#define IP_SET_RTYPE(type, __features) \
struct ip_set_type ip_set_##type = { \
.typename = #type, \
.features = __features, \
.protocol_version = IP_SET_PROTOCOL_VERSION, \
.create = &type##_create, \
.retry = &type##_retry, \
.destroy = &type##_destroy, \
.flush = &type##_flush, \
.reqsize = sizeof(struct ip_set_req_##type), \
.addip = &type##_uadd, \
.addip_kernel = &type##_kadd, \
.delip = &type##_udel, \
.delip_kernel = &type##_kdel, \
.testip = &type##_utest, \
.testip_kernel = &type##_ktest, \
.header_size = sizeof(struct ip_set_req_##type##_create),\
.list_header = &type##_list_header, \
.list_members_size = &type##_list_members_size, \
.list_members = &type##_list_members, \
.me = THIS_MODULE, \
};
/* Helper functions */
static inline void
add_cidr_size(uint8_t *cidr, uint8_t size)
{
uint8_t next;
int i;
for (i = 0; i < 30 && cidr[i]; i++) {
if (cidr[i] < size) {
next = cidr[i];
cidr[i] = size;
size = next;
}
}
if (i < 30)
cidr[i] = size;
}
static inline void
del_cidr_size(uint8_t *cidr, uint8_t size)
{
int i;
for (i = 0; i < 29 && cidr[i]; i++) {
if (cidr[i] == size)
cidr[i] = size = cidr[i+1];
}
cidr[29] = 0;
}
#else
#include <arpa/inet.h>
#endif /* __KERNEL */
#ifndef UINT16_MAX
#define UINT16_MAX 65535
#endif
static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
static inline ip_set_ip_t
pack_ip_cidr(ip_set_ip_t ip, unsigned char cidr)
{
ip_set_ip_t addr, *paddr = &addr;
unsigned char n, t, *a;
addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
#ifdef __KERNEL__
DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
#endif
n = cidr / 8;
t = cidr % 8;
a = &((unsigned char *)paddr)[n];
*a = *a /(1 << (8 - t)) + shifts[t];
#ifdef __KERNEL__
DP("n: %u, t: %u, a: %u", n, t, *a);
DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
HIPQUAD(ip), cidr, NIPQUAD(addr));
#endif
return ntohl(addr);
}
#endif /* __IP_SET_HASHES_H */

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -8,34 +8,24 @@
/* Kernel module implementing an ip hash set */ /* Kernel module implementing an ip hash set */
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h> #include "ip_set_jhash.h"
#include <linux/jhash.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include "ip_set_malloc.h"
#include "ip_set_iphash.h" #include "ip_set_iphash.h"
static int limit = MAX_RANGE; static int limit = MAX_RANGE;
static inline __u32 static inline __u32
jhash_ip(const struct ip_set_iphash *map, uint16_t i, ip_set_ip_t ip) iphash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
}
static inline __u32
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
{ {
struct ip_set_iphash *map = set->data; struct ip_set_iphash *map = set->data;
__u32 id; __u32 id;
@@ -52,188 +42,73 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
if (*elem == *hash_ip) if (*elem == *hash_ip)
return id; return id;
/* No shortcut at testing - there can be deleted /* No shortcut - there can be deleted entries. */
* entries. */
} }
return UINT_MAX; return UINT_MAX;
} }
static inline int static inline int
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) iphash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
return (ip && hash_id(set, ip, hash_ip) != UINT_MAX); return (ip && iphash_id(set, hash_ip, ip) != UINT_MAX);
} }
static int #define KADT_CONDITION
testip(struct ip_set *set, const void *data, size_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_iphash *req = data;
if (size != sizeof(struct ip_set_req_iphash)) { UADT(iphash, test)
ip_set_printk("data length wrong (want %zu, have %zu)", KADT(iphash, test, ipaddr)
sizeof(struct ip_set_req_iphash),
size);
return -EINVAL;
}
return __testip(set, req->ip, hash_ip);
}
static int
testip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __testip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static inline int static inline int
__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip) __iphash_add(struct ip_set_iphash *map, ip_set_ip_t *ip)
{ {
__u32 probe; __u32 probe;
u_int16_t i; u_int16_t i;
ip_set_ip_t *elem; ip_set_ip_t *elem, *slot = NULL;
for (i = 0; i < map->probes; i++) {
probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
if (*elem == *ip)
return -EEXIST;
if (!(slot || *elem))
slot = elem;
/* There can be deleted entries, must check all slots */
}
if (slot) {
*slot = *ip;
map->elements++;
return 0;
}
/* Trigger rehashing */
return -EAGAIN;
}
static inline int
iphash_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{
struct ip_set_iphash *map = set->data;
if (!ip || map->elements >= limit) if (!ip || map->elements >= limit)
return -ERANGE; return -ERANGE;
*hash_ip = ip & map->netmask; *hash_ip = ip & map->netmask;
for (i = 0; i < map->probes; i++) { return __iphash_add(map, hash_ip);
probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
if (*elem == *hash_ip)
return -EEXIST;
if (!*elem) {
*elem = *hash_ip;
map->elements++;
return 0;
}
}
/* Trigger rehashing */
return -EAGAIN;
} }
static int UADT(iphash, add)
addip(struct ip_set *set, const void *data, size_t size, KADT(iphash, add, ipaddr)
ip_set_ip_t *hash_ip)
static inline void
__iphash_retry(struct ip_set_iphash *tmp, struct ip_set_iphash *map)
{ {
const struct ip_set_req_iphash *req = data;
if (size != sizeof(struct ip_set_req_iphash)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_iphash),
size);
return -EINVAL;
}
return __addip(set->data, req->ip, hash_ip);
}
static int
addip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __addip((struct ip_set_iphash *) set->data,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static int retry(struct ip_set *set)
{
struct ip_set_iphash *map = set->data;
ip_set_ip_t hash_ip, *elem;
void *members;
u_int32_t i, hashsize = map->hashsize;
int res;
struct ip_set_iphash *tmp;
if (map->resize == 0)
return -ERANGE;
again:
res = 0;
/* Calculate new hash size */
hashsize += (hashsize * map->resize)/100;
if (hashsize == map->hashsize)
hashsize++;
ip_set_printk("rehashing of set %s triggered: "
"hashsize grows from %u to %u",
set->name, map->hashsize, hashsize);
tmp = kmalloc(sizeof(struct ip_set_iphash)
+ map->probes * sizeof(uint32_t), GFP_ATOMIC);
if (!tmp) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_iphash)
+ map->probes * sizeof(uint32_t));
return -ENOMEM;
}
tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
if (!tmp->members) {
DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
kfree(tmp);
return -ENOMEM;
}
tmp->hashsize = hashsize;
tmp->elements = 0;
tmp->probes = map->probes;
tmp->resize = map->resize;
tmp->netmask = map->netmask; tmp->netmask = map->netmask;
memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
write_lock_bh(&set->lock);
map = set->data; /* Play safe */
for (i = 0; i < map->hashsize && res == 0; i++) {
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
if (*elem)
res = __addip(tmp, *elem, &hash_ip);
}
if (res) {
/* Failure, try again */
write_unlock_bh(&set->lock);
harray_free(tmp->members);
kfree(tmp);
goto again;
} }
/* Success at resizing! */ HASH_RETRY(iphash, ip_set_ip_t)
members = map->members;
map->hashsize = tmp->hashsize;
map->members = tmp->members;
write_unlock_bh(&set->lock);
harray_free(members);
kfree(tmp);
return 0;
}
static inline int static inline int
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) iphash_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_iphash *map = set->data; struct ip_set_iphash *map = set->data;
ip_set_ip_t id, *elem; ip_set_ip_t id, *elem;
@@ -241,7 +116,7 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
if (!ip) if (!ip)
return -ERANGE; return -ERANGE;
id = hash_id(set, ip, hash_ip); id = iphash_id(set, hash_ip, ip);
if (id == UINT_MAX) if (id == UINT_MAX)
return -EEXIST; return -EEXIST;
@@ -252,156 +127,35 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0; return 0;
} }
static int UADT(iphash, del)
delip(struct ip_set *set, const void *data, size_t size, KADT(iphash, del, ipaddr)
ip_set_ip_t *hash_ip)
static inline int
__iphash_create(const struct ip_set_req_iphash_create *req,
struct ip_set_iphash *map)
{ {
const struct ip_set_req_iphash *req = data;
if (size != sizeof(struct ip_set_req_iphash)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_iphash),
size);
return -EINVAL;
}
return __delip(set, req->ip, hash_ip);
}
static int
delip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __delip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static int create(struct ip_set *set, const void *data, size_t size)
{
const struct ip_set_req_iphash_create *req = data;
struct ip_set_iphash *map;
uint16_t i;
if (size != sizeof(struct ip_set_req_iphash_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_iphash_create),
size);
return -EINVAL;
}
if (req->hashsize < 1) {
ip_set_printk("hashsize too small");
return -ENOEXEC;
}
if (req->probes < 1) {
ip_set_printk("probes too small");
return -ENOEXEC;
}
map = kmalloc(sizeof(struct ip_set_iphash)
+ req->probes * sizeof(uint32_t), GFP_KERNEL);
if (!map) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_iphash)
+ req->probes * sizeof(uint32_t));
return -ENOMEM;
}
for (i = 0; i < req->probes; i++)
get_random_bytes(((uint32_t *) map->initval)+i, 4);
map->elements = 0;
map->hashsize = req->hashsize;
map->probes = req->probes;
map->resize = req->resize;
map->netmask = req->netmask; map->netmask = req->netmask;
map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
if (!map->members) {
DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
kfree(map);
return -ENOMEM;
}
set->data = map;
return 0; return 0;
} }
static void destroy(struct ip_set *set) HASH_CREATE(iphash, ip_set_ip_t)
HASH_DESTROY(iphash)
HASH_FLUSH(iphash, ip_set_ip_t)
static inline void
__iphash_list_header(const struct ip_set_iphash *map,
struct ip_set_req_iphash_create *header)
{ {
struct ip_set_iphash *map = set->data;
harray_free(map->members);
kfree(map);
set->data = NULL;
}
static void flush(struct ip_set *set)
{
struct ip_set_iphash *map = set->data;
harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
map->elements = 0;
}
static void list_header(const struct ip_set *set, void *data)
{
struct ip_set_iphash *map = set->data;
struct ip_set_req_iphash_create *header = data;
header->hashsize = map->hashsize;
header->probes = map->probes;
header->resize = map->resize;
header->netmask = map->netmask; header->netmask = map->netmask;
} }
static int list_members_size(const struct ip_set *set) HASH_LIST_HEADER(iphash)
{ HASH_LIST_MEMBERS_SIZE(iphash, ip_set_ip_t)
const struct ip_set_iphash *map = set->data; HASH_LIST_MEMBERS(iphash, ip_set_ip_t)
return (map->hashsize * sizeof(ip_set_ip_t)); IP_SET_RTYPE(iphash, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
}
static void list_members(const struct ip_set *set, void *data)
{
const struct ip_set_iphash *map = set->data;
ip_set_ip_t i, *elem;
for (i = 0; i < map->hashsize; i++) {
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
((ip_set_ip_t *)data)[i] = *elem;
}
}
static struct ip_set_type ip_set_iphash = {
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create,
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_iphash),
.addip = &addip,
.addip_kernel = &addip_kernel,
.retry = &retry,
.delip = &delip,
.delip_kernel = &delip_kernel,
.testip = &testip,
.testip_kernel = &testip_kernel,
.header_size = sizeof(struct ip_set_req_iphash_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -409,17 +163,4 @@ MODULE_DESCRIPTION("iphash type of IP sets");
module_param(limit, int, 0600); module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets"); MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
static int __init ip_set_iphash_init(void) REGISTER_MODULE(iphash)
{
init_max_page_size();
return ip_set_register_set_type(&ip_set_iphash);
}
static void __exit ip_set_iphash_fini(void)
{
/* FIXME: possible race with ip_set_create() */
ip_set_unregister_set_type(&ip_set_iphash);
}
module_init(ip_set_iphash_init);
module_exit(ip_set_iphash_fini);

View File

@@ -2,9 +2,9 @@
#define __IP_SET_IPHASH_H #define __IP_SET_IPHASH_H
#include "ip_set.h" #include "ip_set.h"
#include "ip_set_hashes.h"
#define SETTYPE_NAME "iphash" #define SETTYPE_NAME "iphash"
#define MAX_RANGE 0x0000FFFF
struct ip_set_iphash { struct ip_set_iphash {
ip_set_ip_t *members; /* the iphash proper */ ip_set_ip_t *members; /* the iphash proper */
@@ -13,7 +13,7 @@ struct ip_set_iphash {
uint16_t probes; /* max number of probes */ uint16_t probes; /* max number of probes */
uint16_t resize; /* resize factor in percent */ uint16_t resize; /* resize factor in percent */
ip_set_ip_t netmask; /* netmask */ ip_set_ip_t netmask; /* netmask */
void *initval[0]; /* initvals for jhash_1word */ initval_t initval[0]; /* initvals for jhash_1word */
}; };
struct ip_set_req_iphash_create { struct ip_set_req_iphash_create {

View File

@@ -1,6 +1,6 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
@@ -29,9 +26,9 @@ ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
} }
static inline int static inline int
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) ipmap_test(const struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_ipmap *map = set->data; const struct ip_set_ipmap *map = set->data;
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE; return -ERANGE;
@@ -42,43 +39,13 @@ __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return !!test_bit(ip_to_id(map, *hash_ip), map->members); return !!test_bit(ip_to_id(map, *hash_ip), map->members);
} }
static int #define KADT_CONDITION
testip(struct ip_set *set, const void *data, size_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_ipmap *req = data;
if (size != sizeof(struct ip_set_req_ipmap)) { UADT(ipmap, test)
ip_set_printk("data length wrong (want %zu, have %zu)", KADT(ipmap, test, ipaddr)
sizeof(struct ip_set_req_ipmap),
size);
return -EINVAL;
}
return __testip(set, req->ip, hash_ip);
}
static int
testip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
int res = __testip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
return (res < 0 ? 0 : res);
}
static inline int static inline int
__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) ipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_ipmap *map = set->data; struct ip_set_ipmap *map = set->data;
@@ -93,43 +60,11 @@ __addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0; return 0;
} }
static int UADT(ipmap, add)
addip(struct ip_set *set, const void *data, size_t size, KADT(ipmap, add, ipaddr)
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_ipmap *req = data;
if (size != sizeof(struct ip_set_req_ipmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_ipmap),
size);
return -EINVAL;
}
DP("%u.%u.%u.%u", HIPQUAD(req->ip));
return __addip(set, req->ip, hash_ip);
}
static int
addip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __addip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static inline int static inline int
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) ipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_ipmap *map = set->data; struct ip_set_ipmap *map = set->data;
@@ -144,69 +79,13 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return 0; return 0;
} }
static int UADT(ipmap, del)
delip(struct ip_set *set, const void *data, size_t size, KADT(ipmap, del, ipaddr)
ip_set_ip_t *hash_ip)
static inline int
__ipmap_create(const struct ip_set_req_ipmap_create *req,
struct ip_set_ipmap *map)
{ {
const struct ip_set_req_ipmap *req = data;
if (size != sizeof(struct ip_set_req_ipmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_ipmap),
size);
return -EINVAL;
}
return __delip(set, req->ip, hash_ip);
}
static int
delip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __delip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static int create(struct ip_set *set, const void *data, size_t size)
{
int newbytes;
const struct ip_set_req_ipmap_create *req = data;
struct ip_set_ipmap *map;
if (size != sizeof(struct ip_set_req_ipmap_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_ipmap_create),
size);
return -EINVAL;
}
DP("from %u.%u.%u.%u to %u.%u.%u.%u",
HIPQUAD(req->from), HIPQUAD(req->to));
if (req->from > req->to) {
DP("bad ip range");
return -ENOEXEC;
}
map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
if (!map) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_ipmap));
return -ENOMEM;
}
map->first_ip = req->from;
map->last_ip = req->to;
map->netmask = req->netmask; map->netmask = req->netmask;
if (req->netmask == 0xFFFFFFFF) { if (req->netmask == 0xFFFFFFFF) {
@@ -231,101 +110,33 @@ static int create(struct ip_set *set, const void *data, size_t size)
map->sizeid = 2 << (netmask_bits - mask_bits - 1); map->sizeid = 2 << (netmask_bits - mask_bits - 1);
} }
if (map->sizeid > MAX_RANGE + 1) { if (map->sizeid > MAX_RANGE + 1) {
ip_set_printk("range too big (max %d addresses)", ip_set_printk("range too big, %d elements (max %d)",
MAX_RANGE+1); map->sizeid, MAX_RANGE+1);
kfree(map);
return -ENOEXEC; return -ENOEXEC;
} }
DP("hosts %u, sizeid %u", map->hosts, map->sizeid); DP("hosts %u, sizeid %u", map->hosts, map->sizeid);
newbytes = bitmap_bytes(0, map->sizeid - 1);
map->members = kmalloc(newbytes, GFP_KERNEL);
if (!map->members) {
DP("out of memory for %d bytes", newbytes);
kfree(map);
return -ENOMEM;
}
memset(map->members, 0, newbytes);
set->data = map;
return 0;
}
static void destroy(struct ip_set *set)
{
struct ip_set_ipmap *map = set->data;
kfree(map->members);
kfree(map);
set->data = NULL;
}
static void flush(struct ip_set *set)
{
struct ip_set_ipmap *map = set->data;
memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
}
static void list_header(const struct ip_set *set, void *data)
{
const struct ip_set_ipmap *map = set->data;
struct ip_set_req_ipmap_create *header = data;
header->from = map->first_ip;
header->to = map->last_ip;
header->netmask = map->netmask;
}
static int list_members_size(const struct ip_set *set)
{
const struct ip_set_ipmap *map = set->data;
return bitmap_bytes(0, map->sizeid - 1); return bitmap_bytes(0, map->sizeid - 1);
} }
static void list_members(const struct ip_set *set, void *data) BITMAP_CREATE(ipmap)
{ BITMAP_DESTROY(ipmap)
const struct ip_set_ipmap *map = set->data; BITMAP_FLUSH(ipmap)
int bytes = bitmap_bytes(0, map->sizeid - 1);
memcpy(data, map->members, bytes); static inline void
__ipmap_list_header(const struct ip_set_ipmap *map,
struct ip_set_req_ipmap_create *header)
{
header->netmask = map->netmask;
} }
static struct ip_set_type ip_set_ipmap = { BITMAP_LIST_HEADER(ipmap)
.typename = SETTYPE_NAME, BITMAP_LIST_MEMBERS_SIZE(ipmap)
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE, BITMAP_LIST_MEMBERS(ipmap)
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create, IP_SET_TYPE(ipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_ipmap),
.addip = &addip,
.addip_kernel = &addip_kernel,
.delip = &delip,
.delip_kernel = &delip_kernel,
.testip = &testip,
.testip_kernel = &testip_kernel,
.header_size = sizeof(struct ip_set_req_ipmap_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("ipmap type of IP sets"); MODULE_DESCRIPTION("ipmap type of IP sets");
static int __init ip_set_ipmap_init(void) REGISTER_MODULE(ipmap)
{
return ip_set_register_set_type(&ip_set_ipmap);
}
static void __exit ip_set_ipmap_fini(void)
{
/* FIXME: possible race with ip_set_create() */
ip_set_unregister_set_type(&ip_set_ipmap);
}
module_init(ip_set_ipmap_init);
module_exit(ip_set_ipmap_fini);

View File

@@ -2,9 +2,9 @@
#define __IP_SET_IPMAP_H #define __IP_SET_IPMAP_H
#include "ip_set.h" #include "ip_set.h"
#include "ip_set_bitmaps.h"
#define SETTYPE_NAME "ipmap" #define SETTYPE_NAME "ipmap"
#define MAX_RANGE 0x0000FFFF
struct ip_set_ipmap { struct ip_set_ipmap {
void *members; /* the ipmap proper */ void *members; /* the ipmap proper */
@@ -13,6 +13,7 @@ struct ip_set_ipmap {
ip_set_ip_t netmask; /* subnet netmask */ ip_set_ip_t netmask; /* subnet netmask */
ip_set_ip_t sizeid; /* size of set in IPs */ ip_set_ip_t sizeid; /* size of set in IPs */
ip_set_ip_t hosts; /* number of hosts in a subnet */ ip_set_ip_t hosts; /* number of hosts in a subnet */
u_int32_t size; /* size of the ipmap proper */
}; };
struct ip_set_req_ipmap_create { struct ip_set_req_ipmap_create {
@@ -25,7 +26,7 @@ struct ip_set_req_ipmap {
ip_set_ip_t ip; ip_set_ip_t ip;
}; };
static unsigned int static inline unsigned int
mask_to_bits(ip_set_ip_t mask) mask_to_bits(ip_set_ip_t mask)
{ {
unsigned int bits = 32; unsigned int bits = 32;
@@ -35,19 +36,19 @@ mask_to_bits(ip_set_ip_t mask)
return bits; return bits;
maskaddr = 0xFFFFFFFE; maskaddr = 0xFFFFFFFE;
while (--bits >= 0 && maskaddr != mask) while (--bits > 0 && maskaddr != mask)
maskaddr <<= 1; maskaddr <<= 1;
return bits; return bits;
} }
static ip_set_ip_t static inline ip_set_ip_t
range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits) range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
{ {
ip_set_ip_t mask = 0xFFFFFFFE; ip_set_ip_t mask = 0xFFFFFFFE;
*bits = 32; *bits = 32;
while (--(*bits) >= 0 && mask && (to & mask) != from) while (--(*bits) > 0 && mask && (to & mask) != from)
mask <<= 1; mask <<= 1;
return mask; return mask;

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -8,100 +8,40 @@
/* Kernel module implementing an ip+port hash set */ /* Kernel module implementing an ip+port hash set */
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h> #include "ip_set_jhash.h"
#include <linux/jhash.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include "ip_set_malloc.h"
#include "ip_set_ipporthash.h" #include "ip_set_ipporthash.h"
#include "ip_set_getport.h"
static int limit = MAX_RANGE; static int limit = MAX_RANGE;
/* We must handle non-linear skbs */
static inline ip_set_ip_t
get_port(const struct sk_buff *skb, u_int32_t flags)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
struct iphdr *iph = ip_hdr(skb);
#else
struct iphdr *iph = skb->nh.iph;
#endif
u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
switch (iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr tcph;
/* See comments at tcp_match in ip_tables.c */
if (offset)
return INVALID_PORT;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
#else
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
#endif
/* No choice either */
return INVALID_PORT;
return ntohs(flags & IPSET_SRC ?
tcph.source : tcph.dest);
}
case IPPROTO_UDP: {
struct udphdr udph;
if (offset)
return INVALID_PORT;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
#else
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
#endif
/* No choice either */
return INVALID_PORT;
return ntohs(flags & IPSET_SRC ?
udph.source : udph.dest);
}
default:
return INVALID_PORT;
}
}
static inline __u32 static inline __u32
jhash_ip(const struct ip_set_ipporthash *map, uint16_t i, ip_set_ip_t ip) ipporthash_id(struct ip_set *set, ip_set_ip_t *hash_ip,
{ ip_set_ip_t ip, ip_set_ip_t port)
return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
}
#define HASH_IP(map, ip, port) (port + ((ip - ((map)->first_ip)) << 16))
static inline __u32
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
ip_set_ip_t *hash_ip)
{ {
struct ip_set_ipporthash *map = set->data; struct ip_set_ipporthash *map = set->data;
__u32 id; __u32 id;
u_int16_t i; u_int16_t i;
ip_set_ip_t *elem; ip_set_ip_t *elem;
*hash_ip = HASH_IP(map, ip, port); *hash_ip = pack_ip_port(map, ip, port);
DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u", DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip)); set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
if (!*hash_ip)
return UINT_MAX;
for (i = 0; i < map->probes; i++) { for (i = 0; i < map->probes; i++) {
id = jhash_ip(map, i, *hash_ip) % map->hashsize; id = jhash_ip(map, i, *hash_ip) % map->hashsize;
@@ -109,254 +49,96 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
if (*elem == *hash_ip) if (*elem == *hash_ip)
return id; return id;
/* No shortcut at testing - there can be deleted /* No shortcut - there can be deleted entries. */
* entries. */
} }
return UINT_MAX; return UINT_MAX;
} }
static inline int static inline int
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ipporthash_test(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, ip_set_ip_t port)
{ {
struct ip_set_ipporthash *map = set->data; struct ip_set_ipporthash *map = set->data;
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE; return -ERANGE;
return (hash_id(set, ip, port, hash_ip) != UINT_MAX); return (ipporthash_id(set, hash_ip, ip, port) != UINT_MAX);
} }
static int #define KADT_CONDITION \
testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t port; \
ip_set_ip_t *hash_ip) \
{ if (flags[index+1] == 0) \
const struct ip_set_req_ipporthash *req = data; return 0; \
\
if (size != sizeof(struct ip_set_req_ipporthash)) { port = get_port(skb, flags[index+1]); \
ip_set_printk("data length wrong (want %zu, have %zu)", \
sizeof(struct ip_set_req_ipporthash), if (port == INVALID_PORT) \
size);
return -EINVAL;
}
return __testip(set, req->ip, req->port, hash_ip);
}
static int
testip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
ip_set_ip_t port;
int res;
if (flags[index+1] == 0)
return 0; return 0;
port = get_port(skb, flags[index+1]); UADT(ipporthash, test, req->port)
KADT(ipporthash, test, ipaddr, port)
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
flags[index] & IPSET_SRC ? "SRC" : "DST",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
NIPQUAD(ip_hdr(skb)->saddr),
NIPQUAD(ip_hdr(skb)->daddr));
#else
NIPQUAD(skb->nh.iph->saddr),
NIPQUAD(skb->nh.iph->daddr));
#endif
DP("flag %s port %u",
flags[index+1] & IPSET_SRC ? "SRC" : "DST",
port);
if (port == INVALID_PORT)
return 0;
res = __testip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
port,
hash_ip);
return (res < 0 ? 0 : res);
}
static inline int static inline int
__add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip) __ipporthash_add(struct ip_set_ipporthash *map, ip_set_ip_t *ip)
{ {
__u32 probe; __u32 probe;
u_int16_t i; u_int16_t i;
ip_set_ip_t *elem; ip_set_ip_t *elem, *slot = NULL;
for (i = 0; i < map->probes; i++) { for (i = 0; i < map->probes; i++) {
probe = jhash_ip(map, i, hash_ip) % map->hashsize; probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
if (*elem == hash_ip) if (*elem == *ip)
return -EEXIST; return -EEXIST;
if (!*elem) { if (!(slot || *elem))
*elem = hash_ip; slot = elem;
/* There can be deleted entries, must check all slots */
}
if (slot) {
*slot = *ip;
map->elements++; map->elements++;
return 0; return 0;
} }
}
/* Trigger rehashing */ /* Trigger rehashing */
return -EAGAIN; return -EAGAIN;
} }
static inline int static inline int
__addip(struct ip_set_ipporthash *map, ip_set_ip_t ip, ip_set_ip_t port, ipporthash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, ip_set_ip_t port)
{ {
struct ip_set_ipporthash *map = set->data;
if (map->elements > limit) if (map->elements > limit)
return -ERANGE; return -ERANGE;
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE; return -ERANGE;
*hash_ip = HASH_IP(map, ip, port); *hash_ip = pack_ip_port(map, ip, port);
return __add_haship(map, *hash_ip); if (!*hash_ip)
}
static int
addip(struct ip_set *set, const void *data, size_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_ipporthash *req = data;
if (size != sizeof(struct ip_set_req_ipporthash)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_ipporthash),
size);
return -EINVAL;
}
return __addip(set->data, req->ip, req->port, hash_ip);
}
static int
addip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
ip_set_ip_t port;
if (flags[index+1] == 0)
return -EINVAL;
port = get_port(skb, flags[index+1]);
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
flags[index] & IPSET_SRC ? "SRC" : "DST",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
NIPQUAD(ip_hdr(skb)->saddr),
NIPQUAD(ip_hdr(skb)->daddr));
#else
NIPQUAD(skb->nh.iph->saddr),
NIPQUAD(skb->nh.iph->daddr));
#endif
DP("flag %s port %u",
flags[index+1] & IPSET_SRC ? "SRC" : "DST",
port);
if (port == INVALID_PORT)
return -EINVAL;
return __addip(set->data,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
port,
hash_ip);
}
static int retry(struct ip_set *set)
{
struct ip_set_ipporthash *map = set->data;
ip_set_ip_t *elem;
void *members;
u_int32_t i, hashsize = map->hashsize;
int res;
struct ip_set_ipporthash *tmp;
if (map->resize == 0)
return -ERANGE; return -ERANGE;
again: return __ipporthash_add(map, hash_ip);
res = 0;
/* Calculate new hash size */
hashsize += (hashsize * map->resize)/100;
if (hashsize == map->hashsize)
hashsize++;
ip_set_printk("rehashing of set %s triggered: "
"hashsize grows from %u to %u",
set->name, map->hashsize, hashsize);
tmp = kmalloc(sizeof(struct ip_set_ipporthash)
+ map->probes * sizeof(uint32_t), GFP_ATOMIC);
if (!tmp) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_ipporthash)
+ map->probes * sizeof(uint32_t));
return -ENOMEM;
} }
tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
if (!tmp->members) { UADT(ipporthash, add, req->port)
DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t)); KADT(ipporthash, add, ipaddr, port)
kfree(tmp);
return -ENOMEM; static inline void
} __ipporthash_retry(struct ip_set_ipporthash *tmp,
tmp->hashsize = hashsize; struct ip_set_ipporthash *map)
tmp->elements = 0; {
tmp->probes = map->probes;
tmp->resize = map->resize;
tmp->first_ip = map->first_ip; tmp->first_ip = map->first_ip;
tmp->last_ip = map->last_ip; tmp->last_ip = map->last_ip;
memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
write_lock_bh(&set->lock);
map = set->data; /* Play safe */
for (i = 0; i < map->hashsize && res == 0; i++) {
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
if (*elem)
res = __add_haship(tmp, *elem);
}
if (res) {
/* Failure, try again */
write_unlock_bh(&set->lock);
harray_free(tmp->members);
kfree(tmp);
goto again;
} }
/* Success at resizing! */ HASH_RETRY(ipporthash, ip_set_ip_t)
members = map->members;
map->hashsize = tmp->hashsize;
map->members = tmp->members;
write_unlock_bh(&set->lock);
harray_free(members);
kfree(tmp);
return 0;
}
static inline int static inline int
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port, ipporthash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, ip_set_ip_t port)
{ {
struct ip_set_ipporthash *map = set->data; struct ip_set_ipporthash *map = set->data;
ip_set_ip_t id; ip_set_ip_t id;
@@ -365,7 +147,7 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE; return -ERANGE;
id = hash_id(set, ip, port, hash_ip); id = ipporthash_id(set, hash_ip, ip, port);
if (id == UINT_MAX) if (id == UINT_MAX)
return -EEXIST; return -EEXIST;
@@ -377,181 +159,40 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
return 0; return 0;
} }
static int UADT(ipporthash, del, req->port)
delip(struct ip_set *set, const void *data, size_t size, KADT(ipporthash, del, ipaddr, port)
ip_set_ip_t *hash_ip)
static inline int
__ipporthash_create(const struct ip_set_req_ipporthash_create *req,
struct ip_set_ipporthash *map)
{ {
const struct ip_set_req_ipporthash *req = data; if (req->to - req->from > MAX_RANGE) {
ip_set_printk("range too big, %d elements (max %d)",
if (size != sizeof(struct ip_set_req_ipporthash)) { req->to - req->from + 1, MAX_RANGE+1);
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_ipporthash),
size);
return -EINVAL;
}
return __delip(set, req->ip, req->port, hash_ip);
}
static int
delip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
ip_set_ip_t port;
if (flags[index+1] == 0)
return -EINVAL;
port = get_port(skb, flags[index+1]);
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
flags[index] & IPSET_SRC ? "SRC" : "DST",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
NIPQUAD(ip_hdr(skb)->saddr),
NIPQUAD(ip_hdr(skb)->daddr));
#else
NIPQUAD(skb->nh.iph->saddr),
NIPQUAD(skb->nh.iph->daddr));
#endif
DP("flag %s port %u",
flags[index+1] & IPSET_SRC ? "SRC" : "DST",
port);
if (port == INVALID_PORT)
return -EINVAL;
return __delip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
port,
hash_ip);
}
static int create(struct ip_set *set, const void *data, size_t size)
{
const struct ip_set_req_ipporthash_create *req = data;
struct ip_set_ipporthash *map;
uint16_t i;
if (size != sizeof(struct ip_set_req_ipporthash_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_ipporthash_create),
size);
return -EINVAL;
}
if (req->hashsize < 1) {
ip_set_printk("hashsize too small");
return -ENOEXEC; return -ENOEXEC;
} }
if (req->probes < 1) {
ip_set_printk("probes too small");
return -ENOEXEC;
}
map = kmalloc(sizeof(struct ip_set_ipporthash)
+ req->probes * sizeof(uint32_t), GFP_KERNEL);
if (!map) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_ipporthash)
+ req->probes * sizeof(uint32_t));
return -ENOMEM;
}
for (i = 0; i < req->probes; i++)
get_random_bytes(((uint32_t *) map->initval)+i, 4);
map->elements = 0;
map->hashsize = req->hashsize;
map->probes = req->probes;
map->resize = req->resize;
map->first_ip = req->from; map->first_ip = req->from;
map->last_ip = req->to; map->last_ip = req->to;
map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
if (!map->members) {
DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
kfree(map);
return -ENOMEM;
}
set->data = map;
return 0; return 0;
} }
static void destroy(struct ip_set *set) HASH_CREATE(ipporthash, ip_set_ip_t)
HASH_DESTROY(ipporthash)
HASH_FLUSH(ipporthash, ip_set_ip_t)
static inline void
__ipporthash_list_header(const struct ip_set_ipporthash *map,
struct ip_set_req_ipporthash_create *header)
{ {
struct ip_set_ipporthash *map = set->data;
harray_free(map->members);
kfree(map);
set->data = NULL;
}
static void flush(struct ip_set *set)
{
struct ip_set_ipporthash *map = set->data;
harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
map->elements = 0;
}
static void list_header(const struct ip_set *set, void *data)
{
const struct ip_set_ipporthash *map = set->data;
struct ip_set_req_ipporthash_create *header = data;
header->hashsize = map->hashsize;
header->probes = map->probes;
header->resize = map->resize;
header->from = map->first_ip; header->from = map->first_ip;
header->to = map->last_ip; header->to = map->last_ip;
} }
static int list_members_size(const struct ip_set *set) HASH_LIST_HEADER(ipporthash)
{ HASH_LIST_MEMBERS_SIZE(ipporthash, ip_set_ip_t)
const struct ip_set_ipporthash *map = set->data; HASH_LIST_MEMBERS(ipporthash, ip_set_ip_t)
return (map->hashsize * sizeof(ip_set_ip_t)); IP_SET_RTYPE(ipporthash, IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE)
}
static void list_members(const struct ip_set *set, void *data)
{
const struct ip_set_ipporthash *map = set->data;
ip_set_ip_t i, *elem;
for (i = 0; i < map->hashsize; i++) {
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
((ip_set_ip_t *)data)[i] = *elem;
}
}
static struct ip_set_type ip_set_ipporthash = {
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create,
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_ipporthash),
.addip = &addip,
.addip_kernel = &addip_kernel,
.retry = &retry,
.delip = &delip,
.delip_kernel = &delip_kernel,
.testip = &testip,
.testip_kernel = &testip_kernel,
.header_size = sizeof(struct ip_set_req_ipporthash_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -559,17 +200,4 @@ MODULE_DESCRIPTION("ipporthash type of IP sets");
module_param(limit, int, 0600); module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets"); MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
static int __init ip_set_ipporthash_init(void) REGISTER_MODULE(ipporthash)
{
init_max_page_size();
return ip_set_register_set_type(&ip_set_ipporthash);
}
static void __exit ip_set_ipporthash_fini(void)
{
/* FIXME: possible race with ip_set_create() */
ip_set_unregister_set_type(&ip_set_ipporthash);
}
module_init(ip_set_ipporthash_init);
module_exit(ip_set_ipporthash_fini);

View File

@@ -2,10 +2,9 @@
#define __IP_SET_IPPORTHASH_H #define __IP_SET_IPPORTHASH_H
#include "ip_set.h" #include "ip_set.h"
#include "ip_set_hashes.h"
#define SETTYPE_NAME "ipporthash" #define SETTYPE_NAME "ipporthash"
#define MAX_RANGE 0x0000FFFF
#define INVALID_PORT (MAX_RANGE + 1)
struct ip_set_ipporthash { struct ip_set_ipporthash {
ip_set_ip_t *members; /* the ipporthash proper */ ip_set_ip_t *members; /* the ipporthash proper */
@@ -15,7 +14,7 @@ struct ip_set_ipporthash {
uint16_t resize; /* resize factor in percent */ uint16_t resize; /* resize factor in percent */
ip_set_ip_t first_ip; /* host byte order, included in range */ ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_ip; /* host byte order, included in range */ ip_set_ip_t last_ip; /* host byte order, included in range */
void *initval[0]; /* initvals for jhash_1word */ initval_t initval[0]; /* initvals for jhash_1word */
}; };
struct ip_set_req_ipporthash_create { struct ip_set_req_ipporthash_create {

View File

@@ -0,0 +1,216 @@
/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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.
*/
/* Kernel module implementing an ip+port+ip hash set */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/skbuff.h>
#include "ip_set_jhash.h"
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include "ip_set_ipportiphash.h"
#include "ip_set_getport.h"
static int limit = MAX_RANGE;
#define jhash_ip2(map, i, ipport, ip1) \
jhash_2words(ipport, ip1, *(map->initval + i))
static inline __u32
ipportiphash_id(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
{
struct ip_set_ipportiphash *map = set->data;
__u32 id;
u_int16_t i;
struct ipportip *elem;
*hash_ip = pack_ip_port(map, ip, port);
DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
if (!(*hash_ip || ip1))
return UINT_MAX;
for (i = 0; i < map->probes; i++) {
id = jhash_ip2(map, i, *hash_ip, ip1) % map->hashsize;
DP("hash key: %u", id);
elem = HARRAY_ELEM(map->members, struct ipportip *, id);
if (elem->ip == *hash_ip && elem->ip1 == ip1)
return id;
/* No shortcut - there can be deleted entries. */
}
return UINT_MAX;
}
static inline int
ipportiphash_test(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
{
struct ip_set_ipportiphash *map = set->data;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
return (ipportiphash_id(set, hash_ip, ip, port, ip1) != UINT_MAX);
}
#define KADT_CONDITION \
ip_set_ip_t port, ip1; \
\
if (flags[index+2] == 0) \
return 0; \
\
port = get_port(skb, flags[index+1]); \
ip1 = ipaddr(skb, flags[index+2]); \
\
if (port == INVALID_PORT) \
return 0;
UADT(ipportiphash, test, req->port, req->ip1)
KADT(ipportiphash, test, ipaddr, port, ip1)
static inline int
__ipportip_add(struct ip_set_ipportiphash *map,
ip_set_ip_t hash_ip, ip_set_ip_t ip1)
{
__u32 probe;
u_int16_t i;
struct ipportip *elem, *slot = NULL;
for (i = 0; i < map->probes; i++) {
probe = jhash_ip2(map, i, hash_ip, ip1) % map->hashsize;
elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
if (elem->ip == hash_ip && elem->ip1 == ip1)
return -EEXIST;
if (!(slot || elem->ip || elem->ip1))
slot = elem;
/* There can be deleted entries, must check all slots */
}
if (slot) {
slot->ip = hash_ip;
slot->ip1 = ip1;
map->elements++;
return 0;
}
/* Trigger rehashing */
return -EAGAIN;
}
static inline int
__ipportiphash_add(struct ip_set_ipportiphash *map,
struct ipportip *elem)
{
return __ipportip_add(map, elem->ip, elem->ip1);
}
static inline int
ipportiphash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
{
struct ip_set_ipportiphash *map = set->data;
if (map->elements > limit)
return -ERANGE;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
*hash_ip = pack_ip_port(map, ip, port);
if (!(*hash_ip || ip1))
return -ERANGE;
return __ipportip_add(map, *hash_ip, ip1);
}
UADT(ipportiphash, add, req->port, req->ip1)
KADT(ipportiphash, add, ipaddr, port, ip1)
static inline void
__ipportiphash_retry(struct ip_set_ipportiphash *tmp,
struct ip_set_ipportiphash *map)
{
tmp->first_ip = map->first_ip;
tmp->last_ip = map->last_ip;
}
HASH_RETRY2(ipportiphash, struct ipportip)
static inline int
ipportiphash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
{
struct ip_set_ipportiphash *map = set->data;
ip_set_ip_t id;
struct ipportip *elem;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
id = ipportiphash_id(set, hash_ip, ip, port, ip1);
if (id == UINT_MAX)
return -EEXIST;
elem = HARRAY_ELEM(map->members, struct ipportip *, id);
elem->ip = elem->ip1 = 0;
map->elements--;
return 0;
}
UADT(ipportiphash, del, req->port, req->ip1)
KADT(ipportiphash, del, ipaddr, port, ip1)
static inline int
__ipportiphash_create(const struct ip_set_req_ipportiphash_create *req,
struct ip_set_ipportiphash *map)
{
if (req->to - req->from > MAX_RANGE) {
ip_set_printk("range too big, %d elements (max %d)",
req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC;
}
map->first_ip = req->from;
map->last_ip = req->to;
return 0;
}
HASH_CREATE(ipportiphash, struct ipportip)
HASH_DESTROY(ipportiphash)
HASH_FLUSH(ipportiphash, struct ipportip)
static inline void
__ipportiphash_list_header(const struct ip_set_ipportiphash *map,
struct ip_set_req_ipportiphash_create *header)
{
header->from = map->first_ip;
header->to = map->last_ip;
}
HASH_LIST_HEADER(ipportiphash)
HASH_LIST_MEMBERS_SIZE(ipportiphash, struct ipportip)
HASH_LIST_MEMBERS_MEMCPY(ipportiphash, struct ipportip)
IP_SET_RTYPE(ipportiphash, IPSET_TYPE_IP | IPSET_TYPE_PORT
| IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("ipportiphash type of IP sets");
module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
REGISTER_MODULE(ipportiphash)

View File

@@ -0,0 +1,39 @@
#ifndef __IP_SET_IPPORTIPHASH_H
#define __IP_SET_IPPORTIPHASH_H
#include "ip_set.h"
#include "ip_set_hashes.h"
#define SETTYPE_NAME "ipportiphash"
struct ipportip {
ip_set_ip_t ip;
ip_set_ip_t ip1;
};
struct ip_set_ipportiphash {
struct ipportip *members; /* the ipportip proper */
uint32_t elements; /* number of elements */
uint32_t hashsize; /* hash size */
uint16_t probes; /* max number of probes */
uint16_t resize; /* resize factor in percent */
ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_ip; /* host byte order, included in range */
initval_t initval[0]; /* initvals for jhash_1word */
};
struct ip_set_req_ipportiphash_create {
uint32_t hashsize;
uint16_t probes;
uint16_t resize;
ip_set_ip_t from;
ip_set_ip_t to;
};
struct ip_set_req_ipportiphash {
ip_set_ip_t ip;
ip_set_ip_t port;
ip_set_ip_t ip1;
};
#endif /* __IP_SET_IPPORTIPHASH_H */

View File

@@ -0,0 +1,304 @@
/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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.
*/
/* Kernel module implementing an ip+port+net hash set */
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/skbuff.h>
#include "ip_set_jhash.h"
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/spinlock.h>
#include <linux/random.h>
#include <net/ip.h>
#include "ip_set_ipportnethash.h"
#include "ip_set_getport.h"
static int limit = MAX_RANGE;
#define jhash_ip2(map, i, ipport, ip1) \
jhash_2words(ipport, ip1, *(map->initval + i))
static inline __u32
ipportnethash_id_cidr(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port,
ip_set_ip_t ip1, uint8_t cidr)
{
struct ip_set_ipportnethash *map = set->data;
__u32 id;
u_int16_t i;
struct ipportip *elem;
*hash_ip = pack_ip_port(map, ip, port);
DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
ip1 = pack_ip_cidr(ip1, cidr);
if (!(*hash_ip || ip1))
return UINT_MAX;
for (i = 0; i < map->probes; i++) {
id = jhash_ip2(map, i, *hash_ip, ip1) % map->hashsize;
DP("hash key: %u", id);
elem = HARRAY_ELEM(map->members, struct ipportip *, id);
if (elem->ip == *hash_ip && elem->ip1 == ip1)
return id;
/* No shortcut - there can be deleted entries. */
}
return UINT_MAX;
}
static inline __u32
ipportnethash_id(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
{
struct ip_set_ipportnethash *map = set->data;
__u32 id = UINT_MAX;
int i;
for (i = 0; i < 30 && map->cidr[i]; i++) {
id = ipportnethash_id_cidr(set, hash_ip, ip, port, ip1,
map->cidr[i]);
if (id != UINT_MAX)
break;
}
return id;
}
static inline int
ipportnethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port,
ip_set_ip_t ip1, uint8_t cidr)
{
struct ip_set_ipportnethash *map = set->data;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
return (ipportnethash_id_cidr(set, hash_ip, ip, port, ip1,
cidr) != UINT_MAX);
}
static inline int
ipportnethash_test(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port, ip_set_ip_t ip1)
{
struct ip_set_ipportnethash *map = set->data;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
return (ipportnethash_id(set, hash_ip, ip, port, ip1) != UINT_MAX);
}
static int
ipportnethash_utest(struct ip_set *set, const void *data, u_int32_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_ipportnethash *req = data;
if (req->cidr <= 0 || req->cidr > 32)
return -EINVAL;
return (req->cidr == 32
? ipportnethash_test(set, hash_ip, req->ip, req->port,
req->ip1)
: ipportnethash_test_cidr(set, hash_ip, req->ip, req->port,
req->ip1, req->cidr));
}
#define KADT_CONDITION \
ip_set_ip_t port, ip1; \
\
if (flags[index+2] == 0) \
return 0; \
\
port = get_port(skb, flags[index+1]); \
ip1 = ipaddr(skb, flags[index+2]); \
\
if (port == INVALID_PORT) \
return 0;
KADT(ipportnethash, test, ipaddr, port, ip1)
static inline int
__ipportnet_add(struct ip_set_ipportnethash *map,
ip_set_ip_t hash_ip, ip_set_ip_t ip1)
{
__u32 probe;
u_int16_t i;
struct ipportip *elem, *slot = NULL;
for (i = 0; i < map->probes; i++) {
probe = jhash_ip2(map, i, hash_ip, ip1) % map->hashsize;
elem = HARRAY_ELEM(map->members, struct ipportip *, probe);
if (elem->ip == hash_ip && elem->ip1 == ip1)
return -EEXIST;
if (!(slot || elem->ip || elem->ip1))
slot = elem;
/* There can be deleted entries, must check all slots */
}
if (slot) {
slot->ip = hash_ip;
slot->ip1 = ip1;
map->elements++;
return 0;
}
/* Trigger rehashing */
return -EAGAIN;
}
static inline int
__ipportnethash_add(struct ip_set_ipportnethash *map,
struct ipportip *elem)
{
return __ipportnet_add(map, elem->ip, elem->ip1);
}
static inline int
ipportnethash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port,
ip_set_ip_t ip1, uint8_t cidr)
{
struct ip_set_ipportnethash *map = set->data;
struct ipportip;
int ret;
if (map->elements > limit)
return -ERANGE;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
if (cidr <= 0 || cidr >= 32)
return -EINVAL;
if (map->nets[cidr-1] == UINT16_MAX)
return -ERANGE;
*hash_ip = pack_ip_port(map, ip, port);
ip1 = pack_ip_cidr(ip1, cidr);
if (!(*hash_ip || ip1))
return -ERANGE;
ret =__ipportnet_add(map, *hash_ip, ip1);
if (ret == 0) {
if (!map->nets[cidr-1]++)
add_cidr_size(map->cidr, cidr);
map->elements++;
}
return ret;
}
#undef KADT_CONDITION
#define KADT_CONDITION \
struct ip_set_ipportnethash *map = set->data; \
uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31; \
ip_set_ip_t port, ip1; \
\
if (flags[index+2] == 0) \
return 0; \
\
port = get_port(skb, flags[index+1]); \
ip1 = ipaddr(skb, flags[index+2]); \
\
if (port == INVALID_PORT) \
return 0;
UADT(ipportnethash, add, req->port, req->ip1, req->cidr)
KADT(ipportnethash, add, ipaddr, port, ip1, cidr)
static inline void
__ipportnethash_retry(struct ip_set_ipportnethash *tmp,
struct ip_set_ipportnethash *map)
{
tmp->first_ip = map->first_ip;
tmp->last_ip = map->last_ip;
memcpy(tmp->cidr, map->cidr, sizeof(tmp->cidr));
memcpy(tmp->nets, map->nets, sizeof(tmp->nets));
}
HASH_RETRY2(ipportnethash, struct ipportip)
static inline int
ipportnethash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, ip_set_ip_t port,
ip_set_ip_t ip1, uint8_t cidr)
{
struct ip_set_ipportnethash *map = set->data;
ip_set_ip_t id;
struct ipportip *elem;
if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE;
if (!ip)
return -ERANGE;
if (cidr <= 0 || cidr >= 32)
return -EINVAL;
id = ipportnethash_id_cidr(set, hash_ip, ip, port, ip1, cidr);
if (id == UINT_MAX)
return -EEXIST;
elem = HARRAY_ELEM(map->members, struct ipportip *, id);
elem->ip = elem->ip1 = 0;
map->elements--;
if (!map->nets[cidr-1]--)
del_cidr_size(map->cidr, cidr);
return 0;
}
UADT(ipportnethash, del, req->port, req->ip1, req->cidr)
KADT(ipportnethash, del, ipaddr, port, ip1, cidr)
static inline int
__ipportnethash_create(const struct ip_set_req_ipportnethash_create *req,
struct ip_set_ipportnethash *map)
{
if (req->to - req->from > MAX_RANGE) {
ip_set_printk("range too big, %d elements (max %d)",
req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC;
}
map->first_ip = req->from;
map->last_ip = req->to;
memset(map->cidr, 0, sizeof(map->cidr));
memset(map->nets, 0, sizeof(map->nets));
return 0;
}
HASH_CREATE(ipportnethash, struct ipportip)
HASH_DESTROY(ipportnethash)
HASH_FLUSH_CIDR(ipportnethash, struct ipportip);
static inline void
__ipportnethash_list_header(const struct ip_set_ipportnethash *map,
struct ip_set_req_ipportnethash_create *header)
{
header->from = map->first_ip;
header->to = map->last_ip;
}
HASH_LIST_HEADER(ipportnethash)
HASH_LIST_MEMBERS_SIZE(ipportnethash, struct ipportip)
HASH_LIST_MEMBERS_MEMCPY(ipportnethash, struct ipportip)
IP_SET_RTYPE(ipportnethash, IPSET_TYPE_IP | IPSET_TYPE_PORT
| IPSET_TYPE_IP1 | IPSET_DATA_TRIPLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("ipportnethash type of IP sets");
module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
REGISTER_MODULE(ipportnethash)

View File

@@ -0,0 +1,42 @@
#ifndef __IP_SET_IPPORTNETHASH_H
#define __IP_SET_IPPORTNETHASH_H
#include "ip_set.h"
#include "ip_set_hashes.h"
#define SETTYPE_NAME "ipportnethash"
struct ipportip {
ip_set_ip_t ip;
ip_set_ip_t ip1;
};
struct ip_set_ipportnethash {
struct ipportip *members; /* the ipportip proper */
uint32_t elements; /* number of elements */
uint32_t hashsize; /* hash size */
uint16_t probes; /* max number of probes */
uint16_t resize; /* resize factor in percent */
ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_ip; /* host byte order, included in range */
uint8_t cidr[30]; /* CIDR sizes */
uint16_t nets[30]; /* nr of nets by CIDR sizes */
initval_t initval[0]; /* initvals for jhash_1word */
};
struct ip_set_req_ipportnethash_create {
uint32_t hashsize;
uint16_t probes;
uint16_t resize;
ip_set_ip_t from;
ip_set_ip_t to;
};
struct ip_set_req_ipportnethash {
ip_set_ip_t ip;
ip_set_ip_t port;
ip_set_ip_t ip1;
uint8_t cidr;
};
#endif /* __IP_SET_IPPORTNETHASH_H */

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2005-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -7,24 +7,21 @@
/* Kernel module implementing an IP set type: the iptree type */ /* Kernel module implementing an IP set type: the iptree type */
#include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/jiffies.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/timer.h>
/* Backward compatibility */ #include "ip_set.h"
#ifndef __nocast #include "ip_set_bitmaps.h"
#define __nocast
#endif
#include "ip_set_iptree.h" #include "ip_set_iptree.h"
static int limit = MAX_RANGE; static int limit = MAX_RANGE;
@@ -35,13 +32,9 @@ static int limit = MAX_RANGE;
* to delete the gc timer at destroying/flushing a set */ * to delete the gc timer at destroying/flushing a set */
#define IPTREE_DESTROY_SLEEP 100 #define IPTREE_DESTROY_SLEEP 100
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) static __KMEM_CACHE_T__ *branch_cachep;
static struct kmem_cache *branch_cachep; static __KMEM_CACHE_T__ *leaf_cachep;
static struct kmem_cache *leaf_cachep;
#else
static kmem_cache_t *branch_cachep;
static kmem_cache_t *leaf_cachep;
#endif
#if defined(__LITTLE_ENDIAN) #if defined(__LITTLE_ENDIAN)
#define ABCD(a,b,c,d,addrp) do { \ #define ABCD(a,b,c,d,addrp) do { \
@@ -69,7 +62,7 @@ static kmem_cache_t *leaf_cachep;
} while (0) } while (0)
static inline int static inline int
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) iptree_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree; struct ip_set_iptreeb *btree;
@@ -92,52 +85,10 @@ __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|| time_after(dtree->expires[d], jiffies)); || time_after(dtree->expires[d], jiffies));
} }
static int #define KADT_CONDITION
testip(struct ip_set *set, const void *data, size_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_iptree *req = data;
if (size != sizeof(struct ip_set_req_iptree)) { UADT(iptree, test)
ip_set_printk("data length wrong (want %zu, have %zu)", KADT(iptree, test, ipaddr)
sizeof(struct ip_set_req_iptree),
size);
return -EINVAL;
}
return __testip(set, req->ip, hash_ip);
}
static int
testip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
int res;
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
flags[index] & IPSET_SRC ? "SRC" : "DST",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
NIPQUAD(ip_hdr(skb)->saddr),
NIPQUAD(ip_hdr(skb)->daddr));
#else
NIPQUAD(skb->nh.iph->saddr),
NIPQUAD(skb->nh.iph->daddr));
#endif
res = __testip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
return (res < 0 ? 0 : res);
}
#define ADDIP_WALK(map, elem, branch, type, cachep) do { \ #define ADDIP_WALK(map, elem, branch, type, cachep) do { \
if ((map)->tree[elem]) { \ if ((map)->tree[elem]) { \
@@ -155,8 +106,8 @@ testip_kernel(struct ip_set *set,
} while (0) } while (0)
static inline int static inline int
__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout, iptree_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, unsigned int timeout)
{ {
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree; struct ip_set_iptreeb *btree;
@@ -179,6 +130,8 @@ __addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
if (dtree->expires[d] if (dtree->expires[d]
&& (!map->timeout || time_after(dtree->expires[d], jiffies))) && (!map->timeout || time_after(dtree->expires[d], jiffies)))
ret = -EEXIST; ret = -EEXIST;
if (map->timeout && timeout == 0)
timeout = map->timeout;
dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1; dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
/* Lottery: I won! */ /* Lottery: I won! */
if (dtree->expires[d] == 0) if (dtree->expires[d] == 0)
@@ -189,46 +142,8 @@ __addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
return ret; return ret;
} }
static int UADT(iptree, add, req->timeout)
addip(struct ip_set *set, const void *data, size_t size, KADT(iptree, add, ipaddr, 0)
ip_set_ip_t *hash_ip)
{
struct ip_set_iptree *map = set->data;
const struct ip_set_req_iptree *req = data;
if (size != sizeof(struct ip_set_req_iptree)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_iptree),
size);
return -EINVAL;
}
DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
return __addip(set, req->ip,
req->timeout ? req->timeout : map->timeout,
hash_ip);
}
static int
addip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
struct ip_set_iptree *map = set->data;
return __addip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
map->timeout,
hash_ip);
}
#define DELIP_WALK(map, elem, branch) do { \ #define DELIP_WALK(map, elem, branch) do { \
if ((map)->tree[elem]) { \ if ((map)->tree[elem]) { \
@@ -238,7 +153,7 @@ addip_kernel(struct ip_set *set,
} while (0) } while (0)
static inline int static inline int
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) iptree_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree; struct ip_set_iptreeb *btree;
@@ -263,39 +178,8 @@ __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return -EEXIST; return -EEXIST;
} }
static int UADT(iptree, del)
delip(struct ip_set *set, const void *data, size_t size, KADT(iptree, del, ipaddr)
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_iptree *req = data;
if (size != sizeof(struct ip_set_req_iptree)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_iptree),
size);
return -EINVAL;
}
return __delip(set, req->ip, hash_ip);
}
static int
delip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __delip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
#define LOOP_WALK_BEGIN(map, i, branch) \ #define LOOP_WALK_BEGIN(map, i, branch) \
for (i = 0; i < 256; i++) { \ for (i = 0; i < 256; i++) { \
@@ -305,7 +189,8 @@ delip_kernel(struct ip_set *set,
#define LOOP_WALK_END } #define LOOP_WALK_END }
static void ip_tree_gc(unsigned long ul_set) static void
ip_tree_gc(unsigned long ul_set)
{ {
struct ip_set *set = (struct ip_set *) ul_set; struct ip_set *set = (struct ip_set *) ul_set;
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
@@ -375,7 +260,8 @@ static void ip_tree_gc(unsigned long ul_set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static inline void init_gc_timer(struct ip_set *set) static inline void
init_gc_timer(struct ip_set *set)
{ {
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
@@ -390,21 +276,22 @@ static inline void init_gc_timer(struct ip_set *set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static int create(struct ip_set *set, const void *data, size_t size) static int
iptree_create(struct ip_set *set, const void *data, u_int32_t size)
{ {
const struct ip_set_req_iptree_create *req = data; const struct ip_set_req_iptree_create *req = data;
struct ip_set_iptree *map; struct ip_set_iptree *map;
if (size != sizeof(struct ip_set_req_iptree_create)) { if (size != sizeof(struct ip_set_req_iptree_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)", ip_set_printk("data length wrong (want %zu, have %lu)",
sizeof(struct ip_set_req_iptree_create), sizeof(struct ip_set_req_iptree_create),
size); (unsigned long)size);
return -EINVAL; return -EINVAL;
} }
map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL); map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
if (!map) { if (!map) {
DP("out of memory for %d bytes", DP("out of memory for %zu bytes",
sizeof(struct ip_set_iptree)); sizeof(struct ip_set_iptree));
return -ENOMEM; return -ENOMEM;
} }
@@ -418,7 +305,8 @@ static int create(struct ip_set *set, const void *data, size_t size)
return 0; return 0;
} }
static void __flush(struct ip_set_iptree *map) static inline void
__flush(struct ip_set_iptree *map)
{ {
struct ip_set_iptreeb *btree; struct ip_set_iptreeb *btree;
struct ip_set_iptreec *ctree; struct ip_set_iptreec *ctree;
@@ -437,7 +325,8 @@ static void __flush(struct ip_set_iptree *map)
map->elements = 0; map->elements = 0;
} }
static void destroy(struct ip_set *set) static void
iptree_destroy(struct ip_set *set)
{ {
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
@@ -449,7 +338,8 @@ static void destroy(struct ip_set *set)
set->data = NULL; set->data = NULL;
} }
static void flush(struct ip_set *set) static void
iptree_flush(struct ip_set *set)
{ {
struct ip_set_iptree *map = set->data; struct ip_set_iptree *map = set->data;
unsigned int timeout = map->timeout; unsigned int timeout = map->timeout;
@@ -464,7 +354,8 @@ static void flush(struct ip_set *set)
init_gc_timer(set); init_gc_timer(set);
} }
static void list_header(const struct ip_set *set, void *data) static void
iptree_list_header(const struct ip_set *set, void *data)
{ {
const struct ip_set_iptree *map = set->data; const struct ip_set_iptree *map = set->data;
struct ip_set_req_iptree_create *header = data; struct ip_set_req_iptree_create *header = data;
@@ -472,7 +363,8 @@ static void list_header(const struct ip_set *set, void *data)
header->timeout = map->timeout; header->timeout = map->timeout;
} }
static int list_members_size(const struct ip_set *set) static int
iptree_list_members_size(const struct ip_set *set)
{ {
const struct ip_set_iptree *map = set->data; const struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree; struct ip_set_iptreeb *btree;
@@ -497,7 +389,8 @@ static int list_members_size(const struct ip_set *set)
return (count * sizeof(struct ip_set_req_iptree)); return (count * sizeof(struct ip_set_req_iptree));
} }
static void list_members(const struct ip_set *set, void *data) static void
iptree_list_members(const struct ip_set *set, void *data)
{ {
const struct ip_set_iptree *map = set->data; const struct ip_set_iptree *map = set->data;
struct ip_set_iptreeb *btree; struct ip_set_iptreeb *btree;
@@ -525,26 +418,7 @@ static void list_members(const struct ip_set *set, void *data)
LOOP_WALK_END; LOOP_WALK_END;
} }
static struct ip_set_type ip_set_iptree = { IP_SET_TYPE(iptree, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create,
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_iptree),
.addip = &addip,
.addip_kernel = &addip_kernel,
.delip = &delip,
.delip_kernel = &delip_kernel,
.testip = &testip,
.testip_kernel = &testip_kernel,
.header_size = sizeof(struct ip_set_req_iptree_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -556,29 +430,15 @@ static int __init ip_set_iptree_init(void)
{ {
int ret; int ret;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) branch_cachep = KMEM_CACHE_CREATE("ip_set_iptreeb",
branch_cachep = kmem_cache_create("ip_set_iptreeb", sizeof(struct ip_set_iptreeb));
sizeof(struct ip_set_iptreeb),
0, 0, NULL);
#else
branch_cachep = kmem_cache_create("ip_set_iptreeb",
sizeof(struct ip_set_iptreeb),
0, 0, NULL, NULL);
#endif
if (!branch_cachep) { if (!branch_cachep) {
printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n"); printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) leaf_cachep = KMEM_CACHE_CREATE("ip_set_iptreed",
leaf_cachep = kmem_cache_create("ip_set_iptreed", sizeof(struct ip_set_iptreed));
sizeof(struct ip_set_iptreed),
0, 0, NULL);
#else
leaf_cachep = kmem_cache_create("ip_set_iptreed",
sizeof(struct ip_set_iptreed),
0, 0, NULL, NULL);
#endif
if (!leaf_cachep) { if (!leaf_cachep) {
printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n"); printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
ret = -ENOMEM; ret = -ENOMEM;

View File

@@ -4,7 +4,6 @@
#include "ip_set.h" #include "ip_set.h"
#define SETTYPE_NAME "iptree" #define SETTYPE_NAME "iptree"
#define MAX_RANGE 0x0000FFFF
struct ip_set_iptreed { struct ip_set_iptreed {
unsigned long expires[256]; /* x.x.x.ADDR */ unsigned long expires[256]; /* x.x.x.ADDR */

View File

@@ -11,34 +11,29 @@
* index to find the bitmap and the last octet is used as the bit number. * index to find the bitmap and the last octet is used as the bit number.
*/ */
#include <linux/version.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/jiffies.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/timer.h>
#include "ip_set.h"
#include "ip_set_bitmaps.h"
#include "ip_set_iptreemap.h" #include "ip_set_iptreemap.h"
#define IPTREEMAP_DEFAULT_GC_TIME (5 * 60) #define IPTREEMAP_DEFAULT_GC_TIME (5 * 60)
#define IPTREEMAP_DESTROY_SLEEP (100) #define IPTREEMAP_DESTROY_SLEEP (100)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) static __KMEM_CACHE_T__ *cachep_b;
static struct kmem_cache *cachep_b; static __KMEM_CACHE_T__ *cachep_c;
static struct kmem_cache *cachep_c; static __KMEM_CACHE_T__ *cachep_d;
static struct kmem_cache *cachep_d;
#else
static kmem_cache_t *cachep_b;
static kmem_cache_t *cachep_c;
static kmem_cache_t *cachep_d;
#endif
static struct ip_set_iptreemap_d *fullbitmap_d; static struct ip_set_iptreemap_d *fullbitmap_d;
static struct ip_set_iptreemap_c *fullbitmap_c; static struct ip_set_iptreemap_c *fullbitmap_c;
@@ -256,7 +251,7 @@ free_b(struct ip_set_iptreemap_b *map)
} }
static inline int static inline int
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) iptreemap_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -275,40 +270,13 @@ __testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
return !!test_bit(d, (void *) dtree->bitmap); return !!test_bit(d, (void *) dtree->bitmap);
} }
static int #define KADT_CONDITION
testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
{
const struct ip_set_req_iptreemap *req = data;
if (size != sizeof(struct ip_set_req_iptreemap)) { UADT(iptreemap, test)
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size); KADT(iptreemap, test, ipaddr)
return -EINVAL;
}
return __testip(set, req->start, hash_ip);
}
static int
testip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
{
int res;
res = __testip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
return (res < 0 ? 0 : res);
}
static inline int static inline int
__addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) __addip_single(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data; struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -333,7 +301,8 @@ __addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
} }
static inline int static inline int
__addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip) iptreemap_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t start, ip_set_ip_t end)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -344,7 +313,7 @@ __addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
unsigned char a2, b2, c2, d2; unsigned char a2, b2, c2, d2;
if (start == end) if (start == end)
return __addip_single(set, start, hash_ip); return __addip_single(set, hash_ip, start);
*hash_ip = start; *hash_ip = start;
@@ -365,37 +334,12 @@ __addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
return 0; return 0;
} }
static int UADT0(iptreemap, add, min(req->ip, req->end), max(req->ip, req->end))
addip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip) KADT(iptreemap, add, ipaddr, ip)
{
const struct ip_set_req_iptreemap *req = data;
if (size != sizeof(struct ip_set_req_iptreemap)) {
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
return -EINVAL;
}
return __addip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip);
}
static int
addip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
{
return __addip_single(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static inline int static inline int
__delip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip, unsigned int __nocast flags) __delip_single(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, gfp_t flags)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -420,7 +364,8 @@ __delip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip, unsigne
} }
static inline int static inline int
__delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip, unsigned int __nocast flags) iptreemap_del(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t start, ip_set_ip_t end, gfp_t flags)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -431,7 +376,7 @@ __delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
unsigned char a2, b2, c2, d2; unsigned char a2, b2, c2, d2;
if (start == end) if (start == end)
return __delip_single(set, start, hash_ip, flags); return __delip_single(set, hash_ip, start, flags);
*hash_ip = start; *hash_ip = start;
@@ -452,34 +397,8 @@ __delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_
return 0; return 0;
} }
static int UADT0(iptreemap, del, min(req->ip, req->end), max(req->ip, req->end), GFP_KERNEL)
delip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip) KADT(iptreemap, del, ipaddr, ip, GFP_ATOMIC)
{
const struct ip_set_req_iptreemap *req = data;
if (size != sizeof(struct ip_set_req_iptreemap)) {
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
return -EINVAL;
}
return __delip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip, GFP_KERNEL);
}
static int
delip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
{
return __delip_single(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip,
GFP_ATOMIC);
}
/* Check the status of the bitmap /* Check the status of the bitmap
* -1 == all bits cleared * -1 == all bits cleared
@@ -551,16 +470,12 @@ init_gc_timer(struct ip_set *set)
add_timer(&map->gc); add_timer(&map->gc);
} }
static int create(struct ip_set *set, const void *data, size_t size) static int
iptreemap_create(struct ip_set *set, const void *data, u_int32_t size)
{ {
const struct ip_set_req_iptreemap_create *req = data; const struct ip_set_req_iptreemap_create *req = data;
struct ip_set_iptreemap *map; struct ip_set_iptreemap *map;
if (size != sizeof(struct ip_set_req_iptreemap_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap_create), size);
return -EINVAL;
}
map = kzalloc(sizeof(*map), GFP_KERNEL); map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map) if (!map)
return -ENOMEM; return -ENOMEM;
@@ -573,7 +488,8 @@ static int create(struct ip_set *set, const void *data, size_t size)
return 0; return 0;
} }
static inline void __flush(struct ip_set_iptreemap *map) static inline void
__flush(struct ip_set_iptreemap *map)
{ {
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
unsigned int a; unsigned int a;
@@ -584,7 +500,8 @@ static inline void __flush(struct ip_set_iptreemap *map)
LOOP_WALK_END(); LOOP_WALK_END();
} }
static void destroy(struct ip_set *set) static void
iptreemap_destroy(struct ip_set *set)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
@@ -597,7 +514,8 @@ static void destroy(struct ip_set *set)
set->data = NULL; set->data = NULL;
} }
static void flush(struct ip_set *set) static void
iptreemap_flush(struct ip_set *set)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
@@ -611,7 +529,8 @@ static void flush(struct ip_set *set)
init_gc_timer(set); init_gc_timer(set);
} }
static void list_header(const struct ip_set *set, void *data) static void
iptreemap_list_header(const struct ip_set *set, void *data)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_req_iptreemap_create *header = data; struct ip_set_req_iptreemap_create *header = data;
@@ -619,7 +538,8 @@ static void list_header(const struct ip_set *set, void *data)
header->gc_interval = map->gc_interval; header->gc_interval = map->gc_interval;
} }
static int list_members_size(const struct ip_set *set) static int
iptreemap_list_members_size(const struct ip_set *set)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -648,17 +568,19 @@ static int list_members_size(const struct ip_set *set)
return (count * sizeof(struct ip_set_req_iptreemap)); return (count * sizeof(struct ip_set_req_iptreemap));
} }
static inline size_t add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end) static inline u_int32_t
add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end)
{ {
struct ip_set_req_iptreemap *entry = data + offset; struct ip_set_req_iptreemap *entry = data + offset;
entry->start = start; entry->ip = start;
entry->end = end; entry->end = end;
return sizeof(*entry); return sizeof(*entry);
} }
static void list_members(const struct ip_set *set, void *data) static void
iptreemap_list_members(const struct ip_set *set, void *data)
{ {
struct ip_set_iptreemap *map = set->data; struct ip_set_iptreemap *map = set->data;
struct ip_set_iptreemap_b *btree; struct ip_set_iptreemap_b *btree;
@@ -695,26 +617,7 @@ static void list_members(const struct ip_set *set, void *data)
add_member(data, offset, start, end); add_member(data, offset, start, end);
} }
static struct ip_set_type ip_set_iptreemap = { IP_SET_TYPE(iptreemap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = create,
.destroy = destroy,
.flush = flush,
.reqsize = sizeof(struct ip_set_req_iptreemap),
.addip = addip,
.addip_kernel = addip_kernel,
.delip = delip,
.delip_kernel = delip_kernel,
.testip = testip,
.testip_kernel = testip_kernel,
.header_size = sizeof(struct ip_set_req_iptreemap_create),
.list_header = list_header,
.list_members_size = list_members_size,
.list_members = list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sven Wegener <sven.wegener@stealer.net>"); MODULE_AUTHOR("Sven Wegener <sven.wegener@stealer.net>");
@@ -725,43 +628,22 @@ static int __init ip_set_iptreemap_init(void)
int ret = -ENOMEM; int ret = -ENOMEM;
int a; int a;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) cachep_b = KMEM_CACHE_CREATE("ip_set_iptreemap_b",
cachep_b = kmem_cache_create("ip_set_iptreemap_b", sizeof(struct ip_set_iptreemap_b));
sizeof(struct ip_set_iptreemap_b),
0, 0, NULL);
#else
cachep_b = kmem_cache_create("ip_set_iptreemap_b",
sizeof(struct ip_set_iptreemap_b),
0, 0, NULL, NULL);
#endif
if (!cachep_b) { if (!cachep_b) {
ip_set_printk("Unable to create ip_set_iptreemap_b slab cache"); ip_set_printk("Unable to create ip_set_iptreemap_b slab cache");
goto out; goto out;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) cachep_c = KMEM_CACHE_CREATE("ip_set_iptreemap_c",
cachep_c = kmem_cache_create("ip_set_iptreemap_c", sizeof(struct ip_set_iptreemap_c));
sizeof(struct ip_set_iptreemap_c),
0, 0, NULL);
#else
cachep_c = kmem_cache_create("ip_set_iptreemap_c",
sizeof(struct ip_set_iptreemap_c),
0, 0, NULL, NULL);
#endif
if (!cachep_c) { if (!cachep_c) {
ip_set_printk("Unable to create ip_set_iptreemap_c slab cache"); ip_set_printk("Unable to create ip_set_iptreemap_c slab cache");
goto outb; goto outb;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) cachep_d = KMEM_CACHE_CREATE("ip_set_iptreemap_d",
cachep_d = kmem_cache_create("ip_set_iptreemap_d", sizeof(struct ip_set_iptreemap_d));
sizeof(struct ip_set_iptreemap_d),
0, 0, NULL);
#else
cachep_d = kmem_cache_create("ip_set_iptreemap_d",
sizeof(struct ip_set_iptreemap_d),
0, 0, NULL, NULL);
#endif
if (!cachep_d) { if (!cachep_d) {
ip_set_printk("Unable to create ip_set_iptreemap_d slab cache"); ip_set_printk("Unable to create ip_set_iptreemap_d slab cache");
goto outc; goto outc;

View File

@@ -33,7 +33,7 @@ struct ip_set_req_iptreemap_create {
}; };
struct ip_set_req_iptreemap { struct ip_set_req_iptreemap {
ip_set_ip_t start; ip_set_ip_t ip;
ip_set_ip_t end; ip_set_ip_t end;
}; };

View File

@@ -1,148 +1,157 @@
#ifndef _LINUX_IPSET_JHASH_H #ifndef _LINUX_JHASH_H
#define _LINUX_IPSET_JHASH_H #define _LINUX_JHASH_H
/* This is a copy of linux/jhash.h but the types u32/u8 are changed
* to __u32/__u8 so that the header file can be included into
* userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*/
/* jhash.h: Jenkins hash support. /* jhash.h: Jenkins hash support.
* *
* Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net) * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
* *
* http://burtleburtle.net/bob/hash/ * http://burtleburtle.net/bob/hash/
* *
* These are the credits from Bob's sources: * These are the credits from Bob's sources:
* *
* lookup2.c, by Bob Jenkins, December 1996, Public Domain. * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
* hash(), hash2(), hash3, and mix() are externally useful functions.
* Routines to test the hash are included if SELF_TEST is defined.
* You can use this free for any purpose. It has no warranty.
* *
* Copyright (C) 2003 David S. Miller (davem@redhat.com) * These are functions for producing 32-bit hashes for hash table lookup.
* hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
* are externally useful functions. Routines to test the hash are included
* if SELF_TEST is defined. You can use this free for any purpose. It's in
* the public domain. It has no warranty.
*
* Copyright (C) 2009 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
* *
* I've modified Bob's hash to be useful in the Linux kernel, and * I've modified Bob's hash to be useful in the Linux kernel, and
* any bugs present are surely my fault. -DaveM * any bugs present are my fault. Jozsef
*/ */
/* NOTE: Arguments are modified. */ #define __rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
/* __jhash_mix - mix 3 32-bit values reversibly. */
#define __jhash_mix(a,b,c) \ #define __jhash_mix(a,b,c) \
{ \ { \
a -= b; a -= c; a ^= (c>>13); \ a -= c; a ^= __rot(c, 4); c += b; \
b -= c; b -= a; b ^= (a<<8); \ b -= a; b ^= __rot(a, 6); a += c; \
c -= a; c -= b; c ^= (b>>13); \ c -= b; c ^= __rot(b, 8); b += a; \
a -= b; a -= c; a ^= (c>>12); \ a -= c; a ^= __rot(c,16); c += b; \
b -= c; b -= a; b ^= (a<<16); \ b -= a; b ^= __rot(a,19); a += c; \
c -= a; c -= b; c ^= (b>>5); \ c -= b; c ^= __rot(b, 4); b += a; \
a -= b; a -= c; a ^= (c>>3); \ }
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \ /* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
#define __jhash_final(a,b,c) \
{ \
c ^= b; c -= __rot(b,14); \
a ^= c; a -= __rot(c,11); \
b ^= a; b -= __rot(a,25); \
c ^= b; c -= __rot(b,16); \
a ^= c; a -= __rot(c,4); \
b ^= a; b -= __rot(a,14); \
c ^= b; c -= __rot(b,24); \
} }
/* The golden ration: an arbitrary value */ /* The golden ration: an arbitrary value */
#define JHASH_GOLDEN_RATIO 0x9e3779b9 #define JHASH_GOLDEN_RATIO 0xdeadbeef
/* The most generic version, hashes an arbitrary sequence /* The most generic version, hashes an arbitrary sequence
* of bytes. No alignment or length assumptions are made about * of bytes. No alignment or length assumptions are made about
* the input key. * the input key. The result depends on endianness.
*/ */
static inline __u32 jhash(void *key, __u32 length, __u32 initval) static inline u32 jhash(const void *key, u32 length, u32 initval)
{ {
__u32 a, b, c, len; u32 a,b,c;
__u8 *k = key; const u8 *k = key;
len = length; /* Set up the internal state */
a = b = JHASH_GOLDEN_RATIO; a = b = c = JHASH_GOLDEN_RATIO + length + initval;
c = initval;
while (len >= 12) {
a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24));
b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24));
c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24));
/* all but the last block: affect some 32 bits of (a,b,c) */
while (length > 12) {
a += (k[0] + ((u32)k[1]<<8) + ((u32)k[2]<<16) + ((u32)k[3]<<24));
b += (k[4] + ((u32)k[5]<<8) + ((u32)k[6]<<16) + ((u32)k[7]<<24));
c += (k[8] + ((u32)k[9]<<8) + ((u32)k[10]<<16) + ((u32)k[11]<<24));
__jhash_mix(a, b, c); __jhash_mix(a, b, c);
length -= 12;
k += 12; k += 12;
len -= 12;
} }
c += length; /* last block: affect all 32 bits of (c) */
switch (len) { /* all the case statements fall through */
case 11: c += ((__u32)k[10]<<24); switch (length) {
case 10: c += ((__u32)k[9]<<16); case 12: c += (u32)k[11]<<24;
case 9 : c += ((__u32)k[8]<<8); case 11: c += (u32)k[10]<<16;
case 8 : b += ((__u32)k[7]<<24); case 10: c += (u32)k[9]<<8;
case 7 : b += ((__u32)k[6]<<16); case 9 : c += k[8];
case 6 : b += ((__u32)k[5]<<8); case 8 : b += (u32)k[7]<<24;
case 7 : b += (u32)k[6]<<16;
case 6 : b += (u32)k[5]<<8;
case 5 : b += k[4]; case 5 : b += k[4];
case 4 : a += ((__u32)k[3]<<24); case 4 : a += (u32)k[3]<<24;
case 3 : a += ((__u32)k[2]<<16); case 3 : a += (u32)k[2]<<16;
case 2 : a += ((__u32)k[1]<<8); case 2 : a += (u32)k[1]<<8;
case 1 : a += k[0]; case 1 : a += k[0];
}; __jhash_final(a, b, c);
case 0 :
__jhash_mix(a,b,c); break;
}
return c; return c;
} }
/* A special optimized version that handles 1 or more of __u32s. /* A special optimized version that handles 1 or more of u32s.
* The length parameter here is the number of __u32s in the key. * The length parameter here is the number of u32s in the key.
*/ */
static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval) static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
{ {
__u32 a, b, c, len; u32 a, b, c;
a = b = JHASH_GOLDEN_RATIO; /* Set up the internal state */
c = initval; a = b = c = JHASH_GOLDEN_RATIO + (length<<2) + initval;
len = length;
while (len >= 3) { /* handle most of the key */
while (length > 3) {
a += k[0]; a += k[0];
b += k[1]; b += k[1];
c += k[2]; c += k[2];
__jhash_mix(a, b, c); __jhash_mix(a, b, c);
k += 3; len -= 3; length -= 3;
k += 3;
} }
c += length * 4; /* handle the last 3 u32's */
/* all the case statements fall through */
switch (len) { switch (length) {
case 3: c += k[2];
case 2: b += k[1]; case 2: b += k[1];
case 1: a += k[0]; case 1: a += k[0];
}; __jhash_final(a, b, c);
case 0: /* case 0: nothing left to add */
__jhash_mix(a,b,c); break;
}
return c; return c;
} }
/* A special ultra-optimized versions that knows they are hashing exactly /* A special ultra-optimized versions that knows they are hashing exactly
* 3, 2 or 1 word(s). * 3, 2 or 1 word(s).
*
* NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
* done at the end is not done here.
*/ */
static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval) static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
{ {
a += JHASH_GOLDEN_RATIO; a += JHASH_GOLDEN_RATIO + initval;
b += JHASH_GOLDEN_RATIO; b += JHASH_GOLDEN_RATIO + initval;
c += initval; c += JHASH_GOLDEN_RATIO + initval;
__jhash_mix(a, b, c); __jhash_final(a, b, c);
return c; return c;
} }
static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval) static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
{ {
return jhash_3words(a, b, 0, initval); return jhash_3words(0, a, b, initval);
} }
static inline __u32 jhash_1word(__u32 a, __u32 initval) static inline u32 jhash_1word(u32 a, u32 initval)
{ {
return jhash_3words(a, 0, 0, initval); return jhash_3words(0, 0, a, initval);
} }
#endif /* _LINUX_IPSET_JHASH_H */ #endif /* _LINUX_JHASH_H */

View File

@@ -1,7 +1,7 @@
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
* Patrick Schaaf <bof@bof.de> * Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se> * Martin Josefsson <gandalf@wlug.westbo.se>
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -13,41 +13,29 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/vmalloc.h>
#include "ip_set_malloc.h"
#include "ip_set_macipmap.h" #include "ip_set_macipmap.h"
static int static int
testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip) macipmap_utest(struct ip_set *set, const void *data, u_int32_t size,
ip_set_ip_t *hash_ip)
{ {
struct ip_set_macipmap *map = set->data; const struct ip_set_macipmap *map = set->data;
struct ip_set_macip *table = map->members; const struct ip_set_macip *table = map->members;
const struct ip_set_req_macipmap *req = data; const struct ip_set_req_macipmap *req = data;
if (size != sizeof(struct ip_set_req_macipmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_macipmap),
size);
return -EINVAL;
}
if (req->ip < map->first_ip || req->ip > map->last_ip) if (req->ip < map->first_ip || req->ip > map->last_ip)
return -ERANGE; return -ERANGE;
*hash_ip = req->ip; *hash_ip = req->ip;
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip)); set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
if (test_bit(IPSET_MACIP_ISSET, if (table[req->ip - map->first_ip].match) {
(void *) &table[req->ip - map->first_ip].flags)) {
return (memcmp(req->ethernet, return (memcmp(req->ethernet,
&table[req->ip - map->first_ip].ethernet, &table[req->ip - map->first_ip].ethernet,
ETH_ALEN) == 0); ETH_ALEN) == 0);
@@ -57,24 +45,17 @@ testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
} }
static int static int
testip_kernel(struct ip_set *set, macipmap_ktest(struct ip_set *set,
const struct sk_buff *skb, const struct sk_buff *skb,
ip_set_ip_t *hash_ip, ip_set_ip_t *hash_ip,
const u_int32_t *flags, const u_int32_t *flags,
unsigned char index) unsigned char index)
{ {
struct ip_set_macipmap *map = set->data; const struct ip_set_macipmap *map = set->data;
struct ip_set_macip *table = map->members; const struct ip_set_macip *table = map->members;
ip_set_ip_t ip; ip_set_ip_t ip;
ip = ntohl(flags[index] & IPSET_SRC ip = ipaddr(skb, flags[index]);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr);
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr);
#endif
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return 0; return 0;
@@ -82,17 +63,11 @@ testip_kernel(struct ip_set *set,
*hash_ip = ip; *hash_ip = ip;
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u", DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip)); set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
if (test_bit(IPSET_MACIP_ISSET, if (table[ip - map->first_ip].match) {
(void *) &table[ip - map->first_ip].flags)) {
/* Is mac pointer valid? /* Is mac pointer valid?
* If so, compare... */ * If so, compare... */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
return (skb_mac_header(skb) >= skb->head return (skb_mac_header(skb) >= skb->head
&& (skb_mac_header(skb) + ETH_HLEN) <= skb->data && (skb_mac_header(skb) + ETH_HLEN) <= skb->data
#else
return (skb->mac.raw >= skb->head
&& (skb->mac.raw + ETH_HLEN) <= skb->data
#endif
&& (memcmp(eth_hdr(skb)->h_source, && (memcmp(eth_hdr(skb)->h_source,
&table[ip - map->first_ip].ethernet, &table[ip - map->first_ip].ethernet,
ETH_ALEN) == 0)); ETH_ALEN) == 0));
@@ -103,258 +78,87 @@ testip_kernel(struct ip_set *set,
/* returns 0 on success */ /* returns 0 on success */
static inline int static inline int
__addip(struct ip_set *set, macipmap_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t ip, const unsigned char *ethernet, ip_set_ip_t *hash_ip) ip_set_ip_t ip, const unsigned char *ethernet)
{ {
struct ip_set_macipmap *map = set->data; struct ip_set_macipmap *map = set->data;
struct ip_set_macip *table = map->members; struct ip_set_macip *table = map->members;
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE; return -ERANGE;
if (test_and_set_bit(IPSET_MACIP_ISSET, if (table[ip - map->first_ip].match)
(void *) &table[ip - map->first_ip].flags))
return -EEXIST; return -EEXIST;
*hash_ip = ip; *hash_ip = ip;
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN); memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
table[ip - map->first_ip].match = IPSET_MACIP_ISSET;
return 0; return 0;
} }
static int #define KADT_CONDITION \
addip(struct ip_set *set, const void *data, size_t size, if (!(skb_mac_header(skb) >= skb->head \
ip_set_ip_t *hash_ip) && (skb_mac_header(skb) + ETH_HLEN) <= skb->data))\
{
const struct ip_set_req_macipmap *req = data;
if (size != sizeof(struct ip_set_req_macipmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_macipmap),
size);
return -EINVAL;
}
return __addip(set, req->ip, req->ethernet, hash_ip);
}
static int
addip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
ip_set_ip_t ip;
ip = ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr);
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
if (!(skb_mac_header(skb) >= skb->head
&& (skb_mac_header(skb) + ETH_HLEN) <= skb->data))
#else
if (!(skb->mac.raw >= skb->head
&& (skb->mac.raw + ETH_HLEN) <= skb->data))
#endif
return -EINVAL; return -EINVAL;
return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip); UADT(macipmap, add, req->ethernet)
} KADT(macipmap, add, ipaddr, eth_hdr(skb)->h_source)
static inline int static inline int
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) macipmap_del(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_macipmap *map = set->data; struct ip_set_macipmap *map = set->data;
struct ip_set_macip *table = map->members; struct ip_set_macip *table = map->members;
if (ip < map->first_ip || ip > map->last_ip) if (ip < map->first_ip || ip > map->last_ip)
return -ERANGE; return -ERANGE;
if (!test_and_clear_bit(IPSET_MACIP_ISSET, if (!table[ip - map->first_ip].match)
(void *)&table[ip - map->first_ip].flags))
return -EEXIST; return -EEXIST;
*hash_ip = ip; *hash_ip = ip;
table[ip - map->first_ip].match = 0;
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip)); DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
return 0; return 0;
} }
static int #undef KADT_CONDITION
delip(struct ip_set *set, const void *data, size_t size, #define KADT_CONDITION
ip_set_ip_t *hash_ip)
UADT(macipmap, del)
KADT(macipmap, del, ipaddr)
static inline int
__macipmap_create(const struct ip_set_req_macipmap_create *req,
struct ip_set_macipmap *map)
{ {
const struct ip_set_req_macipmap *req = data;
if (size != sizeof(struct ip_set_req_macipmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_macipmap),
size);
return -EINVAL;
}
return __delip(set, req->ip, hash_ip);
}
static int
delip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __delip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static inline size_t members_size(ip_set_ip_t from, ip_set_ip_t to)
{
return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
}
static int create(struct ip_set *set, const void *data, size_t size)
{
size_t newbytes;
const struct ip_set_req_macipmap_create *req = data;
struct ip_set_macipmap *map;
if (size != sizeof(struct ip_set_req_macipmap_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_macipmap_create),
size);
return -EINVAL;
}
DP("from %u.%u.%u.%u to %u.%u.%u.%u",
HIPQUAD(req->from), HIPQUAD(req->to));
if (req->from > req->to) {
DP("bad ip range");
return -ENOEXEC;
}
if (req->to - req->from > MAX_RANGE) { if (req->to - req->from > MAX_RANGE) {
ip_set_printk("range too big (max %d addresses)", ip_set_printk("range too big, %d elements (max %d)",
MAX_RANGE+1); req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC; return -ENOEXEC;
} }
map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
if (!map) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_macipmap));
return -ENOMEM;
}
map->flags = req->flags; map->flags = req->flags;
map->first_ip = req->from; return (req->to - req->from + 1) * sizeof(struct ip_set_macip);
map->last_ip = req->to;
newbytes = members_size(map->first_ip, map->last_ip);
map->members = ip_set_malloc(newbytes);
DP("members: %u %p", newbytes, map->members);
if (!map->members) {
DP("out of memory for %d bytes", newbytes);
kfree(map);
return -ENOMEM;
}
memset(map->members, 0, newbytes);
set->data = map;
return 0;
} }
static void destroy(struct ip_set *set) BITMAP_CREATE(macipmap)
BITMAP_DESTROY(macipmap)
BITMAP_FLUSH(macipmap)
static inline void
__macipmap_list_header(const struct ip_set_macipmap *map,
struct ip_set_req_macipmap_create *header)
{ {
struct ip_set_macipmap *map = set->data;
ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
kfree(map);
set->data = NULL;
}
static void flush(struct ip_set *set)
{
struct ip_set_macipmap *map = set->data;
memset(map->members, 0, members_size(map->first_ip, map->last_ip));
}
static void list_header(const struct ip_set *set, void *data)
{
const struct ip_set_macipmap *map = set->data;
struct ip_set_req_macipmap_create *header = data;
DP("list_header %x %x %u", map->first_ip, map->last_ip,
map->flags);
header->from = map->first_ip;
header->to = map->last_ip;
header->flags = map->flags; header->flags = map->flags;
} }
static int list_members_size(const struct ip_set *set) BITMAP_LIST_HEADER(macipmap)
{ BITMAP_LIST_MEMBERS_SIZE(macipmap)
const struct ip_set_macipmap *map = set->data; BITMAP_LIST_MEMBERS(macipmap)
DP("%u", members_size(map->first_ip, map->last_ip)); IP_SET_TYPE(macipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
return members_size(map->first_ip, map->last_ip);
}
static void list_members(const struct ip_set *set, void *data)
{
const struct ip_set_macipmap *map = set->data;
int bytes = members_size(map->first_ip, map->last_ip);
DP("members: %u %p", bytes, map->members);
memcpy(data, map->members, bytes);
}
static struct ip_set_type ip_set_macipmap = {
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create,
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_macipmap),
.addip = &addip,
.addip_kernel = &addip_kernel,
.delip = &delip,
.delip_kernel = &delip_kernel,
.testip = &testip,
.testip_kernel = &testip_kernel,
.header_size = sizeof(struct ip_set_req_macipmap_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("macipmap type of IP sets"); MODULE_DESCRIPTION("macipmap type of IP sets");
static int __init ip_set_macipmap_init(void) REGISTER_MODULE(macipmap)
{
init_max_page_size();
return ip_set_register_set_type(&ip_set_macipmap);
}
static void __exit ip_set_macipmap_fini(void)
{
/* FIXME: possible race with ip_set_create() */
ip_set_unregister_set_type(&ip_set_macipmap);
}
module_init(ip_set_macipmap_init);
module_exit(ip_set_macipmap_fini);

View File

@@ -2,9 +2,9 @@
#define __IP_SET_MACIPMAP_H #define __IP_SET_MACIPMAP_H
#include "ip_set.h" #include "ip_set.h"
#include "ip_set_bitmaps.h"
#define SETTYPE_NAME "macipmap" #define SETTYPE_NAME "macipmap"
#define MAX_RANGE 0x0000FFFF
/* general flags */ /* general flags */
#define IPSET_MACIP_MATCHUNSET 1 #define IPSET_MACIP_MATCHUNSET 1
@@ -17,6 +17,7 @@ struct ip_set_macipmap {
ip_set_ip_t first_ip; /* host byte order, included in range */ ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_ip; /* host byte order, included in range */ ip_set_ip_t last_ip; /* host byte order, included in range */
u_int32_t flags; u_int32_t flags;
u_int32_t size; /* size of the ipmap proper */
}; };
struct ip_set_req_macipmap_create { struct ip_set_req_macipmap_create {
@@ -31,7 +32,7 @@ struct ip_set_req_macipmap {
}; };
struct ip_set_macip { struct ip_set_macip {
unsigned short flags; unsigned short match;
unsigned char ethernet[ETH_ALEN]; unsigned char ethernet[ETH_ALEN];
}; };

View File

@@ -2,11 +2,20 @@
#define _IP_SET_MALLOC_H #define _IP_SET_MALLOC_H
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/vmalloc.h>
static size_t max_malloc_size = 0, max_page_size = 0; static size_t max_malloc_size = 0, max_page_size = 0;
static size_t default_max_malloc_size = 131072; /* Guaranteed: slab.c */
static inline unsigned int init_max_page_size(void) static inline int init_max_page_size(void)
{ {
/* Compatibility glues to support 2.4.36 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
#define __GFP_NOWARN 0
/* Guaranteed: slab.c */
max_malloc_size = max_page_size = default_max_malloc_size;
#else
size_t page_size = 0; size_t page_size = 0;
#define CACHE(x) if (max_page_size == 0 || x < max_page_size) \ #define CACHE(x) if (max_page_size == 0 || x < max_page_size) \
@@ -21,6 +30,7 @@ static inline unsigned int init_max_page_size(void)
return 1; return 1;
} }
#endif
return 0; return 0;
} }
@@ -30,7 +40,7 @@ struct harray {
}; };
static inline void * static inline void *
__harray_malloc(size_t hashsize, size_t typesize, int flags) __harray_malloc(size_t hashsize, size_t typesize, gfp_t flags)
{ {
struct harray *harray; struct harray *harray;
size_t max_elements, size, i, j; size_t max_elements, size, i, j;
@@ -78,7 +88,7 @@ __harray_malloc(size_t hashsize, size_t typesize, int flags)
} }
static inline void * static inline void *
harray_malloc(size_t hashsize, size_t typesize, int flags) harray_malloc(size_t hashsize, size_t typesize, gfp_t flags)
{ {
void *harray; void *harray;
@@ -122,7 +132,7 @@ static inline void * ip_set_malloc(size_t bytes)
{ {
BUG_ON(max_malloc_size == 0); BUG_ON(max_malloc_size == 0);
if (bytes > max_malloc_size) if (bytes > default_max_malloc_size)
return vmalloc(bytes); return vmalloc(bytes);
else else
return kmalloc(bytes, GFP_KERNEL | __GFP_NOWARN); return kmalloc(bytes, GFP_KERNEL | __GFP_NOWARN);
@@ -132,7 +142,7 @@ static inline void ip_set_free(void * data, size_t bytes)
{ {
BUG_ON(max_malloc_size == 0); BUG_ON(max_malloc_size == 0);
if (bytes > max_malloc_size) if (bytes > default_max_malloc_size)
vfree(data); vfree(data);
else else
kfree(data); kfree(data);

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -8,43 +8,35 @@
/* Kernel module implementing a cidr nethash set */ /* Kernel module implementing a cidr nethash set */
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h> #include "ip_set_jhash.h"
#include <linux/jhash.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/vmalloc.h>
#include <linux/random.h> #include <linux/random.h>
#include <net/ip.h> #include <net/ip.h>
#include "ip_set_malloc.h"
#include "ip_set_nethash.h" #include "ip_set_nethash.h"
static int limit = MAX_RANGE; static int limit = MAX_RANGE;
static inline __u32 static inline __u32
jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t ip) nethash_id_cidr(const struct ip_set_nethash *map,
{ ip_set_ip_t *hash_ip,
return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
}
static inline __u32
hash_id_cidr(struct ip_set_nethash *map,
ip_set_ip_t ip, ip_set_ip_t ip,
unsigned char cidr, uint8_t cidr)
ip_set_ip_t *hash_ip)
{ {
__u32 id; __u32 id;
u_int16_t i; u_int16_t i;
ip_set_ip_t *elem; ip_set_ip_t *elem;
*hash_ip = pack(ip, cidr); *hash_ip = pack_ip_cidr(ip, cidr);
if (!*hash_ip)
return MAX_RANGE;
for (i = 0; i < map->probes; i++) { for (i = 0; i < map->probes; i++) {
id = jhash_ip(map, i, *hash_ip) % map->hashsize; id = jhash_ip(map, i, *hash_ip) % map->hashsize;
@@ -52,19 +44,20 @@ hash_id_cidr(struct ip_set_nethash *map,
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
if (*elem == *hash_ip) if (*elem == *hash_ip)
return id; return id;
/* No shortcut - there can be deleted entries. */
} }
return UINT_MAX; return UINT_MAX;
} }
static inline __u32 static inline __u32
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) nethash_id(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
struct ip_set_nethash *map = set->data; const struct ip_set_nethash *map = set->data;
__u32 id = UINT_MAX; __u32 id = UINT_MAX;
int i; int i;
for (i = 0; i < 30 && map->cidr[i]; i++) { for (i = 0; i < 30 && map->cidr[i]; i++) {
id = hash_id_cidr(map, ip, map->cidr[i], hash_ip); id = nethash_id_cidr(map, hash_ip, ip, map->cidr[i]);
if (id != UINT_MAX) if (id != UINT_MAX)
break; break;
} }
@@ -72,401 +65,156 @@ hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
} }
static inline int static inline int
__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr, nethash_test_cidr(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, uint8_t cidr)
{ {
struct ip_set_nethash *map = set->data; const struct ip_set_nethash *map = set->data;
return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX); return (nethash_id_cidr(map, hash_ip, ip, cidr) != UINT_MAX);
} }
static inline int static inline int
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip) nethash_test(struct ip_set *set, ip_set_ip_t *hash_ip, ip_set_ip_t ip)
{ {
return (ip && hash_id(set, ip, hash_ip) != UINT_MAX); return (nethash_id(set, hash_ip, ip) != UINT_MAX);
} }
static int static int
testip(struct ip_set *set, const void *data, size_t size, nethash_utest(struct ip_set *set, const void *data, u_int32_t size,
ip_set_ip_t *hash_ip) ip_set_ip_t *hash_ip)
{ {
const struct ip_set_req_nethash *req = data; const struct ip_set_req_nethash *req = data;
if (size != sizeof(struct ip_set_req_nethash)) { if (req->cidr <= 0 || req->cidr > 32)
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_nethash),
size);
return -EINVAL; return -EINVAL;
} return (req->cidr == 32 ? nethash_test(set, hash_ip, req->ip)
return (req->cidr == 32 ? __testip(set, req->ip, hash_ip) : nethash_test_cidr(set, hash_ip, req->ip, req->cidr));
: __testip_cidr(set, req->ip, req->cidr, hash_ip));
} }
static int #define KADT_CONDITION
testip_kernel(struct ip_set *set,
const struct sk_buff *skb, KADT(nethash, test, ipaddr)
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
return __testip(set,
ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr),
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr),
#endif
hash_ip);
}
static inline int static inline int
__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip) __nethash_add(struct ip_set_nethash *map, ip_set_ip_t *ip)
{ {
__u32 probe; __u32 probe;
u_int16_t i; u_int16_t i;
ip_set_ip_t *elem; ip_set_ip_t *elem, *slot = NULL;
for (i = 0; i < map->probes; i++) { for (i = 0; i < map->probes; i++) {
probe = jhash_ip(map, i, ip) % map->hashsize; probe = jhash_ip(map, i, *ip) % map->hashsize;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
if (*elem == ip) if (*elem == *ip)
return -EEXIST; return -EEXIST;
if (!*elem) { if (!(slot || *elem))
*elem = ip; slot = elem;
/* There can be deleted entries, must check all slots */
}
if (slot) {
*slot = *ip;
map->elements++; map->elements++;
return 0; return 0;
} }
}
/* Trigger rehashing */ /* Trigger rehashing */
return -EAGAIN; return -EAGAIN;
} }
static inline int static inline int
__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr, nethash_add(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, uint8_t cidr)
{ {
if (!ip || map->elements >= limit) struct ip_set_nethash *map = set->data;
return -ERANGE;
*hash_ip = pack(ip, cidr);
DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
return __addip_base(map, *hash_ip);
}
static void
update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
{
unsigned char next;
int i;
for (i = 0; i < 30 && map->cidr[i]; i++) {
if (map->cidr[i] == cidr) {
return;
} else if (map->cidr[i] < cidr) {
next = map->cidr[i];
map->cidr[i] = cidr;
cidr = next;
}
}
if (i < 30)
map->cidr[i] = cidr;
}
static int
addip(struct ip_set *set, const void *data, size_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_req_nethash *req = data;
int ret; int ret;
if (size != sizeof(struct ip_set_req_nethash)) { if (map->elements >= limit || map->nets[cidr-1] == UINT16_MAX)
ip_set_printk("data length wrong (want %zu, have %zu)", return -ERANGE;
sizeof(struct ip_set_req_nethash), if (cidr <= 0 || cidr >= 32)
size);
return -EINVAL; return -EINVAL;
}
ret = __addip(set->data, req->ip, req->cidr, hash_ip);
if (ret == 0) *hash_ip = pack_ip_cidr(ip, cidr);
update_cidr_sizes(set->data, req->cidr); DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
if (!*hash_ip)
return ret;
}
static int
addip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
struct ip_set_nethash *map = set->data;
int ret = -ERANGE;
ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr);
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr);
#endif
if (map->cidr[0])
ret = __addip(map, ip, map->cidr[0], hash_ip);
return ret;
}
static int retry(struct ip_set *set)
{
struct ip_set_nethash *map = set->data;
ip_set_ip_t *elem;
void *members;
u_int32_t i, hashsize = map->hashsize;
int res;
struct ip_set_nethash *tmp;
if (map->resize == 0)
return -ERANGE; return -ERANGE;
again: ret = __nethash_add(map, hash_ip);
res = 0; if (ret == 0) {
if (!map->nets[cidr-1]++)
/* Calculate new parameters */ add_cidr_size(map->cidr, cidr);
hashsize += (hashsize * map->resize)/100; map->elements++;
if (hashsize == map->hashsize)
hashsize++;
ip_set_printk("rehashing of set %s triggered: "
"hashsize grows from %u to %u",
set->name, map->hashsize, hashsize);
tmp = kmalloc(sizeof(struct ip_set_nethash)
+ map->probes * sizeof(uint32_t), GFP_ATOMIC);
if (!tmp) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_nethash)
+ map->probes * sizeof(uint32_t));
return -ENOMEM;
}
tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
if (!tmp->members) {
DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
kfree(tmp);
return -ENOMEM;
}
tmp->hashsize = hashsize;
tmp->elements = 0;
tmp->probes = map->probes;
tmp->resize = map->resize;
memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
memcpy(tmp->cidr, map->cidr, 30 * sizeof(unsigned char));
write_lock_bh(&set->lock);
map = set->data; /* Play safe */
for (i = 0; i < map->hashsize && res == 0; i++) {
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
if (*elem)
res = __addip_base(tmp, *elem);
}
if (res) {
/* Failure, try again */
write_unlock_bh(&set->lock);
harray_free(tmp->members);
kfree(tmp);
goto again;
} }
/* Success at resizing! */ return ret;
members = map->members;
map->hashsize = tmp->hashsize;
map->members = tmp->members;
write_unlock_bh(&set->lock);
harray_free(members);
kfree(tmp);
return 0;
} }
#undef KADT_CONDITION
#define KADT_CONDITION \
struct ip_set_nethash *map = set->data; \
uint8_t cidr = map->cidr[0] ? map->cidr[0] : 31;
UADT(nethash, add, req->cidr)
KADT(nethash, add, ipaddr, cidr)
static inline void
__nethash_retry(struct ip_set_nethash *tmp, struct ip_set_nethash *map)
{
memcpy(tmp->cidr, map->cidr, sizeof(tmp->cidr));
memcpy(tmp->nets, map->nets, sizeof(tmp->nets));
}
HASH_RETRY(nethash, ip_set_ip_t)
static inline int static inline int
__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr, nethash_del(struct ip_set *set, ip_set_ip_t *hash_ip,
ip_set_ip_t *hash_ip) ip_set_ip_t ip, uint8_t cidr)
{ {
struct ip_set_nethash *map = set->data;
ip_set_ip_t id, *elem; ip_set_ip_t id, *elem;
if (!ip) if (cidr <= 0 || cidr >= 32)
return -ERANGE; return -EINVAL;
id = hash_id_cidr(map, ip, cidr, hash_ip); id = nethash_id_cidr(map, hash_ip, ip, cidr);
if (id == UINT_MAX) if (id == UINT_MAX)
return -EEXIST; return -EEXIST;
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id); elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
*elem = 0; *elem = 0;
map->elements--; map->elements--;
if (!map->nets[cidr-1]--)
del_cidr_size(map->cidr, cidr);
return 0; return 0;
} }
static int UADT(nethash, del, req->cidr)
delip(struct ip_set *set, const void *data, size_t size, KADT(nethash, del, ipaddr, cidr)
ip_set_ip_t *hash_ip)
static inline int
__nethash_create(const struct ip_set_req_nethash_create *req,
struct ip_set_nethash *map)
{ {
const struct ip_set_req_nethash *req = data; memset(map->cidr, 0, sizeof(map->cidr));
memset(map->nets, 0, sizeof(map->nets));
if (size != sizeof(struct ip_set_req_nethash)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_nethash),
size);
return -EINVAL;
}
/* TODO: no garbage collection in map->cidr */
return __delip(set->data, req->ip, req->cidr, hash_ip);
}
static int
delip_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
struct ip_set_nethash *map = set->data;
int ret = -ERANGE;
ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
? ip_hdr(skb)->saddr
: ip_hdr(skb)->daddr);
#else
? skb->nh.iph->saddr
: skb->nh.iph->daddr);
#endif
if (map->cidr[0])
ret = __delip(map, ip, map->cidr[0], hash_ip);
return ret;
}
static int create(struct ip_set *set, const void *data, size_t size)
{
const struct ip_set_req_nethash_create *req = data;
struct ip_set_nethash *map;
uint16_t i;
if (size != sizeof(struct ip_set_req_nethash_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_nethash_create),
size);
return -EINVAL;
}
if (req->hashsize < 1) {
ip_set_printk("hashsize too small");
return -ENOEXEC;
}
if (req->probes < 1) {
ip_set_printk("probes too small");
return -ENOEXEC;
}
map = kmalloc(sizeof(struct ip_set_nethash)
+ req->probes * sizeof(uint32_t), GFP_KERNEL);
if (!map) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_nethash)
+ req->probes * sizeof(uint32_t));
return -ENOMEM;
}
for (i = 0; i < req->probes; i++)
get_random_bytes(((uint32_t *) map->initval)+i, 4);
map->elements = 0;
map->hashsize = req->hashsize;
map->probes = req->probes;
map->resize = req->resize;
memset(map->cidr, 0, 30 * sizeof(unsigned char));
map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
if (!map->members) {
DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
kfree(map);
return -ENOMEM;
}
set->data = map;
return 0; return 0;
} }
static void destroy(struct ip_set *set) HASH_CREATE(nethash, ip_set_ip_t)
HASH_DESTROY(nethash)
HASH_FLUSH_CIDR(nethash, ip_set_ip_t)
static inline void
__nethash_list_header(const struct ip_set_nethash *map,
struct ip_set_req_nethash_create *header)
{ {
struct ip_set_nethash *map = set->data;
harray_free(map->members);
kfree(map);
set->data = NULL;
} }
static void flush(struct ip_set *set) HASH_LIST_HEADER(nethash)
{ HASH_LIST_MEMBERS_SIZE(nethash, ip_set_ip_t)
struct ip_set_nethash *map = set->data; HASH_LIST_MEMBERS(nethash, ip_set_ip_t)
harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
memset(map->cidr, 0, 30 * sizeof(unsigned char));
map->elements = 0;
}
static void list_header(const struct ip_set *set, void *data) IP_SET_RTYPE(nethash, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
{
const struct ip_set_nethash *map = set->data;
struct ip_set_req_nethash_create *header = data;
header->hashsize = map->hashsize;
header->probes = map->probes;
header->resize = map->resize;
}
static int list_members_size(const struct ip_set *set)
{
struct ip_set_nethash *map = set->data;
return (map->hashsize * sizeof(ip_set_ip_t));
}
static void list_members(const struct ip_set *set, void *data)
{
const struct ip_set_nethash *map = set->data;
ip_set_ip_t i, *elem;
for (i = 0; i < map->hashsize; i++) {
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
((ip_set_ip_t *)data)[i] = *elem;
}
}
static struct ip_set_type ip_set_nethash = {
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create,
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_nethash),
.addip = &addip,
.addip_kernel = &addip_kernel,
.retry = &retry,
.delip = &delip,
.delip_kernel = &delip_kernel,
.testip = &testip,
.testip_kernel = &testip_kernel,
.header_size = sizeof(struct ip_set_req_nethash_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
@@ -474,17 +222,4 @@ MODULE_DESCRIPTION("nethash type of IP sets");
module_param(limit, int, 0600); module_param(limit, int, 0600);
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets"); MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
static int __init ip_set_nethash_init(void) REGISTER_MODULE(nethash)
{
init_max_page_size();
return ip_set_register_set_type(&ip_set_nethash);
}
static void __exit ip_set_nethash_fini(void)
{
/* FIXME: possible race with ip_set_create() */
ip_set_unregister_set_type(&ip_set_nethash);
}
module_init(ip_set_nethash_init);
module_exit(ip_set_nethash_fini);

View File

@@ -2,9 +2,9 @@
#define __IP_SET_NETHASH_H #define __IP_SET_NETHASH_H
#include "ip_set.h" #include "ip_set.h"
#include "ip_set_hashes.h"
#define SETTYPE_NAME "nethash" #define SETTYPE_NAME "nethash"
#define MAX_RANGE 0x0000FFFF
struct ip_set_nethash { struct ip_set_nethash {
ip_set_ip_t *members; /* the nethash proper */ ip_set_ip_t *members; /* the nethash proper */
@@ -12,8 +12,9 @@ struct ip_set_nethash {
uint32_t hashsize; /* hash size */ uint32_t hashsize; /* hash size */
uint16_t probes; /* max number of probes */ uint16_t probes; /* max number of probes */
uint16_t resize; /* resize factor in percent */ uint16_t resize; /* resize factor in percent */
unsigned char cidr[30]; /* CIDR sizes */ uint8_t cidr[30]; /* CIDR sizes */
void *initval[0]; /* initvals for jhash_1word */ uint16_t nets[30]; /* nr of nets by CIDR sizes */
initval_t initval[0]; /* initvals for jhash_1word */
}; };
struct ip_set_req_nethash_create { struct ip_set_req_nethash_create {
@@ -24,32 +25,7 @@ struct ip_set_req_nethash_create {
struct ip_set_req_nethash { struct ip_set_req_nethash {
ip_set_ip_t ip; ip_set_ip_t ip;
unsigned char cidr; uint8_t cidr;
}; };
static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
static inline ip_set_ip_t
pack(ip_set_ip_t ip, unsigned char cidr)
{
ip_set_ip_t addr, *paddr = &addr;
unsigned char n, t, *a;
addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
#ifdef __KERNEL__
DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
#endif
n = cidr / 8;
t = cidr % 8;
a = &((unsigned char *)paddr)[n];
*a = *a /(1 << (8 - t)) + shifts[t];
#ifdef __KERNEL__
DP("n: %u, t: %u, a: %u", n, t, *a);
DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
HIPQUAD(ip), cidr, NIPQUAD(addr));
#endif
return ntohl(addr);
}
#endif /* __IP_SET_NETHASH_H */ #endif /* __IP_SET_NETHASH_H */

View File

@@ -1,4 +1,4 @@
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> /* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,6 @@
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include "ip_set.h"
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/bitops.h> #include <asm/bitops.h>
@@ -23,113 +20,37 @@
#include <net/ip.h> #include <net/ip.h>
#include "ip_set_portmap.h" #include "ip_set_portmap.h"
#include "ip_set_getport.h"
/* We must handle non-linear skbs */
static inline ip_set_ip_t
get_port(const struct sk_buff *skb, u_int32_t flags)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
struct iphdr *iph = ip_hdr(skb);
#else
struct iphdr *iph = skb->nh.iph;
#endif
u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
switch (iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr tcph;
/* See comments at tcp_match in ip_tables.c */
if (offset)
return INVALID_PORT;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
#else
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
#endif
/* No choice either */
return INVALID_PORT;
return ntohs(flags & IPSET_SRC ?
tcph.source : tcph.dest);
}
case IPPROTO_UDP: {
struct udphdr udph;
if (offset)
return INVALID_PORT;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
#else
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
#endif
/* No choice either */
return INVALID_PORT;
return ntohs(flags & IPSET_SRC ?
udph.source : udph.dest);
}
default:
return INVALID_PORT;
}
}
static inline int static inline int
__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) portmap_test(const struct ip_set *set, ip_set_ip_t *hash_port,
ip_set_ip_t port)
{ {
struct ip_set_portmap *map = set->data; const struct ip_set_portmap *map = set->data;
if (port < map->first_port || port > map->last_port) if (port < map->first_ip || port > map->last_ip)
return -ERANGE; return -ERANGE;
*hash_port = port; *hash_port = port;
DP("set: %s, port:%u, %u", set->name, port, *hash_port); DP("set: %s, port:%u, %u", set->name, port, *hash_port);
return !!test_bit(port - map->first_port, map->members); return !!test_bit(port - map->first_ip, map->members);
} }
static int #define KADT_CONDITION \
testport(struct ip_set *set, const void *data, size_t size, if (ip == INVALID_PORT) \
ip_set_ip_t *hash_port)
{
const struct ip_set_req_portmap *req = data;
if (size != sizeof(struct ip_set_req_portmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_portmap),
size);
return -EINVAL;
}
return __testport(set, req->port, hash_port);
}
static int
testport_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_port,
const u_int32_t *flags,
unsigned char index)
{
int res;
ip_set_ip_t port = get_port(skb, flags[index]);
DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
if (port == INVALID_PORT)
return 0; return 0;
res = __testport(set, port, hash_port); UADT(portmap, test)
KADT(portmap, test, get_port)
return (res < 0 ? 0 : res);
}
static inline int static inline int
__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) portmap_add(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port)
{ {
struct ip_set_portmap *map = set->data; struct ip_set_portmap *map = set->data;
if (port < map->first_port || port > map->last_port) if (port < map->first_ip || port > map->last_ip)
return -ERANGE; return -ERANGE;
if (test_and_set_bit(port - map->first_port, map->members)) if (test_and_set_bit(port - map->first_ip, map->members))
return -EEXIST; return -EEXIST;
*hash_port = port; *hash_port = port;
@@ -137,44 +58,17 @@ __addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
return 0; return 0;
} }
static int UADT(portmap, add)
addport(struct ip_set *set, const void *data, size_t size, KADT(portmap, add, get_port)
ip_set_ip_t *hash_port)
{
const struct ip_set_req_portmap *req = data;
if (size != sizeof(struct ip_set_req_portmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_portmap),
size);
return -EINVAL;
}
return __addport(set, req->port, hash_port);
}
static int
addport_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_port,
const u_int32_t *flags,
unsigned char index)
{
ip_set_ip_t port = get_port(skb, flags[index]);
if (port == INVALID_PORT)
return -EINVAL;
return __addport(set, port, hash_port);
}
static inline int static inline int
__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port) portmap_del(struct ip_set *set, ip_set_ip_t *hash_port, ip_set_ip_t port)
{ {
struct ip_set_portmap *map = set->data; struct ip_set_portmap *map = set->data;
if (port < map->first_port || port > map->last_port) if (port < map->first_ip || port > map->last_ip)
return -ERANGE; return -ERANGE;
if (!test_and_clear_bit(port - map->first_port, map->members)) if (!test_and_clear_bit(port - map->first_ip, map->members))
return -EEXIST; return -EEXIST;
*hash_port = port; *hash_port = port;
@@ -182,160 +76,39 @@ __delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
return 0; return 0;
} }
static int UADT(portmap, del)
delport(struct ip_set *set, const void *data, size_t size, KADT(portmap, del, get_port)
ip_set_ip_t *hash_port)
static inline int
__portmap_create(const struct ip_set_req_portmap_create *req,
struct ip_set_portmap *map)
{ {
const struct ip_set_req_portmap *req = data;
if (size != sizeof(struct ip_set_req_portmap)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_portmap),
size);
return -EINVAL;
}
return __delport(set, req->port, hash_port);
}
static int
delport_kernel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_port,
const u_int32_t *flags,
unsigned char index)
{
ip_set_ip_t port = get_port(skb, flags[index]);
if (port == INVALID_PORT)
return -EINVAL;
return __delport(set, port, hash_port);
}
static int create(struct ip_set *set, const void *data, size_t size)
{
int newbytes;
const struct ip_set_req_portmap_create *req = data;
struct ip_set_portmap *map;
if (size != sizeof(struct ip_set_req_portmap_create)) {
ip_set_printk("data length wrong (want %zu, have %zu)",
sizeof(struct ip_set_req_portmap_create),
size);
return -EINVAL;
}
DP("from %u to %u", req->from, req->to);
if (req->from > req->to) {
DP("bad port range");
return -ENOEXEC;
}
if (req->to - req->from > MAX_RANGE) { if (req->to - req->from > MAX_RANGE) {
ip_set_printk("range too big (max %d ports)", ip_set_printk("range too big, %d elements (max %d)",
MAX_RANGE+1); req->to - req->from + 1, MAX_RANGE+1);
return -ENOEXEC; return -ENOEXEC;
} }
return bitmap_bytes(req->from, req->to);
map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
if (!map) {
DP("out of memory for %d bytes",
sizeof(struct ip_set_portmap));
return -ENOMEM;
}
map->first_port = req->from;
map->last_port = req->to;
newbytes = bitmap_bytes(req->from, req->to);
map->members = kmalloc(newbytes, GFP_KERNEL);
if (!map->members) {
DP("out of memory for %d bytes", newbytes);
kfree(map);
return -ENOMEM;
}
memset(map->members, 0, newbytes);
set->data = map;
return 0;
} }
static void destroy(struct ip_set *set) BITMAP_CREATE(portmap)
BITMAP_DESTROY(portmap)
BITMAP_FLUSH(portmap)
static inline void
__portmap_list_header(const struct ip_set_portmap *map,
struct ip_set_req_portmap_create *header)
{ {
struct ip_set_portmap *map = set->data;
kfree(map->members);
kfree(map);
set->data = NULL;
} }
static void flush(struct ip_set *set) BITMAP_LIST_HEADER(portmap)
{ BITMAP_LIST_MEMBERS_SIZE(portmap)
struct ip_set_portmap *map = set->data; BITMAP_LIST_MEMBERS(portmap)
memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
}
static void list_header(const struct ip_set *set, void *data) IP_SET_TYPE(portmap, IPSET_TYPE_PORT | IPSET_DATA_SINGLE)
{
const struct ip_set_portmap *map = set->data;
struct ip_set_req_portmap_create *header = data;
DP("list_header %u %u", map->first_port, map->last_port);
header->from = map->first_port;
header->to = map->last_port;
}
static int list_members_size(const struct ip_set *set)
{
const struct ip_set_portmap *map = set->data;
return bitmap_bytes(map->first_port, map->last_port);
}
static void list_members(const struct ip_set *set, void *data)
{
const struct ip_set_portmap *map = set->data;
int bytes = bitmap_bytes(map->first_port, map->last_port);
memcpy(data, map->members, bytes);
}
static struct ip_set_type ip_set_portmap = {
.typename = SETTYPE_NAME,
.features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE,
.protocol_version = IP_SET_PROTOCOL_VERSION,
.create = &create,
.destroy = &destroy,
.flush = &flush,
.reqsize = sizeof(struct ip_set_req_portmap),
.addip = &addport,
.addip_kernel = &addport_kernel,
.delip = &delport,
.delip_kernel = &delport_kernel,
.testip = &testport,
.testip_kernel = &testport_kernel,
.header_size = sizeof(struct ip_set_req_portmap_create),
.list_header = &list_header,
.list_members_size = &list_members_size,
.list_members = &list_members,
.me = THIS_MODULE,
};
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("portmap type of IP sets"); MODULE_DESCRIPTION("portmap type of IP sets");
static int __init ip_set_portmap_init(void) REGISTER_MODULE(portmap)
{
return ip_set_register_set_type(&ip_set_portmap);
}
static void __exit ip_set_portmap_fini(void)
{
/* FIXME: possible race with ip_set_create() */
ip_set_unregister_set_type(&ip_set_portmap);
}
module_init(ip_set_portmap_init);
module_exit(ip_set_portmap_fini);

View File

@@ -2,15 +2,15 @@
#define __IP_SET_PORTMAP_H #define __IP_SET_PORTMAP_H
#include "ip_set.h" #include "ip_set.h"
#include "ip_set_bitmaps.h"
#define SETTYPE_NAME "portmap" #define SETTYPE_NAME "portmap"
#define MAX_RANGE 0x0000FFFF
#define INVALID_PORT (MAX_RANGE + 1)
struct ip_set_portmap { struct ip_set_portmap {
void *members; /* the portmap proper */ void *members; /* the portmap proper */
ip_set_ip_t first_port; /* host byte order, included in range */ ip_set_ip_t first_ip; /* host byte order, included in range */
ip_set_ip_t last_port; /* host byte order, included in range */ ip_set_ip_t last_ip; /* host byte order, included in range */
u_int32_t size; /* size of the ipmap proper */
}; };
struct ip_set_req_portmap_create { struct ip_set_req_portmap_create {
@@ -19,7 +19,7 @@ struct ip_set_req_portmap_create {
}; };
struct ip_set_req_portmap { struct ip_set_req_portmap {
ip_set_ip_t port; ip_set_ip_t ip;
}; };
#endif /* __IP_SET_PORTMAP_H */ #endif /* __IP_SET_PORTMAP_H */

View File

@@ -0,0 +1,330 @@
/* Copyright (C) 2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
*
* 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.
*/
/* Kernel module implementing an IP set type: the setlist type */
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include "ip_set.h"
#include "ip_set_bitmaps.h"
#include "ip_set_setlist.h"
/*
* before ==> index, ref
* after ==> ref, index
*/
static inline int
next_index_eq(const struct ip_set_setlist *map, int i, ip_set_id_t index)
{
return i < map->size && map->index[i] == index;
}
static int
setlist_utest(struct ip_set *set, const void *data, u_int32_t size,
ip_set_ip_t *hash_ip)
{
const struct ip_set_setlist *map = set->data;
const struct ip_set_req_setlist *req = data;
ip_set_id_t index, ref = IP_SET_INVALID_ID;
int i, res = 0;
struct ip_set *s;
if (req->before && req->ref[0] == '\0')
return 0;
index = __ip_set_get_byname(req->name, &s);
if (index == IP_SET_INVALID_ID)
return 0;
if (req->ref[0] != '\0') {
ref = __ip_set_get_byname(req->ref, &s);
if (ref == IP_SET_INVALID_ID)
goto finish;
}
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID; i++) {
if (req->before && map->index[i] == index) {
res = next_index_eq(map, i + 1, ref);
break;
} else if (!req->before) {
if ((ref == IP_SET_INVALID_ID
&& map->index[i] == index)
|| (map->index[i] == ref
&& next_index_eq(map, i + 1, index))) {
res = 1;
break;
}
}
}
if (ref != IP_SET_INVALID_ID)
__ip_set_put_byindex(ref);
finish:
__ip_set_put_byindex(index);
return res;
}
static int
setlist_ktest(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
struct ip_set_setlist *map = set->data;
int i, res = 0;
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID
&& res == 0; i++)
res = ip_set_testip_kernel(map->index[i], skb, flags);
return res;
}
static inline int
insert_setlist(struct ip_set_setlist *map, int i, ip_set_id_t index)
{
ip_set_id_t tmp;
int j;
DP("i: %u, last %u\n", i, map->index[map->size - 1]);
if (i >= map->size || map->index[map->size - 1] != IP_SET_INVALID_ID)
return -ERANGE;
for (j = i; j < map->size
&& index != IP_SET_INVALID_ID; j++) {
tmp = map->index[j];
map->index[j] = index;
index = tmp;
}
return 0;
}
static int
setlist_uadd(struct ip_set *set, const void *data, u_int32_t size,
ip_set_ip_t *hash_ip)
{
struct ip_set_setlist *map = set->data;
const struct ip_set_req_setlist *req = data;
ip_set_id_t index, ref = IP_SET_INVALID_ID;
int i, res = -ERANGE;
struct ip_set *s;
if (req->before && req->ref[0] == '\0')
return -EINVAL;
index = __ip_set_get_byname(req->name, &s);
if (index == IP_SET_INVALID_ID)
return -EEXIST;
/* "Loop detection" */
if (strcmp(s->type->typename, "setlist") == 0)
goto finish;
if (req->ref[0] != '\0') {
ref = __ip_set_get_byname(req->ref, &s);
if (ref == IP_SET_INVALID_ID) {
res = -EEXIST;
goto finish;
}
}
for (i = 0; i < map->size; i++) {
if (map->index[i] != ref)
continue;
if (req->before)
res = insert_setlist(map, i, index);
else
res = insert_setlist(map,
ref == IP_SET_INVALID_ID ? i : i + 1,
index);
break;
}
if (ref != IP_SET_INVALID_ID)
__ip_set_put_byindex(ref);
/* In case of success, we keep the reference to the set */
finish:
if (res != 0)
__ip_set_put_byindex(index);
return res;
}
static int
setlist_kadd(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
struct ip_set_setlist *map = set->data;
int i, res = -EINVAL;
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID
&& res != 0; i++)
res = ip_set_addip_kernel(map->index[i], skb, flags);
return res;
}
static inline int
unshift_setlist(struct ip_set_setlist *map, int i)
{
int j;
for (j = i; j < map->size - 1; j++)
map->index[j] = map->index[j+1];
map->index[map->size-1] = IP_SET_INVALID_ID;
return 0;
}
static int
setlist_udel(struct ip_set *set, const void *data, u_int32_t size,
ip_set_ip_t *hash_ip)
{
struct ip_set_setlist *map = set->data;
const struct ip_set_req_setlist *req = data;
ip_set_id_t index, ref = IP_SET_INVALID_ID;
int i, res = -EEXIST;
struct ip_set *s;
if (req->before && req->ref[0] == '\0')
return -EINVAL;
index = __ip_set_get_byname(req->name, &s);
if (index == IP_SET_INVALID_ID)
return -EEXIST;
if (req->ref[0] != '\0') {
ref = __ip_set_get_byname(req->ref, &s);
if (ref == IP_SET_INVALID_ID)
goto finish;
}
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID; i++) {
if (req->before) {
if (map->index[i] == index
&& next_index_eq(map, i + 1, ref)) {
res = unshift_setlist(map, i);
break;
}
} else if (ref == IP_SET_INVALID_ID) {
if (map->index[i] == index) {
res = unshift_setlist(map, i);
break;
}
} else if (map->index[i] == ref
&& next_index_eq(map, i + 1, index)) {
res = unshift_setlist(map, i + 1);
break;
}
}
if (ref != IP_SET_INVALID_ID)
__ip_set_put_byindex(ref);
finish:
__ip_set_put_byindex(index);
/* In case of success, release the reference to the set */
if (res == 0)
__ip_set_put_byindex(index);
return res;
}
static int
setlist_kdel(struct ip_set *set,
const struct sk_buff *skb,
ip_set_ip_t *hash_ip,
const u_int32_t *flags,
unsigned char index)
{
struct ip_set_setlist *map = set->data;
int i, res = -EINVAL;
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID
&& res != 0; i++)
res = ip_set_delip_kernel(map->index[i], skb, flags);
return res;
}
static int
setlist_create(struct ip_set *set, const void *data, u_int32_t size)
{
struct ip_set_setlist *map;
const struct ip_set_req_setlist_create *req = data;
int i;
map = kmalloc(sizeof(struct ip_set_setlist) +
req->size * sizeof(ip_set_id_t), GFP_KERNEL);
if (!map)
return -ENOMEM;
map->size = req->size;
for (i = 0; i < map->size; i++)
map->index[i] = IP_SET_INVALID_ID;
set->data = map;
return 0;
}
static void
setlist_destroy(struct ip_set *set)
{
struct ip_set_setlist *map = set->data;
int i;
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID; i++)
__ip_set_put_byindex(map->index[i]);
kfree(map);
set->data = NULL;
}
static void
setlist_flush(struct ip_set *set)
{
struct ip_set_setlist *map = set->data;
int i;
for (i = 0; i < map->size
&& map->index[i] != IP_SET_INVALID_ID; i++) {
__ip_set_put_byindex(map->index[i]);
map->index[i] = IP_SET_INVALID_ID;
}
}
static void
setlist_list_header(const struct ip_set *set, void *data)
{
const struct ip_set_setlist *map = set->data;
struct ip_set_req_setlist_create *header = data;
header->size = map->size;
}
static int
setlist_list_members_size(const struct ip_set *set)
{
const struct ip_set_setlist *map = set->data;
return map->size * sizeof(ip_set_id_t);
}
static void
setlist_list_members(const struct ip_set *set, void *data)
{
struct ip_set_setlist *map = set->data;
int i;
for (i = 0; i < map->size; i++)
*((ip_set_id_t *)data + i) = ip_set_id(map->index[i]);
}
IP_SET_TYPE(setlist, IPSET_TYPE_SETNAME | IPSET_DATA_SINGLE)
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("setlist type of IP sets");
REGISTER_MODULE(setlist)

View File

@@ -0,0 +1,26 @@
#ifndef __IP_SET_SETLIST_H
#define __IP_SET_SETLIST_H
#include "ip_set.h"
#define SETTYPE_NAME "setlist"
#define IP_SET_SETLIST_ADD_AFTER 0
#define IP_SET_SETLIST_ADD_BEFORE 1
struct ip_set_setlist {
uint8_t size;
ip_set_id_t index[0];
};
struct ip_set_req_setlist_create {
uint8_t size;
};
struct ip_set_req_setlist {
char name[IP_SET_MAXNAMELEN];
char ref[IP_SET_MAXNAMELEN];
uint8_t before;
};
#endif /* __IP_SET_SETLIST_H */

View File

@@ -50,6 +50,9 @@ IP set bindings pointing to sets and iptables matches and targets
referring to sets creates references, which protects the given sets in referring to sets creates references, which protects the given sets in
the kernel. A set cannot be removed (destroyed) while there is a single the kernel. A set cannot be removed (destroyed) while there is a single
reference pointing to it. reference pointing to it.
.P
.B
Please note, binding sets is a deprecated feature and will be removed in a later release. Switch to the multidata type of sets from using bindings.
.SH OPTIONS .SH OPTIONS
The options that are recognized by The options that are recognized by
.B ipset .B ipset
@@ -87,14 +90,9 @@ is given. Bindings are not affected by the flush operation.
Rename a set. Set identified by to-setname must not exist. Rename a set. Set identified by to-setname must not exist.
.TP .TP
.BI "-W, --swap " "\fIfrom-setname\fP \fIto-setname\fP" .BI "-W, --swap " "\fIfrom-setname\fP \fIto-setname\fP"
Swap two sets as they referenced in the Linux kernel. Swap the content of two sets, or in another words,
.B exchange the name of two sets. The referred sets must exist and
iptables identical type of sets can be swapped only.
rules or
.B
ipset
bindings pointing to the content of from-setname will point to
the content of to-setname and vice versa. Both sets must exist.
.TP .TP
.BI "-L, --list " "[\fIsetname\fP]" .BI "-L, --list " "[\fIsetname\fP]"
List the entries and bindings for the specified set, or for List the entries and bindings for the specified set, or for
@@ -203,12 +201,12 @@ ipset supports the following set types:
The ipmap set type uses a memory range, where each bit represents The ipmap set type uses a memory range, where each bit represents
one IP address. An ipmap set can store up to 65536 (B-class network) one IP address. An ipmap set can store up to 65536 (B-class network)
IP addresses. The ipmap set type is very fast and memory cheap, great IP addresses. The ipmap set type is very fast and memory cheap, great
for use when one want to match certain IPs in a range. Using the for use when one want to match certain IPs in a range. If the optional
.B "--netmask" .B "--netmask"
option with a CIDR netmask value between 0-32 when creating an ipmap parameter is specified with a CIDR netmask value between 1-31 then
set, you will be able to store and match network addresses: i.e an network addresses are stored in the given set: i.e an
IP address will be in the set if the value resulted by masking the address IP address will be in the set if the network address, which is resulted
with the specified netmask can be found in the set. by masking the address with the specified netmask, can be found in the set.
.P .P
Options to use when creating an ipmap set: Options to use when creating an ipmap set:
.TP .TP
@@ -225,17 +223,16 @@ When the optional
.B "--netmask" .B "--netmask"
parameter specified, network addresses will be parameter specified, network addresses will be
stored in the set instead of IP addresses, and the from-IP parameter stored in the set instead of IP addresses, and the from-IP parameter
must be a network address. must be a network address. The CIDR-netmask value must be between 1-31.
.SS macipmap .SS macipmap
The macipmap set type uses a memory range, where each 8 bytes The macipmap set type uses a memory range, where each 8 bytes
represents one IP and a MAC addresses. A macipmap set type can store represents one IP and a MAC addresses. A macipmap set type can store
up to 65536 (B-class network) IP addresses with MAC. up to 65536 (B-class network) IP addresses with MAC.
When adding an entry to a macipmap set, you must specify the entry as When adding an entry to a macipmap set, you must specify the entry as
.I IP:MAC. .I IP,MAC.
When deleting or testing macipmap entries, the When deleting or testing macipmap entries, the
.I :MAC .I ,MAC
part is not mandatory. (The old "%" separation token instead of ":", i.e part is not mandatory.
IP%MAC is accepted as well.)
.P .P
Options to use when creating an macipmap set: Options to use when creating an macipmap set:
.TP .TP
@@ -279,12 +276,12 @@ Create a portmap set from the specified range.
The iphash set type uses a hash to store IP addresses. The iphash set type uses a hash to store IP addresses.
In order to avoid clashes in the hash double-hashing, and as a last In order to avoid clashes in the hash double-hashing, and as a last
resort, dynamic growing of the hash performed. The iphash set type is resort, dynamic growing of the hash performed. The iphash set type is
great to store random addresses. By supplyig the great to store random addresses. If the optional
.B "--netmask" .B "--netmask"
option with a CIDR netmask value between 0-32 at creating the set, parameter is specified with a CIDR netmask value between 1-31 then
you will be able to store and match network addresses instead: i.e network addresses are stored in the given set: i.e an
an IP address will be in the set if the value of the address IP address will be in the set if the network address, which is resulted
masked with the specified netmask can be found in the set. by masking the address with the specified netmask, can be found in the set.
.P .P
Options to use when creating an iphash set: Options to use when creating an iphash set:
.TP .TP
@@ -306,21 +303,22 @@ number of double-hashing.
When the optional When the optional
.B "--netmask" .B "--netmask"
parameter specified, network addresses will be parameter specified, network addresses will be
stored in the set instead of IP addresses. stored in the set instead of IP addresses. The CIDR-netmask value must
be between 1-31.
.P .P
The iphash type of sets can store up to 65536 entries. If a set is full, The iphash type of sets can store up to 65536 entries. If a set is full,
no new entries can be added to it. no new entries can be added to it.
.P .P
Sets created by zero valued resize parameter won't be resized at all. Sets created by zero valued resize parameter won't be resized at all.
The lookup time in an iphash type of set approximately linearly grows with The lookup time in an iphash type of set grows approximately linearly with
the value of the the value of the
.B .B
probes probes
parameter. At the same time higher parameter. In general higher
.B .B
probes probe
values result a better utilized hash while smaller values value results better utilized hash while smaller value
produce a larger, sparse hash. produces larger, sparser hash.
.SS nethash .SS nethash
The nethash set type uses a hash to store different size of The nethash set type uses a hash to store different size of
network addresses. The network addresses. The
@@ -349,18 +347,18 @@ an IP to the hash could not be performed after
The nethash type of sets can store up to 65536 entries. If a set is full, The nethash type of sets can store up to 65536 entries. If a set is full,
no new entries can be added to it. no new entries can be added to it.
.P .P
An IP address will be in a nethash type of set if it is in any of the An IP address will be in a nethash type of set if it belongs to any of the
netblocks added to the set and the matching always start from the smallest netblocks added to the set. The matching always start from the smallest
size of netblock (most specific netmask) to the biggest ones (least size of netblock (most specific netmask) to the largest ones (least
specific netmasks). When adding/deleting IP addresses specific netmasks). When adding/deleting IP addresses
to a nethash set by the to a nethash set by the
.I .I
SET SET
netfilter kernel module, it will be added/deleted by the smallest netfilter kernel module, it will be added/deleted by the smallest
netblock size which can be found in the set. netblock size which can be found in the set, or by /31 if the set is empty.
.P .P
The lookup time in a nethash type of set is approximately linearly The lookup time in a nethash type of set grows approximately linearly
grows with the times of the with the times of the
.B .B
probes probes
parameter and the number of different mask parameters in the hash. parameter and the number of different mask parameters in the hash.
@@ -374,8 +372,7 @@ store up to 65536 (B-class network) IP addresses with all possible port
values. When adding, deleting and testing values in an ipporthash type of values. When adding, deleting and testing values in an ipporthash type of
set, the entries must be specified as set, the entries must be specified as
.B .B
"IP:port". "IP,port".
(Old "IP%port" format accepted as well.)
.P .P
The ipporthash types of sets evaluates two src/dst parameters of the The ipporthash types of sets evaluates two src/dst parameters of the
.I .I
@@ -411,6 +408,94 @@ number of double-hashing.
.P .P
The same resizing, speed and memory efficiency comments applies here The same resizing, speed and memory efficiency comments applies here
as at the iphash type. as at the iphash type.
.SS ipportiphash
The ipportiphash set type uses a hash to store IP address,port and IP
address triples. The first IP address must come form a maximum /16
sized network or range while the port number and the second IP address
parameters are arbitrary. When adding, deleting and testing values in an
ipportiphash type of set, the entries must be specified as
.B
"IP,port,IP".
.P
The ipportiphash types of sets evaluates three src/dst parameters of the
.I
set
match and
.I
SET
target.
.P
Options to use when creating an ipportiphash set:
.TP
.BR "--from " from-IP
.TP
.BR "--to " to-IP
Create an ipportiphash set from the specified range.
.TP
.BR "--network " IP/mask
Create an ipportiphash set from the specified network.
.TP
.BR "--hashsize " hashsize
The initial hash size (default 1024)
.TP
.BR "--probes " probes
How many times try to resolve clashing at adding an IP to the hash
by double-hashing (default 8).
.TP
.BR "--resize " percent
Increase the hash size by this many percent (default 50) when adding
an IP to the hash could not be performed after
.B
probes
number of double-hashing.
.P
The same resizing, speed and memory efficiency comments applies here
as at the iphash type.
.SS ipportnethash
The ipportnethash set type uses a hash to store IP address, port, and
network address triples. The IP address must come form a maximum /16
sized network or range while the port number and the network address
parameters are arbitrary, but the size of the network address must be
between /1-/31. When adding, deleting
and testing values in an ipportnethash type of set, the entries must be
specified as
.B
"IP,port,IP/cidr-size".
.P
The ipportnethash types of sets evaluates three src/dst parameters of the
.I
set
match and
.I
SET
target.
.P
Options to use when creating an ipportnethash set:
.TP
.BR "--from " from-IP
.TP
.BR "--to " to-IP
Create an ipporthash set from the specified range.
.TP
.BR "--network " IP/mask
Create an ipporthash set from the specified network.
.TP
.BR "--hashsize " hashsize
The initial hash size (default 1024)
.TP
.BR "--probes " probes
How many times try to resolve clashing at adding an IP to the hash
by double-hashing (default 8).
.TP
.BR "--resize " percent
Increase the hash size by this many percent (default 50) when adding
an IP to the hash could not be performed after
.B
probes
number of double-hashing.
.P
The same resizing, speed and memory efficiency comments applies here
as at the iphash type.
.SS iptree .SS iptree
The iptree set type uses a tree to store IP addresses, optionally The iptree set type uses a tree to store IP addresses, optionally
with timeout values. with timeout values.
@@ -424,7 +509,7 @@ If a set was created with a nonzero valued
.B "--timeout" .B "--timeout"
parameter then one may add IP addresses to the set with a specific parameter then one may add IP addresses to the set with a specific
timeout value using the syntax timeout value using the syntax
.I IP:timeout-value. .I IP,timeout-value.
Similarly to the hash types, the iptree type of sets can store up to 65536 Similarly to the hash types, the iptree type of sets can store up to 65536
entries. entries.
.SS iptreemap .SS iptreemap
@@ -432,12 +517,67 @@ The iptreemap set type uses a tree to store IP addresses or networks,
where the last octet of an IP address are stored in a bitmap. where the last octet of an IP address are stored in a bitmap.
As input entry, you can add IP addresses, CIDR blocks or network ranges As input entry, you can add IP addresses, CIDR blocks or network ranges
to the set. Network ranges can be specified in the format to the set. Network ranges can be specified in the format
.I IP1:IP2 .I IP1-IP2
.P .P
Options to use when creating an iptreemap set: Options to use when creating an iptreemap set:
.TP .TP
.BR "--gc " value .BR "--gc " value
How often the garbage collection should be called, in seconds (default 300) How often the garbage collection should be called, in seconds (default 300)
.SS setlist
The setlist type uses a simple list in which you can store sets. By the
.I
ipset
command you can add, delete and test sets in a setlist type of set.
You can specify the sets as
.B
"setname[,after|before,setname]".
By default new sets are added after (appended to) the existing
elements. Setlist type of sets cannot be added to a setlist type of set.
.P
Options to use when creating a setlist type of set:
.TP
.BR "--size " size
Create a setlist type of set with the given size (default 8).
.P
By the
.I
set
match or
.I
SET
target of
.I
iptables
you can test, add or delete entries in the sets. The match
will try to find a matching IP address/port in the sets and
the target will try to add the IP address/port to the first set
to which it can be added. The number of src,dst options of
the match and target are important: sets which eats more src,dst
parameters than specified are skipped, while sets with equal
or less parameters are checked, elements added. For example
if
.I
a
and
.I
b
are setlist type of sets then in the command
.TP
iptables -m set --match-set a src,dst -j SET --add-set b src,dst
the match and target will skip any set in
.I a
and
.I b
which stores
data triples, but will check all sets with single or double
data storage in
.I a
set and add src to the first single or src,dst to the first double
data storage set in
.I b.
.P
You can imagine a setlist type of set as an ordered union of
the set elements.
.SH GENERAL RESTRICTIONS .SH GENERAL RESTRICTIONS
Setnames starting with colon (:) cannot be defined. Zero valued set Setnames starting with colon (:) cannot be defined. Zero valued set
entries cannot be used with hash type of sets. entries cannot be used with hash type of sets.
@@ -447,6 +587,8 @@ If you want to store same size subnets from a given network
If you want to store random same size networks (say random /24 blocks), If you want to store random same size networks (say random /24 blocks),
use the iphash set type. If you have got random size of netblocks, use the iphash set type. If you have got random size of netblocks,
use nethash. use nethash.
.P
Old separator tokens (':' and '%") are still accepted.
.SH DIAGNOSTICS .SH DIAGNOSTICS
Various error messages are printed to standard error. The exit code Various error messages are printed to standard error. The exit code
is 0 for correct functioning. Errors which appear to be caused by is 0 for correct functioning. Errors which appear to be caused by
@@ -463,8 +605,4 @@ Joakim Axelsson, Patrick Schaaf and Martin Josefsson.
.P .P
Sven Wegener wrote the iptreemap type. Sven Wegener wrote the iptreemap type.
.SH LAST REMARK .SH LAST REMARK
.BR "I stand on the shoulder of giants." .BR "I stand on the shoulders of giants."
.\" .. and did I mention that we are incredibly cool people?
.\" .. sexy, too ..
.\" .. witty, charming, powerful ..
.\" .. and most of all, modest ..

View File

@@ -7,23 +7,22 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#include <stdio.h> #include <stdio.h> /* *printf, perror, sscanf, fdopen */
#include <string.h> #include <string.h> /* mem*, str* */
#include <errno.h> #include <errno.h> /* errno, perror */
#include <time.h> #include <time.h> /* time, ctime */
#include <ctype.h> #include <netdb.h> /* gethostby*, getnetby*, getservby* */
#include <stdlib.h> #include <stdlib.h> /* exit, malloc, free, strtol, getenv, mkstemp */
#include <unistd.h> #include <unistd.h> /* read, close, fork, exec*, unlink */
#include <sys/socket.h> #include <sys/types.h> /* open, wait, socket, *sockopt, umask */
#include <sys/types.h> #include <sys/stat.h> /* open, umask */
#include <sys/stat.h> #include <sys/wait.h> /* wait */
#include <sys/wait.h> #include <sys/socket.h> /* socket, *sockopt, gethostby*, inet_* */
#include <arpa/inet.h> #include <netinet/in.h> /* inet_* */
#include <stdarg.h> #include <fcntl.h> /* open */
#include <netdb.h> #include <arpa/inet.h> /* htonl, inet_* */
#include <dlfcn.h> #include <stdarg.h> /* va_* */
#include <fcntl.h> #include <dlfcn.h> /* dlopen */
/* #include <asm/bitops.h> */
#include "ipset.h" #include "ipset.h"
@@ -31,11 +30,11 @@
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
#endif #endif
#define IPSET_VERSION "2.3.2a" #define IPSET_VERSION "3.2"
char program_name[] = "ipset"; char program_name[] = "ipset";
char program_version[] = IPSET_VERSION; char program_version[] = IPSET_VERSION;
const char *xtables_libdir = XTABLES_LIBDIR; const char *ipset_libdir = IPSET_LIB_DIR;
/* The list of loaded set types */ /* The list of loaded set types */
static struct settype *all_settypes = NULL; static struct settype *all_settypes = NULL;
@@ -53,7 +52,8 @@ void *restore_data = NULL;
struct ip_set_restore *restore_set = NULL; struct ip_set_restore *restore_set = NULL;
size_t restore_offset = 0; size_t restore_offset = 0;
socklen_t restore_size; socklen_t restore_size;
unsigned int g_line = 0; unsigned restore_line = 0;
unsigned warn_once = 0;
#define TEMPFILE_PATTERN "/ipsetXXXXXX" #define TEMPFILE_PATTERN "/ipsetXXXXXX"
@@ -78,9 +78,10 @@ static const char cmdflags[] = { ' ', /* CMD_NONE */
#define OPT_QUIET 0x0004U /* -q */ #define OPT_QUIET 0x0004U /* -q */
#define OPT_DEBUG 0x0008U /* -z */ #define OPT_DEBUG 0x0008U /* -z */
#define OPT_BINDING 0x0010U /* -b */ #define OPT_BINDING 0x0010U /* -b */
#define NUMBER_OF_OPT 5 #define OPT_RESOLVE 0x0020U /* -r */
#define NUMBER_OF_OPT 6
static const char optflags[] = static const char optflags[] =
{ 'n', 's', 'q', 'z', 'b' }; { 'n', 's', 'q', 'z', 'b', 'r' };
static struct option opts_long[] = { static struct option opts_long[] = {
/* set operations */ /* set operations */
@@ -108,6 +109,7 @@ static struct option opts_long[] = {
{"sorted", 0, 0, 's'}, {"sorted", 0, 0, 's'},
{"quiet", 0, 0, 'q'}, {"quiet", 0, 0, 'q'},
{"binding", 1, 0, 'b'}, {"binding", 1, 0, 'b'},
{"resolve", 0, 0, 'r'},
#ifdef IPSET_DEBUG #ifdef IPSET_DEBUG
/* debug (if compiled with it) */ /* debug (if compiled with it) */
@@ -119,11 +121,11 @@ static struct option opts_long[] = {
{"help", 2, 0, 'H'}, {"help", 2, 0, 'H'},
/* end */ /* end */
{0} {NULL},
}; };
static char opts_short[] = static char opts_short[] =
"-N:X::F::E:W:L::S::RA:D:T:B:U:nsqzb:Vh::H::"; "-N:X::F::E:W:L::S::RA:D:T:B:U:nrsqzb:Vh::H::";
/* Table of legal combinations of commands and options. If any of the /* Table of legal combinations of commands and options. If any of the
* given commands make an option legal, that option is legal. * given commands make an option legal, that option is legal.
@@ -135,21 +137,21 @@ static char opts_short[] =
static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = {
/* -n -s -q -z -b */ /* -n -s -q -z -b */
/*CREATE*/ {'x', 'x', ' ', ' ', 'x'}, /*CREATE*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*DESTROY*/ {'x', 'x', ' ', ' ', 'x'}, /*DESTROY*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*FLUSH*/ {'x', 'x', ' ', ' ', 'x'}, /*FLUSH*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*RENAME*/ {'x', 'x', ' ', ' ', 'x'}, /*RENAME*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*SWAP*/ {'x', 'x', ' ', ' ', 'x'}, /*SWAP*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*LIST*/ {' ', ' ', 'x', ' ', 'x'}, /*LIST*/ {' ', ' ', 'x', ' ', 'x', ' '},
/*SAVE*/ {'x', 'x', ' ', ' ', 'x'}, /*SAVE*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*RESTORE*/ {'x', 'x', ' ', ' ', 'x'}, /*RESTORE*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*ADD*/ {'x', 'x', ' ', ' ', 'x'}, /*ADD*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*DEL*/ {'x', 'x', ' ', ' ', 'x'}, /*DEL*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*TEST*/ {'x', 'x', ' ', ' ', ' '}, /*TEST*/ {'x', 'x', ' ', ' ', ' ', 'x'},
/*BIND*/ {'x', 'x', ' ', ' ', '+'}, /*BIND*/ {'x', 'x', ' ', ' ', '+', 'x'},
/*UNBIND*/ {'x', 'x', ' ', ' ', 'x'}, /*UNBIND*/ {'x', 'x', ' ', ' ', 'x', 'x'},
/*HELP*/ {'x', 'x', 'x', ' ', 'x'}, /*HELP*/ {'x', 'x', 'x', ' ', 'x', 'x'},
/*VERSION*/ {'x', 'x', 'x', ' ', 'x'}, /*VERSION*/ {'x', 'x', 'x', ' ', 'x', 'x'},
}; };
/* Main parser function */ /* Main parser function */
@@ -163,18 +165,18 @@ static void exit_tryhelp(int status)
exit(status); exit(status);
} }
void exit_error(enum exittype status, const char *msg, ...) void exit_error(int status, const char *msg, ...)
{ {
if (!option_quiet) {
va_list args; va_list args;
if (!option_quiet) {
va_start(args, msg); va_start(args, msg);
fprintf(stderr, "%s v%s: ", program_name, program_version); fprintf(stderr, "%s v%s: ", program_name, program_version);
vfprintf(stderr, msg, args); vfprintf(stderr, msg, args);
va_end(args); va_end(args);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
if (g_line) if (restore_line)
fprintf(stderr, "Restore failed at line %u:\n", g_line); fprintf(stderr, "Restore failed at line %u:\n", restore_line);
if (status == PARAMETER_PROBLEM) if (status == PARAMETER_PROBLEM)
exit_tryhelp(status); exit_tryhelp(status);
if (status == VERSION_PROBLEM) if (status == VERSION_PROBLEM)
@@ -188,9 +190,9 @@ void exit_error(enum exittype status, const char *msg, ...)
static void ipset_printf(const char *msg, ...) static void ipset_printf(const char *msg, ...)
{ {
if (!option_quiet) {
va_list args; va_list args;
if (!option_quiet) {
va_start(args, msg); va_start(args, msg);
vfprintf(stdout, msg, args); vfprintf(stdout, msg, args);
va_end(args); va_end(args);
@@ -198,7 +200,7 @@ static void ipset_printf(const char *msg, ...)
} }
} }
static void generic_opt_check(int command, int options) static void generic_opt_check(int command, unsigned int options)
{ {
int i, j, legal = 0; int i, j, legal = 0;
@@ -233,7 +235,7 @@ static void generic_opt_check(int command, int options)
} }
} }
static char opt2char(int option) static char opt2char(unsigned int option)
{ {
const char *ptr; const char *ptr;
for (ptr = optflags; option > 1; option >>= 1, ptr++); for (ptr = optflags; option > 1; option >>= 1, ptr++);
@@ -241,12 +243,12 @@ static char opt2char(int option)
return *ptr; return *ptr;
} }
static char cmd2char(int option) static char cmd2char(int cmd)
{ {
if (option <= CMD_NONE || option > NUMBER_OF_CMD) if (cmd <= CMD_NONE || cmd > NUMBER_OF_CMD)
return ' '; return ' ';
return cmdflags[option]; return cmdflags[cmd];
} }
/* From iptables.c ... */ /* From iptables.c ... */
@@ -266,6 +268,7 @@ static char *get_modprobe(void)
switch (read(procfile, ret, PROCFILE_BUFSIZ)) { switch (read(procfile, ret, PROCFILE_BUFSIZ)) {
case -1: goto fail; case -1: goto fail;
case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */ case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */
default: ; /* nothing */
} }
if (ret[strlen(ret)-1]=='\n') if (ret[strlen(ret)-1]=='\n')
ret[strlen(ret)-1]=0; ret[strlen(ret)-1]=0;
@@ -334,7 +337,7 @@ static void kernel_error(unsigned cmd, int err)
struct translate_error { struct translate_error {
int err; int err;
unsigned cmd; unsigned cmd;
char *message; const char *message;
} table[] = } table[] =
{ /* Generic error codes */ { /* Generic error codes */
{ EPERM, 0, "Missing capability" }, { EPERM, 0, "Missing capability" },
@@ -352,11 +355,12 @@ static void kernel_error(unsigned cmd, int err)
{ ENOENT, 0, "Unknown set" }, { ENOENT, 0, "Unknown set" },
{ EAGAIN, 0, "Sets are busy, try again later" }, { EAGAIN, 0, "Sets are busy, try again later" },
{ ERANGE, CMD_CREATE, "No free slot remained to add a new set" }, { ERANGE, CMD_CREATE, "No free slot remained to add a new set" },
{ ERANGE, 0, "IP/port is outside of the set" }, { ERANGE, 0, "IP/port/element is outside of the set or set is full" },
{ ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" }, { ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" },
{ ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" }, { ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" },
{ EEXIST, CMD_CREATE, "Set already exists" }, { EEXIST, CMD_CREATE, "Set already exists" },
{ EEXIST, CMD_RENAME, "Set with new name already exists" }, { EEXIST, CMD_RENAME, "Set with new name already exists" },
{ EEXIST, 0, "Set specified as element does not exist" },
{ EBUSY, 0, "Set is in use, operation not permitted" }, { EBUSY, 0, "Set is in use, operation not permitted" },
}; };
for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) { for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) {
@@ -409,7 +413,7 @@ static void kernel_getfrom(unsigned cmd, void *data, socklen_t * size)
kernel_error(cmd, errno); kernel_error(cmd, errno);
} }
static int kernel_sendto_handleerrno(unsigned cmd, unsigned op, static int kernel_sendto_handleerrno(unsigned cmd,
void *data, socklen_t size) void *data, socklen_t size)
{ {
int res = wrapped_setsockopt(data, size); int res = wrapped_setsockopt(data, size);
@@ -432,7 +436,7 @@ static void kernel_sendto(unsigned cmd, void *data, size_t size)
kernel_error(cmd, errno); kernel_error(cmd, errno);
} }
static int kernel_getfrom_handleerrno(unsigned cmd, void *data, size_t * size) static int kernel_getfrom_handleerrno(unsigned cmd, void *data, socklen_t *size)
{ {
int res = wrapped_getsockopt(data, size); int res = wrapped_getsockopt(data, size);
@@ -471,7 +475,7 @@ static void check_protocolversion(void)
req_version.version, IP_SET_PROTOCOL_VERSION); req_version.version, IP_SET_PROTOCOL_VERSION);
} }
static void set_command(unsigned *cmd, const int newcmd) static void set_command(int *cmd, int newcmd)
{ {
if (*cmd != CMD_NONE) if (*cmd != CMD_NONE)
exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n", exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n",
@@ -513,18 +517,17 @@ char *ipset_strdup(const char *s)
return p; return p;
} }
void ipset_free(void **data) void ipset_free(void *data)
{ {
if (*data == NULL) if (data == NULL)
return; return;
free(*data); free(data);
*data = NULL;
} }
static struct option *merge_options(struct option *oldopts, static struct option *merge_options(struct option *oldopts,
const struct option *newopts, const struct option *newopts,
unsigned int *option_offset) int *option_offset)
{ {
unsigned int num_old, num_new, i; unsigned int num_old, num_new, i;
struct option *merge; struct option *merge;
@@ -564,7 +567,7 @@ static char *ip_tonetwork(const struct in_addr *addr)
{ {
struct netent *net; struct netent *net;
if ((net = getnetbyaddr((long) ntohl(addr->s_addr), if ((net = getnetbyaddr(ntohl(addr->s_addr),
AF_INET)) != NULL) { AF_INET)) != NULL) {
DP("%s", net->n_name); DP("%s", net->n_name);
return (char *) net->n_name; return (char *) net->n_name;
@@ -591,7 +594,8 @@ char *ip_tostring(ip_set_ip_t ip, unsigned options)
return inet_ntoa(addr); return inet_ntoa(addr);
} }
char *binding_ip_tostring(struct set *set, ip_set_ip_t ip, unsigned options) char *binding_ip_tostring(struct set *set UNUSED,
ip_set_ip_t ip, unsigned options)
{ {
return ip_tostring(ip, options); return ip_tostring(ip, options);
} }
@@ -625,7 +629,8 @@ void parse_ip(const char *str, ip_set_ip_t * ip)
"host/network `%s' resolves to serveral ip-addresses. " "host/network `%s' resolves to serveral ip-addresses. "
"Please specify one.", str); "Please specify one.", str);
*ip = ntohl(((struct in_addr *) host->h_addr_list[0])->s_addr); memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr));
*ip = ntohl(addr.s_addr);
return; return;
} }
@@ -636,7 +641,7 @@ void parse_ip(const char *str, ip_set_ip_t * ip)
void parse_mask(const char *str, ip_set_ip_t * mask) void parse_mask(const char *str, ip_set_ip_t * mask)
{ {
struct in_addr addr; struct in_addr addr;
unsigned int bits; int bits;
DP("%s", str); DP("%s", str);
@@ -711,12 +716,12 @@ int
string_to_number(const char *str, unsigned int min, unsigned int max, string_to_number(const char *str, unsigned int min, unsigned int max,
ip_set_ip_t *port) ip_set_ip_t *port)
{ {
long number; unsigned long number;
char *end; char *end;
/* Handle hex, octal, etc. */ /* Handle hex, octal, etc. */
errno = 0; errno = 0;
number = strtol(str, &end, 0); number = strtoul(str, &end, 0);
if (*end == '\0' && end != str) { if (*end == '\0' && end != str) {
/* we parsed a number, let's see if we want this */ /* we parsed a number, let's see if we want this */
if (errno != ERANGE && min <= number && number <= max) { if (errno != ERANGE && min <= number && number <= max) {
@@ -733,10 +738,9 @@ string_to_port(const char *str, ip_set_ip_t *port)
struct servent *service; struct servent *service;
if ((service = getservbyname(str, "tcp")) != NULL) { if ((service = getservbyname(str, "tcp")) != NULL) {
*port = ntohs((unsigned short) service->s_port); *port = ntohs((uint16_t) service->s_port);
return 0; return 0;
} }
return -1; return -1;
} }
@@ -771,7 +775,8 @@ static struct settype *settype_find(const char *typename)
static struct settype *settype_load(const char *typename) static struct settype *settype_load(const char *typename)
{ {
char path[256]; char path[sizeof(IPSET_LIB_DIR) + sizeof(IPSET_LIB_NAME) +
strlen(typename)];
struct settype *settype; struct settype *settype;
/* do some search in list */ /* do some search in list */
@@ -780,8 +785,7 @@ static struct settype *settype_load(const char *typename)
return settype; /* found */ return settype; /* found */
/* Else we have to load it */ /* Else we have to load it */
snprintf(path, sizeof(path), "%s/libipset_%s.so", sprintf(path, IPSET_LIB_DIR IPSET_LIB_NAME, typename);
xtables_libdir, typename);
if (dlopen(path, RTLD_NOW)) { if (dlopen(path, RTLD_NOW)) {
/* Found library. */ /* Found library. */
@@ -859,7 +863,7 @@ void settype_register(struct settype *settype)
} }
/* Find set functions */ /* Find set functions */
static struct set *set_find_byid(ip_set_id_t id) struct set *set_find_byid(ip_set_id_t id)
{ {
struct set *set = NULL; struct set *set = NULL;
ip_set_id_t i; ip_set_id_t i;
@@ -876,7 +880,7 @@ static struct set *set_find_byid(ip_set_id_t id)
return set; return set;
} }
static struct set *set_find_byname(const char *name) struct set *set_find_byname(const char *name)
{ {
struct set *set = NULL; struct set *set = NULL;
ip_set_id_t i; ip_set_id_t i;
@@ -1137,6 +1141,11 @@ static size_t save_bindings(void *data, size_t offset, size_t len)
if (!(set && set_list[hash->binding])) if (!(set && set_list[hash->binding]))
exit_error(OTHER_PROBLEM, exit_error(OTHER_PROBLEM,
"Save binding failed, try again later."); "Save binding failed, try again later.");
if (!set->settype->bindip_tostring)
exit_error(OTHER_PROBLEM,
"Internal error, binding is not supported with set %s"
" of settype %s\n",
set->name, set->settype->typename);
printf("-B %s %s -b %s\n", printf("-B %s %s -b %s\n",
set->name, set->name,
set->settype->bindip_tostring(set, hash->ip, OPT_NUMERIC), set->settype->bindip_tostring(set, hash->ip, OPT_NUMERIC),
@@ -1263,7 +1272,7 @@ static int try_save_sets(const char name[IP_SET_MAXNAMELEN])
printf("COMMIT\n"); printf("COMMIT\n");
now = time(NULL); now = time(NULL);
printf("# Completed on %s", ctime(&now)); printf("# Completed on %s", ctime(&now));
ipset_free(&data); ipset_free(data);
return res; return res;
} }
@@ -1297,7 +1306,7 @@ static char *newargv[255];
static int newargc = 0; static int newargc = 0;
/* Build faked argv from parsed line */ /* Build faked argv from parsed line */
static void build_argv(int line, char *buffer) { static void build_argv(unsigned line, char *buffer) {
char *ptr; char *ptr;
int i; int i;
@@ -1309,7 +1318,7 @@ static void build_argv(int line, char *buffer) {
ptr = strtok(buffer, " \t\n"); ptr = strtok(buffer, " \t\n");
newargv[newargc++] = ipset_strdup(ptr); newargv[newargc++] = ipset_strdup(ptr);
while ((ptr = strtok(NULL, " \t\n")) != NULL) { while ((ptr = strtok(NULL, " \t\n")) != NULL) {
if ((newargc + 1) < sizeof(newargv)/sizeof(char *)) if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
newargv[newargc++] = ipset_strdup(ptr); newargv[newargc++] = ipset_strdup(ptr);
else else
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
@@ -1319,14 +1328,14 @@ static void build_argv(int line, char *buffer) {
static FILE *create_tempfile(void) static FILE *create_tempfile(void)
{ {
char buffer[1024]; char buffer[1024], __tmpdir[] = "/tmp";
char *tmpdir = NULL; char *tmpdir = NULL;
char *filename; char *filename;
int fd; int fd;
FILE *file; FILE *file;
if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP"))) if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP")))
tmpdir = "/tmp"; tmpdir = __tmpdir;
filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1); filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1);
strcpy(filename, tmpdir); strcpy(filename, tmpdir);
strcat(filename, TEMPFILE_PATTERN); strcat(filename, TEMPFILE_PATTERN);
@@ -1357,7 +1366,7 @@ static void set_restore(char *argv0)
char buffer[1024]; char buffer[1024];
char *ptr, *name = NULL; char *ptr, *name = NULL;
char cmd = ' '; char cmd = ' ';
int line = 0, first_pass, i, bindings = 0; int first_pass, i, bindings = 0;
struct settype *settype = NULL; struct settype *settype = NULL;
struct ip_set_req_setnames *header; struct ip_set_req_setnames *header;
ip_set_id_t idx; ip_set_id_t idx;
@@ -1371,12 +1380,13 @@ static void set_restore(char *argv0)
load_set_list(IPSET_TOKEN_ALL, &idx, load_set_list(IPSET_TOKEN_ALL, &idx,
IP_SET_OP_LIST_SIZE, CMD_RESTORE); IP_SET_OP_LIST_SIZE, CMD_RESTORE);
restore_line = 0;
restore_size = sizeof(struct ip_set_req_setnames)/* header */ restore_size = sizeof(struct ip_set_req_setnames)/* header */
+ sizeof(struct ip_set_restore); /* marker */ + sizeof(struct ip_set_restore); /* marker */
DP("restore_size: %u", restore_size); DP("restore_size: %u", restore_size);
/* First pass: calculate required amount of data */ /* First pass: calculate required amount of data */
while (fgets(buffer, sizeof(buffer), in)) { while (fgets(buffer, sizeof(buffer), in)) {
line++; restore_line++;
if (buffer[0] == '\n') if (buffer[0] == '\n')
continue; continue;
@@ -1399,7 +1409,7 @@ static void set_restore(char *argv0)
|| ptr[2] != '\0') { || ptr[2] != '\0') {
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Line %u does not start as a valid restore command\n", "Line %u does not start as a valid restore command\n",
line); restore_line);
} }
cmd = ptr[1]; cmd = ptr[1];
/* setname */ /* setname */
@@ -1408,7 +1418,7 @@ static void set_restore(char *argv0)
if (ptr == NULL) if (ptr == NULL)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Missing set name in line %u\n", "Missing set name in line %u\n",
line); restore_line);
DP("cmd %c", cmd); DP("cmd %c", cmd);
switch (cmd) { switch (cmd) {
case 'N': { case 'N': {
@@ -1418,11 +1428,11 @@ static void set_restore(char *argv0)
if (ptr == NULL) if (ptr == NULL)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Missing settype in line %u\n", "Missing settype in line %u\n",
line); restore_line);
if (bindings) if (bindings)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Invalid line %u: create must precede bindings\n", "Invalid line %u: create must precede bindings\n",
line); restore_line);
settype = check_set_typename(ptr); settype = check_set_typename(ptr);
restore_size += sizeof(struct ip_set_restore) restore_size += sizeof(struct ip_set_restore)
+ settype->create_size; + settype->create_size;
@@ -1435,11 +1445,11 @@ static void set_restore(char *argv0)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Add IP to set %s in line %u without " "Add IP to set %s in line %u without "
"preceding corresponding create set line\n", "preceding corresponding create set line\n",
ptr, line); ptr, restore_line);
if (bindings) if (bindings)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Invalid line %u: adding entries must precede bindings\n", "Invalid line %u: adding entries must precede bindings\n",
line); restore_line);
restore_size += settype->adt_size; restore_size += settype->adt_size;
DP("restore_size (A): %u", restore_size); DP("restore_size (A): %u", restore_size);
break; break;
@@ -1453,7 +1463,7 @@ static void set_restore(char *argv0)
default: { default: {
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Unrecognized restore command in line %u\n", "Unrecognized restore command in line %u\n",
line); restore_line);
} }
} /* end of switch */ } /* end of switch */
} }
@@ -1470,15 +1480,15 @@ static void set_restore(char *argv0)
/* Rewind to scan the file again */ /* Rewind to scan the file again */
fseek(in, 0L, SEEK_SET); fseek(in, 0L, SEEK_SET);
first_pass = line; first_pass = restore_line;
line = 0; restore_line = 0;
/* Initialize newargv/newargc */ /* Initialize newargv/newargc */
newargv[newargc++] = ipset_strdup(argv0); newargv[newargc++] = ipset_strdup(argv0);
/* Second pass: build up restore request */ /* Second pass: build up restore request */
while (fgets(buffer, sizeof(buffer), in)) { while (fgets(buffer, sizeof(buffer), in)) {
line++; restore_line++;
if (buffer[0] == '\n') if (buffer[0] == '\n')
continue; continue;
@@ -1488,7 +1498,7 @@ static void set_restore(char *argv0)
goto do_restore; goto do_restore;
DP("restoring: %s", buffer); DP("restoring: %s", buffer);
/* Build faked argv, argc */ /* Build faked argv, argc */
build_argv(line, buffer); build_argv(restore_line, buffer);
for (i = 0; i < newargc; i++) for (i = 0; i < newargc; i++)
DP("argv[%u]: %s", i, newargv[i]); DP("argv[%u]: %s", i, newargv[i]);
@@ -1570,7 +1580,7 @@ static int set_adtip(struct set *set, const char *adt,
/* Alloc memory for the data to send */ /* Alloc memory for the data to send */
size = sizeof(struct ip_set_req_adt) + set->settype->adt_size ; size = sizeof(struct ip_set_req_adt) + set->settype->adt_size ;
DP("alloc size %i", size); DP("alloc size %d", size);
data = ipset_malloc(size); data = ipset_malloc(size);
/* Fill out the request */ /* Fill out the request */
@@ -1580,7 +1590,7 @@ static int set_adtip(struct set *set, const char *adt,
memcpy(data + sizeof(struct ip_set_req_adt), memcpy(data + sizeof(struct ip_set_req_adt),
set->settype->data, set->settype->adt_size); set->settype->data, set->settype->adt_size);
if (kernel_sendto_handleerrno(cmd, op, data, size) == -1) if (kernel_sendto_handleerrno(cmd, data, size) == -1)
switch (op) { switch (op) {
case IP_SET_OP_ADD_IP: case IP_SET_OP_ADD_IP:
exit_error(OTHER_PROBLEM, "%s is already in set %s.", exit_error(OTHER_PROBLEM, "%s is already in set %s.",
@@ -1611,7 +1621,7 @@ static int set_adtip(struct set *set, const char *adt,
return res; return res;
} }
static void set_restore_add(struct set *set, const char *adt) static void set_restore_add(struct set *set, const char *adt UNUSED)
{ {
DP("%s %s", set->name, adt); DP("%s %s", set->name, adt);
/* Sanity checking */ /* Sanity checking */
@@ -1641,9 +1651,14 @@ static int set_bind(struct set *set, const char *adt,
DP("(%s, %s) -> %s", set ? set->name : IPSET_TOKEN_ALL, adt, binding); DP("(%s, %s) -> %s", set ? set->name : IPSET_TOKEN_ALL, adt, binding);
/* Ugly */ /* Ugly */
if (set && strcmp(set->settype->typename, "iptreemap") == 0) if (set != NULL
&& ((strcmp(set->settype->typename, "iptreemap") == 0)
|| (strcmp(set->settype->typename, "ipportiphash") == 0)
|| (strcmp(set->settype->typename, "ipportnethash") == 0)
|| (strcmp(set->settype->typename, "setlist") == 0)))
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"iptreemap type of sets cannot be used at binding operations\n"); "%s type of sets cannot be used at binding operations\n",
set->settype->typename);
/* Alloc memory for the data to send */ /* Alloc memory for the data to send */
size = sizeof(struct ip_set_req_bind); size = sizeof(struct ip_set_req_bind);
if (op != IP_SET_OP_UNBIND_SET && adt[0] == ':') if (op != IP_SET_OP_UNBIND_SET && adt[0] == ':')
@@ -1651,7 +1666,7 @@ static int set_bind(struct set *set, const char *adt,
size += IP_SET_MAXNAMELEN; size += IP_SET_MAXNAMELEN;
else if (!(op == IP_SET_OP_UNBIND_SET && set == NULL)) else if (!(op == IP_SET_OP_UNBIND_SET && set == NULL))
size += set->settype->adt_size; size += set->settype->adt_size;
DP("alloc size %i", size); DP("alloc size %d", size);
data = ipset_malloc(size); data = ipset_malloc(size);
/* Fill out the request */ /* Fill out the request */
@@ -1671,7 +1686,7 @@ static int set_bind(struct set *set, const char *adt,
} }
if (op == IP_SET_OP_TEST_BIND_SET) { if (op == IP_SET_OP_TEST_BIND_SET) {
if (kernel_sendto_handleerrno(cmd, op, data, size) == -1) { if (kernel_sendto_handleerrno(cmd, data, size) == -1) {
ipset_printf("%s in set %s is bound to %s.", ipset_printf("%s in set %s is bound to %s.",
adt, set->name, binding); adt, set->name, binding);
res = 0; res = 0;
@@ -1717,8 +1732,14 @@ static void set_restore_bind(struct set *set,
DP("%s -> %s", adt, binding); DP("%s -> %s", adt, binding);
if (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0) if (strcmp(adt, IPSET_TOKEN_DEFAULT) == 0)
hash_restore->ip = 0; hash_restore->ip = 0;
else else {
if (!set->settype->bindip_parse)
exit_error(OTHER_PROBLEM,
"Internal error, binding is not supported with set %s"
" of settype %s\n",
set->name, set->settype->typename);
set->settype->bindip_parse(adt, &hash_restore->ip); set->settype->bindip_parse(adt, &hash_restore->ip);
}
hash_restore->id = set->index; hash_restore->id = set->index;
hash_restore->binding = (set_find_byname(binding))->index; hash_restore->binding = (set_find_byname(binding))->index;
DP("id %u, ip %u, binding %u", DP("id %u, ip %u, binding %u",
@@ -1738,6 +1759,12 @@ static void print_bindings(struct set *set,
size_t offset = 0; size_t offset = 0;
struct ip_set_hash_list *hash; struct ip_set_hash_list *hash;
if (offset < size && !printip)
exit_error(OTHER_PROBLEM,
"Internal error, binding is not supported with set %s"
" of settype %s\n",
set->name, set->settype->typename);
while (offset < size) { while (offset < size) {
hash = (struct ip_set_hash_list *) (data + offset); hash = (struct ip_set_hash_list *) (data + offset);
printf("%s -> %s\n", printf("%s -> %s\n",
@@ -1750,7 +1777,7 @@ static void print_bindings(struct set *set,
/* Help function to set_list() */ /* Help function to set_list() */
static size_t print_set(void *data, unsigned options) static size_t print_set(void *data, unsigned options)
{ {
struct ip_set_list *setlist = (struct ip_set_list *) data; struct ip_set_list *setlist = data;
struct set *set = set_list[setlist->index]; struct set *set = set_list[setlist->index];
struct settype *settype = set->settype; struct settype *settype = set->settype;
size_t offset; size_t offset;
@@ -1784,6 +1811,7 @@ static size_t print_set(void *data, unsigned options)
/* Print bindings */ /* Print bindings */
printf("Bindings:\n"); printf("Bindings:\n");
offset += setlist->members_size; offset += setlist->members_size;
if (set->settype->bindip_tostring)
print_bindings(set, print_bindings(set,
data + offset, setlist->bindings_size, options, data + offset, setlist->bindings_size, options,
settype->bindip_tostring); settype->bindip_tostring);
@@ -1801,6 +1829,10 @@ static int try_list_sets(const char name[IP_SET_MAXNAMELEN],
socklen_t size, req_size; socklen_t size, req_size;
int res = 0; int res = 0;
/* Default is numeric listing */
if (!(options & (OPT_RESOLVE|OPT_NUMERIC)))
options |= OPT_NUMERIC;
DP("%s", name); DP("%s", name);
/* Load set_list from kernel */ /* Load set_list from kernel */
size = req_size = load_set_list(name, &idx, size = req_size = load_set_list(name, &idx,
@@ -1823,7 +1855,7 @@ static int try_list_sets(const char name[IP_SET_MAXNAMELEN],
while (size != req_size) while (size != req_size)
size += print_set(data + size, options); size += print_set(data + size, options);
ipset_free(&data); ipset_free(data);
return res; return res;
} }
@@ -1853,13 +1885,6 @@ static void list_sets(const char name[IP_SET_MAXNAMELEN], unsigned options)
*/ */
static void set_help(const struct settype *settype) static void set_help(const struct settype *settype)
{ {
#ifdef IPSET_DEBUG
char debughelp[] =
" --debug -z Enable debugging\n\n";
#else
char debughelp[] = "\n";
#endif
printf("%s v%s\n\n" printf("%s v%s\n\n"
"Usage: %s -N new-set settype [options]\n" "Usage: %s -N new-set settype [options]\n"
" %s -[XFLSH] [set] [options]\n" " %s -[XFLSH] [set] [options]\n"
@@ -1910,10 +1935,15 @@ static void set_help(const struct settype *settype)
" Prints version information\n\n" " Prints version information\n\n"
"Options:\n" "Options:\n"
" --sorted -s Numeric sort of the IPs in -L\n" " --sorted -s Numeric sort of the IPs in -L\n"
" --numeric -n Numeric output of addresses in a -L\n" " --numeric -n Numeric output of addresses in a -L (default)\n"
" --resolve -r Try to resolve addresses in a -L\n"
" --quiet -q Suppress any output to stdout and stderr.\n" " --quiet -q Suppress any output to stdout and stderr.\n"
" --binding -b Specifies the binding for -B\n"); " --binding -b Specifies the binding for -B\n");
printf(debughelp); #ifdef IPSET_DEBUG
printf(" --debug -z Enable debugging\n\n");
#else
printf("\n");
#endif
if (settype != NULL) { if (settype != NULL) {
printf("Type '%s' specific:\n", settype->typename); printf("Type '%s' specific:\n", settype->typename);
@@ -1921,7 +1951,7 @@ static void set_help(const struct settype *settype)
} }
} }
static int find_cmd(const char option) static int find_cmd(int option)
{ {
int i; int i;
@@ -1932,7 +1962,7 @@ static int find_cmd(const char option)
return CMD_NONE; return CMD_NONE;
} }
static int parse_adt_cmdline(unsigned command, static int parse_adt_cmdline(int command,
const char *name, const char *name,
char *adt, char *adt,
struct set **set, struct set **set,
@@ -1982,7 +2012,7 @@ static int parse_adt_cmdline(unsigned command,
int parse_commandline(int argc, char *argv[]) int parse_commandline(int argc, char *argv[])
{ {
int res = 0; int res = 0;
unsigned command = CMD_NONE; int command = CMD_NONE;
unsigned options = 0; unsigned options = 0;
int c; int c;
@@ -2146,6 +2176,11 @@ int parse_commandline(int argc, char *argv[])
add_option(&options, OPT_NUMERIC); add_option(&options, OPT_NUMERIC);
break; break;
case 'r':
if (!(options & OPT_NUMERIC))
add_option(&options, OPT_RESOLVE);
break;
case 's': case 's':
add_option(&options, OPT_SORTED); add_option(&options, OPT_SORTED);
break; break;
@@ -2169,7 +2204,7 @@ int parse_commandline(int argc, char *argv[])
case 1: /* non option */ case 1: /* non option */
printf("Bad argument `%s'\n", optarg); printf("Bad argument `%s'\n", optarg);
exit_tryhelp(2); exit_tryhelp(PARAMETER_PROBLEM);
break; /*always good */ break; /*always good */
default:{ default:{
@@ -2272,6 +2307,8 @@ int parse_commandline(int argc, char *argv[])
break; break;
case CMD_BIND: case CMD_BIND:
fprintf(stderr, "Warning: binding will be removed from the next release.\n"
"Please replace bindigs with sets of ipportmap and ipportiphash types\n");
if (restore) if (restore)
set_restore_bind(set, adt, binding); set_restore_bind(set, adt, binding);
else else
@@ -2299,11 +2336,6 @@ int parse_commandline(int argc, char *argv[])
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const char *p = getenv("XTABLES_LIBDIR");
if (p != NULL)
xtables_libdir = p;
return parse_commandline(argc, argv); return parse_commandline(argc, argv);
} }

View File

@@ -20,12 +20,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <getopt.h> #include <getopt.h> /* struct option */
#include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
#include <netdb.h>
#include "ip_set.h" #include "ip_set.h"
#define IPSET_LIB_NAME "/libipset_%s.so"
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
#define LIST_TRIES 5 #define LIST_TRIES 5
@@ -94,7 +95,7 @@ struct settype {
*/ */
/* Size of create data. Will be sent to kernel */ /* Size of create data. Will be sent to kernel */
size_t create_size; u_int32_t create_size;
/* Initialize the create. */ /* Initialize the create. */
void (*create_init) (void *data); void (*create_init) (void *data);
@@ -114,17 +115,17 @@ struct settype {
*/ */
/* Size of data. Will be sent to kernel */ /* Size of data. Will be sent to kernel */
size_t adt_size; u_int32_t adt_size;
/* Function which parses command options */ /* Function which parses command options */
ip_set_ip_t (*adt_parser) (unsigned cmd, const char *optarg, void *data); ip_set_ip_t (*adt_parser) (int cmd, const char *optarg, void *data);
/* /*
* Printing * Printing
*/ */
/* Size of header. */ /* Size of header. */
size_t header_size; u_int32_t header_size;
/* Initialize the type-header */ /* Initialize the type-header */
void (*initheader) (struct set *set, const void *data); void (*initheader) (struct set *set, const void *data);
@@ -133,16 +134,16 @@ struct settype {
void (*printheader) (struct set *set, unsigned options); void (*printheader) (struct set *set, unsigned options);
/* Pretty print all IPs */ /* Pretty print all IPs */
void (*printips) (struct set *set, void *data, size_t len, unsigned options); void (*printips) (struct set *set, void *data, u_int32_t len, unsigned options);
/* Pretty print all IPs sorted */ /* Pretty print all IPs sorted */
void (*printips_sorted) (struct set *set, void *data, size_t len, unsigned options); void (*printips_sorted) (struct set *set, void *data, u_int32_t len, unsigned options);
/* Print save arguments for creating the set */ /* Print save arguments for creating the set */
void (*saveheader) (struct set *set, unsigned options); void (*saveheader) (struct set *set, unsigned options);
/* Print save for all IPs */ /* Print save for all IPs */
void (*saveips) (struct set *set, void *data, size_t len, unsigned options); void (*saveips) (struct set *set, void *data, u_int32_t len, unsigned options);
/* Conver a single IP (binding) to string */ /* Conver a single IP (binding) to string */
char * (*bindip_tostring)(struct set *set, ip_set_ip_t ip, unsigned options); char * (*bindip_tostring)(struct set *set, ip_set_ip_t ip, unsigned options);
@@ -156,7 +157,7 @@ struct settype {
/* Internal data */ /* Internal data */
void *header; void *header;
void *data; void *data;
unsigned int option_offset; int option_offset;
unsigned int flags; unsigned int flags;
}; };
@@ -164,7 +165,7 @@ extern void settype_register(struct settype *settype);
/* extern void unregister_settype(set_type_t *set_type); */ /* extern void unregister_settype(set_type_t *set_type); */
extern void exit_error(enum exittype status, const char *msg, ...); extern void exit_error(int status, const char *msg, ...);
extern char *binding_ip_tostring(struct set *set, extern char *binding_ip_tostring(struct set *set,
ip_set_ip_t ip, unsigned options); ip_set_ip_t ip, unsigned options);
@@ -181,11 +182,24 @@ extern int string_to_number(const char *str, unsigned int min, unsigned int max,
extern void *ipset_malloc(size_t size); extern void *ipset_malloc(size_t size);
extern char *ipset_strdup(const char *); extern char *ipset_strdup(const char *);
extern void ipset_free(void **data); extern void ipset_free(void *data);
#define BITSPERBYTE (8*sizeof(char)) extern struct set *set_find_byname(const char *name);
#define ID2BYTE(id) ((id)/BITSPERBYTE) extern struct set *set_find_byid(ip_set_id_t id);
#define ID2MASK(id) (1 << ((id)%BITSPERBYTE))
#define test_bit(id, heap) ((((char *)(heap))[ID2BYTE(id)] & ID2MASK(id)) != 0) extern unsigned warn_once;
#define BITS_PER_LONG (8*sizeof(unsigned long))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
static inline int test_bit(int nr, const unsigned long *addr)
{
return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
}
#define UNUSED __attribute__ ((unused))
#define CONSTRUCTOR(module) \
void __attribute__ ((constructor)) module##_init(void); \
void module##_init(void)
#endif /* __IPSET_H */ #endif /* __IPSET_H */

View File

@@ -15,24 +15,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <errno.h> #include <limits.h> /* UINT_MAX */
#include <limits.h> #include <stdio.h> /* *printf */
#include <stdio.h> #include <string.h> /* mem* */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include "ip_set_iphash.h"
#include "ip_set_jhash.h"
#include "ipset.h" #include "ipset.h"
#include "ip_set_iphash.h"
#define BUFLEN 30; #define BUFLEN 30;
#define OPT_CREATE_HASHSIZE 0x01U #define OPT_CREATE_HASHSIZE 0x01U
@@ -41,10 +31,10 @@
#define OPT_CREATE_NETMASK 0x08U #define OPT_CREATE_NETMASK 0x08U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data)
{ {
struct ip_set_req_iphash_create *mydata = struct ip_set_req_iphash_create *mydata = data;
(struct ip_set_req_iphash_create *) data;
DP("create INIT"); DP("create INIT");
@@ -57,7 +47,8 @@ static void create_init(void *data)
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_iphash_create *mydata = struct ip_set_req_iphash_create *mydata =
(struct ip_set_req_iphash_create *) data; (struct ip_set_req_iphash_create *) data;
@@ -125,31 +116,25 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data UNUSED, unsigned int flags UNUSED)
{ {
#ifdef IPSET_DEBUG
struct ip_set_req_iphash_create *mydata =
(struct ip_set_req_iphash_create *) data;
DP("hashsize %u probes %u resize %u",
mydata->hashsize, mydata->probes, mydata->resize);
#endif
} }
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"hashsize", 1, 0, '1'}, {.name = "hashsize", .has_arg = required_argument, .val = '1'},
{"probes", 1, 0, '2'}, {.name = "probes", .has_arg = required_argument, .val = '2'},
{"resize", 1, 0, '3'}, {.name = "resize", .has_arg = required_argument, .val = '3'},
{"netmask", 1, 0, '4'}, {.name = "netmask", .has_arg = required_argument, .val = '4'},
{NULL}, {NULL},
}; };
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_iphash *mydata = struct ip_set_req_iphash *mydata = data;
(struct ip_set_req_iphash *) data;
parse_ip(arg, &mydata->ip); parse_ip(arg, &mydata->ip);
if (!mydata->ip) if (!mydata->ip)
@@ -163,12 +148,11 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_iphash_create *header = const struct ip_set_req_iphash_create *header = data;
(struct ip_set_req_iphash_create *) data; struct ip_set_iphash *map = set->settype->header;
struct ip_set_iphash *map =
(struct ip_set_iphash *) set->settype->header;
memset(map, 0, sizeof(struct ip_set_iphash)); memset(map, 0, sizeof(struct ip_set_iphash));
map->hashsize = header->hashsize; map->hashsize = header->hashsize;
@@ -187,16 +171,16 @@ mask_to_bits(ip_set_ip_t mask)
return bits; return bits;
maskaddr = 0xFFFFFFFE; maskaddr = 0xFFFFFFFE;
while (--bits >= 0 && maskaddr != mask) while (--bits > 0 && maskaddr != mask)
maskaddr <<= 1; maskaddr <<= 1;
return bits; return bits;
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options UNUSED)
{ {
struct ip_set_iphash *mysetdata = struct ip_set_iphash *mysetdata = set->settype->header;
(struct ip_set_iphash *) set->settype->header;
printf(" hashsize: %u", mysetdata->hashsize); printf(" hashsize: %u", mysetdata->hashsize);
printf(" probes: %u", mysetdata->probes); printf(" probes: %u", mysetdata->probes);
@@ -207,8 +191,8 @@ static void printheader(struct set *set, unsigned int options)
printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask)); printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
} }
static void printips(struct set *set, void *data, size_t len, static void
unsigned int options) printips(struct set *set UNUSED, void *data, u_int32_t len, unsigned options)
{ {
size_t offset = 0; size_t offset = 0;
ip_set_ip_t *ip; ip_set_ip_t *ip;
@@ -221,10 +205,10 @@ static void printips(struct set *set, void *data, size_t len,
} }
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options UNUSED)
{ {
struct ip_set_iphash *mysetdata = struct ip_set_iphash *mysetdata = set->settype->header;
(struct ip_set_iphash *) set->settype->header;
printf("-N %s %s --hashsize %u --probes %u --resize %u", printf("-N %s %s --hashsize %u --probes %u --resize %u",
set->name, set->settype->typename, set->name, set->settype->typename,
@@ -236,8 +220,8 @@ static void saveheader(struct set *set, unsigned int options)
} }
/* Print save for an IP */ /* Print save for an IP */
static void saveips(struct set *set, void *data, size_t len, static void
unsigned int options) saveips(struct set *set UNUSED, void *data, u_int32_t len, unsigned options)
{ {
size_t offset = 0; size_t offset = 0;
ip_set_ip_t *ip; ip_set_ip_t *ip;
@@ -292,7 +276,7 @@ static struct settype settype_iphash = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void iphash_init(void) CONSTRUCTOR(iphash)
{ {
settype_register(&settype_iphash); settype_register(&settype_iphash);

View File

@@ -17,15 +17,12 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <stdio.h> #include <stdio.h> /* *printf */
#include <string.h> #include <string.h> /* mem* */
#include <sys/socket.h>
#include <netinet/in.h> #include "ipset.h"
#include <arpa/inet.h>
/* #include <asm/bitops.h> */
#include "ip_set_ipmap.h" #include "ip_set_ipmap.h"
#include "ipset.h"
#define BUFLEN 30; #define BUFLEN 30;
@@ -37,20 +34,20 @@
#define OPT_ADDDEL_IP 0x01U #define OPT_ADDDEL_IP 0x01U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data)
{ {
struct ip_set_req_ipmap_create *mydata = struct ip_set_req_ipmap_create *mydata = data;
(struct ip_set_req_ipmap_create *) data;
DP("create INIT"); DP("create INIT");
mydata->netmask = 0xFFFFFFFF; mydata->netmask = 0xFFFFFFFF;
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_ipmap_create *mydata = struct ip_set_req_ipmap_create *mydata = data;
(struct ip_set_req_ipmap_create *) data;
unsigned int bits; unsigned int bits;
DP("create_parse"); DP("create_parse");
@@ -116,15 +113,12 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
return 1; return 1;
} }
#define ERRSTRLEN 256
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data, unsigned int flags)
{ {
struct ip_set_req_ipmap_create *mydata = struct ip_set_req_ipmap_create *mydata = data;
(struct ip_set_req_ipmap_create *) data;
ip_set_ip_t range; ip_set_ip_t range;
char errstr[ERRSTRLEN];
if (flags == 0) if (flags == 0)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
@@ -164,26 +158,14 @@ static void create_final(void *data, unsigned int flags)
mask = range_to_mask(mydata->from, mydata->to, &mask_bits); mask = range_to_mask(mydata->from, mydata->to, &mask_bits);
if (!mask if (!mask
&& (mydata->from || mydata->to != 0xFFFFFFFF)) { && (mydata->from || mydata->to != 0xFFFFFFFF)) {
strncpy(errstr, ip_tostring_numeric(mydata->from),
ERRSTRLEN-2);
errstr[ERRSTRLEN-1] = '\0';
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"%s-%s is not a full network (%x)\n", "You have to define a full network with --from"
errstr, " and --to if you specify the --network option\n");
ip_tostring_numeric(mydata->to), mask);
} }
netmask_bits = mask_to_bits(mydata->netmask); netmask_bits = mask_to_bits(mydata->netmask);
if (netmask_bits <= mask_bits) { if (netmask_bits <= mask_bits) {
strncpy(errstr, ip_tostring_numeric(mydata->from),
ERRSTRLEN-2);
errstr[ERRSTRLEN-1] = '\0';
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"%d netmask specifies larger or equal netblock than %s-%s (%d)\n", "%d netmask specifies larger or equal netblock than the network itself\n");
netmask_bits,
errstr,
ip_tostring_numeric(mydata->to),
mask_bits);
} }
range = (1<<(netmask_bits - mask_bits)) - 1; range = (1<<(netmask_bits - mask_bits)) - 1;
} else { } else {
@@ -197,18 +179,18 @@ static void create_final(void *data, unsigned int flags)
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"from", 1, 0, '1'}, {.name = "from", .has_arg = required_argument, .val = '1'},
{"to", 1, 0, '2'}, {.name = "to", .has_arg = required_argument, .val = '2'},
{"network", 1, 0, '3'}, {.name = "network", .has_arg = required_argument, .val = '3'},
{"netmask", 1, 0, '4'}, {.name = "netmask", .has_arg = required_argument, .val = '4'},
{NULL}, {NULL},
}; };
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_ipmap *mydata = struct ip_set_req_ipmap *mydata = data;
(struct ip_set_req_ipmap *) data;
DP("ipmap: %p %p", arg, data); DP("ipmap: %p %p", arg, data);
@@ -222,12 +204,11 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_ipmap_create *header = const struct ip_set_req_ipmap_create *header = data;
(struct ip_set_req_ipmap_create *) data; struct ip_set_ipmap *map = set->settype->header;
struct ip_set_ipmap *map =
(struct ip_set_ipmap *) set->settype->header;
memset(map, 0, sizeof(struct ip_set_ipmap)); memset(map, 0, sizeof(struct ip_set_ipmap));
map->first_ip = header->from; map->first_ip = header->from;
@@ -244,18 +225,18 @@ static void initheader(struct set *set, const void *data)
mask = range_to_mask(header->from, header->to, &mask_bits); mask = range_to_mask(header->from, header->to, &mask_bits);
netmask_bits = mask_to_bits(header->netmask); netmask_bits = mask_to_bits(header->netmask);
DP("bits: %i %i", mask_bits, netmask_bits); DP("bits: %d %d", mask_bits, netmask_bits);
map->hosts = 2 << (32 - netmask_bits - 1); map->hosts = 2 << (32 - netmask_bits - 1);
map->sizeid = 2 << (netmask_bits - mask_bits - 1); map->sizeid = 2 << (netmask_bits - mask_bits - 1);
} }
DP("%i %i", map->hosts, map->sizeid ); DP("%d %d", map->hosts, map->sizeid );
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options)
{ {
struct ip_set_ipmap *mysetdata = struct ip_set_ipmap *mysetdata = set->settype->header;
(struct ip_set_ipmap *) set->settype->header;
printf(" from: %s", ip_tostring(mysetdata->first_ip, options)); printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
printf(" to: %s", ip_tostring(mysetdata->last_ip, options)); printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
@@ -265,11 +246,11 @@ static void printheader(struct set *set, unsigned int options)
printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask)); printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
} }
static void printips_sorted(struct set *set, void *data, size_t len, static void
unsigned int options) printips_sorted(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options)
{ {
struct ip_set_ipmap *mysetdata = struct ip_set_ipmap *mysetdata = set->settype->header;
(struct ip_set_ipmap *) set->settype->header;
ip_set_ip_t id; ip_set_ip_t id;
for (id = 0; id < mysetdata->sizeid; id++) for (id = 0; id < mysetdata->sizeid; id++)
@@ -280,10 +261,10 @@ static void printips_sorted(struct set *set, void *data, size_t len,
options)); options));
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options)
{ {
struct ip_set_ipmap *mysetdata = struct ip_set_ipmap *mysetdata = set->settype->header;
(struct ip_set_ipmap *) set->settype->header;
printf("-N %s %s --from %s", printf("-N %s %s --from %s",
set->name, set->settype->typename, set->name, set->settype->typename,
@@ -297,11 +278,10 @@ static void saveheader(struct set *set, unsigned int options)
mask_to_bits(mysetdata->netmask)); mask_to_bits(mysetdata->netmask));
} }
static void saveips(struct set *set, void *data, size_t len, static void
unsigned int options) saveips(struct set *set, void *data, u_int32_t len UNUSED, unsigned options)
{ {
struct ip_set_ipmap *mysetdata = struct ip_set_ipmap *mysetdata = set->settype->header;
(struct ip_set_ipmap *) set->settype->header;
ip_set_ip_t id; ip_set_ip_t id;
DP("%s", set->name); DP("%s", set->name);
@@ -355,7 +335,7 @@ static struct settype settype_ipmap = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void ipmap_init(void) CONSTRUCTOR(ipmap)
{ {
settype_register(&settype_ipmap); settype_register(&settype_ipmap);

View File

@@ -15,24 +15,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <errno.h> #include <limits.h> /* UINT_MAX */
#include <limits.h> #include <stdio.h> /* *printf */
#include <stdio.h> #include <string.h> /* mem*, str* */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include "ip_set_ipporthash.h"
#include "ip_set_jhash.h"
#include "ipset.h" #include "ipset.h"
#include "ip_set_ipporthash.h"
#define OPT_CREATE_HASHSIZE 0x01U #define OPT_CREATE_HASHSIZE 0x01U
#define OPT_CREATE_PROBES 0x02U #define OPT_CREATE_PROBES 0x02U
#define OPT_CREATE_RESIZE 0x04U #define OPT_CREATE_RESIZE 0x04U
@@ -41,10 +31,10 @@
#define OPT_CREATE_TO 0x20U #define OPT_CREATE_TO 0x20U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data)
{ {
struct ip_set_req_ipporthash_create *mydata = struct ip_set_req_ipporthash_create *mydata = data;
(struct ip_set_req_ipporthash_create *) data;
DP("create INIT"); DP("create INIT");
@@ -55,10 +45,10 @@ static void create_init(void *data)
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_ipporthash_create *mydata = struct ip_set_req_ipporthash_create *mydata = data;
(struct ip_set_req_ipporthash_create *) data;
ip_set_ip_t value; ip_set_ip_t value;
DP("create_parse"); DP("create_parse");
@@ -146,10 +136,10 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data, unsigned int flags)
{ {
struct ip_set_req_ipporthash_create *mydata = struct ip_set_req_ipporthash_create *mydata = data;
(struct ip_set_req_ipporthash_create *) data;
#ifdef IPSET_DEBUG #ifdef IPSET_DEBUG
DP("hashsize %u probes %u resize %u", DP("hashsize %u probes %u resize %u",
@@ -188,34 +178,42 @@ static void create_final(void *data, unsigned int flags)
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"hashsize", 1, 0, '1'}, {.name = "hashsize", .has_arg = required_argument, .val = '1'},
{"probes", 1, 0, '2'}, {.name = "probes", .has_arg = required_argument, .val = '2'},
{"resize", 1, 0, '3'}, {.name = "resize", .has_arg = required_argument, .val = '3'},
{"from", 1, 0, '4'}, {.name = "from", .has_arg = required_argument, .val = '4'},
{"to", 1, 0, '5'}, {.name = "to", .has_arg = required_argument, .val = '5'},
{"network", 1, 0, '6'}, {.name = "network", .has_arg = required_argument, .val = '6'},
{NULL}, {NULL},
}; };
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_ipporthash *mydata = struct ip_set_req_ipporthash *mydata = data;
(struct ip_set_req_ipporthash *) data;
char *saved = ipset_strdup(arg); char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved; char *ptr, *tmp = saved;
DP("ipporthash: %p %p", arg, data); DP("ipporthash: %p %p", arg, data);
ptr = strsep(&tmp, ":%"); if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1)
fprintf(stderr, "Warning: please use ',' separator token between ip,port.\n"
"Next release won't support old separator tokens.\n");
ptr = strsep(&tmp, ":%,");
parse_ip(ptr, &mydata->ip); parse_ip(ptr, &mydata->ip);
if (tmp) if (tmp)
parse_port(tmp, &mydata->port); parse_port(tmp, &mydata->port);
else else
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"IP address and port must be specified: ip%%port"); "IP address and port must be specified: ip,port");
free(saved);
if (!(mydata->ip || mydata->port))
exit_error(PARAMETER_PROBLEM,
"Zero valued IP address and port `%s' specified", arg);
ipset_free(saved);
return 1; return 1;
}; };
@@ -223,12 +221,11 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_ipporthash_create *header = const struct ip_set_req_ipporthash_create *header = data;
(struct ip_set_req_ipporthash_create *) data; struct ip_set_ipporthash *map = set->settype->header;
struct ip_set_ipporthash *map =
(struct ip_set_ipporthash *) set->settype->header;
memset(map, 0, sizeof(struct ip_set_ipporthash)); memset(map, 0, sizeof(struct ip_set_ipporthash));
map->hashsize = header->hashsize; map->hashsize = header->hashsize;
@@ -238,10 +235,10 @@ static void initheader(struct set *set, const void *data)
map->last_ip = header->to; map->last_ip = header->to;
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options)
{ {
struct ip_set_ipporthash *mysetdata = struct ip_set_ipporthash *mysetdata = set->settype->header;
(struct ip_set_ipporthash *) set->settype->header;
printf(" from: %s", ip_tostring(mysetdata->first_ip, options)); printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
printf(" to: %s", ip_tostring(mysetdata->last_ip, options)); printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
@@ -250,11 +247,10 @@ static void printheader(struct set *set, unsigned int options)
printf(" resize: %u\n", mysetdata->resize); printf(" resize: %u\n", mysetdata->resize);
} }
static void printips(struct set *set, void *data, size_t len, static void
unsigned int options) printips(struct set *set, void *data, u_int32_t len, unsigned options)
{ {
struct ip_set_ipporthash *mysetdata = struct ip_set_ipporthash *mysetdata = set->settype->header;
(struct ip_set_ipporthash *) set->settype->header;
size_t offset = 0; size_t offset = 0;
ip_set_ip_t *ipptr, ip; ip_set_ip_t *ipptr, ip;
uint16_t port; uint16_t port;
@@ -264,7 +260,7 @@ static void printips(struct set *set, void *data, size_t len,
if (*ipptr) { if (*ipptr) {
ip = (*ipptr>>16) + mysetdata->first_ip; ip = (*ipptr>>16) + mysetdata->first_ip;
port = (uint16_t) *ipptr; port = (uint16_t) *ipptr;
printf("%s:%s\n", printf("%s,%s\n",
ip_tostring(ip, options), ip_tostring(ip, options),
port_tostring(port, options)); port_tostring(port, options));
} }
@@ -272,10 +268,10 @@ static void printips(struct set *set, void *data, size_t len,
} }
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options)
{ {
struct ip_set_ipporthash *mysetdata = struct ip_set_ipporthash *mysetdata = set->settype->header;
(struct ip_set_ipporthash *) set->settype->header;
printf("-N %s %s --from %s", printf("-N %s %s --from %s",
set->name, set->settype->typename, set->name, set->settype->typename,
@@ -287,11 +283,10 @@ static void saveheader(struct set *set, unsigned int options)
} }
/* Print save for an IP */ /* Print save for an IP */
static void saveips(struct set *set, void *data, size_t len, static void
unsigned int options) saveips(struct set *set, void *data, u_int32_t len, unsigned options)
{ {
struct ip_set_ipporthash *mysetdata = struct ip_set_ipporthash *mysetdata = set->settype->header;
(struct ip_set_ipporthash *) set->settype->header;
size_t offset = 0; size_t offset = 0;
ip_set_ip_t *ipptr, ip; ip_set_ip_t *ipptr, ip;
uint16_t port; uint16_t port;
@@ -301,7 +296,7 @@ static void saveips(struct set *set, void *data, size_t len,
if (*ipptr) { if (*ipptr) {
ip = (*ipptr>>16) + mysetdata->first_ip; ip = (*ipptr>>16) + mysetdata->first_ip;
port = (uint16_t) *ipptr; port = (uint16_t) *ipptr;
printf("-A %s %s:%s\n", set->name, printf("-A %s %s,%s\n", set->name,
ip_tostring(ip, options), ip_tostring(ip, options),
port_tostring(port, options)); port_tostring(port, options));
} }
@@ -311,15 +306,15 @@ static void saveips(struct set *set, void *data, size_t len,
static char buffer[22]; static char buffer[22];
static char * unpack_ipport_tostring(struct set *set, ip_set_ip_t bip, unsigned options) static char *
unpack_ipport_tostring(struct set *set, ip_set_ip_t bip, unsigned options)
{ {
struct ip_set_ipporthash *mysetdata = struct ip_set_ipporthash *mysetdata = set->settype->header;
(struct ip_set_ipporthash *) set->settype->header;
ip_set_ip_t ip, port; ip_set_ip_t ip, port;
ip = (bip>>16) + mysetdata->first_ip; ip = (bip>>16) + mysetdata->first_ip;
port = (uint16_t) bip; port = (uint16_t) bip;
sprintf(buffer, "%s:%s", sprintf(buffer, "%s,%s",
ip_tostring(ip, options), port_tostring(port, options)); ip_tostring(ip, options), port_tostring(port, options));
return buffer; return buffer;
@@ -332,9 +327,9 @@ static void usage(void)
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n" " [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
"-N set ipporthash --network IP/mask\n" "-N set ipporthash --network IP/mask\n"
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n" " [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
"-A set IP:port\n" "-A set IP,port\n"
"-D set IP:port\n" "-D set IP,port\n"
"-T set IP:port\n"); "-T set IP,port\n");
} }
static struct settype settype_ipporthash = { static struct settype settype_ipporthash = {
@@ -368,7 +363,7 @@ static struct settype settype_ipporthash = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void ipporthash_init(void) CONSTRUCTOR(ipporthash)
{ {
settype_register(&settype_ipporthash); settype_register(&settype_ipporthash);

View File

@@ -0,0 +1,361 @@
/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <limits.h> /* UINT_MAX */
#include <stdio.h> /* *printf */
#include <string.h> /* mem*, str* */
#include "ipset.h"
#include "ip_set_ipportiphash.h"
#define OPT_CREATE_HASHSIZE 0x01U
#define OPT_CREATE_PROBES 0x02U
#define OPT_CREATE_RESIZE 0x04U
#define OPT_CREATE_NETWORK 0x08U
#define OPT_CREATE_FROM 0x10U
#define OPT_CREATE_TO 0x20U
/* Initialize the create. */
static void
create_init(void *data)
{
struct ip_set_req_ipportiphash_create *mydata = data;
DP("create INIT");
/* Default create parameters */
mydata->hashsize = 1024;
mydata->probes = 8;
mydata->resize = 50;
}
/* Function which parses command options; returns true if it ate an option */
static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{
struct ip_set_req_ipportiphash_create *mydata = data;
ip_set_ip_t value;
DP("create_parse");
switch (c) {
case '1':
if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
*flags |= OPT_CREATE_HASHSIZE;
DP("--hashsize %u", mydata->hashsize);
break;
case '2':
if (string_to_number(optarg, 1, 65535, &value))
exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
mydata->probes = value;
*flags |= OPT_CREATE_PROBES;
DP("--probes %u", mydata->probes);
break;
case '3':
if (string_to_number(optarg, 0, 65535, &value))
exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
mydata->resize = value;
*flags |= OPT_CREATE_RESIZE;
DP("--resize %u", mydata->resize);
break;
case '4':
parse_ip(optarg, &mydata->from);
*flags |= OPT_CREATE_FROM;
DP("--from %x (%s)", mydata->from,
ip_tostring_numeric(mydata->from));
break;
case '5':
parse_ip(optarg, &mydata->to);
*flags |= OPT_CREATE_TO;
DP("--to %x (%s)", mydata->to,
ip_tostring_numeric(mydata->to));
break;
case '6':
parse_ipandmask(optarg, &mydata->from, &mydata->to);
/* Make to the last of from + mask */
if (mydata->to)
mydata->to = mydata->from | ~(mydata->to);
else {
mydata->from = 0x00000000;
mydata->to = 0xFFFFFFFF;
}
*flags |= OPT_CREATE_NETWORK;
DP("--network from %x (%s)",
mydata->from, ip_tostring_numeric(mydata->from));
DP("--network to %x (%s)",
mydata->to, ip_tostring_numeric(mydata->to));
break;
default:
return 0;
}
return 1;
}
/* Final check; exit if not ok. */
static void
create_final(void *data, unsigned int flags)
{
struct ip_set_req_ipportiphash_create *mydata = data;
#ifdef IPSET_DEBUG
DP("hashsize %u probes %u resize %u",
mydata->hashsize, mydata->probes, mydata->resize);
#endif
if (flags & OPT_CREATE_NETWORK) {
/* --network */
if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
exit_error(PARAMETER_PROBLEM,
"Can't specify --from or --to with --network\n");
} else if (flags & (OPT_CREATE_FROM | OPT_CREATE_TO)) {
/* --from --to */
if (!(flags & OPT_CREATE_FROM) || !(flags & OPT_CREATE_TO))
exit_error(PARAMETER_PROBLEM,
"Need to specify both --from and --to\n");
} else {
exit_error(PARAMETER_PROBLEM,
"Need to specify --from and --to, or --network\n");
}
DP("from : %x to: %x diff: %x",
mydata->from, mydata->to,
mydata->to - mydata->from);
if (mydata->from > mydata->to)
exit_error(PARAMETER_PROBLEM,
"From can't be higher than to.\n");
if (mydata->to - mydata->from > MAX_RANGE)
exit_error(PARAMETER_PROBLEM,
"Range too large. Max is %d IPs in range\n",
MAX_RANGE+1);
}
/* Create commandline options */
static const struct option create_opts[] = {
{.name = "hashsize", .has_arg = required_argument, .val = '1'},
{.name = "probes", .has_arg = required_argument, .val = '2'},
{.name = "resize", .has_arg = required_argument, .val = '3'},
{.name = "from", .has_arg = required_argument, .val = '4'},
{.name = "to", .has_arg = required_argument, .val = '5'},
{.name = "network", .has_arg = required_argument, .val = '6'},
{NULL},
};
/* Add, del, test parser */
static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{
struct ip_set_req_ipportiphash *mydata = data;
char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved;
DP("ipportiphash: %p %p", arg, data);
if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1)
fprintf(stderr, "Warning: please use ',' separator token between ip,port,ip.\n"
"Next release won't support old separator tokens.\n");
ptr = strsep(&tmp, ":%,");
parse_ip(ptr, &mydata->ip);
if (!tmp)
exit_error(PARAMETER_PROBLEM,
"IP address, port and IP address must be specified: ip,port,ip");
ptr = strsep(&tmp, ":%,");
parse_port(ptr, &mydata->port);
if (tmp)
parse_ip(tmp, &mydata->ip1);
else
exit_error(PARAMETER_PROBLEM,
"IP address, port and IP address must be specified: ip,port,ip");
if (!(mydata->ip || mydata->port || mydata->ip1))
exit_error(PARAMETER_PROBLEM,
"Zero valued IP address, port and IP address `%s' specified", arg);
ipset_free(saved);
return 1;
};
/*
* Print and save
*/
static void
initheader(struct set *set, const void *data)
{
const struct ip_set_req_ipportiphash_create *header = data;
struct ip_set_ipportiphash *map = set->settype->header;
memset(map, 0, sizeof(struct ip_set_ipportiphash));
map->hashsize = header->hashsize;
map->probes = header->probes;
map->resize = header->resize;
map->first_ip = header->from;
map->last_ip = header->to;
}
static void
printheader(struct set *set, unsigned options)
{
struct ip_set_ipportiphash *mysetdata = set->settype->header;
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
printf(" hashsize: %u", mysetdata->hashsize);
printf(" probes: %u", mysetdata->probes);
printf(" resize: %u\n", mysetdata->resize);
}
static void
printips(struct set *set, void *data, u_int32_t len, unsigned options)
{
struct ip_set_ipportiphash *mysetdata = set->settype->header;
size_t offset = 0;
struct ipportip *ipptr;
ip_set_ip_t ip;
uint16_t port;
while (offset < len) {
ipptr = data + offset;
if (ipptr->ip && ipptr->ip1) {
ip = (ipptr->ip>>16) + mysetdata->first_ip;
port = (uint16_t) ipptr->ip;
printf("%s,%s,",
ip_tostring(ip, options),
port_tostring(port, options));
printf("%s\n",
ip_tostring(ipptr->ip1, options));
}
offset += sizeof(struct ipportip);
}
}
static void
saveheader(struct set *set, unsigned options)
{
struct ip_set_ipportiphash *mysetdata = set->settype->header;
printf("-N %s %s --from %s",
set->name, set->settype->typename,
ip_tostring(mysetdata->first_ip, options));
printf(" --to %s",
ip_tostring(mysetdata->last_ip, options));
printf(" --hashsize %u --probes %u --resize %u\n",
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
}
/* Print save for an IP */
static void
saveips(struct set *set, void *data, u_int32_t len, unsigned options)
{
struct ip_set_ipportiphash *mysetdata = set->settype->header;
size_t offset = 0;
struct ipportip *ipptr;
ip_set_ip_t ip;
uint16_t port;
while (offset < len) {
ipptr = data + offset;
if (ipptr->ip && ipptr->ip1) {
ip = (ipptr->ip>>16) + mysetdata->first_ip;
port = (uint16_t) ipptr->ip;
printf("-A %s %s,%s,", set->name,
ip_tostring(ip, options),
port_tostring(port, options));
printf("%s\n",
ip_tostring(ipptr->ip1, options));
}
offset += sizeof(struct ipportip);
}
}
static void usage(void)
{
printf
("-N set ipportiphash --from IP --to IP\n"
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
"-N set ipportiphash --network IP/mask\n"
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
"-A set IP,port,IP\n"
"-D set IP,port,IP\n"
"-T set IP,port,IP\n");
}
static struct settype settype_ipportiphash = {
.typename = SETTYPE_NAME,
.protocol_version = IP_SET_PROTOCOL_VERSION,
/* Create */
.create_size = sizeof(struct ip_set_req_ipportiphash_create),
.create_init = &create_init,
.create_parse = &create_parse,
.create_final = &create_final,
.create_opts = create_opts,
/* Add/del/test */
.adt_size = sizeof(struct ip_set_req_ipportiphash),
.adt_parser = &adt_parser,
/* Printing */
.header_size = sizeof(struct ip_set_ipportiphash),
.initheader = &initheader,
.printheader = &printheader,
.printips = &printips, /* We only have the unsorted version */
.printips_sorted = &printips,
.saveheader = &saveheader,
.saveips = &saveips,
.usage = &usage,
};
CONSTRUCTOR(ipportiphash)
{
settype_register(&settype_ipportiphash);
}

View File

@@ -0,0 +1,426 @@
/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <limits.h> /* UINT_MAX */
#include <stdio.h> /* *printf */
#include <string.h> /* mem*, str* */
#include "ipset.h"
#include "ip_set_ipportnethash.h"
#define OPT_CREATE_HASHSIZE 0x01U
#define OPT_CREATE_PROBES 0x02U
#define OPT_CREATE_RESIZE 0x04U
#define OPT_CREATE_NETWORK 0x08U
#define OPT_CREATE_FROM 0x10U
#define OPT_CREATE_TO 0x20U
/* Initialize the create. */
static void
create_init(void *data)
{
struct ip_set_req_ipportnethash_create *mydata = data;
DP("create INIT");
/* Default create parameters */
mydata->hashsize = 1024;
mydata->probes = 8;
mydata->resize = 50;
}
/* Function which parses command options; returns true if it ate an option */
static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{
struct ip_set_req_ipportnethash_create *mydata = data;
ip_set_ip_t value;
DP("create_parse");
switch (c) {
case '1':
if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
*flags |= OPT_CREATE_HASHSIZE;
DP("--hashsize %u", mydata->hashsize);
break;
case '2':
if (string_to_number(optarg, 1, 65535, &value))
exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
mydata->probes = value;
*flags |= OPT_CREATE_PROBES;
DP("--probes %u", mydata->probes);
break;
case '3':
if (string_to_number(optarg, 0, 65535, &value))
exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
mydata->resize = value;
*flags |= OPT_CREATE_RESIZE;
DP("--resize %u", mydata->resize);
break;
case '4':
parse_ip(optarg, &mydata->from);
*flags |= OPT_CREATE_FROM;
DP("--from %x (%s)", mydata->from,
ip_tostring_numeric(mydata->from));
break;
case '5':
parse_ip(optarg, &mydata->to);
*flags |= OPT_CREATE_TO;
DP("--to %x (%s)", mydata->to,
ip_tostring_numeric(mydata->to));
break;
case '6':
parse_ipandmask(optarg, &mydata->from, &mydata->to);
/* Make to the last of from + mask */
if (mydata->to)
mydata->to = mydata->from | ~(mydata->to);
else {
mydata->from = 0x00000000;
mydata->to = 0xFFFFFFFF;
}
*flags |= OPT_CREATE_NETWORK;
DP("--network from %x (%s)",
mydata->from, ip_tostring_numeric(mydata->from));
DP("--network to %x (%s)",
mydata->to, ip_tostring_numeric(mydata->to));
break;
default:
return 0;
}
return 1;
}
/* Final check; exit if not ok. */
static void
create_final(void *data, unsigned int flags)
{
struct ip_set_req_ipportnethash_create *mydata = data;
#ifdef IPSET_DEBUG
DP("hashsize %u probes %u resize %u",
mydata->hashsize, mydata->probes, mydata->resize);
#endif
if (flags & OPT_CREATE_NETWORK) {
/* --network */
if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
exit_error(PARAMETER_PROBLEM,
"Can't specify --from or --to with --network\n");
} else if (flags & (OPT_CREATE_FROM | OPT_CREATE_TO)) {
/* --from --to */
if (!(flags & OPT_CREATE_FROM) || !(flags & OPT_CREATE_TO))
exit_error(PARAMETER_PROBLEM,
"Need to specify both --from and --to\n");
} else {
exit_error(PARAMETER_PROBLEM,
"Need to specify --from and --to, or --network\n");
}
DP("from : %x to: %x diff: %x",
mydata->from, mydata->to,
mydata->to - mydata->from);
if (mydata->from > mydata->to)
exit_error(PARAMETER_PROBLEM,
"From can't be higher than to.\n");
if (mydata->to - mydata->from > MAX_RANGE)
exit_error(PARAMETER_PROBLEM,
"Range too large. Max is %d IPs in range\n",
MAX_RANGE+1);
}
/* Create commandline options */
static const struct option create_opts[] = {
{.name = "hashsize", .has_arg = required_argument, .val = '1'},
{.name = "probes", .has_arg = required_argument, .val = '2'},
{.name = "resize", .has_arg = required_argument, .val = '3'},
{.name = "from", .has_arg = required_argument, .val = '4'},
{.name = "to", .has_arg = required_argument, .val = '5'},
{.name = "network", .has_arg = required_argument, .val = '6'},
{NULL},
};
/* Add, del, test parser */
static ip_set_ip_t
adt_parser(int cmd, const char *arg, void *data)
{
struct ip_set_req_ipportnethash *mydata = data;
char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved;
ip_set_ip_t cidr;
DP("ipportnethash: %p %p", arg, data);
if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1)
fprintf(stderr, "Warning: please use ',' separator token between ip,port,net.\n"
"Next release won't support old separator tokens.\n");
ptr = strsep(&tmp, ":%,");
parse_ip(ptr, &mydata->ip);
if (!tmp)
exit_error(PARAMETER_PROBLEM,
"IP address, port and network address must be specified: ip,port,net");
ptr = strsep(&tmp, ":%,");
parse_port(ptr, &mydata->port);
if (!tmp)
exit_error(PARAMETER_PROBLEM,
"IP address, port and network address must be specified: ip,port,net");
ptr = strsep(&tmp, "/");
if (tmp == NULL)
if (cmd == CMD_TEST)
cidr = 32;
else
exit_error(PARAMETER_PROBLEM,
"Missing /cidr from `%s'", arg);
else
if (string_to_number(tmp, 1, 31, &cidr))
exit_error(PARAMETER_PROBLEM,
"Out of range cidr `%s' specified", arg);
mydata->cidr = cidr;
parse_ip(ptr, &mydata->ip1);
ipset_free(saved);
return 1;
};
/*
* Print and save
*/
static void
initheader(struct set *set, const void *data)
{
const struct ip_set_req_ipportnethash_create *header = data;
struct ip_set_ipportnethash *map = set->settype->header;
memset(map, 0, sizeof(struct ip_set_ipportnethash));
map->hashsize = header->hashsize;
map->probes = header->probes;
map->resize = header->resize;
map->first_ip = header->from;
map->last_ip = header->to;
}
static void
printheader(struct set *set, unsigned options)
{
struct ip_set_ipportnethash *mysetdata = set->settype->header;
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
printf(" hashsize: %u", mysetdata->hashsize);
printf(" probes: %u", mysetdata->probes);
printf(" resize: %u\n", mysetdata->resize);
}
static char buf[20];
static char *
unpack_ip_tostring(ip_set_ip_t ip, unsigned options UNUSED)
{
int i, j = 3;
unsigned char a, b;
ip = htonl(ip);
for (i = 3; i >= 0; i--)
if (((unsigned char *)&ip)[i] != 0) {
j = i;
break;
}
a = ((unsigned char *)&ip)[j];
if (a <= 128) {
a = (a - 1) * 2;
b = 7;
} else if (a <= 192) {
a = (a - 129) * 4;
b = 6;
} else if (a <= 224) {
a = (a - 193) * 8;
b = 5;
} else if (a <= 240) {
a = (a - 225) * 16;
b = 4;
} else if (a <= 248) {
a = (a - 241) * 32;
b = 3;
} else if (a <= 252) {
a = (a - 249) * 64;
b = 2;
} else if (a <= 254) {
a = (a - 253) * 128;
b = 1;
} else {
a = b = 0;
}
((unsigned char *)&ip)[j] = a;
b += j * 8;
sprintf(buf, "%u.%u.%u.%u/%u",
((unsigned char *)&ip)[0],
((unsigned char *)&ip)[1],
((unsigned char *)&ip)[2],
((unsigned char *)&ip)[3],
b);
DP("%s %s", ip_tostring(ntohl(ip), 0), buf);
return buf;
}
static void
printips(struct set *set, void *data, u_int32_t len, unsigned options)
{
struct ip_set_ipportnethash *mysetdata = set->settype->header;
size_t offset = 0;
struct ipportip *ipptr;
ip_set_ip_t ip;
uint16_t port;
while (offset < len) {
ipptr = data + offset;
if (ipptr->ip || ipptr->ip1) {
ip = (ipptr->ip>>16) + mysetdata->first_ip;
port = (uint16_t) ipptr->ip;
printf("%s,%s,",
ip_tostring(ip, options),
port_tostring(port, options));
printf("%s\n",
unpack_ip_tostring(ipptr->ip1, options));
}
offset += sizeof(struct ipportip);
}
}
static void
saveheader(struct set *set, unsigned options)
{
struct ip_set_ipportnethash *mysetdata = set->settype->header;
printf("-N %s %s --from %s",
set->name, set->settype->typename,
ip_tostring(mysetdata->first_ip, options));
printf(" --to %s",
ip_tostring(mysetdata->last_ip, options));
printf(" --hashsize %u --probes %u --resize %u\n",
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
}
/* Print save for an IP */
static void
saveips(struct set *set, void *data, u_int32_t len, unsigned options)
{
struct ip_set_ipportnethash *mysetdata = set->settype->header;
size_t offset = 0;
struct ipportip *ipptr;
ip_set_ip_t ip;
uint16_t port;
while (offset < len) {
ipptr = data + offset;
if (ipptr) {
ip = (ipptr->ip>>16) + mysetdata->first_ip;
port = (uint16_t) ipptr->ip;
printf("-A %s %s,%s,", set->name,
ip_tostring(ip, options),
port_tostring(port, options));
printf("%s\n",
unpack_ip_tostring(ipptr->ip, options));
}
offset += sizeof(struct ipportip);
}
}
static void usage(void)
{
printf
("-N set ipportnethash --from IP --to IP\n"
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
"-N set ipportnethash --network IP/mask\n"
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
"-A set IP,port,IP/net\n"
"-D set IP,port,IP/net\n"
"-T set IP,port,IP[/net]\n");
}
static struct settype settype_ipportnethash = {
.typename = SETTYPE_NAME,
.protocol_version = IP_SET_PROTOCOL_VERSION,
/* Create */
.create_size = sizeof(struct ip_set_req_ipportnethash_create),
.create_init = &create_init,
.create_parse = &create_parse,
.create_final = &create_final,
.create_opts = create_opts,
/* Add/del/test */
.adt_size = sizeof(struct ip_set_req_ipportnethash),
.adt_parser = &adt_parser,
/* Printing */
.header_size = sizeof(struct ip_set_ipportnethash),
.initheader = &initheader,
.printheader = &printheader,
.printips = &printips, /* We only have the unsorted version */
.printips_sorted = &printips,
.saveheader = &saveheader,
.saveips = &saveips,
.usage = &usage,
};
CONSTRUCTOR(ipportnethash)
{
settype_register(&settype_ipportnethash);
}

View File

@@ -15,36 +15,33 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <limits.h> #include <limits.h> /* UINT_MAX */
#include <stdio.h> #include <stdio.h> /* *printf */
#include <stdlib.h> #include <string.h> /* mem* */
#include <string.h>
#include <sys/socket.h> #include "ipset.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ip_set_iptree.h" #include "ip_set_iptree.h"
#include "ipset.h"
#define BUFLEN 30; #define BUFLEN 30;
#define OPT_CREATE_TIMEOUT 0x01U #define OPT_CREATE_TIMEOUT 0x01U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data)
{ {
struct ip_set_req_iptree_create *mydata = struct ip_set_req_iptree_create *mydata = data;
(struct ip_set_req_iptree_create *) data;
DP("create INIT"); DP("create INIT");
mydata->timeout = 0; mydata->timeout = 0;
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_iptree_create *mydata = struct ip_set_req_iptree_create *mydata = data;
(struct ip_set_req_iptree_create *) data;
DP("create_parse"); DP("create_parse");
@@ -65,27 +62,32 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data UNUSED, unsigned int flags UNUSED)
{ {
} }
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"timeout", 1, 0, '1'}, {.name = "timeout", .has_arg = required_argument, .val = '1'},
{NULL}, {NULL},
}; };
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_iptree *mydata = struct ip_set_req_iptree *mydata = data;
(struct ip_set_req_iptree *) data;
char *saved = ipset_strdup(arg); char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved; char *ptr, *tmp = saved;
DP("iptree: %p %p", arg, data); DP("iptree: %p %p", arg, data);
ptr = strsep(&tmp, ":%"); if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1)
fprintf(stderr, "Warning: please use ',' separator token between ip,timeout.\n"
"Next release won't support old separator tokens.\n");
ptr = strsep(&tmp, ":%,");
parse_ip(ptr, &mydata->ip); parse_ip(ptr, &mydata->ip);
if (tmp) if (tmp)
@@ -93,7 +95,7 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
else else
mydata->timeout = 0; mydata->timeout = 0;
free(saved); ipset_free(saved);
return 1; return 1;
} }
@@ -101,38 +103,36 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_iptree_create *header = const struct ip_set_req_iptree_create *header = data;
(struct ip_set_req_iptree_create *) data; struct ip_set_iptree *map = set->settype->header;
struct ip_set_iptree *map =
(struct ip_set_iptree *) set->settype->header;
map->timeout = header->timeout; map->timeout = header->timeout;
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options UNUSED)
{ {
struct ip_set_iptree *mysetdata = struct ip_set_iptree *mysetdata = set->settype->header;
(struct ip_set_iptree *) set->settype->header;
if (mysetdata->timeout) if (mysetdata->timeout)
printf(" timeout: %u", mysetdata->timeout); printf(" timeout: %u", mysetdata->timeout);
printf("\n"); printf("\n");
} }
static void printips_sorted(struct set *set, void *data, size_t len, static void
unsigned int options) printips_sorted(struct set *set, void *data, u_int32_t len, unsigned options)
{ {
struct ip_set_iptree *mysetdata = struct ip_set_iptree *mysetdata = set->settype->header;
(struct ip_set_iptree *) set->settype->header;
struct ip_set_req_iptree *req; struct ip_set_req_iptree *req;
size_t offset = 0; size_t offset = 0;
while (len >= offset + sizeof(struct ip_set_req_iptree)) { while (len >= offset + sizeof(struct ip_set_req_iptree)) {
req = (struct ip_set_req_iptree *)(data + offset); req = (struct ip_set_req_iptree *)(data + offset);
if (mysetdata->timeout) if (mysetdata->timeout)
printf("%s:%u\n", ip_tostring(req->ip, options), printf("%s,%u\n", ip_tostring(req->ip, options),
req->timeout); req->timeout);
else else
printf("%s\n", ip_tostring(req->ip, options)); printf("%s\n", ip_tostring(req->ip, options));
@@ -140,10 +140,10 @@ static void printips_sorted(struct set *set, void *data, size_t len,
} }
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options UNUSED)
{ {
struct ip_set_iptree *mysetdata = struct ip_set_iptree *mysetdata = set->settype->header;
(struct ip_set_iptree *) set->settype->header;
if (mysetdata->timeout) if (mysetdata->timeout)
printf("-N %s %s --timeout %u\n", printf("-N %s %s --timeout %u\n",
@@ -154,11 +154,10 @@ static void saveheader(struct set *set, unsigned int options)
set->name, set->settype->typename); set->name, set->settype->typename);
} }
static void saveips(struct set *set, void *data, size_t len, static void
unsigned int options) saveips(struct set *set, void *data, u_int32_t len, unsigned options)
{ {
struct ip_set_iptree *mysetdata = struct ip_set_iptree *mysetdata = set->settype->header;
(struct ip_set_iptree *) set->settype->header;
struct ip_set_req_iptree *req; struct ip_set_req_iptree *req;
size_t offset = 0; size_t offset = 0;
@@ -167,7 +166,7 @@ static void saveips(struct set *set, void *data, size_t len,
while (len >= offset + sizeof(struct ip_set_req_iptree)) { while (len >= offset + sizeof(struct ip_set_req_iptree)) {
req = (struct ip_set_req_iptree *)(data + offset); req = (struct ip_set_req_iptree *)(data + offset);
if (mysetdata->timeout) if (mysetdata->timeout)
printf("-A %s %s:%u\n", printf("-A %s %s,%u\n",
set->name, set->name,
ip_tostring(req->ip, options), ip_tostring(req->ip, options),
req->timeout); req->timeout);
@@ -183,7 +182,7 @@ static void usage(void)
{ {
printf printf
("-N set iptree [--timeout value]\n" ("-N set iptree [--timeout value]\n"
"-A set IP[:timeout]\n" "-A set IP[,timeout]\n"
"-D set IP\n" "-D set IP\n"
"-T set IP\n"); "-T set IP\n");
} }
@@ -219,7 +218,7 @@ static struct settype settype_iptree = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void iptree_init(void) CONSTRUCTOR(iptree)
{ {
settype_register(&settype_iptree); settype_register(&settype_iptree);

View File

@@ -15,17 +15,14 @@
* Place, Suite 330, Boston, MA 02111-1307 USA * Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <limits.h> #include <limits.h> /* UINT_MAX */
#include <stdio.h> #include <stdio.h> /* *printf */
#include <string.h> #include <string.h> /* mem* */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ip_set_iptreemap.h"
#include "ipset.h" #include "ipset.h"
#include "ip_set_iptreemap.h"
#define OPT_CREATE_GC 0x1 #define OPT_CREATE_GC 0x1
static void static void
@@ -37,7 +34,7 @@ create_init(void *data)
} }
static int static int
create_parse(int c, char *argv[], void *data, unsigned int *flags) create_parse(int c, char *argv[] UNUSED, void *data, unsigned int *flags)
{ {
struct ip_set_req_iptreemap_create *mydata = data; struct ip_set_req_iptreemap_create *mydata = data;
@@ -56,17 +53,17 @@ create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
static void static void
create_final(void *data, unsigned int flags) create_final(void *data UNUSED, unsigned int flags UNUSED)
{ {
} }
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"gc", 1, 0, 'g'}, {.name = "gc", .has_arg = required_argument, .val = 'g'},
{NULL}, {NULL},
}; };
static ip_set_ip_t static ip_set_ip_t
adt_parser(unsigned int cmd, const char *arg, void *data) adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_iptreemap *mydata = data; struct ip_set_req_iptreemap *mydata = data;
ip_set_ip_t mask; ip_set_ip_t mask;
@@ -75,19 +72,24 @@ adt_parser(unsigned int cmd, const char *arg, void *data)
char *ptr, *tmp = saved; char *ptr, *tmp = saved;
if (strchr(tmp, '/')) { if (strchr(tmp, '/')) {
parse_ipandmask(tmp, &mydata->start, &mask); parse_ipandmask(tmp, &mydata->ip, &mask);
mydata->end = mydata->start | ~mask; mydata->end = mydata->ip | ~mask;
} else { } else {
ptr = strsep(&tmp, ":"); if ((ptr = strchr(tmp, ':')) != NULL && ++warn_once == 1)
parse_ip(ptr, &mydata->start); fprintf(stderr, "Warning: please use '-' separator token between IP range.\n"
"Next release won't support old separator token.\n");
ptr = strsep(&tmp, "-:");
parse_ip(ptr, &mydata->ip);
if (tmp) { if (tmp) {
parse_ip(tmp, &mydata->end); parse_ip(tmp, &mydata->end);
} else { } else {
mydata->end = mydata->start; mydata->end = mydata->ip;
} }
} }
ipset_free(saved);
return 1; return 1;
} }
@@ -101,7 +103,7 @@ initheader(struct set *set, const void *data)
} }
static void static void
printheader(struct set *set, unsigned int options) printheader(struct set *set, unsigned int options UNUSED)
{ {
struct ip_set_iptreemap *mysetdata = set->settype->header; struct ip_set_iptreemap *mysetdata = set->settype->header;
@@ -112,7 +114,8 @@ printheader(struct set *set, unsigned int options)
} }
static void static void
printips_sorted(struct set *set, void *data, size_t len, unsigned int options) printips_sorted(struct set *set UNUSED, void *data,
u_int32_t len, unsigned int options)
{ {
struct ip_set_req_iptreemap *req; struct ip_set_req_iptreemap *req;
size_t offset = 0; size_t offset = 0;
@@ -120,9 +123,9 @@ printips_sorted(struct set *set, void *data, size_t len, unsigned int options)
while (len >= offset + sizeof(struct ip_set_req_iptreemap)) { while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
req = data + offset; req = data + offset;
printf("%s", ip_tostring(req->start, options)); printf("%s", ip_tostring(req->ip, options));
if (req->start != req->end) if (req->ip != req->end)
printf(":%s", ip_tostring(req->end, options)); printf("-%s", ip_tostring(req->end, options));
printf("\n"); printf("\n");
offset += sizeof(struct ip_set_req_iptreemap); offset += sizeof(struct ip_set_req_iptreemap);
@@ -130,7 +133,7 @@ printips_sorted(struct set *set, void *data, size_t len, unsigned int options)
} }
static void static void
saveheader(struct set *set, unsigned int options) saveheader(struct set *set, unsigned int options UNUSED)
{ {
struct ip_set_iptreemap *mysetdata = set->settype->header; struct ip_set_iptreemap *mysetdata = set->settype->header;
@@ -143,7 +146,8 @@ saveheader(struct set *set, unsigned int options)
} }
static void static void
saveips(struct set *set, void *data, size_t len, unsigned int options) saveips(struct set *set UNUSED, void *data,
u_int32_t len, unsigned int options)
{ {
struct ip_set_req_iptreemap *req; struct ip_set_req_iptreemap *req;
size_t offset = 0; size_t offset = 0;
@@ -151,10 +155,10 @@ saveips(struct set *set, void *data, size_t len, unsigned int options)
while (len >= offset + sizeof(struct ip_set_req_iptreemap)) { while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
req = data + offset; req = data + offset;
printf("-A %s %s", set->name, ip_tostring(req->start, options)); printf("-A %s %s", set->name, ip_tostring(req->ip, options));
if (req->start != req->end) if (req->ip != req->end)
printf(":%s", ip_tostring(req->end, options)); printf("-%s", ip_tostring(req->end, options));
printf("\n"); printf("\n");
@@ -200,7 +204,7 @@ static struct settype settype_iptreemap = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void iptreemap_init(void) CONSTRUCTOR(iptreemap)
{ {
settype_register(&settype_iptreemap); settype_register(&settype_iptreemap);
} }

View File

@@ -18,16 +18,14 @@
*/ */
#include <stdio.h> #include <stdio.h> /* *printf */
#include <stdlib.h> #include <stdlib.h> /* mem* */
#include <string.h> #include <string.h> /* str* */
#include <sys/socket.h> #include <net/ethernet.h> /* ETH_ALEN */
#include <netinet/in.h>
#include <arpa/inet.h> #include "ipset.h"
#include <linux/if_ether.h>
#include "ip_set_macipmap.h" #include "ip_set_macipmap.h"
#include "ipset.h"
#define BUFLEN 30; #define BUFLEN 30;
@@ -40,17 +38,18 @@
#define OPT_ADDDEL_MAC 0x02U #define OPT_ADDDEL_MAC 0x02U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data UNUSED)
{ {
DP("create INIT"); DP("create INIT");
/* Nothing */ /* Nothing */
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_macipmap_create *mydata = struct ip_set_req_macipmap_create *mydata = data;
(struct ip_set_req_macipmap_create *) data;
DP("create_parse"); DP("create_parse");
@@ -107,10 +106,10 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data, unsigned int flags)
{ {
struct ip_set_req_macipmap_create *mydata = struct ip_set_req_macipmap_create *mydata = data;
(struct ip_set_req_macipmap_create *) data;
if (flags == 0) if (flags == 0)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
@@ -146,14 +145,15 @@ static void create_final(void *data, unsigned int flags)
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"from", 1, 0, '1'}, {.name = "from", .has_arg = required_argument, .val = '1'},
{"to", 1, 0, '2'}, {.name = "to", .has_arg = required_argument, .val = '2'},
{"network", 1, 0, '3'}, {.name = "network", .has_arg = required_argument, .val = '3'},
{"matchunset", 0, 0, '4'}, {.name = "matchunset", .has_arg = no_argument, .val = '4'},
{NULL}, {NULL},
}; };
static void parse_mac(const char *mac, unsigned char *ethernet) static void
parse_mac(const char *mac, unsigned char *ethernet)
{ {
unsigned int i = 0; unsigned int i = 0;
@@ -175,16 +175,23 @@ static void parse_mac(const char *mac, unsigned char *ethernet)
} }
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_macipmap *mydata = struct ip_set_req_macipmap *mydata = data;
(struct ip_set_req_macipmap *) data;
char *saved = ipset_strdup(arg); char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved; char *ptr, *tmp = saved;
DP("macipmap: %p %p", arg, data); DP("macipmap: %p %p", arg, data);
ptr = strsep(&tmp, ",");
if (!tmp) {
tmp = saved;
ptr = strsep(&tmp, ":%"); ptr = strsep(&tmp, ":%");
if (tmp && ++warn_once == 1)
fprintf(stderr, "Warning: please use ',' separator token between ip,mac.\n"
"Next release won't support old separator tokens.\n");
}
parse_ip(ptr, &mydata->ip); parse_ip(ptr, &mydata->ip);
if (tmp) if (tmp)
@@ -193,6 +200,7 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
memset(mydata->ethernet, 0, ETH_ALEN); memset(mydata->ethernet, 0, ETH_ALEN);
free(saved); free(saved);
return 1; return 1;
} }
@@ -200,12 +208,11 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_macipmap_create *header = const struct ip_set_req_macipmap_create *header = data;
(struct ip_set_req_macipmap_create *) data; struct ip_set_macipmap *map = set->settype->header;
struct ip_set_macipmap *map =
(struct ip_set_macipmap *) set->settype->header;
memset(map, 0, sizeof(struct ip_set_macipmap)); memset(map, 0, sizeof(struct ip_set_macipmap));
map->first_ip = header->from; map->first_ip = header->from;
@@ -213,10 +220,10 @@ static void initheader(struct set *set, const void *data)
map->flags = header->flags; map->flags = header->flags;
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options)
{ {
struct ip_set_macipmap *mysetdata = struct ip_set_macipmap *mysetdata = set->settype->header;
(struct ip_set_macipmap *) set->settype->header;
printf(" from: %s", ip_tostring(mysetdata->first_ip, options)); printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
printf(" to: %s", ip_tostring(mysetdata->last_ip, options)); printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
@@ -226,7 +233,8 @@ static void printheader(struct set *set, unsigned int options)
printf("\n"); printf("\n");
} }
static void print_mac(unsigned char macaddress[ETH_ALEN]) static void
print_mac(unsigned char macaddress[ETH_ALEN])
{ {
unsigned int i; unsigned int i;
@@ -235,19 +243,17 @@ static void print_mac(unsigned char macaddress[ETH_ALEN])
printf(":%02X", macaddress[i]); printf(":%02X", macaddress[i]);
} }
static void printips_sorted(struct set *set, void *data, size_t len, static void
unsigned int options) printips_sorted(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options)
{ {
struct ip_set_macipmap *mysetdata = struct ip_set_macipmap *mysetdata = set->settype->header;
(struct ip_set_macipmap *) set->settype->header; struct ip_set_macip *table = data;
struct ip_set_macip *table =
(struct ip_set_macip *) data;
u_int32_t addr = mysetdata->first_ip; u_int32_t addr = mysetdata->first_ip;
while (addr <= mysetdata->last_ip) { while (addr <= mysetdata->last_ip) {
if (test_bit(IPSET_MACIP_ISSET, if (table[addr - mysetdata->first_ip].match) {
(void *)&table[addr - mysetdata->first_ip].flags)) { printf("%s,", ip_tostring(addr, options));
printf("%s:", ip_tostring(addr, options));
print_mac(table[addr - mysetdata->first_ip]. print_mac(table[addr - mysetdata->first_ip].
ethernet); ethernet);
printf("\n"); printf("\n");
@@ -256,10 +262,10 @@ static void printips_sorted(struct set *set, void *data, size_t len,
} }
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options)
{ {
struct ip_set_macipmap *mysetdata = struct ip_set_macipmap *mysetdata = set->settype->header;
(struct ip_set_macipmap *) set->settype->header;
printf("-N %s %s --from %s", printf("-N %s %s --from %s",
set->name, set->settype->typename, set->name, set->settype->typename,
@@ -271,19 +277,17 @@ static void saveheader(struct set *set, unsigned int options)
printf("\n"); printf("\n");
} }
static void saveips(struct set *set, void *data, size_t len, static void
unsigned int options) saveips(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options)
{ {
struct ip_set_macipmap *mysetdata = struct ip_set_macipmap *mysetdata = set->settype->header;
(struct ip_set_macipmap *) set->settype->header; struct ip_set_macip *table = data;
struct ip_set_macip *table =
(struct ip_set_macip *) data;
u_int32_t addr = mysetdata->first_ip; u_int32_t addr = mysetdata->first_ip;
while (addr <= mysetdata->last_ip) { while (addr <= mysetdata->last_ip) {
if (test_bit(IPSET_MACIP_ISSET, if (table[addr - mysetdata->first_ip].match) {
(void *)&table[addr - mysetdata->first_ip].flags)) { printf("-A %s %s,",
printf("-A %s %s:",
set->name, ip_tostring(addr, options)); set->name, ip_tostring(addr, options));
print_mac(table[addr - mysetdata->first_ip]. print_mac(table[addr - mysetdata->first_ip].
ethernet); ethernet);
@@ -298,9 +302,9 @@ static void usage(void)
printf printf
("-N set macipmap --from IP --to IP [--matchunset]\n" ("-N set macipmap --from IP --to IP [--matchunset]\n"
"-N set macipmap --network IP/mask [--matchunset]\n" "-N set macipmap --network IP/mask [--matchunset]\n"
"-A set IP:MAC\n" "-A set IP[,MAC]\n"
"-D set IP[:MAC]\n" "-D set IP[,MAC]\n"
"-T set IP[:MAC]\n"); "-T set IP[,MAC]\n");
} }
static struct settype settype_macipmap = { static struct settype settype_macipmap = {
@@ -334,7 +338,7 @@ static struct settype settype_macipmap = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void macipmap_init(void) CONSTRUCTOR(macipmap)
{ {
settype_register(&settype_macipmap); settype_register(&settype_macipmap);

View File

@@ -15,24 +15,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <errno.h> #include <limits.h> /* UINT_MAX */
#include <limits.h> #include <stdio.h> /* *printf */
#include <stdio.h> #include <string.h> /* mem*, str* */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <asm/types.h>
#include "ip_set_nethash.h"
#include "ip_set_jhash.h"
#include "ipset.h" #include "ipset.h"
#include "ip_set_nethash.h"
#define BUFLEN 30; #define BUFLEN 30;
#define OPT_CREATE_HASHSIZE 0x01U #define OPT_CREATE_HASHSIZE 0x01U
@@ -40,10 +30,10 @@
#define OPT_CREATE_RESIZE 0x04U #define OPT_CREATE_RESIZE 0x04U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data)
{ {
struct ip_set_req_nethash_create *mydata = struct ip_set_req_nethash_create *mydata = data;
(struct ip_set_req_nethash_create *) data;
DP("create INIT"); DP("create INIT");
@@ -54,10 +44,10 @@ static void create_init(void *data)
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_nethash_create *mydata = struct ip_set_req_nethash_create *mydata = data;
(struct ip_set_req_nethash_create *) data;
ip_set_ip_t value; ip_set_ip_t value;
DP("create_parse"); DP("create_parse");
@@ -106,30 +96,24 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data UNUSED, unsigned int flags UNUSED)
{ {
#ifdef IPSET_DEBUG
struct ip_set_req_nethash_create *mydata =
(struct ip_set_req_nethash_create *) data;
DP("hashsize %u probes %u resize %u",
mydata->hashsize, mydata->probes, mydata->resize);
#endif
} }
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"hashsize", 1, 0, '1'}, {.name = "hashsize", .has_arg = required_argument, .val = '1'},
{"probes", 1, 0, '2'}, {.name = "probes", .has_arg = required_argument, .val = '2'},
{"resize", 1, 0, '3'}, {.name = "resize", .has_arg = required_argument, .val = '3'},
{NULL}, {NULL},
}; };
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd, const char *arg, void *data)
{ {
struct ip_set_req_nethash *mydata = struct ip_set_req_nethash *mydata = data;
(struct ip_set_req_nethash *) data;
char *saved = ipset_strdup(arg); char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved; char *ptr, *tmp = saved;
ip_set_ip_t cidr; ip_set_ip_t cidr;
@@ -149,24 +133,25 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
mydata->cidr = cidr; mydata->cidr = cidr;
parse_ip(ptr, &mydata->ip); parse_ip(ptr, &mydata->ip);
#if 0
if (!mydata->ip) if (!mydata->ip)
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
"Zero valued IP address `%s' specified", ptr); "Zero valued IP address `%s' specified", ptr);
free(saved); #endif
ipset_free(saved);
return mydata->ip; return 1;
}; };
/* /*
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_nethash_create *header = const struct ip_set_req_nethash_create *header = data;
(struct ip_set_req_nethash_create *) data; struct ip_set_nethash *map = set->settype->header;
struct ip_set_nethash *map =
(struct ip_set_nethash *) set->settype->header;
memset(map, 0, sizeof(struct ip_set_nethash)); memset(map, 0, sizeof(struct ip_set_nethash));
map->hashsize = header->hashsize; map->hashsize = header->hashsize;
@@ -174,10 +159,10 @@ static void initheader(struct set *set, const void *data)
map->resize = header->resize; map->resize = header->resize;
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options UNUSED)
{ {
struct ip_set_nethash *mysetdata = struct ip_set_nethash *mysetdata = set->settype->header;
(struct ip_set_nethash *) set->settype->header;
printf(" hashsize: %u", mysetdata->hashsize); printf(" hashsize: %u", mysetdata->hashsize);
printf(" probes: %u", mysetdata->probes); printf(" probes: %u", mysetdata->probes);
@@ -186,7 +171,8 @@ static void printheader(struct set *set, unsigned int options)
static char buf[20]; static char buf[20];
static char * unpack_ip_tostring(ip_set_ip_t ip, unsigned options) static char *
unpack_ip_tostring(ip_set_ip_t ip, unsigned options UNUSED)
{ {
int i, j = 3; int i, j = 3;
unsigned char a, b; unsigned char a, b;
@@ -233,12 +219,12 @@ static char * unpack_ip_tostring(ip_set_ip_t ip, unsigned options)
((unsigned char *)&ip)[3], ((unsigned char *)&ip)[3],
b); b);
DP("%s %s", ip_tostring(ntohl(ip), options), buf); DP("%s %s", ip_tostring(ntohl(ip), 0), buf);
return buf; return buf;
} }
static void printips(struct set *set, void *data, size_t len, static void
unsigned int options) printips(struct set *set UNUSED, void *data, u_int32_t len, unsigned options)
{ {
size_t offset = 0; size_t offset = 0;
ip_set_ip_t *ip; ip_set_ip_t *ip;
@@ -251,10 +237,10 @@ static void printips(struct set *set, void *data, size_t len,
} }
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options UNUSED)
{ {
struct ip_set_nethash *mysetdata = struct ip_set_nethash *mysetdata = set->settype->header;
(struct ip_set_nethash *) set->settype->header;
printf("-N %s %s --hashsize %u --probes %u --resize %u\n", printf("-N %s %s --hashsize %u --probes %u --resize %u\n",
set->name, set->settype->typename, set->name, set->settype->typename,
@@ -262,8 +248,8 @@ static void saveheader(struct set *set, unsigned int options)
} }
/* Print save for an IP */ /* Print save for an IP */
static void saveips(struct set *set, void *data, size_t len, static void
unsigned int options) saveips(struct set *set UNUSED, void *data, u_int32_t len, unsigned options)
{ {
size_t offset = 0; size_t offset = 0;
ip_set_ip_t *ip; ip_set_ip_t *ip;
@@ -277,14 +263,16 @@ static void saveips(struct set *set, void *data, size_t len,
} }
} }
static char * net_tostring(struct set *set, ip_set_ip_t ip, unsigned options) static char *
net_tostring(struct set *set UNUSED, ip_set_ip_t ip, unsigned options)
{ {
return unpack_ip_tostring(ip, options); return unpack_ip_tostring(ip, options);
} }
static void parse_net(const char *str, ip_set_ip_t *ip) static void
parse_net(const char *str, ip_set_ip_t *ip)
{ {
char *saved = strdup(str); char *saved = ipset_strdup(str);
char *ptr, *tmp = saved; char *ptr, *tmp = saved;
ip_set_ip_t cidr; ip_set_ip_t cidr;
@@ -299,9 +287,9 @@ static void parse_net(const char *str, ip_set_ip_t *ip)
"Out of range cidr `%s' specified", str); "Out of range cidr `%s' specified", str);
parse_ip(ptr, ip); parse_ip(ptr, ip);
free(saved); ipset_free(saved);
*ip = pack(*ip, cidr); *ip = pack_ip_cidr(*ip, cidr);
} }
static void usage(void) static void usage(void)
@@ -345,7 +333,7 @@ static struct settype settype_nethash = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void nethash_init(void) CONSTRUCTOR(nethash)
{ {
settype_register(&settype_nethash); settype_register(&settype_nethash);

View File

@@ -16,15 +16,12 @@
*/ */
#include <stdio.h> #include <stdio.h> /* *printf */
#include <string.h> #include <string.h> /* mem* */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ip_set_portmap.h"
#include "ipset.h" #include "ipset.h"
#include "ip_set_portmap.h"
#define BUFLEN 30; #define BUFLEN 30;
@@ -34,17 +31,18 @@
#define OPT_ADDDEL_PORT 0x01U #define OPT_ADDDEL_PORT 0x01U
/* Initialize the create. */ /* Initialize the create. */
static void create_init(void *data) static void
create_init(void *data UNUSED)
{ {
DP("create INIT"); DP("create INIT");
/* Nothing */ /* Nothing */
} }
/* Function which parses command options; returns true if it ate an option */ /* Function which parses command options; returns true if it ate an option */
static int create_parse(int c, char *argv[], void *data, unsigned int *flags) static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
{ {
struct ip_set_req_portmap_create *mydata = struct ip_set_req_portmap_create *mydata = data;
(struct ip_set_req_portmap_create *) data;
DP("create_parse"); DP("create_parse");
@@ -77,10 +75,10 @@ static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
} }
/* Final check; exit if not ok. */ /* Final check; exit if not ok. */
static void create_final(void *data, unsigned int flags) static void
create_final(void *data, unsigned int flags)
{ {
struct ip_set_req_portmap_create *mydata = struct ip_set_req_portmap_create *mydata = data;
(struct ip_set_req_portmap_create *) data;
if (flags == 0) { if (flags == 0) {
exit_error(PARAMETER_PROBLEM, exit_error(PARAMETER_PROBLEM,
@@ -108,19 +106,19 @@ static void create_final(void *data, unsigned int flags)
/* Create commandline options */ /* Create commandline options */
static const struct option create_opts[] = { static const struct option create_opts[] = {
{"from", 1, 0, '1'}, {.name = "from", .has_arg = required_argument, .val = '1'},
{"to", 1, 0, '2'}, {.name = "to", .has_arg = required_argument, .val = '2'},
{NULL}, {NULL},
}; };
/* Add, del, test parser */ /* Add, del, test parser */
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data) static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{ {
struct ip_set_req_portmap *mydata = struct ip_set_req_portmap *mydata = data;
(struct ip_set_req_portmap *) data;
parse_port(arg, &mydata->port); parse_port(arg, &mydata->ip);
DP("%s", port_tostring(mydata->port, 0)); DP("%s", port_tostring(mydata->ip, 0));
return 1; return 1;
} }
@@ -129,70 +127,70 @@ static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
* Print and save * Print and save
*/ */
static void initheader(struct set *set, const void *data) static void
initheader(struct set *set, const void *data)
{ {
struct ip_set_req_portmap_create *header = const struct ip_set_req_portmap_create *header = data;
(struct ip_set_req_portmap_create *) data; struct ip_set_portmap *map = set->settype->header;
struct ip_set_portmap *map =
(struct ip_set_portmap *) set->settype->header;
memset(map, 0, sizeof(struct ip_set_portmap)); memset(map, 0, sizeof(struct ip_set_portmap));
map->first_port = header->from; map->first_ip = header->from;
map->last_port = header->to; map->last_ip = header->to;
} }
static void printheader(struct set *set, unsigned int options) static void
printheader(struct set *set, unsigned options)
{ {
struct ip_set_portmap *mysetdata = struct ip_set_portmap *mysetdata = set->settype->header;
(struct ip_set_portmap *) set->settype->header;
printf(" from: %s", port_tostring(mysetdata->first_port, options)); printf(" from: %s", port_tostring(mysetdata->first_ip, options));
printf(" to: %s\n", port_tostring(mysetdata->last_port, options)); printf(" to: %s\n", port_tostring(mysetdata->last_ip, options));
} }
static void printports_sorted(struct set *set, void *data, size_t len, static void
unsigned int options) printports_sorted(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options)
{ {
struct ip_set_portmap *mysetdata = struct ip_set_portmap *mysetdata = set->settype->header;
(struct ip_set_portmap *) set->settype->header; u_int32_t addr = mysetdata->first_ip;
u_int32_t addr = mysetdata->first_port;
DP("%u -- %u", mysetdata->first_port, mysetdata->last_port); DP("%u -- %u", mysetdata->first_ip, mysetdata->last_ip);
while (addr <= mysetdata->last_port) { while (addr <= mysetdata->last_ip) {
if (test_bit(addr - mysetdata->first_port, data)) if (test_bit(addr - mysetdata->first_ip, data))
printf("%s\n", port_tostring(addr, options)); printf("%s\n", port_tostring(addr, options));
addr++; addr++;
} }
} }
static char *binding_port_tostring(struct set *set, ip_set_ip_t ip, static char *
unsigned int options) binding_port_tostring(struct set *set UNUSED,
ip_set_ip_t ip, unsigned options)
{ {
return port_tostring(ip, options); return port_tostring(ip, options);
} }
static void saveheader(struct set *set, unsigned int options) static void
saveheader(struct set *set, unsigned options)
{ {
struct ip_set_portmap *mysetdata = struct ip_set_portmap *mysetdata = set->settype->header;
(struct ip_set_portmap *) set->settype->header;
printf("-N %s %s --from %s", printf("-N %s %s --from %s",
set->name, set->name,
set->settype->typename, set->settype->typename,
port_tostring(mysetdata->first_port, options)); port_tostring(mysetdata->first_ip, options));
printf(" --to %s\n", printf(" --to %s\n",
port_tostring(mysetdata->last_port, options)); port_tostring(mysetdata->last_ip, options));
} }
static void saveports(struct set *set, void *data, size_t len, static void
unsigned int options) saveports(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options)
{ {
struct ip_set_portmap *mysetdata = struct ip_set_portmap *mysetdata = set->settype->header;
(struct ip_set_portmap *) set->settype->header; u_int32_t addr = mysetdata->first_ip;
u_int32_t addr = mysetdata->first_port;
while (addr <= mysetdata->last_port) { while (addr <= mysetdata->last_ip) {
if (test_bit(addr - mysetdata->first_port, data)) if (test_bit(addr - mysetdata->first_ip, data))
printf("-A %s %s\n", printf("-A %s %s\n",
set->name, set->name,
port_tostring(addr, options)); port_tostring(addr, options));
@@ -240,7 +238,7 @@ static struct settype settype_portmap = {
.usage = &usage, .usage = &usage,
}; };
static __attribute__((constructor)) void portmap_init(void) CONSTRUCTOR(portmap)
{ {
settype_register(&settype_portmap); settype_register(&settype_portmap);

View File

@@ -0,0 +1,221 @@
/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ip_set_setlist.h"
#include "ipset.h"
/* Initialize the create. */
static void
create_init(void *data)
{
struct ip_set_req_setlist_create *mydata = data;
mydata->size = 8;
}
/* Function which parses command options; returns true if it ate an option */
static int
create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags UNUSED)
{
struct ip_set_req_setlist_create *mydata = data;
unsigned int size;
switch (c) {
case '1':
if (string_to_number(optarg, 1, 255, &size))
exit_error(PARAMETER_PROBLEM,
"Invalid size '%s specified: must be "
"between 1-255", optarg);
mydata->size = size;
break;
default:
return 0;
}
return 1;
}
/* Final check; exit if not ok. */
static void
create_final(void *data UNUSED, unsigned int flags UNUSED)
{
}
/* Create commandline options */
static const struct option create_opts[] = {
{.name = "size", .has_arg = required_argument, .val = '1'},
{NULL},
};
static void check_setname(const char *name)
{
if (strlen(name) > IP_SET_MAXNAMELEN - 1)
exit_error(PARAMETER_PROBLEM,
"Setname %s is longer than %d characters.",
name, IP_SET_MAXNAMELEN - 1);
}
/* Add, del, test parser */
static ip_set_ip_t
adt_parser(int cmd UNUSED, const char *arg, void *data)
{
struct ip_set_req_setlist *mydata = data;
char *saved = ipset_strdup(arg);
char *ptr, *tmp = saved;
DP("setlist: %p %p", arg, data);
ptr = strsep(&tmp, ",");
check_setname(ptr);
strcpy(mydata->name, ptr);
if (!tmp) {
mydata->before = 0;
mydata->ref[0] = '\0';
return 1;
}
ptr = strsep(&tmp, ",");
if (tmp == NULL || !(strcmp(ptr, "before") == 0 || strcmp(ptr, "after") == 0))
exit_error(PARAMETER_PROBLEM,
"Syntax error, you must specify elements as setname,[before|after],setname");
check_setname(tmp);
strcpy(mydata->ref, tmp);
mydata->before = !strcmp(ptr, "before");
free(saved);
return 1;
}
/*
* Print and save
*/
static void
initheader(struct set *set, const void *data)
{
const struct ip_set_req_setlist_create *header = data;
struct ip_set_setlist *map = set->settype->header;
memset(map, 0, sizeof(struct ip_set_setlist));
map->size = header->size;
}
static void
printheader(struct set *set, unsigned options UNUSED)
{
struct ip_set_setlist *mysetdata = set->settype->header;
printf(" size: %u\n", mysetdata->size);
}
static void
printips_sorted(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options UNUSED)
{
struct ip_set_setlist *mysetdata = set->settype->header;
int i;
ip_set_id_t id;
struct set *elem;
for (i = 0; i < mysetdata->size; i++ ) {
id = *((ip_set_id_t *)data + i);
if (id == IP_SET_INVALID_ID)
return;
elem = set_find_byid(id);
printf("%s\n", elem->name);
}
}
static void
saveheader(struct set *set, unsigned options UNUSED)
{
struct ip_set_setlist *mysetdata = set->settype->header;
printf("-N %s %s --size %u\n",
set->name, set->settype->typename,
mysetdata->size);
}
static void
saveips(struct set *set, void *data,
u_int32_t len UNUSED, unsigned options UNUSED)
{
struct ip_set_setlist *mysetdata = set->settype->header;
int i;
ip_set_id_t id;
struct set *elem;
for (i = 0; i < mysetdata->size; i++ ) {
id = *((ip_set_id_t *)data + i);
if (id == IP_SET_INVALID_ID)
return;
elem = set_find_byid(id);
printf("-A %s %s\n", set->name, elem->name);
}
}
static void usage(void)
{
printf
("-N set setlist --size size\n"
"-A set setname[,before|after,setname]\n"
"-D set setname\n"
"-T set setname\n");
}
static struct settype settype_setlist = {
.typename = SETTYPE_NAME,
.protocol_version = IP_SET_PROTOCOL_VERSION,
/* Create */
.create_size = sizeof(struct ip_set_req_setlist_create),
.create_init = &create_init,
.create_parse = &create_parse,
.create_final = &create_final,
.create_opts = create_opts,
/* Add/del/test */
.adt_size = sizeof(struct ip_set_req_setlist),
.adt_parser = &adt_parser,
/* Printing */
.header_size = sizeof(struct ip_set_setlist),
.initheader = &initheader,
.printheader = &printheader,
.printips = &printips_sorted, /* We only have sorted version */
.printips_sorted = &printips_sorted,
.saveheader = &saveheader,
.saveips = &saveips,
.usage = &usage,
};
CONSTRUCTOR(setlist)
{
settype_register(&settype_setlist);
}

View File

@@ -10,82 +10,48 @@
/* ipt_SET.c - netfilter target to manipulate IP sets */ /* ipt_SET.c - netfilter target to manipulate IP sets */
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/timer.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netfilter.h> #include <linux/ip.h>
#include <linux/netdevice.h> #include <linux/skbuff.h>
#include <linux/if.h>
#include <linux/inetdevice.h>
#include <linux/version.h> #include <linux/version.h>
#include <net/protocol.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#define xt_register_target ipt_register_target
#define xt_unregister_target ipt_unregister_target
#define xt_target ipt_target
#define XT_CONTINUE IPT_CONTINUE
#else
#include <linux/netfilter/x_tables.h>
#endif
#include "ipt_set.h" #include "ipt_set.h"
#include "../compat_xtables.h"
static unsigned int static unsigned int
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) target(struct sk_buff **pskb, const struct xt_target_param *par)
target(struct sk_buff *skb,
#else
target(struct sk_buff **pskb,
#endif
const struct net_device *in,
const struct net_device *out,
unsigned int hooknum,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
const struct xt_target *target,
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
const void *targinfo,
void *userinfo)
#else
const void *targinfo)
#endif
{ {
const struct ipt_set_info_target *info = targinfo; const struct ipt_set_info_target *info = par->targinfo;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
struct sk_buff *skb = *pskb;
#endif
if (info->add_set.index != IP_SET_INVALID_ID) if (info->add_set.index != IP_SET_INVALID_ID)
ip_set_addip_kernel(info->add_set.index, ip_set_addip_kernel(info->add_set.index,
skb, *pskb,
info->add_set.flags); info->add_set.flags);
if (info->del_set.index != IP_SET_INVALID_ID) if (info->del_set.index != IP_SET_INVALID_ID)
ip_set_delip_kernel(info->del_set.index, ip_set_delip_kernel(info->del_set.index,
skb, *pskb,
info->del_set.flags); info->del_set.flags);
return IPT_CONTINUE; return XT_CONTINUE;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
static bool static bool
#else checkentry(const struct xt_tgchk_param *par)
static int
#endif
checkentry(const char *tablename,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
const void *e,
#else
const struct ipt_entry *e,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
const struct xt_target *target,
#endif
void *targinfo,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
unsigned int targinfosize,
#endif
unsigned int hook_mask)
{ {
struct ipt_set_info_target *info = targinfo; struct ipt_set_info_target *info = par->targinfo;
ip_set_id_t index; ip_set_id_t index;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
if (targinfosize != IPT_ALIGN(sizeof(*info))) { if (targinfosize != IPT_ALIGN(sizeof(*info))) {
DP("bad target info size %u", targinfosize); DP("bad target info size %u", targinfosize);
return 0; return 0;
@@ -118,61 +84,54 @@ checkentry(const char *tablename,
return 1; return 1;
} }
static void destroy( static void destroy(const struct xt_tgdtor_param *par)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
const struct xt_target *target,
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
void *targetinfo, unsigned int targetsize)
#else
void *targetinfo)
#endif
{ {
struct ipt_set_info_target *info = targetinfo; struct ipt_set_info_target *info = par->targinfo;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) { if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
ip_set_printk("invalid targetsize %d", targetsize); ip_set_printk("invalid targetsize %d", targetsize);
return; return;
} }
#endif #endif
if (info->add_set.index != IP_SET_INVALID_ID) if (info->add_set.index != IP_SET_INVALID_ID)
ip_set_put(info->add_set.index); ip_set_put_byindex(info->add_set.index);
if (info->del_set.index != IP_SET_INVALID_ID) if (info->del_set.index != IP_SET_INVALID_ID)
ip_set_put(info->del_set.index); ip_set_put_byindex(info->del_set.index);
} }
static struct ipt_target SET_target = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
static struct xt_target SET_target = {
.name = "SET", .name = "SET",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
.family = AF_INET,
#endif
.target = target, .target = target,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
.targetsize = sizeof(struct ipt_set_info_target),
#endif
.checkentry = checkentry, .checkentry = checkentry,
.destroy = destroy, .destroy = destroy,
.me = THIS_MODULE .me = THIS_MODULE
}; };
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) */
static struct xt_target SET_target = {
.name = "SET",
.family = AF_INET,
.target = target,
.targetsize = sizeof(struct ipt_set_info_target),
.checkentry = checkentry,
.destroy = destroy,
.me = THIS_MODULE
};
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("iptables IP set target module"); MODULE_DESCRIPTION("iptables IP set target module");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
#define ipt_register_target xt_register_target
#define ipt_unregister_target xt_unregister_target
#endif
static int __init ipt_SET_init(void) static int __init ipt_SET_init(void)
{ {
return ipt_register_target(&SET_target); return xt_register_target(&SET_target);
} }
static void __exit ipt_SET_fini(void) static void __exit ipt_SET_fini(void)
{ {
ipt_unregister_target(&SET_target); xt_unregister_target(&SET_target);
} }
module_init(ipt_SET_init); module_init(ipt_SET_init);

View File

@@ -15,9 +15,17 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#define xt_register_match ipt_register_match
#define xt_unregister_match ipt_unregister_match
#define xt_match ipt_match
#else
#include <linux/netfilter/x_tables.h>
#endif
#include "ip_set.h" #include "ip_set.h"
#include "ipt_set.h" #include "ipt_set.h"
#include "../compat_xtables.h"
static inline int static inline int
match_set(const struct ipt_set_info *info, match_set(const struct ipt_set_info *info,
@@ -29,57 +37,23 @@ match_set(const struct ipt_set_info *info,
return inv; return inv;
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
static bool static bool
#else match(const struct sk_buff *skb, const struct xt_match_param *par)
static int
#endif
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
const struct xt_match *match,
#endif
const void *matchinfo,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
int offset, unsigned int protoff, bool *hotdrop)
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
int offset, unsigned int protoff, int *hotdrop)
#else
int offset, int *hotdrop)
#endif
{ {
const struct ipt_set_info_match *info = matchinfo; const struct ipt_set_info_match *info = par->matchinfo;
return match_set(&info->match_set, return match_set(&info->match_set,
skb, skb,
info->match_set.flags[0] & IPSET_MATCH_INV); info->match_set.flags[0] & IPSET_MATCH_INV);
} }
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
static bool static bool
#else checkentry(const struct xt_mtchk_param *par)
static int
#endif
checkentry(const char *tablename,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
const void *inf,
#else
const struct ipt_ip *ip,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
const struct xt_match *match,
#endif
void *matchinfo,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
unsigned int matchsize,
#endif
unsigned int hook_mask)
{ {
struct ipt_set_info_match *info = matchinfo; struct ipt_set_info_match *info = par->matchinfo;
ip_set_id_t index; ip_set_id_t index;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) { if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
ip_set_printk("invalid matchsize %d", matchsize); ip_set_printk("invalid matchsize %d", matchsize);
return 0; return 0;
@@ -101,58 +75,51 @@ checkentry(const char *tablename,
return 1; return 1;
} }
static void destroy( static void destroy(const struct xt_mtdtor_param *par)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
const struct xt_match *match,
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
void *matchinfo, unsigned int matchsize)
#else
void *matchinfo)
#endif
{ {
struct ipt_set_info_match *info = matchinfo; struct ipt_set_info_match *info = par->matchinfo;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) { if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
ip_set_printk("invalid matchsize %d", matchsize); ip_set_printk("invalid matchsize %d", matchsize);
return; return;
} }
#endif #endif
ip_set_put(info->match_set.index); ip_set_put_byindex(info->match_set.index);
} }
static struct ipt_match set_match = { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
static struct xt_match set_match = {
.name = "set", .name = "set",
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
.family = AF_INET,
#endif
.match = &match, .match = &match,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
.matchsize = sizeof(struct ipt_set_info_match),
#endif
.checkentry = &checkentry, .checkentry = &checkentry,
.destroy = &destroy, .destroy = &destroy,
.me = THIS_MODULE .me = THIS_MODULE
}; };
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17) */
static struct xt_match set_match = {
.name = "set",
.family = AF_INET,
.match = &match,
.matchsize = sizeof(struct ipt_set_info_match),
.checkentry = &checkentry,
.destroy = &destroy,
.me = THIS_MODULE
};
#endif
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("iptables IP set match module"); MODULE_DESCRIPTION("iptables IP set match module");
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
#define ipt_register_match xt_register_match
#define ipt_unregister_match xt_unregister_match
#endif
static int __init ipt_ipset_init(void) static int __init ipt_ipset_init(void)
{ {
return ipt_register_match(&set_match); return xt_register_match(&set_match);
} }
static void __exit ipt_ipset_fini(void) static void __exit ipt_ipset_fini(void)
{ {
ipt_unregister_match(&set_match); xt_unregister_match(&set_match);
} }
module_init(ipt_ipset_init); module_init(ipt_ipset_init);

View File

@@ -0,0 +1,109 @@
/*
* rawpost table for ip_tables
* written by Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2009
* placed in the Public Domain
*/
#include <linux/module.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/version.h>
#include <net/ip.h>
#include "compat_xtables.h"
#include "compat_rawpost.h"
enum {
RAWPOST_VALID_HOOKS = 1 << NF_INET_POST_ROUTING,
};
static struct {
struct ipt_replace repl;
struct ipt_standard entries[1];
struct ipt_error term;
} rawpost4_initial __initdata = {
.repl = {
.name = "rawpost",
.valid_hooks = RAWPOST_VALID_HOOKS,
.num_entries = 2,
.size = sizeof(struct ipt_standard) +
sizeof(struct ipt_error),
.hook_entry = {
[NF_INET_POST_ROUTING] = 0,
},
.underflow = {
[NF_INET_POST_ROUTING] = 0,
},
},
.entries = {
IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
},
.term = IPT_ERROR_INIT, /* ERROR */
};
static struct xt_table *rawpost4_ptable;
static struct xt_table rawpost4_itable = {
.name = "rawpost",
.af = NFPROTO_IPV4,
.valid_hooks = RAWPOST_VALID_HOOKS,
.me = THIS_MODULE,
};
static unsigned int rawpost4_hook_fn(unsigned int hook, sk_buff_t *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
return ipt_do_table(skb, hook, in, out, rawpost4_ptable);
#else
return ipt_do_table(skb, hook, in, out, rawpost4_ptable, NULL);
#endif
}
static struct nf_hook_ops rawpost4_hook_ops __read_mostly = {
.hook = rawpost4_hook_fn,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_LAST,
.owner = THIS_MODULE,
};
static int __init rawpost4_table_init(void)
{
int ret;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 29)
rwlock_init(&rawpost4_itable.lock);
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
rawpost4_ptable = ipt_register_table(&init_net, &rawpost4_itable,
&rawpost4_initial.repl);
if (IS_ERR(rawpost4_ptable))
return PTR_ERR(rawpost4_ptable);
#else
ret = ipt_register_table(&rawpost4_itable, &rawpost4_initial.repl);
if (ret < 0)
return ret;
rawpost4_ptable = &rawpost4_itable;
#endif
ret = nf_register_hook(&rawpost4_hook_ops);
if (ret < 0)
goto out;
return ret;
out:
ipt_unregister_table(rawpost4_ptable);
return ret;
}
static void __exit rawpost4_table_exit(void)
{
nf_unregister_hook(&rawpost4_hook_ops);
ipt_unregister_table(rawpost4_ptable);
}
module_init(rawpost4_table_init);
module_exit(rawpost4_table_exit);
MODULE_DESCRIPTION("Xtables: rawpost table for use with RAWNAT");
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
MODULE_LICENSE("GPL");

168
extensions/libxt_ACCOUNT.c Normal file
View File

@@ -0,0 +1,168 @@
/* Shared library add-on to iptables to add ACCOUNT(ing) support.
Author: Intra2net AG <opensource@intra2net.com>
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <syslog.h>
#include <getopt.h>
#include <stddef.h>
#include <xtables.h>
#include "xt_ACCOUNT.h"
static struct option account_tg_opts[] = {
{ .name = "addr", .has_arg = 1, .flag = 0, .val = 'a' },
{ .name = "tname", .has_arg = 1, .flag = 0, .val = 't' },
{ .name = 0 }
};
/* Function which prints out usage message. */
static void account_tg_help(void)
{
printf(
"ACCOUNT target options:\n"
" --%s ip/netmask\t\tBase network IP and netmask used for this table\n"
" --%s name\t\t\tTable name for the userspace library\n",
account_tg_opts[0].name, account_tg_opts[1].name);
}
/* Initialize the target. */
static void
account_tg_init(struct xt_entry_target *t)
{
struct ipt_acc_info *accountinfo = (struct ipt_acc_info *)t->data;
accountinfo->table_nr = -1;
}
#define IPT_ACCOUNT_OPT_ADDR 0x01
#define IPT_ACCOUNT_OPT_TABLE 0x02
/* Function which parses command options; returns true if it
ate an option */
static int account_tg_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct ipt_acc_info *accountinfo = (struct ipt_acc_info *)(*target)->data;
struct in_addr *addrs = NULL, mask;
unsigned int naddrs = 0;
switch (c) {
case 'a':
if (*flags & IPT_ACCOUNT_OPT_ADDR)
xtables_error(PARAMETER_PROBLEM, "Can't specify --%s twice",
account_tg_opts[0].name);
if (xtables_check_inverse(optarg, &invert, NULL, 0))
xtables_error(PARAMETER_PROBLEM, "Unexpected `!' after --%s",
account_tg_opts[0].name);
xtables_ipparse_any(optarg, &addrs, &mask, &naddrs);
if (naddrs > 1)
xtables_error(PARAMETER_PROBLEM, "multiple IP addresses not allowed");
accountinfo->net_ip = addrs[0].s_addr;
accountinfo->net_mask = mask.s_addr;
*flags |= IPT_ACCOUNT_OPT_ADDR;
break;
case 't':
if (*flags & IPT_ACCOUNT_OPT_TABLE)
xtables_error(PARAMETER_PROBLEM,
"Can't specify --%s twice",
account_tg_opts[1].name);
if (xtables_check_inverse(optarg, &invert, NULL, 0))
xtables_error(PARAMETER_PROBLEM,
"Unexpected `!' after --%s",
account_tg_opts[1].name);
if (strlen(optarg) > ACCOUNT_TABLE_NAME_LEN - 1)
xtables_error(PARAMETER_PROBLEM,
"Maximum table name length %u for --%s",
ACCOUNT_TABLE_NAME_LEN - 1,
account_tg_opts[1].name);
strcpy(accountinfo->table_name, optarg);
*flags |= IPT_ACCOUNT_OPT_TABLE;
break;
default:
return 0;
}
return 1;
}
static void account_tg_check(unsigned int flags)
{
if (!(flags & IPT_ACCOUNT_OPT_ADDR) || !(flags & IPT_ACCOUNT_OPT_TABLE))
xtables_error(PARAMETER_PROBLEM, "ACCOUNT: needs --%s and --%s",
account_tg_opts[0].name, account_tg_opts[1].name);
}
static void account_tg_print_it(const void *ip,
const struct xt_entry_target *target, char do_prefix)
{
const struct ipt_acc_info *accountinfo
= (const struct ipt_acc_info *)target->data;
struct in_addr a;
if (!do_prefix)
printf("ACCOUNT ");
// Network information
if (do_prefix)
printf("--");
printf("%s ", account_tg_opts[0].name);
a.s_addr = accountinfo->net_ip;
printf("%s", xtables_ipaddr_to_numeric(&a));
a.s_addr = accountinfo->net_mask;
printf("%s", xtables_ipmask_to_numeric(&a));
printf(" ");
if (do_prefix)
printf("--");
printf("%s %s", account_tg_opts[1].name, accountinfo->table_name);
}
static void
account_tg_print(const void *ip,
const struct xt_entry_target *target,
int numeric)
{
account_tg_print_it(ip, target, 0);
}
/* Saves the union ipt_targinfo in parsable form to stdout. */
static void
account_tg_save(const void *ip, const struct xt_entry_target *target)
{
account_tg_print_it(ip, target, 1);
}
static struct xtables_target account_tg_reg = {
.name = "ACCOUNT",
.family = AF_INET,
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct ipt_acc_info)),
.userspacesize = offsetof(struct ipt_acc_info, table_nr),
.help = account_tg_help,
.init = account_tg_init,
.parse = account_tg_parse,
.final_check = account_tg_check,
.print = account_tg_print,
.save = account_tg_save,
.extra_opts = account_tg_opts,
};
static __attribute__((constructor)) void account_tg_ldr(void)
{
xtables_register_target(&account_tg_reg);
}

View File

@@ -0,0 +1,72 @@
The ACCOUNT target is a high performance accounting system for large
local networks. It allows per-IP accounting in whole prefixes of IPv4
addresses with size of up to /8 without the need to add individual
accouting rule for each IP address.
.PP
The ACCOUNT is designed to be queried for data every second or at
least every ten seconds. It is written as kernel module to handle high
bandwidths without packet loss.
.PP
The largest possible subnet size is 24 bit, meaning for example 10.0.0.0/8
network. ACCOUNT uses fixed internal data structures
which speeds up the processing of each packet. Furthermore,
accounting data for one complete 192.168.1.X/24 network takes 4 KB of
memory. Memory for 16 or 24 bit networks is only allocated when
needed.
.PP
To optimize the kernel<->userspace data transfer a bit more, the
kernel module only transfers information about IPs, where the src/dst
packet counter is not 0. This saves precious kernel time.
.PP
There is no /proc interface as it would be too slow for continuous access.
The read-and-flush query operation is the fastest, as no internal data
snapshot needs to be created&copied for all data. Use the "read"
operation without flush only for debugging purposes!
.PP
Usage:
.PP
ACCOUNT takes two mandatory parameters:
.TP
\fB\-\-addr\fR \fInetwork\fP\fB/\fP\fInetmask\fR
where \fInetwork\fP\fB/\fP\fInetmask\fP is the subnet to account for, in CIDR syntax
.TP
\fB\-\-tname\fP \fINAME\fP
where \fINAME\fP is the name of the table where the accounting information
should be stored
.PP
The subnet 0.0.0.0/0 is a special case: all data are then stored in the src_bytes
and src_packets structure of slot "0". This is useful if you want
to account the overall traffic to/from your internet provider.
.PP
The data can be queried using the userspace libxt_ACCOUNT_cl library,
and by the reference implementation to show usage of this library,
the \fBiptaccount\fP(8) tool, which features following options:
.PP
[\fB\-u\fP] show kernel handle usage
.PP
[\fB\-h\fP] free all kernel handles (experts only!)
.PP
[\fB\-a\fP] list all table names
.PP
[\fB\-l\fP \fIname\fP] show data in table \fIname\fP
.PP
[\fB\-f\fP] flush data after showing
.PP
[\fB\-c\fP] loop every second (abort with CTRL+C)
.PP
Here is an example of use:
.PP
iptables \-A FORWARD \-j ACCOUNT \-\-addr 0.0.0.0/0 \-\-tname all_outgoing
iptables \-A FORWARD \-j ACCOUNT \-\-addr 192.168.1.0/24 \-\-tname sales
.PP
This creates two tables called "all_outgoing" and "sales" which can be
queried using the userspace library/iptaccount tool.
.PP
Note that this target is non-terminating \(em the packet destined to it
will continue traversing the chain in which it has been used.
.PP
Also note that once a table has been defined for specific CIDR address/netmask
block, it can be referenced multiple times using \-j ACCOUNT, provided
that both the original table name and address/netmask block are specified.
.PP
For more information go to http://www.intra2net.com/en/developer/ipt_ACCOUNT/

View File

@@ -25,7 +25,7 @@ enum {
static const struct option chaos_tg_opts[] = { static const struct option chaos_tg_opts[] = {
{.name = "delude", .has_arg = false, .val = 'd'}, {.name = "delude", .has_arg = false, .val = 'd'},
{.name = "tarpit", .has_arg = false, .val = 't'}, {.name = "tarpit", .has_arg = false, .val = 't'},
{}, {NULL},
}; };
static void chaos_tg_help(void) static void chaos_tg_help(void)
@@ -58,7 +58,7 @@ static void chaos_tg_check(unsigned int flags)
{ {
if (flags == (F_DELUDE | F_TARPIT)) if (flags == (F_DELUDE | F_TARPIT))
/* If flags == 0x03, both were specified, which should not be. */ /* If flags == 0x03, both were specified, which should not be. */
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"CHAOS: only one of --tarpit or --delude " "CHAOS: only one of --tarpit or --delude "
"may be specified"); "may be specified");
} }
@@ -106,8 +106,7 @@ static struct xtables_target chaos_tg_reg = {
.extra_opts = chaos_tg_opts, .extra_opts = chaos_tg_opts,
}; };
void _init(void); static __attribute__((constructor)) void chaos_tg_ldr(void)
void _init(void)
{ {
xtables_register_target(&chaos_tg_reg); xtables_register_target(&chaos_tg_reg);
} }

View File

@@ -18,4 +18,4 @@ The randomness factor of not replying vs. replying can be set during load-time
of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters. of the xt_CHAOS module or during runtime in /sys/modules/xt_CHAOS/parameters.
.PP .PP
See http://jengelh.medozas.de/projects/chaostables/ for more information See http://jengelh.medozas.de/projects/chaostables/ for more information
about CHAOS, DELUDE and portscan. about CHAOS, DELUDE and lscan.

View File

@@ -41,8 +41,7 @@ static struct xtables_target delude_tg_reg = {
.final_check = delude_tg_check, .final_check = delude_tg_check,
}; };
void _init(void); static __attribute__((constructor)) void delude_tg_ldr(void)
void _init(void)
{ {
xtables_register_target(&delude_tg_reg); xtables_register_target(&delude_tg_reg);
} }

View File

@@ -1,101 +0,0 @@
/*
* "DHCPADDR" target extension for iptables
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <getopt.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ether.h>
#include <xtables.h>
#include "xt_DHCPADDR.h"
#include "mac.c"
enum {
F_MAC = 1 << 0,
};
static const struct option dhcpaddr_tg_opts[] = {
{.name = "set-mac", .has_arg = true, .val = 'M'},
{NULL},
};
static void dhcpaddr_tg_help(void)
{
printf(
"DHCPADDDR target options:\n"
" --set-mac lladdr[/mask] Set MAC address in DHCP Client Host field\n"
);
}
static int dhcpaddr_tg_parse(int c, char **argv, int invert,
unsigned int *flags, const void *entry, struct xt_entry_target **target)
{
struct dhcpaddr_info *info = (void *)(*target)->data;
switch (c) {
case 'M':
param_act(P_ONLY_ONCE, "DHCPADDR", "--set-mac", *flags & F_MAC);
param_act(P_NO_INVERT, "DHCPADDR", "--set-mac", invert);
if (!mac_parse(optarg, info->addr, &info->mask))
param_act(P_BAD_VALUE, "DHCPADDR", "--set-mac", optarg);
*flags |= F_MAC;
return true;
}
return false;
}
static void dhcpaddr_tg_check(unsigned int flags)
{
if (flags == 0)
exit_error(PARAMETER_PROBLEM, "DHCPADDR target: "
"--set-mac parameter required");
}
static void dhcpaddr_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct dhcpaddr_info *info = (void *)target->data;
printf("DHCPADDR %s" DH_MAC_FMT "/%u ",
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
}
static void dhcpaddr_tg_save(const void *ip,
const struct xt_entry_target *target)
{
const struct dhcpaddr_info *info = (const void *)target->data;
if (info->invert)
printf("! ");
printf("--set-mac " DH_MAC_FMT "/%u ",
DH_MAC_HEX(info->addr), info->mask);
}
static struct xtables_target dhcpaddr_tg_reg = {
.version = XTABLES_VERSION,
.name = "DHCPADDR",
.revision = 0,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct dhcpaddr_info)),
.userspacesize = XT_ALIGN(sizeof(struct dhcpaddr_info)),
.help = dhcpaddr_tg_help,
.parse = dhcpaddr_tg_parse,
.final_check = dhcpaddr_tg_check,
.print = dhcpaddr_tg_print,
.save = dhcpaddr_tg_save,
.extra_opts = dhcpaddr_tg_opts,
};
static void _init(void)
{
xtables_register_target(&dhcpaddr_tg_reg);
}

101
extensions/libxt_DHCPMAC.c Normal file
View File

@@ -0,0 +1,101 @@
/*
* "DHCPMAC" target extension for iptables
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <getopt.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ether.h>
#include <xtables.h>
#include "xt_DHCPMAC.h"
#include "mac.c"
enum {
F_MAC = 1 << 0,
};
static const struct option dhcpmac_tg_opts[] = {
{.name = "set-mac", .has_arg = true, .val = 'M'},
{NULL},
};
static void dhcpmac_tg_help(void)
{
printf(
"DHCPMAC target options:\n"
" --set-mac lladdr[/mask] Set MAC address in DHCP Client Host field\n"
);
}
static int dhcpmac_tg_parse(int c, char **argv, int invert,
unsigned int *flags, const void *entry, struct xt_entry_target **target)
{
struct dhcpmac_info *info = (void *)(*target)->data;
switch (c) {
case 'M':
xtables_param_act(XTF_ONLY_ONCE, "DHCPMAC", "--set-mac", *flags & F_MAC);
xtables_param_act(XTF_NO_INVERT, "DHCPMAC", "--set-mac", invert);
if (!mac_parse(optarg, info->addr, &info->mask))
xtables_param_act(XTF_BAD_VALUE, "DHCPMAC", "--set-mac", optarg);
*flags |= F_MAC;
return true;
}
return false;
}
static void dhcpmac_tg_check(unsigned int flags)
{
if (flags == 0)
xtables_error(PARAMETER_PROBLEM, "DHCPMAC target: "
"--set-mac parameter required");
}
static void dhcpmac_tg_print(const void *ip,
const struct xt_entry_target *target, int numeric)
{
const struct dhcpmac_info *info = (void *)target->data;
printf("DHCPMAC %s" DH_MAC_FMT "/%u ",
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
}
static void dhcpmac_tg_save(const void *ip,
const struct xt_entry_target *target)
{
const struct dhcpmac_info *info = (const void *)target->data;
if (info->invert)
printf("! ");
printf("--set-mac " DH_MAC_FMT "/%u ",
DH_MAC_HEX(info->addr), info->mask);
}
static struct xtables_target dhcpmac_tg_reg = {
.version = XTABLES_VERSION,
.name = "DHCPMAC",
.revision = 0,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct dhcpmac_info)),
.userspacesize = XT_ALIGN(sizeof(struct dhcpmac_info)),
.help = dhcpmac_tg_help,
.parse = dhcpmac_tg_parse,
.final_check = dhcpmac_tg_check,
.print = dhcpmac_tg_print,
.save = dhcpmac_tg_save,
.extra_opts = dhcpmac_tg_opts,
};
static __attribute__((constructor)) void dhcpmac_tg_ldr(void)
{
xtables_register_target(&dhcpmac_tg_reg);
}

View File

@@ -1,4 +1,4 @@
In conjunction with ebtables, DHCPADDR can be used to completely change all MAC In conjunction with ebtables, DHCPMAC can be used to completely change all MAC
addresses from and to a VMware-based virtual machine. This is needed because addresses from and to a VMware-based virtual machine. This is needed because
VMware does not allow to set a non-VMware MAC address before an operating VMware does not allow to set a non-VMware MAC address before an operating
system is booted (and the MAC be changed with `ip link set eth0 address system is booted (and the MAC be changed with `ip link set eth0 address
@@ -13,11 +13,11 @@ EXAMPLE, replacing all addresses from one of VMware's assigned vendor IDs
(00:50:56) addresses with something else: (00:50:56) addresses with something else:
.PP .PP
iptables -t mangle -A FORWARD -p udp --dport 67 -m physdev --physdev-in vmnet1 iptables -t mangle -A FORWARD -p udp --dport 67 -m physdev --physdev-in vmnet1
-m dhcpaddr --mac 00:50:56:00:00:00/24 -j DHCPADDR --set-mac -m dhcpmac --mac 00:50:56:00:00:00/24 -j DHCPMAC --set-mac
ab:cd:ef:00:00:00/24 ab:cd:ef:00:00:00/24
.PP .PP
iptables -t mangle -A FORWARD -p udp --dport 68 -m physdev --physdev-out vmnet1 iptables -t mangle -A FORWARD -p udp --dport 68 -m physdev --physdev-out vmnet1
-m dhcpaddr --mac ab:cd:ef:00:00:00/24 -j DHCPADDR --set-mac -m dhcpmac --mac ab:cd:ef:00:00:00/24 -j DHCPMAC --set-mac
00:50:56:00:00:00/24 00:50:56:00:00:00/24
.PP .PP
(This assumes there is a bridge interface that has vmnet1 as a port. You will (This assumes there is a bridge interface that has vmnet1 as a port. You will

View File

@@ -37,7 +37,7 @@ static struct xtables_target echo_tg_reg = {
.final_check = echo_tg_check, .final_check = echo_tg_check,
}; };
static void _init(void) static __attribute__((constructor)) void echo_tg_ldr(void)
{ {
xtables_register_target(&echo_tg_reg); xtables_register_target(&echo_tg_reg);
} }

View File

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

View File

@@ -58,45 +58,46 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) { switch (c) {
case '1': case '1':
param_act(P_ONLY_ONCE, "IPMARK", "addr", *flags & FL_ADDR_USED); xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "addr", *flags & FL_ADDR_USED);
param_act(P_NO_INVERT, "IPMARK", "addr", invert); xtables_param_act(XTF_NO_INVERT, "IPMARK", "addr", invert);
if (strcmp(optarg, "src") == 0) if (strcmp(optarg, "src") == 0)
info->selector = XT_IPMARK_SRC; info->selector = XT_IPMARK_SRC;
else if (strcmp(optarg, "dst") == 0) else if (strcmp(optarg, "dst") == 0)
info->selector = XT_IPMARK_DST; info->selector = XT_IPMARK_DST;
else else
exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg); xtables_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg);
*flags |= FL_ADDR_USED; *flags |= FL_ADDR_USED;
return true; return true;
case '2': case '2':
param_act(P_ONLY_ONCE, "IPMARK", "and-mask", *flags & FL_AND_MASK_USED); xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "and-mask", *flags & FL_AND_MASK_USED);
param_act(P_NO_INVERT, "IPMARK", "and-mask", invert); xtables_param_act(XTF_NO_INVERT, "IPMARK", "and-mask", invert);
if (!strtonum(optarg, NULL, &n, 0, ~0U)) if (!xtables_strtoui(optarg, NULL, &n, 0, ~0U))
param_act(P_BAD_VALUE, "IPMARK", "and-mask", optarg); xtables_param_act(XTF_BAD_VALUE, "IPMARK", "and-mask", optarg);
info->andmask = n; info->andmask = n;
*flags |= FL_AND_MASK_USED; *flags |= FL_AND_MASK_USED;
return true; return true;
case '3': case '3':
param_act(P_ONLY_ONCE, "IPMARK", "or-mask", *flags & FL_OR_MASK_USED); xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "or-mask", *flags & FL_OR_MASK_USED);
param_act(P_NO_INVERT, "IPMARK", "or-mask", invert); xtables_param_act(XTF_NO_INVERT, "IPMARK", "or-mask", invert);
if (!strtonum(optarg, NULL, &n, 0, ~0U)) if (!xtables_strtoui(optarg, NULL, &n, 0, ~0U))
param_act(P_BAD_VALUE, "IPMARK", "or-mask", optarg); xtables_param_act(XTF_BAD_VALUE, "IPMARK", "or-mask", optarg);
info->ormask = n; info->ormask = n;
*flags |= FL_OR_MASK_USED; *flags |= FL_OR_MASK_USED;
return true; return true;
case '4': case '4':
param_act(P_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT); xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT);
param_act(P_NO_INVERT, "IPMARK", "--shift", invert); xtables_param_act(XTF_NO_INVERT, "IPMARK", "--shift", invert);
/* /*
* Anything >31 does not make sense for IPv4, but it still * Anything >31 does not make sense for IPv4, but it still
* does the right thing. * does the right thing.
*/ */
if (!strtonum(optarg, NULL, &n, 0, 128)) if (!xtables_strtoui(optarg, NULL, &n, 0, 128))
param_act(P_BAD_VALUE, "IPMARK", "--shift", optarg); xtables_param_act(XTF_BAD_VALUE, "IPMARK", "--shift", optarg);
info->shift = n; info->shift = n;
*flags |= FL_SHIFT;
return true; return true;
} }
@@ -106,7 +107,7 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
static void ipmark_tg_check(unsigned int flags) static void ipmark_tg_check(unsigned int flags)
{ {
if (!(flags & FL_ADDR_USED)) if (!(flags & FL_ADDR_USED))
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"IPMARK target: Parameter --addr is required"); "IPMARK target: Parameter --addr is required");
} }
@@ -121,6 +122,8 @@ ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
else else
printf("IPMARK dst ip "); printf("IPMARK dst ip ");
if (info->shift != 0)
printf("shift %u ", (unsigned int)info->shift);
if (info->andmask != ~0U) if (info->andmask != ~0U)
printf("and 0x%x ", (unsigned int)info->andmask); printf("and 0x%x ", (unsigned int)info->andmask);
if (info->ormask != 0) if (info->ormask != 0)
@@ -137,17 +140,19 @@ ipmark_tg_save(const void *entry, const struct xt_entry_target *target)
else else
printf("--addr dst "); printf("--addr dst ");
if (info->shift != 0)
printf("--shift %u ", (unsigned int)info->shift);
if (info->andmask != ~0U) if (info->andmask != ~0U)
printf("--and-mask 0x%x ", (unsigned int)info->andmask); printf("--and-mask 0x%x ", (unsigned int)info->andmask);
if (info->ormask != 0) if (info->ormask != 0)
printf("--or-mask 0x%x ", (unsigned int)info->ormask); printf("--or-mask 0x%x ", (unsigned int)info->ormask);
} }
static struct xtables_target ipmark_tg4_reg = { static struct xtables_target ipmark_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "IPMARK", .name = "IPMARK",
.family = PF_INET, .family = PF_UNSPEC,
.revision = 0, .revision = 1,
.size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), .size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.help = ipmark_tg_help, .help = ipmark_tg_help,
@@ -159,24 +164,7 @@ static struct xtables_target ipmark_tg4_reg = {
.extra_opts = ipmark_tg_opts, .extra_opts = ipmark_tg_opts,
}; };
static struct xtables_target ipmark_tg6_reg = { static __attribute__((constructor)) void ipmark_tg_ldr(void)
.version = XTABLES_VERSION,
.name = "IPMARK",
.family = PF_INET6,
.revision = 0,
.size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
.help = ipmark_tg_help,
.init = ipmark_tg_init,
.parse = ipmark_tg_parse,
.final_check = ipmark_tg_check,
.print = ipmark_tg_print,
.save = ipmark_tg_save,
.extra_opts = ipmark_tg_opts,
};
static void _init(void)
{ {
xtables_register_target(&ipmark_tg4_reg); xtables_register_target(&ipmark_tg_reg);
xtables_register_target(&ipmark_tg6_reg);
} }

View File

@@ -22,7 +22,7 @@ enum {
static const struct option logmark_tg_opts[] = { static const struct option logmark_tg_opts[] = {
{.name = "log-level", .has_arg = true, .val = 'l'}, {.name = "log-level", .has_arg = true, .val = 'l'},
{.name = "log-prefix", .has_arg = true, .val = 'p'}, {.name = "log-prefix", .has_arg = true, .val = 'p'},
{}, {NULL},
}; };
static void logmark_tg_help(void) static void logmark_tg_help(void)
@@ -51,23 +51,23 @@ logmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) { switch (c) {
case 'l': /* --log-level */ case 'l': /* --log-level */
param_act(P_ONLY_ONCE, "LOGMARK", "--log-level", *flags & F_LEVEL); xtables_param_act(XTF_ONLY_ONCE, "LOGMARK", "--log-level", *flags & F_LEVEL);
param_act(P_NO_INVERT, "LOGMARK", "--log-level", invert); xtables_param_act(XTF_NO_INVERT, "LOGMARK", "--log-level", invert);
if (!strtonum(optarg, NULL, &x, 0, 8)) if (!xtables_strtoui(optarg, NULL, &x, 0, 8))
param_act(P_BAD_VALUE, "LOGMARK", "--log-level", optarg); xtables_param_act(XTF_BAD_VALUE, "LOGMARK", "--log-level", optarg);
info->level = x; info->level = x;
*flags |= F_LEVEL; *flags |= F_LEVEL;
return true; return true;
case 'p': /* --log-prefix */ case 'p': /* --log-prefix */
param_act(P_ONLY_ONCE, "LOGMARK", "--log-prefix", *flags & F_PREFIX); xtables_param_act(XTF_ONLY_ONCE, "LOGMARK", "--log-prefix", *flags & F_PREFIX);
param_act(P_NO_INVERT, "LOGMARK", "--log-prefix", invert); xtables_param_act(XTF_NO_INVERT, "LOGMARK", "--log-prefix", invert);
if (strlen(optarg) > sizeof(info->prefix)) if (strlen(optarg) > sizeof(info->prefix))
exit_error(PARAMETER_PROBLEM, "LOGMARK: Maximum " xtables_error(PARAMETER_PROBLEM, "LOGMARK: Maximum "
"prefix length is %zu", "prefix length is %zu",
sizeof(info->prefix)); sizeof(info->prefix));
if (strchr(optarg, '\n')) if (strchr(optarg, '\n'))
exit_error(PARAMETER_PROBLEM, "LOGMARK: Newlines not " xtables_error(PARAMETER_PROBLEM, "LOGMARK: Newlines not "
"allowed in log prefix"); "allowed in log prefix");
strncpy(info->prefix, optarg, sizeof(info->prefix)); strncpy(info->prefix, optarg, sizeof(info->prefix));
*flags |= F_PREFIX; *flags |= F_PREFIX;
@@ -111,8 +111,7 @@ static struct xtables_target logmark_tg_reg = {
.extra_opts = logmark_tg_opts, .extra_opts = logmark_tg_opts,
}; };
void _init(void); static __attribute__((constructor)) void logmark_tg_ldr(void)
void _init(void)
{ {
xtables_register_target(&logmark_tg_reg); xtables_register_target(&logmark_tg_reg);
} }

187
extensions/libxt_RAWDNAT.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* "RAWNAT" target extension for iptables
* Copyright © Jan Engelhardt, 2008 - 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <netinet/in.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter.h>
#include "xt_RAWNAT.h"
enum {
FLAGS_TO = 1 << 0,
};
static const struct option rawdnat_tg_opts[] = {
{.name = "to-destination", .has_arg = true, .val = 't'},
{},
};
static void rawdnat_tg_help(void)
{
printf(
"RAWDNAT target options:\n"
" --to-destination addr[/mask] Address or network to map to\n"
);
}
static int
rawdnat_tg4_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
struct in_addr *a;
unsigned int mask;
char *end;
switch (c) {
case 't':
info->mask = 32;
end = strchr(optarg, '/');
if (end != NULL) {
*end++ = '\0';
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
"--to-destination", optarg);
info->mask = mask;
}
a = xtables_numeric_to_ipaddr(optarg);
if (a == NULL)
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
"--to-destination", optarg);
memcpy(&info->addr.in, a, sizeof(*a));
*flags |= FLAGS_TO;
return true;
}
return false;
}
static int
rawdnat_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
struct in6_addr *a;
unsigned int mask;
char *end;
switch (c) {
case 't':
info->mask = 128;
end = strchr(optarg, '/');
if (end != NULL) {
*end++ = '\0';
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
"--to-destination", optarg);
info->mask = mask;
}
a = xtables_numeric_to_ip6addr(optarg);
if (a == NULL)
xtables_param_act(XTF_BAD_VALUE, "RAWDNAT",
"--to-destination", optarg);
memcpy(&info->addr.in6, a, sizeof(*a));
*flags |= FLAGS_TO;
return true;
}
return false;
}
static void rawdnat_tg_check(unsigned int flags)
{
if (!(flags & FLAGS_TO))
xtables_error(PARAMETER_PROBLEM, "RAWDNAT: "
"\"--to-destination\" is required.");
}
static void
rawdnat_tg4_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
if (!numeric && info->mask == 32)
printf("to-destination %s ",
xtables_ipaddr_to_anyname(&info->addr.in));
else
printf("to-destination %s/%u ",
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
}
static void
rawdnat_tg6_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
if (!numeric && info->mask == 128)
printf("to-destination %s ",
xtables_ip6addr_to_anyname(&info->addr.in6));
else
printf("to-destination %s/%u ",
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
}
static void
rawdnat_tg4_save(const void *entry, const struct xt_entry_target *target)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
printf("--to-destination %s/%u ",
xtables_ipaddr_to_numeric(&info->addr.in),
info->mask);
}
static void
rawdnat_tg6_save(const void *entry, const struct xt_entry_target *target)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
printf("--to-destination %s/%u ",
xtables_ip6addr_to_numeric(&info->addr.in6),
info->mask);
}
static struct xtables_target rawdnat_tg4_reg = {
.version = XTABLES_VERSION,
.name = "RAWDNAT",
.revision = 0,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.help = rawdnat_tg_help,
.parse = rawdnat_tg4_parse,
.final_check = rawdnat_tg_check,
.print = rawdnat_tg4_print,
.save = rawdnat_tg4_save,
.extra_opts = rawdnat_tg_opts,
};
static struct xtables_target rawdnat_tg6_reg = {
.version = XTABLES_VERSION,
.name = "RAWDNAT",
.revision = 0,
.family = PF_INET6,
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.help = rawdnat_tg_help,
.parse = rawdnat_tg6_parse,
.final_check = rawdnat_tg_check,
.print = rawdnat_tg6_print,
.save = rawdnat_tg6_save,
.extra_opts = rawdnat_tg_opts,
};
static void _init(void)
{
xtables_register_target(&rawdnat_tg4_reg);
xtables_register_target(&rawdnat_tg6_reg);
}

View File

@@ -0,0 +1,10 @@
The \fBRAWDNAT\fR target will rewrite the destination address in the IP header,
much like the \fBNETMAP\fR target.
.TP
\fB--to-destination\fR \fIaddr\fR[\fB/\fR\fImask\fR]
Network address to map to. The resulting address will be constructed the
following way: All 'one' bits in the \fImask\fR are filled in from the new
\fIaddress\fR. All bits that are zero in the mask are filled in from the
original address.
.PP
See the \fBRAWSNAT\fR help entry for examples and constraints.

187
extensions/libxt_RAWSNAT.c Normal file
View File

@@ -0,0 +1,187 @@
/*
* "RAWNAT" target extension for iptables
* Copyright © Jan Engelhardt, 2008 - 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <netinet/in.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include <linux/netfilter.h>
#include "xt_RAWNAT.h"
enum {
FLAGS_TO = 1 << 0,
};
static const struct option rawsnat_tg_opts[] = {
{.name = "to-source", .has_arg = true, .val = 't'},
{},
};
static void rawsnat_tg_help(void)
{
printf(
"RAWSNAT target options:\n"
" --to-source addr[/mask] Address or network to map to\n"
);
}
static int
rawsnat_tg4_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
struct in_addr *a;
unsigned int mask;
char *end;
switch (c) {
case 't':
info->mask = 32;
end = strchr(optarg, '/');
if (end != NULL) {
*end++ = '\0';
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
"--to-source", optarg);
info->mask = mask;
}
a = xtables_numeric_to_ipaddr(optarg);
if (a == NULL)
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
"--to-source", optarg);
memcpy(&info->addr.in, a, sizeof(*a));
*flags |= FLAGS_TO;
return true;
}
return false;
}
static int
rawsnat_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_rawnat_tginfo *info = (void *)(*target)->data;
struct in6_addr *a;
unsigned int mask;
char *end;
switch (c) {
case 't':
info->mask = 128;
end = strchr(optarg, '/');
if (end != NULL) {
*end++ = '\0';
if (!xtables_strtoui(end, NULL, &mask, 0, 32))
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
"--to-source", optarg);
info->mask = mask;
}
a = xtables_numeric_to_ip6addr(optarg);
if (a == NULL)
xtables_param_act(XTF_BAD_VALUE, "RAWSNAT",
"--to-source", optarg);
memcpy(&info->addr.in6, a, sizeof(*a));
*flags |= FLAGS_TO;
return true;
}
return false;
}
static void rawsnat_tg_check(unsigned int flags)
{
if (!(flags & FLAGS_TO))
xtables_error(PARAMETER_PROBLEM, "RAWSNAT: "
"\"--to-source\" is required.");
}
static void
rawsnat_tg4_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
if (!numeric && info->mask == 32)
printf("to-source %s ",
xtables_ipaddr_to_anyname(&info->addr.in));
else
printf("to-source %s/%u ",
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
}
static void
rawsnat_tg6_print(const void *entry, const struct xt_entry_target *target,
int numeric)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
if (!numeric && info->mask == 128)
printf("to-source %s ",
xtables_ip6addr_to_anyname(&info->addr.in6));
else
printf("to-source %s/%u ",
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
}
static void
rawsnat_tg4_save(const void *entry, const struct xt_entry_target *target)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
printf("--to-source %s/%u ",
xtables_ipaddr_to_numeric(&info->addr.in),
info->mask);
}
static void
rawsnat_tg6_save(const void *entry, const struct xt_entry_target *target)
{
const struct xt_rawnat_tginfo *info = (const void *)target->data;
printf("--to-source %s/%u ",
xtables_ip6addr_to_numeric(&info->addr.in6),
info->mask);
}
static struct xtables_target rawsnat_tg4_reg = {
.version = XTABLES_VERSION,
.name = "RAWSNAT",
.revision = 0,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.help = rawsnat_tg_help,
.parse = rawsnat_tg4_parse,
.final_check = rawsnat_tg_check,
.print = rawsnat_tg4_print,
.save = rawsnat_tg4_save,
.extra_opts = rawsnat_tg_opts,
};
static struct xtables_target rawsnat_tg6_reg = {
.version = XTABLES_VERSION,
.name = "RAWSNAT",
.revision = 0,
.family = PF_INET6,
.size = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_rawnat_tginfo)),
.help = rawsnat_tg_help,
.parse = rawsnat_tg6_parse,
.final_check = rawsnat_tg_check,
.print = rawsnat_tg6_print,
.save = rawsnat_tg6_save,
.extra_opts = rawsnat_tg_opts,
};
static void _init(void)
{
xtables_register_target(&rawsnat_tg4_reg);
xtables_register_target(&rawsnat_tg6_reg);
}

View File

@@ -0,0 +1,38 @@
The \fBRAWSNAT\fR and \fBRAWDNAT\fP targets provide stateless network address
translation.
.PP
The \fBRAWSNAT\fR target will rewrite the source address in the IP header, much
like the \fBNETMAP\fP target. \fBRAWSNAT\fP (and \fBRAWDNAT\fP) may only be
used in the \fBraw\fP or \fBrawpost\fP tables, but can be used in all chains,
which makes it possible to change the source address either when the packet
enters the machine or when it leaves it. The reason for this table constraint
is that RAWNAT must happen outside of connection tracking.
.TP
\fB--to-source\fR \fIaddr\fR[\fB/\fR\fImask\fR]
Network address to map to. The resulting address will be constructed the
following way: All 'one' bits in the \fImask\fR are filled in from the new
\fIaddress\fR. All bits that are zero in the mask are filled in from the
original address.
.PP
As an example, changing the destination for packets forwarded from an internal
LAN to the internet:
.IP
-t raw -A PREROUTING -i lan0 -d 212.201.100.135 -j RAWDNAT --to-destination 199.181.132.250
-t rawpost -A POSTROUTING -o lan0 -s 199.181.132.250 -j RAWSNAT --to-source 212.201.100.135
.PP
Note that changing addresses may influence the route selection! Specifically,
it statically NATs packets, not connections, like the normal DNAT/SNAT targets
would do. Also note that it can transform already-NATed connections -- as said,
it is completely external to Netfilter's connection tracking/NAT.
.PP
If the machine itself generates packets that are to be rawnat'ed, you need a
rule in the OUTPUT chain instead, just like you would with the stateful NAT
targets.
.PP
It may be necessary that in doing so, you also need an extra RAWSNAT rule, to
override the automatic source address selection that the routing code does
before passing packets to iptables. If the connecting socket has not been
explicitly bound to an address, as is the common mode of operation, the address
that will be chosen is the primary address of the device through which the
packet would be routed with its initial destination address - the address as
seen before any RAWNAT takes place.

33
extensions/libxt_STEAL.c Normal file
View File

@@ -0,0 +1,33 @@
#include <stdio.h>
#include <xtables.h>
static void steal_tg_help(void)
{
printf("STEAL takes no options\n\n");
}
static int steal_tg_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
return 0;
}
static void steal_tg_check(unsigned int flags)
{
}
static struct xtables_target steal_tg_reg = {
.version = XTABLES_VERSION,
.name = "STEAL",
.family = AF_UNSPEC,
.size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0),
.help = steal_tg_help,
.parse = steal_tg_parse,
.final_check = steal_tg_check,
};
static void _init(void)
{
xtables_register_target(&steal_tg_reg);
}

View File

@@ -0,0 +1,2 @@
Like the DROP target, but does not throw an error like DROP when used in the
\fBOUTPUT\fP chain.

View File

@@ -21,10 +21,11 @@ static void sysrq_tg_check(unsigned int flags)
{ {
} }
static struct xtables_target sysrq_tg4_reg = { static struct xtables_target sysrq_tg_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "SYSRQ", .name = "SYSRQ",
.family = PF_INET, .revision = 1,
.family = PF_UNSPEC,
.size = XT_ALIGN(0), .size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0), .userspacesize = XT_ALIGN(0),
.help = sysrq_tg_help, .help = sysrq_tg_help,
@@ -32,19 +33,7 @@ static struct xtables_target sysrq_tg4_reg = {
.final_check = sysrq_tg_check, .final_check = sysrq_tg_check,
}; };
static struct xtables_target sysrq_tg6_reg = { static __attribute__((constructor)) void sysrq_tg_ldr(void)
.version = XTABLES_VERSION,
.name = "SYSRQ",
.family = PF_INET6,
.size = XT_ALIGN(0),
.userspacesize = XT_ALIGN(0),
.help = sysrq_tg_help,
.parse = sysrq_tg_parse,
.final_check = sysrq_tg_check,
};
static void _init(void)
{ {
xtables_register_target(&sysrq_tg4_reg); xtables_register_target(&sysrq_tg_reg);
xtables_register_target(&sysrq_tg6_reg);
} }

View File

@@ -1,17 +1,19 @@
The SYSRQ target allows to remotely trigger sysrq on the local machine over the The SYSRQ target allows to remotely trigger sysrq on the local machine over the
network. This can be useful when vital parts of the machine hang, for example network. This can be useful when vital parts of the machine hang, for example
an oops in a filesystem causing locks to be not released and processes to get an oops in a filesystem causing locks to be not released and processes to get
stuck as a result -- if still possible, use /proc/sysrq-trigger. Even when stuck as a result - if still possible, use /proc/sysrq-trigger. Even when
processes are stuck, interrupts are likely to be still processed, and as such, processes are stuck, interrupts are likely to be still processed, and as such,
sysrq can be triggered through incoming network packets. sysrq can be triggered through incoming network packets.
.PP .PP
This xt_SYSRQ implementation does not use any encryption, so you should change The xt_SYSRQ implementation uses a salted hash and a sequence number to prevent
the SYSRQ password after use unless you have made sure it was transmitted network sniffers from either guessing the password or replaying earlier
securely and no one sniffed the network, e.g. by use of an IPsec tunnel whose requests. The initial sequence number comes from the time of day so you will
endpoint is at the machine where you want to trigger the sysrq. Also, you have a small window of vulnerability should time go backwards at a reboot.
should limit as to who can issue commands using \fB-s\fP and/or \fB-m mac\fP, However, the file /sys/module/xt_SYSREQ/seqno can be used to both query and
and also that the destination is correct using \fB-d\fP (to protect against update the current sequence number. Also, you should limit as to who can issue
potential broadcast packets), noting that it is still short of MAC/IP spoofing: commands using \fB-s\fP and/or \fB-m mac\fP, and also that the destination is
correct using \fB-d\fP (to protect against potential broadcast packets), noting
that it is still short of MAC/IP spoofing:
.IP .IP
-A INPUT -s 10.10.25.1 -m mac --mac-source aa:bb:cc:dd:ee:ff -d 10.10.25.7 -A INPUT -s 10.10.25.1 -m mac --mac-source aa:bb:cc:dd:ee:ff -d 10.10.25.7
-p udp --dport 9 -j SYSRQ -p udp --dport 9 -j SYSRQ
@@ -20,28 +22,59 @@ potential broadcast packets), noting that it is still short of MAC/IP spoofing:
ipsec --proto esp --tunnel-src 10.10.25.1 --tunnel-dst 10.10.25.7 ipsec --proto esp --tunnel-src 10.10.25.1 --tunnel-dst 10.10.25.7
-p udp --dport 9 -j SYSRQ -p udp --dport 9 -j SYSRQ
.PP .PP
You should also limit the rate at which connections can be received to limit
the CPU time taken by illegal requests, for example:
.IP
-A INPUT -s 10.10.25.1 -m mac --mac-source aa:bb:cc:dd:ee:ff -d 10.10.25.7
-p udp --dport 9 -m limit --limit 5/minute -j SYSRQ
.PP
This extension does not take any options. The \fB-p udp\fP options are This extension does not take any options. The \fB-p udp\fP options are
required. required.
.PP .PP
The SYSRQ password can be changed through The SYSRQ password can be changed through
/sys/module/xt_SYSRQ/parameters/password; note you need to use `echo -n` to /sys/module/xt_SYSRQ/parameters/password, for example:
not add a newline to the password, i.e.
.IP .IP
echo -n "password" >/sys/.../password echo -n "password" >/sys/module/xt_SYSRQ/parameters/password
.PP .PP
Alternatively, the password may be specified at modprobe time, but this is Alternatively, the password may be specified at modprobe time, but this is
insecure as people can possible see it through ps(1). You can use an option insecure as people can possible see it through ps(1). You can use an option
line in /etc/modprobe.d/sysrq if it is properly guarded, that is, only readable line in e.g. /etc/modprobe.d/xt_sysrq if it is properly guarded, that is, only
by root. readable by root.
.IP .IP
options xt_SYSRQ password=cookies options xt_SYSRQ password=cookies
.PP .PP
To trigger SYSRQ from a remote host, just use netcat or socat, specifying the The hash algorithm can also be specified as a module option, for example, to
action (only one) as first character, followed by the password: use SHA-256 instead of the default SHA-1:
.IP .IP
echo -n "scookies" | socat stdin udp-sendto:10.10.25.7:9 options xt_SYSRQ hash=sha256
.IP
echo -n "scookies" | netcat -u 10.10.25.7 9
.PP .PP
See the Linux docs for possible sysrq keys. Important ones are: The xt_SYSRQ module is normally silent unless a successful request is received,
re(b)oot, power(o)ff, (s)ync filesystems, (u)mount and remount readonly. but the \fIdebug\fP module parameter can be used to find exactly why a
seemingly correct request is not being processed.
.PP
To trigger SYSRQ from a remote host, just use netcat or socat:
.PP
.nf
sysrq_key="s" # the SysRq key(s)
password="password"
seqno="$(date +%s)"
salt="$(dd bs=12 count=1 if=/dev/urandom 2>/dev/null |
openssl enc -base64)"
req="$sysrq_key,$seqno,$salt"
req="$req,$(echo -n "$req,$password" | sha1sum | cut -c1-40)"
echo "$req" | socat stdin udp-sendto:10.10.25.7:9
# or
echo "$req" | netcat -uw1 10.10.25.7 9
.fi
.PP
See the Linux docs for possible sysrq keys. Important ones are: re(b)oot,
power(o)ff, (s)ync filesystems, (u)mount and remount readonly. More than one
sysrq key can be used at once, but bear in mind that, for example, a sync may
not complete before a subsequent reboot or poweroff.
.PP
The hashing scheme should be enough to prevent mis-use of SYSRQ in many
environments, but it is not perfect: take reasonable precautions to
protect your machines. Most importantly ensure that each machine has a
different password; there is scant protection for a SYSRQ packet being
applied to a machine that happens to have the same password.

View File

@@ -32,7 +32,7 @@ static struct xtables_target tarpit_tg_reg = {
.final_check = tarpit_tg_check, .final_check = tarpit_tg_check,
}; };
static void _init(void) static __attribute__((constructor)) void tarpit_tg_ldr(void)
{ {
xtables_register_target(&tarpit_tg_reg); xtables_register_target(&tarpit_tg_reg);
} }

View File

@@ -1,7 +1,7 @@
/* /*
* "TEE" target extension for iptables * "TEE" target extension for iptables
* Copyright © Sebastian Claßen <sebastian.classen [at] freenet.ag>, 2007 * Copyright © Sebastian Claßen <sebastian.classen [at] freenet.ag>, 2007
* Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2008 * Jan Engelhardt <jengelh [at] medozas de>, 2007 - 2009
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either * modify it under the terms of the GNU General Public License; either
@@ -30,7 +30,7 @@ enum {
static const struct option tee_tg_opts[] = { static const struct option tee_tg_opts[] = {
{.name = "gateway", .has_arg = true, .val = 'g'}, {.name = "gateway", .has_arg = true, .val = 'g'},
{}, {NULL},
}; };
static void tee_tg_help(void) static void tee_tg_help(void)
@@ -50,16 +50,37 @@ static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) { switch (c) {
case 'g': case 'g':
if (*flags & FLAG_GATEWAY) if (*flags & FLAG_GATEWAY)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"Cannot specify --gw more than once"); "Cannot specify --gw more than once");
if (check_inverse(optarg, &invert, NULL, 0)) ia = xtables_numeric_to_ipaddr(optarg);
exit_error(PARAMETER_PROBLEM,
"Unexpected \"!\" after --gateway");
ia = numeric_to_ipaddr(optarg);
if (ia == NULL) if (ia == NULL)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"Invalid IP address %s", optarg);
memcpy(&info->gw, ia, sizeof(*ia));
*flags |= FLAG_GATEWAY;
return true;
}
return false;
}
static int tee_tg6_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_target **target)
{
struct xt_tee_tginfo *info = (void *)(*target)->data;
const struct in6_addr *ia;
switch (c) {
case 'g':
if (*flags & FLAG_GATEWAY)
xtables_error(PARAMETER_PROBLEM,
"Cannot specify --gw more than once");
ia = xtables_numeric_to_ip6addr(optarg);
if (ia == NULL)
xtables_error(PARAMETER_PROBLEM,
"Invalid IP address %s", optarg); "Invalid IP address %s", optarg);
memcpy(&info->gw, ia, sizeof(*ia)); memcpy(&info->gw, ia, sizeof(*ia));
@@ -73,7 +94,7 @@ static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
static void tee_tg_check(unsigned int flags) static void tee_tg_check(unsigned int flags)
{ {
if (flags == 0) if (flags == 0)
exit_error(PARAMETER_PROBLEM, "TEE target: " xtables_error(PARAMETER_PROBLEM, "TEE target: "
"--gateway parameter required"); "--gateway parameter required");
} }
@@ -83,21 +104,41 @@ static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
const struct xt_tee_tginfo *info = (const void *)target->data; const struct xt_tee_tginfo *info = (const void *)target->data;
if (numeric) if (numeric)
printf("TEE gw:%s ", ipaddr_to_anyname(&info->gw.in)); printf("TEE gw:%s ", xtables_ipaddr_to_numeric(&info->gw.in));
else else
printf("TEE gw:%s ", ipaddr_to_numeric(&info->gw.in)); printf("TEE gw:%s ", xtables_ipaddr_to_anyname(&info->gw.in));
}
static void tee_tg6_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
if (numeric)
printf("TEE gw:%s ", xtables_ip6addr_to_numeric(&info->gw.in6));
else
printf("TEE gw:%s ", xtables_ip6addr_to_anyname(&info->gw.in6));
} }
static void tee_tg_save(const void *ip, const struct xt_entry_target *target) static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
{ {
const struct xt_tee_tginfo *info = (const void *)target->data; const struct xt_tee_tginfo *info = (const void *)target->data;
printf("--gateway %s ", ipaddr_to_numeric(&info->gw.in)); printf("--gateway %s ", xtables_ipaddr_to_numeric(&info->gw.in));
}
static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_tee_tginfo *info = (const void *)target->data;
printf("--gateway %s ", xtables_ip6addr_to_numeric(&info->gw.in6));
} }
static struct xtables_target tee_tg_reg = { static struct xtables_target tee_tg_reg = {
.name = "TEE", .name = "TEE",
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.revision = 0,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)), .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.help = tee_tg_help, .help = tee_tg_help,
@@ -108,7 +149,23 @@ static struct xtables_target tee_tg_reg = {
.extra_opts = tee_tg_opts, .extra_opts = tee_tg_opts,
}; };
static void _init(void) static struct xtables_target tee_tg6_reg = {
.name = "TEE",
.version = XTABLES_VERSION,
.revision = 0,
.family = PF_INET6,
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
.help = tee_tg_help,
.parse = tee_tg6_parse,
.final_check = tee_tg_check,
.print = tee_tg6_print,
.save = tee_tg6_save,
.extra_opts = tee_tg_opts,
};
static __attribute__((constructor)) void tee_tg_ldr(void)
{ {
xtables_register_target(&tee_tg_reg); xtables_register_target(&tee_tg_reg);
xtables_register_target(&tee_tg6_reg);
} }

8
extensions/libxt_TEE.man Normal file
View File

@@ -0,0 +1,8 @@
The \fBTEE\fP target will clone a packet and redirect this clone to another
machine on the \fBlocal\fP network segment. In other words, the nexthop
must be the target, or you will have to configure the nexthop to forward it
further if so desired.
.TP
\fB--gw\fP \fIipaddr\fP
Send the cloned packet to the host reachable at the given IP address.
Use of 0.0.0.0 (for IPv4 packets) or :: (IPv6) is invalid.

View File

@@ -37,13 +37,13 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
if (c == 'X') { if (c == 'X') {
if (*flags) if (*flags)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"Can't specify multiple conditions"); "Can't specify multiple conditions");
if (strlen(optarg) < sizeof(info->name)) if (strlen(optarg) < sizeof(info->name))
strcpy(info->name, optarg); strcpy(info->name, optarg);
else else
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"File name too long"); "File name too long");
info->invert = invert; info->invert = invert;
@@ -57,7 +57,7 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
static void condition_check(unsigned int flags) static void condition_check(unsigned int flags)
{ {
if (flags == 0) if (flags == 0)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"Condition match: must specify --condition"); "Condition match: must specify --condition");
} }
@@ -74,12 +74,12 @@ static void condition_save(const void *ip, const struct xt_entry_match *match)
{ {
const struct xt_condition_mtinfo *info = (const void *)match->data; const struct xt_condition_mtinfo *info = (const void *)match->data;
printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name); printf("%s--condition \"%s\" ", info->invert ? "! " : "", info->name);
} }
static struct xtables_match condition_mt_reg = { static struct xtables_match condition_mt_reg = {
.name = "condition", .name = "condition",
.revision = 0, .revision = 1,
.family = PF_UNSPEC, .family = PF_UNSPEC,
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)), .size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
@@ -92,7 +92,7 @@ static struct xtables_match condition_mt_reg = {
.extra_opts = condition_opts, .extra_opts = condition_opts,
}; };
static void _init(void) static __attribute__((constructor)) void condition_mt_ldr(void)
{ {
xtables_register_match(&condition_mt_reg); xtables_register_match(&condition_mt_reg);
} }

View File

@@ -1,4 +0,0 @@
.TP
\fB--mac\fP \fIaa:bb:cc:dd:ee:ff\fP[\fB/\fP\fImask\fP]
Matches the DHCP Client Host address in a DHCP message. \fImask\fP specifies
the prefix length of the initial portion to match.

View File

@@ -1,5 +1,5 @@
/* /*
* "dhcpaddr" match extension for iptables * "dhcpmac" match extension for iptables
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008 * Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@@ -14,37 +14,37 @@
#include <netdb.h> #include <netdb.h>
#include <net/ethernet.h> #include <net/ethernet.h>
#include <xtables.h> #include <xtables.h>
#include "xt_DHCPADDR.h" #include "xt_DHCPMAC.h"
#include "mac.c" #include "mac.c"
enum { enum {
F_MAC = 1 << 0, F_MAC = 1 << 0,
}; };
static const struct option dhcpaddr_mt_opts[] = { static const struct option dhcpmac_mt_opts[] = {
{.name = "mac", .has_arg = true, .val = 'M'}, {.name = "mac", .has_arg = true, .val = 'M'},
{NULL}, {NULL},
}; };
static void dhcpaddr_mt_help(void) static void dhcpmac_mt_help(void)
{ {
printf( printf(
"dhcpaddr match options:\n" "dhcpmac match options:\n"
"[!] --mac lladdr[/mask] Match on MAC address in DHCP Client Host field\n" "[!] --mac lladdr[/mask] Match on MAC address in DHCP Client Host field\n"
); );
} }
static int dhcpaddr_mt_parse(int c, char **argv, int invert, static int dhcpmac_mt_parse(int c, char **argv, int invert,
unsigned int *flags, const void *entry, struct xt_entry_match **match) unsigned int *flags, const void *entry, struct xt_entry_match **match)
{ {
struct dhcpaddr_info *info = (void *)(*match)->data; struct dhcpmac_info *info = (void *)(*match)->data;
switch (c) { switch (c) {
case 'M': case 'M':
param_act(P_ONLY_ONCE, "dhcpaddr", "--mac", *flags & F_MAC); xtables_param_act(XTF_ONLY_ONCE, "dhcpmac", "--mac", *flags & F_MAC);
param_act(P_NO_INVERT, "dhcpaddr", "--mac", invert); xtables_param_act(XTF_NO_INVERT, "dhcpmac", "--mac", invert);
if (!mac_parse(optarg, info->addr, &info->mask)) if (!mac_parse(optarg, info->addr, &info->mask))
param_act(P_BAD_VALUE, "dhcpaddr", "--mac", optarg); xtables_param_act(XTF_BAD_VALUE, "dhcpmac", "--mac", optarg);
if (invert) if (invert)
info->invert = true; info->invert = true;
*flags |= F_MAC; *flags |= F_MAC;
@@ -54,26 +54,26 @@ static int dhcpaddr_mt_parse(int c, char **argv, int invert,
return false; return false;
} }
static void dhcpaddr_mt_check(unsigned int flags) static void dhcpmac_mt_check(unsigned int flags)
{ {
if (flags == 0) if (flags == 0)
exit_error(PARAMETER_PROBLEM, "dhcpaddr match: " xtables_error(PARAMETER_PROBLEM, "dhcpmac match: "
"--mac parameter required"); "--mac parameter required");
} }
static void dhcpaddr_mt_print(const void *ip, static void dhcpmac_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric) const struct xt_entry_match *match, int numeric)
{ {
const struct dhcpaddr_info *info = (void *)match->data; const struct dhcpmac_info *info = (void *)match->data;
printf("dhcpaddr %s" DH_MAC_FMT "/%u ", printf("dhcpmac %s" DH_MAC_FMT "/%u ",
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask); info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
} }
static void dhcpaddr_mt_save(const void *ip, static void dhcpmac_mt_save(const void *ip,
const struct xt_entry_match *match) const struct xt_entry_match *match)
{ {
const struct dhcpaddr_info *info = (void *)match->data; const struct dhcpmac_info *info = (void *)match->data;
if (info->invert) if (info->invert)
printf("! "); printf("! ");
@@ -81,22 +81,22 @@ static void dhcpaddr_mt_save(const void *ip,
DH_MAC_HEX(info->addr), info->mask); DH_MAC_HEX(info->addr), info->mask);
} }
static struct xtables_match dhcpaddr_mt_reg = { static struct xtables_match dhcpmac_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "dhcpaddr", .name = "dhcpmac",
.revision = 0, .revision = 0,
.family = PF_INET, .family = PF_INET,
.size = XT_ALIGN(sizeof(struct dhcpaddr_info)), .size = XT_ALIGN(sizeof(struct dhcpmac_info)),
.userspacesize = XT_ALIGN(sizeof(struct dhcpaddr_info)), .userspacesize = XT_ALIGN(sizeof(struct dhcpmac_info)),
.help = dhcpaddr_mt_help, .help = dhcpmac_mt_help,
.parse = dhcpaddr_mt_parse, .parse = dhcpmac_mt_parse,
.final_check = dhcpaddr_mt_check, .final_check = dhcpmac_mt_check,
.print = dhcpaddr_mt_print, .print = dhcpmac_mt_print,
.save = dhcpaddr_mt_save, .save = dhcpmac_mt_save,
.extra_opts = dhcpaddr_mt_opts, .extra_opts = dhcpmac_mt_opts,
}; };
static void _init(void) static __attribute__((constructor)) void dhcpmac_mt_ldr(void)
{ {
xtables_register_match(&dhcpaddr_mt_reg); xtables_register_match(&dhcpmac_mt_reg);
} }

View File

@@ -0,0 +1,4 @@
.TP
\fB--mac\fP \fIaa:bb:cc:dd:ee:ff\fP[\fB/\fP\fImask\fP]
Matches the DHCP "Client Host" address (a MAC address) in a DHCP message.
\fImask\fP specifies the prefix length of the initial portion to match.

View File

@@ -9,6 +9,7 @@
*/ */
#include <getopt.h> #include <getopt.h>
#include <netdb.h> #include <netdb.h>
#include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -54,22 +55,22 @@ static int fuzzy_mt_parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) { switch (c) {
case '1': case '1':
if (invert) if (invert)
exit_error(PARAMETER_PROBLEM,"Can't specify ! --lower-limit"); xtables_error(PARAMETER_PROBLEM,"Can't specify ! --lower-limit");
if (*flags & IPT_FUZZY_OPT_MINIMUM) if (*flags & IPT_FUZZY_OPT_MINIMUM)
exit_error(PARAMETER_PROBLEM,"Can't specify --lower-limit twice"); xtables_error(PARAMETER_PROBLEM,"Can't specify --lower-limit twice");
if (string_to_number(optarg,1,FUZZY_MAX_RATE,&num) == -1 || num < 1) if (!xtables_strtoui(optarg, NULL, &num, 1, FUZZY_MAX_RATE) || num < 1)
exit_error(PARAMETER_PROBLEM,"BAD --lower-limit"); xtables_error(PARAMETER_PROBLEM,"BAD --lower-limit");
info->minimum_rate = num; info->minimum_rate = num;
*flags |= IPT_FUZZY_OPT_MINIMUM; *flags |= IPT_FUZZY_OPT_MINIMUM;
return true; return true;
case '2': case '2':
if (invert) if (invert)
exit_error(PARAMETER_PROBLEM,"Can't specify ! --upper-limit"); xtables_error(PARAMETER_PROBLEM,"Can't specify ! --upper-limit");
if (*flags & IPT_FUZZY_OPT_MAXIMUM) if (*flags & IPT_FUZZY_OPT_MAXIMUM)
exit_error(PARAMETER_PROBLEM,"Can't specify --upper-limit twice"); xtables_error(PARAMETER_PROBLEM,"Can't specify --upper-limit twice");
if (string_to_number(optarg,1,FUZZY_MAX_RATE,&num) == -1 || num < 1) if (!xtables_strtoui(optarg, NULL, &num, 1, FUZZY_MAX_RATE) || num < 1)
exit_error(PARAMETER_PROBLEM,"BAD --upper-limit"); xtables_error(PARAMETER_PROBLEM,"BAD --upper-limit");
info->maximum_rate = num; info->maximum_rate = num;
*flags |= IPT_FUZZY_OPT_MAXIMUM; *flags |= IPT_FUZZY_OPT_MAXIMUM;
return true; return true;
@@ -100,9 +101,10 @@ static void fuzzy_mt_save(const void *ip, const struct xt_entry_match *match)
static struct xtables_match fuzzy_mt_reg = { static struct xtables_match fuzzy_mt_reg = {
.name = "fuzzy", .name = "fuzzy",
.revision = 1,
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_fuzzy_mtinfo)), .size = XT_ALIGN(sizeof(struct xt_fuzzy_mtinfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_fuzzy_mtinfo)), .userspacesize = offsetof(struct xt_fuzzy_mtinfo, packets_total),
.help = fuzzy_mt_help, .help = fuzzy_mt_help,
.init = fuzzy_mt_init, .init = fuzzy_mt_init,
.parse = fuzzy_mt_parse, .parse = fuzzy_mt_parse,
@@ -112,7 +114,7 @@ static struct xtables_match fuzzy_mt_reg = {
.extra_opts = fuzzy_mt_opts, .extra_opts = fuzzy_mt_opts,
}; };
static void _init(void) static __attribute__((constructor)) void fuzzy_mt_ldr(void)
{ {
xtables_register_match(&fuzzy_mt_reg); xtables_register_match(&fuzzy_mt_reg);
} }

View File

@@ -64,16 +64,16 @@ static struct geoip_subnet *geoip_get_subnets(const char *code, uint32_t *count)
if ((fd = open(buf, O_RDONLY)) < 0) { if ((fd = open(buf, O_RDONLY)) < 0) {
fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno)); fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
exit_error(OTHER_PROBLEM, "Could not read geoip database"); xtables_error(OTHER_PROBLEM, "Could not read geoip database");
} }
fstat(fd, &sb); fstat(fd, &sb);
if (sb.st_size % sizeof(struct geoip_subnet) != 0) if (sb.st_size % sizeof(struct geoip_subnet) != 0)
exit_error(OTHER_PROBLEM, "Database file %s seems to be " xtables_error(OTHER_PROBLEM, "Database file %s seems to be "
"corrupted", buf); "corrupted", buf);
subnets = malloc(sb.st_size); subnets = malloc(sb.st_size);
if (subnets == NULL) if (subnets == NULL)
exit_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);
*count = sb.st_size / sizeof(struct geoip_subnet); *count = sb.st_size / sizeof(struct geoip_subnet);
@@ -103,7 +103,7 @@ check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
if (strlen(cc) != 2) /* Country must be 2 chars long according if (strlen(cc) != 2) /* Country must be 2 chars long according
to the ISO3166 standard */ to the ISO3166 standard */
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: invalid country code '%s'", cc); "geoip: invalid country code '%s'", cc);
// Verification will fail if chars aren't uppercased. // Verification will fail if chars aren't uppercased.
@@ -112,7 +112,7 @@ check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
if (isalnum(cc[i]) != 0) if (isalnum(cc[i]) != 0)
cc[i] = toupper(cc[i]); cc[i] = toupper(cc[i]);
else else
exit_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.
@@ -140,7 +140,7 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
buffer = strdup(ccstr); buffer = strdup(ccstr);
if (!buffer) if (!buffer)
exit_error(OTHER_PROBLEM, xtables_error(OTHER_PROBLEM,
"geoip: insufficient memory available"); "geoip: insufficient memory available");
for (cp = buffer, i = 0; cp && i < XT_GEOIP_MAX; cp = next, i++) for (cp = buffer, i = 0; cp && i < XT_GEOIP_MAX; cp = next, i++)
@@ -150,19 +150,19 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) { if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
if ((mem[count++].user = (unsigned long)geoip_load_cc(cp, cctmp)) == 0) if ((mem[count++].user = (unsigned long)geoip_load_cc(cp, cctmp)) == 0)
exit_error(OTHER_PROBLEM, xtables_error(OTHER_PROBLEM,
"geoip: insufficient memory available"); "geoip: insufficient memory available");
cc[count-1] = cctmp; cc[count-1] = cctmp;
} }
} }
if (cp) if (cp)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: too many countries specified"); "geoip: too many countries specified");
free(buffer); free(buffer);
if (count == 0) if (count == 0)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: don't know what happened"); "geoip: don't know what happened");
return count; return count;
@@ -176,7 +176,7 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) { switch (c) {
case '1': case '1':
if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST)) if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST))
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: Only exactly one of --source-country " "geoip: Only exactly one of --source-country "
"or --destination-country must be specified!"); "or --destination-country must be specified!");
@@ -190,7 +190,7 @@ static int geoip_parse(int c, char **argv, int invert, unsigned int *flags,
case '2': case '2':
if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST)) if (*flags & (XT_GEOIP_SRC | XT_GEOIP_DST))
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: Only exactly one of --source-country " "geoip: Only exactly one of --source-country "
"or --destination-country must be specified!"); "or --destination-country must be specified!");
@@ -210,7 +210,7 @@ static void
geoip_final_check(unsigned int flags) geoip_final_check(unsigned int flags)
{ {
if (!flags) if (!flags)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"geoip: missing arguments"); "geoip: missing arguments");
} }
@@ -261,9 +261,10 @@ geoip_save(const void *ip, const struct xt_entry_match *match)
static struct xtables_match geoip_match = { static struct xtables_match geoip_match = {
.family = AF_INET, .family = AF_INET,
.name = "geoip", .name = "geoip",
.revision = 1,
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof(struct xt_geoip_match_info)), .size = XT_ALIGN(sizeof(struct xt_geoip_match_info)),
.userspacesize = XT_ALIGN(offsetof(struct xt_geoip_match_info, mem)), .userspacesize = offsetof(struct xt_geoip_match_info, mem),
.help = geoip_help, .help = geoip_help,
.parse = geoip_parse, .parse = geoip_parse,
.final_check = geoip_final_check, .final_check = geoip_final_check,
@@ -272,7 +273,7 @@ static struct xtables_match geoip_match = {
.extra_opts = geoip_opts, .extra_opts = geoip_opts,
}; };
static void _init(void) static __attribute__((constructor)) void geoip_mt_ldr(void)
{ {
xtables_register_match(&geoip_match); xtables_register_match(&geoip_match);
} }

217
extensions/libxt_iface.c Normal file
View File

@@ -0,0 +1,217 @@
/*
* Shared library add-on to iptables to add interface state matching
* support.
*
* (C) 2008 Gáspár Lajos <gaspar.lajos@glsys.eu>
*
* This program is released under the terms of GNU GPL version 2.
*/
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xtables.h>
#include "xt_iface.h"
static const struct option iface_mt_opts[] = {
{.name = "iface", .has_arg = true, .val = 'i'},
{.name = "up", .has_arg = false, .val = 'u'},
{.name = "down", .has_arg = false, .val = 'U'}, /* not up */
{.name = "broadcast", .has_arg = false, .val = 'b'},
{.name = "loopback", .has_arg = false, .val = 'l'},
{.name = "pointopoint", .has_arg = false, .val = 'p'},
{.name = "pointtopoint", .has_arg = false, .val = 'p'}, /* eq pointopoint */
{.name = "running", .has_arg = false, .val = 'r'},
{.name = "noarp", .has_arg = false, .val = 'n'},
{.name = "arp", .has_arg = false, .val = 'N'}, /* not noarp */
{.name = "promisc", .has_arg = false, .val = 'o'},
{.name = "multicast", .has_arg = false, .val = 'm'},
{.name = "dynamic", .has_arg = false, .val = 'd'},
{.name = "lower-up", .has_arg = false, .val = 'w'},
{.name = "dormant", .has_arg = false, .val = 'a'},
{NULL},
};
static void iface_print_opt(const struct xt_iface_mtinfo *info,
const unsigned int option, const char *command)
{
if (info->flags & option)
printf(" %s", command);
if (info->invflags & option)
printf(" ! %s", command);
}
static void iface_setflag(struct xt_iface_mtinfo *info,
unsigned int *flags, int invert, u_int16_t flag, const char *command)
{
if (*flags & flag)
xtables_error(PARAMETER_PROBLEM,
"iface: \"--%s\" flag already specified", command);
if (invert)
info->invflags |= flag;
else
info->flags |= flag;
*flags |= flag;
}
static bool iface_valid_name(const char *name)
{
static const char invalid_chars[] = ".+!*";
return strlen(name) < IFNAMSIZ && strpbrk(name, invalid_chars) == NULL;
}
static void iface_mt_help(void)
{
printf(
"iface match options:\n"
" --iface interface Name of interface\n"
"[!] --up / --down match if UP flag (not) set\n"
"[!] --broadcast match if BROADCAST flag (not) set\n"
"[!] --loopback match if LOOPBACK flag (not) set\n"
"[!] --pointopoint\n"
"[!] --pointtopoint match if POINTOPOINT flag (not) set\n"
"[!] --running match if RUNNING flag (not) set\n"
"[!] --noarp / --arp match if NOARP flag (not) set\n"
"[!] --promisc match if PROMISC flag (not) set\n"
"[!] --multicast match if MULTICAST flag (not) set\n"
"[!] --dynamic match if DYNAMIC flag (not) set\n"
"[!] --lower-up match if LOWER_UP flag (not) set\n"
"[!] --dormant match if DORMANT flag (not) set\n");
}
static int iface_mt_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_iface_mtinfo *info = (void *)(*match)->data;
switch (c) {
case 'U':
c = 'u';
invert = !invert;
break;
case 'N':
c = 'n';
invert = !invert;
break;
}
switch (c) {
case 'i': /* interface name */
if (*flags & XT_IFACE_IFACE)
xtables_error(PARAMETER_PROBLEM,
"iface: Interface name already specified");
if (!iface_valid_name(optarg))
xtables_error(PARAMETER_PROBLEM,
"iface: Invalid interface name!");
strcpy(info->ifname, optarg);
*flags |= XT_IFACE_IFACE;
return true;
case 'u': /* UP */
iface_setflag(info, flags, invert, XT_IFACE_UP, "up");
return true;
case 'b': /* BROADCAST */
iface_setflag(info, flags, invert, XT_IFACE_BROADCAST, "broadcast");
return true;
case 'l': /* LOOPBACK */
iface_setflag(info, flags, invert, XT_IFACE_LOOPBACK, "loopback");
return true;
case 'p': /* POINTOPOINT */
iface_setflag(info, flags, invert, XT_IFACE_POINTOPOINT, "pointopoint");
return true;
case 'r': /* RUNNING */
iface_setflag(info, flags, invert, XT_IFACE_RUNNING, "running");
return true;
case 'n': /* NOARP */
iface_setflag(info, flags, invert, XT_IFACE_NOARP, "noarp");
return true;
case 'o': /* PROMISC */
iface_setflag(info, flags, invert, XT_IFACE_PROMISC, "promisc");
return true;
case 'm': /* MULTICAST */
iface_setflag(info, flags, invert, XT_IFACE_MULTICAST, "multicast");
return true;
case 'd': /* DYNAMIC */
iface_setflag(info, flags, invert, XT_IFACE_DYNAMIC, "dynamic");
return true;
case 'w': /* LOWER_UP */
iface_setflag(info, flags, invert, XT_IFACE_LOWER_UP, "lower_up");
return true;
case 'a': /* DORMANT */
iface_setflag(info, flags, invert, XT_IFACE_DORMANT, "dormant");
return true;
}
return false;
}
static void iface_mt_check(unsigned int flags)
{
if (!(flags & XT_IFACE_IFACE))
xtables_error(PARAMETER_PROBLEM,
"iface: You must specify an interface");
if (flags == 0 || flags == XT_IFACE_IFACE)
xtables_error(PARAMETER_PROBLEM,
"iface: You must specify at least one option");
}
static void iface_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_iface_mtinfo *info = (const void *)match->data;
printf("iface: \"%s\" [state:", info->ifname);
iface_print_opt(info, XT_IFACE_UP, "up");
iface_print_opt(info, XT_IFACE_BROADCAST, "broadcast");
iface_print_opt(info, XT_IFACE_LOOPBACK, "loopback");
iface_print_opt(info, XT_IFACE_POINTOPOINT, "pointopoint");
iface_print_opt(info, XT_IFACE_RUNNING, "running");
iface_print_opt(info, XT_IFACE_NOARP, "noarp");
iface_print_opt(info, XT_IFACE_PROMISC, "promisc");
iface_print_opt(info, XT_IFACE_MULTICAST, "multicast");
iface_print_opt(info, XT_IFACE_DYNAMIC, "dynamic");
iface_print_opt(info, XT_IFACE_LOWER_UP, "lower_up");
iface_print_opt(info, XT_IFACE_DORMANT, "dormant");
printf("] ");
}
static void iface_mt_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_iface_mtinfo *info = (const void *)match->data;
printf(" --iface %s", info->ifname);
iface_print_opt(info, XT_IFACE_UP, "--up");
iface_print_opt(info, XT_IFACE_BROADCAST, "--broadcast");
iface_print_opt(info, XT_IFACE_LOOPBACK, "--loopback");
iface_print_opt(info, XT_IFACE_POINTOPOINT, "--pointopoint");
iface_print_opt(info, XT_IFACE_RUNNING, "--running");
iface_print_opt(info, XT_IFACE_NOARP, "--noarp");
iface_print_opt(info, XT_IFACE_PROMISC, "--promisc");
iface_print_opt(info, XT_IFACE_MULTICAST, "--multicast");
iface_print_opt(info, XT_IFACE_DYNAMIC, "--dynamic");
iface_print_opt(info, XT_IFACE_LOWER_UP, "--lower_up");
iface_print_opt(info, XT_IFACE_DORMANT, "--dormant");
printf(" ");
}
static struct xtables_match iface_mt_reg = {
.version = XTABLES_VERSION,
.name = "iface",
.revision = 0,
.family = AF_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_iface_mtinfo)),
.userspacesize = XT_ALIGN(sizeof(struct xt_iface_mtinfo)),
.help = iface_mt_help,
.parse = iface_mt_parse,
.final_check = iface_mt_check,
.print = iface_mt_print,
.save = iface_mt_save,
.extra_opts = iface_mt_opts,
};
static void _init(void)
{
xtables_register_match(&iface_mt_reg);
}

View File

@@ -0,0 +1,37 @@
Allows you to check interface states.
.TP
\fB\-\-iface\fP \fIname\fP
Check the states on the given interface. This option is required.
.TP
[\fB!\fP] \fB\-\-up\fP, [\fB!\fP] \fB\-\-down\fP
Check the UP flag.
.TP
[\fB!\fP] \fB\-\-broadcast\fP
Check the BROADCAST flag.
.TP
[\fB!\fP] \fB\-\-loopback\fP
Check the LOOPBACK flag.
.TP
[\fB!\fP] \fB\-\-pointtopoint\fP
Check the POINTTOPOINT flag.
.TP
[\fB!\fP] \fB\-\-running\fP
Check the RUNNING flag. Do NOT rely on it!
.TP
[\fB!\fP] \fB\-\-noarp\fP, [\fB!\fP] \fB\-\-arp\fP
Check the NOARP flag.
.TP
[\fB!\fP] \fB\-\-promisc\fP
Check the PROMISC flag.
.TP
[\fB!\fP] \fB\-\-multicast\fP
Check the MULTICAST flag.
.TP
[\fB!\fP] \fB\-\-dynamic\fP
Check the DYNAMIC flag.
.TP
[\fB!\fP] \fB\-\-lower-up\fP
Check the LOWER_UP flag.
.TP
[\fB!\fP] \fB\-\-dormant\fP
Check the DORMANT flag.

View File

@@ -1,7 +1,7 @@
/* /*
* "ipp2p" match extension for iptables * "ipp2p" match extension for iptables
* Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>, 2005 - 2006 * Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>, 2005 - 2006
* Jan Engelhardt <jengelh [at] medozas de>, 2008 * Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2009
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either * modify it under the terms of the GNU General Public License; either
@@ -17,12 +17,12 @@
#include <ctype.h> #include <ctype.h>
#include <xtables.h> #include <xtables.h>
#include "xt_ipp2p.h" #include "xt_ipp2p.h"
#define param_act(t, s, f) param_act((t), "ipp2p", (s), (f)) #define param_act(t, s, f) xtables_param_act((t), "ipp2p", (s), (f))
static void ipp2p_mt_help(void) static void ipp2p_mt_help(void)
{ {
printf( printf(
"IPP2P v%s options:\n" "ipp2p v%s match options:\n"
" --edk [tcp,udp] All known eDonkey/eMule/Overnet packets\n" " --edk [tcp,udp] All known eDonkey/eMule/Overnet packets\n"
" --dc [tcp] All known Direct Connect packets\n" " --dc [tcp] All known Direct Connect packets\n"
" --kazaa [tcp,udp] All known KaZaA packets\n" " --kazaa [tcp,udp] All known KaZaA packets\n"
@@ -32,19 +32,10 @@ static void ipp2p_mt_help(void)
" --winmx [tcp] All known WinMX\n" " --winmx [tcp] All known WinMX\n"
" --soul [tcp] All known SoulSeek\n" " --soul [tcp] All known SoulSeek\n"
" --ares [tcp] All known Ares\n\n" " --ares [tcp] All known Ares\n\n"
"EXPERIMENTAL protocols (please send feedback to: ipp2p@ipp2p.org) :\n" "EXPERIMENTAL protocols:\n"
" --mute [tcp] All known Mute packets\n" " --mute [tcp] All known Mute packets\n"
" --waste [tcp] All known Waste packets\n" " --waste [tcp] All known Waste packets\n"
" --xdcc [tcp] All known XDCC packets (only xdcc login)\n\n" " --xdcc [tcp] All known XDCC packets (only xdcc login)\n\n"
"DEBUG SUPPPORT, use only if you know why\n"
" --debug Generate kernel debug output, THIS WILL SLOW DOWN THE FILTER\n"
"\nIPP2P was intended for TCP only. Due to increasing usage of UDP we needed to change this.\n"
"You can now use -p udp to search UDP packets only or without -p switch to search UDP and TCP packets.\n"
"\nSee README included with this package for more details or visit http://www.ipp2p.org\n"
"\nExamples:\n"
" iptables -A FORWARD -m ipp2p --ipp2p -j MARK --set-mark 0x01\n"
" iptables -A FORWARD -p udp -m ipp2p --kazaa --bit -j DROP\n"
" iptables -A FORWARD -p tcp -m ipp2p --edk --soul -j DROP\n\n"
, IPP2P_VERSION); , IPP2P_VERSION);
} }
@@ -72,109 +63,109 @@ static int ipp2p_mt_parse(int c, char **argv, int invert, unsigned int *flags,
switch (c) { switch (c) {
case '2': /*cmd: edk*/ case '2': /*cmd: edk*/
param_act(P_ONLY_ONCE, "--edk", *flags & IPP2P_EDK); param_act(XTF_ONLY_ONCE, "--edk", *flags & IPP2P_EDK);
param_act(P_NO_INVERT, "--edk", invert); param_act(XTF_NO_INVERT, "--edk", invert);
if (*flags & IPP2P_DATA_EDK) if (*flags & IPP2P_DATA_EDK)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"ipp2p: use `--edk' OR `--edk-data' but not both of them!"); "ipp2p: use `--edk' OR `--edk-data' but not both of them!");
*flags |= IPP2P_EDK; *flags |= IPP2P_EDK;
info->cmd |= IPP2P_EDK; info->cmd |= IPP2P_EDK;
break; break;
case '7': /*cmd: dc*/ case '7': /*cmd: dc*/
param_act(P_ONLY_ONCE, "--dc", *flags & IPP2P_DC); param_act(XTF_ONLY_ONCE, "--dc", *flags & IPP2P_DC);
param_act(P_NO_INVERT, "--dc", invert); param_act(XTF_NO_INVERT, "--dc", invert);
if (*flags & IPP2P_DATA_DC) if (*flags & IPP2P_DATA_DC)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"ipp2p: use `--dc' OR `--dc-data' but not both of them!"); "ipp2p: use `--dc' OR `--dc-data' but not both of them!");
*flags |= IPP2P_DC; *flags |= IPP2P_DC;
info->cmd |= IPP2P_DC; info->cmd |= IPP2P_DC;
break; break;
case '9': /*cmd: gnu*/ case '9': /*cmd: gnu*/
param_act(P_ONLY_ONCE, "--gnu", *flags & IPP2P_GNU); param_act(XTF_ONLY_ONCE, "--gnu", *flags & IPP2P_GNU);
param_act(P_NO_INVERT, "--gnu", invert); param_act(XTF_NO_INVERT, "--gnu", invert);
if (*flags & IPP2P_DATA_GNU) if (*flags & IPP2P_DATA_GNU)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"ipp2p: use `--gnu' OR `--gnu-data' but not both of them!"); "ipp2p: use `--gnu' OR `--gnu-data' but not both of them!");
*flags |= IPP2P_GNU; *flags |= IPP2P_GNU;
info->cmd |= IPP2P_GNU; info->cmd |= IPP2P_GNU;
break; break;
case 'a': /*cmd: kazaa*/ case 'a': /*cmd: kazaa*/
param_act(P_ONLY_ONCE, "--kazaa", *flags & IPP2P_KAZAA); param_act(XTF_ONLY_ONCE, "--kazaa", *flags & IPP2P_KAZAA);
param_act(P_NO_INVERT, "--kazaa", invert); param_act(XTF_NO_INVERT, "--kazaa", invert);
if (*flags & IPP2P_DATA_KAZAA) if (*flags & IPP2P_DATA_KAZAA)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!"); "ipp2p: use `--kazaa' OR `--kazaa-data' but not both of them!");
*flags |= IPP2P_KAZAA; *flags |= IPP2P_KAZAA;
info->cmd |= IPP2P_KAZAA; info->cmd |= IPP2P_KAZAA;
break; break;
case 'b': /*cmd: bit*/ case 'b': /*cmd: bit*/
param_act(P_ONLY_ONCE, "--kazaa", *flags & IPP2P_BIT); param_act(XTF_ONLY_ONCE, "--bit", *flags & IPP2P_BIT);
param_act(P_NO_INVERT, "--kazaa", invert); param_act(XTF_NO_INVERT, "--bit", invert);
*flags |= IPP2P_BIT; *flags |= IPP2P_BIT;
info->cmd |= IPP2P_BIT; info->cmd |= IPP2P_BIT;
break; break;
case 'c': /*cmd: apple*/ case 'c': /*cmd: apple*/
param_act(P_ONLY_ONCE, "--apple", *flags & IPP2P_APPLE); param_act(XTF_ONLY_ONCE, "--apple", *flags & IPP2P_APPLE);
param_act(P_NO_INVERT, "--apple", invert); param_act(XTF_NO_INVERT, "--apple", invert);
*flags |= IPP2P_APPLE; *flags |= IPP2P_APPLE;
info->cmd |= IPP2P_APPLE; info->cmd |= IPP2P_APPLE;
break; break;
case 'd': /*cmd: soul*/ case 'd': /*cmd: soul*/
param_act(P_ONLY_ONCE, "--soul", *flags & IPP2P_SOUL); param_act(XTF_ONLY_ONCE, "--soul", *flags & IPP2P_SOUL);
param_act(P_NO_INVERT, "--soul", invert); param_act(XTF_NO_INVERT, "--soul", invert);
*flags |= IPP2P_SOUL; *flags |= IPP2P_SOUL;
info->cmd |= IPP2P_SOUL; info->cmd |= IPP2P_SOUL;
break; break;
case 'e': /*cmd: winmx*/ case 'e': /*cmd: winmx*/
param_act(P_ONLY_ONCE, "--winmx", *flags & IPP2P_WINMX); param_act(XTF_ONLY_ONCE, "--winmx", *flags & IPP2P_WINMX);
param_act(P_NO_INVERT, "--winmx", invert); param_act(XTF_NO_INVERT, "--winmx", invert);
*flags |= IPP2P_WINMX; *flags |= IPP2P_WINMX;
info->cmd |= IPP2P_WINMX; info->cmd |= IPP2P_WINMX;
break; break;
case 'f': /*cmd: ares*/ case 'f': /*cmd: ares*/
param_act(P_ONLY_ONCE, "--ares", *flags & IPP2P_ARES); param_act(XTF_ONLY_ONCE, "--ares", *flags & IPP2P_ARES);
param_act(P_NO_INVERT, "--ares", invert); param_act(XTF_NO_INVERT, "--ares", invert);
*flags |= IPP2P_ARES; *flags |= IPP2P_ARES;
info->cmd |= IPP2P_ARES; info->cmd |= IPP2P_ARES;
break; break;
case 'g': /*cmd: mute*/ case 'g': /*cmd: mute*/
param_act(P_ONLY_ONCE, "--mute", *flags & IPP2P_MUTE); param_act(XTF_ONLY_ONCE, "--mute", *flags & IPP2P_MUTE);
param_act(P_NO_INVERT, "--mute", invert); param_act(XTF_NO_INVERT, "--mute", invert);
*flags |= IPP2P_MUTE; *flags |= IPP2P_MUTE;
info->cmd |= IPP2P_MUTE; info->cmd |= IPP2P_MUTE;
break; break;
case 'h': /*cmd: waste*/ case 'h': /*cmd: waste*/
param_act(P_ONLY_ONCE, "--waste", *flags & IPP2P_WASTE); param_act(XTF_ONLY_ONCE, "--waste", *flags & IPP2P_WASTE);
param_act(P_NO_INVERT, "--waste", invert); param_act(XTF_NO_INVERT, "--waste", invert);
*flags |= IPP2P_WASTE; *flags |= IPP2P_WASTE;
info->cmd |= IPP2P_WASTE; info->cmd |= IPP2P_WASTE;
break; break;
case 'i': /*cmd: xdcc*/ case 'i': /*cmd: xdcc*/
param_act(P_ONLY_ONCE, "--xdcc", *flags & IPP2P_XDCC); param_act(XTF_ONLY_ONCE, "--xdcc", *flags & IPP2P_XDCC);
param_act(P_NO_INVERT, "--xdcc", invert); param_act(XTF_NO_INVERT, "--xdcc", invert);
*flags |= IPP2P_XDCC; *flags |= IPP2P_XDCC;
info->cmd |= IPP2P_XDCC; info->cmd |= IPP2P_XDCC;
break; break;
case 'j': /*cmd: debug*/ case 'j': /*cmd: debug*/
param_act(P_ONLY_ONCE, "--debug", info->debug); param_act(XTF_ONLY_ONCE, "--debug", info->debug);
param_act(P_NO_INVERT, "--debug", invert); param_act(XTF_NO_INVERT, "--debug", invert);
info->debug = 1; info->debug = 1;
break; break;
default: default:
// exit_error(PARAMETER_PROBLEM, // xtables_error(PARAMETER_PROBLEM,
// "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n"); // "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
return 0; return 0;
} }
@@ -184,7 +175,7 @@ static int ipp2p_mt_parse(int c, char **argv, int invert, unsigned int *flags,
static void ipp2p_mt_check(unsigned int flags) static void ipp2p_mt_check(unsigned int flags)
{ {
if (!flags) if (!flags)
exit_error(PARAMETER_PROBLEM, xtables_error(PARAMETER_PROBLEM,
"\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n"); "\nipp2p-parameter problem: for ipp2p usage type: iptables -m ipp2p --help\n");
} }
@@ -208,7 +199,7 @@ static const char *const ipp2p_cmds[] = {
}; };
static void static void
ipp2p_mt_print(const void *entry, const struct xt_entry_match *match, ipp2p_mt_print1(const void *entry, const struct xt_entry_match *match,
int numeric) int numeric)
{ {
const struct ipt_p2p_info *info = (const void *)match->data; const struct ipt_p2p_info *info = (const void *)match->data;
@@ -222,15 +213,22 @@ ipp2p_mt_print(const void *entry, const struct xt_entry_match *match,
printf("--debug "); printf("--debug ");
} }
static void ipp2p_mt_print(const void *entry,
const struct xt_entry_match *match, int numeric)
{
printf("ipp2p ");
ipp2p_mt_print1(entry, match, true);
}
static void ipp2p_mt_save(const void *entry, const struct xt_entry_match *match) static void ipp2p_mt_save(const void *entry, const struct xt_entry_match *match)
{ {
ipp2p_mt_print(entry, match, true); ipp2p_mt_print1(entry, match, true);
} }
static struct xtables_match ipp2p_mt_reg = { static struct xtables_match ipp2p_mt_reg = {
.version = XTABLES_VERSION, .version = XTABLES_VERSION,
.name = "ipp2p", .name = "ipp2p",
.revision = 0, .revision = 1,
.family = AF_INET, .family = AF_INET,
.size = XT_ALIGN(sizeof(struct ipt_p2p_info)), .size = XT_ALIGN(sizeof(struct ipt_p2p_info)),
.userspacesize = XT_ALIGN(sizeof(struct ipt_p2p_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_p2p_info)),
@@ -242,7 +240,7 @@ static struct xtables_match ipp2p_mt_reg = {
.extra_opts = ipp2p_mt_opts, .extra_opts = ipp2p_mt_opts,
}; };
static void _init(void) static __attribute__((constructor)) void ipp2p_mt_ldr(void)
{ {
xtables_register_match(&ipp2p_mt_reg); xtables_register_match(&ipp2p_mt_reg);
} }

View File

@@ -1,12 +1,12 @@
This module matches certain packets in P2P flows. It is not This module matches certain packets in P2P flows. It is not
designed to match all packets belonging to a P2P connection - designed to match all packets belonging to a P2P connection -
use IPP2P together with CONNMARK for this purpose. Also visit use IPP2P together with CONNMARK for this purpose.
http://www.ipp2p.org for detailed information. .PP
Use it together with -p tcp or -p udp to search these protocols Use it together with -p tcp or -p udp to search these protocols
only or without -p switch to search packets of both protocols. only or without -p switch to search packets of both protocols.
.PP
IPP2P provides the following options: IPP2P provides the following options, of which one or more may be specified
on the command line:
.TP .TP
.B "--edk " .B "--edk "
Matches as many eDonkey/eMule packets as possible. Matches as many eDonkey/eMule packets as possible.
@@ -38,3 +38,11 @@ Matches Ares and AresLite packets. Use together with -j DROP only.
.B "--debug " .B "--debug "
Prints some information about each hit into kernel logfile. May Prints some information about each hit into kernel logfile. May
produce huge logfiles so beware! produce huge logfiles so beware!
.PP
Note that ipp2p may not (and often, does not) identify all packets that are
exchanged as a result of running filesharing programs.
.PP
There is more information on http://ipp2p.org/ , but it has not been updated
since September 2006, and the syntax there is different from the ipp2p.c
provided in Xtables-addons; most importantly, the --ipp2p flag was removed due
to its ambiguity to match "all known" protocols.

View File

@@ -0,0 +1,177 @@
/*
* "ipv4options" match extension for iptables
* Coprygith © Jan Engelhardt, 2009
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License; either
* version 2 of the License, or any later version, as published by the
* Free Software Foundation.
*/
#include <getopt.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <xtables.h>
#include "xt_ipv4options.h"
/*
* Overview from http://www.networksorcery.com/enp/protocol/ip.htm
* Not providing strings for options that seem to be most distant in the past.
*/
static const char *const v4opt_names[32] = {
[ 1] = "nop",
[ 2] = "security", /* RFC 1108 */
[ 3] = "lsrr", /* RFC 791 */
[ 4] = "timestamp", /* RFC 781, 791 */
[ 7] = "record-route", /* RFC 791 */
[ 9] = "ssrr", /* RFC 791 */
[11] = "mtu-probe", /* RFC 1063 */
[12] = "mtu-reply", /* RFC 1063 */
[18] = "traceroute", /* RFC 1393 */
[20] = "router-alert", /* RFC 2113 */
};
static void ipv4options_mt_help(void)
{
printf(
"ipv4options match options:\n"
"--flags [!]symbol[,...] Match presence/absence (!) of option\n"
" (either by name or number)\n"
"--any Interpret --flags as OR-combined\n\n");
}
static const struct option ipv4options_mt_opts[] = {
{.name = "flags", .has_arg = true, .val = 'f'},
{.name = "any", .has_arg = false, .val = 'a'},
{NULL},
};
static void ipv4options_parse_flagspec(struct xt_ipv4options_mtinfo1 *info,
char *arg)
{
unsigned int i, opt;
bool inv;
char *p;
while (true) {
p = strchr(arg, ',');
if (p != NULL)
*p = '\0';
inv = false;
opt = 0;
if (*arg == '!') {
inv = true;
++arg;
}
for (i = 1; i < 32;++i)
if (v4opt_names[i] != NULL &&
strcmp(v4opt_names[i], arg) == 0) {
opt = i;
break;
}
if (opt == 0 &&
!xtables_strtoui(arg, NULL, &opt, 0, UINT8_MAX))
xtables_error(PARAMETER_PROBLEM,
"ipv4options: Bad option value \"%s\"", arg);
if (opt == 0)
xtables_error(PARAMETER_PROBLEM,
"ipv4options: Option value may not be zero");
info->map |= (1 << opt);
if (inv)
info->invert |= (1 << opt);
if (p == NULL)
break;
arg = p + 1;
}
}
static int ipv4options_mt_parse(int c, char **argv, int invert,
unsigned int *flags, const void *entry, struct xt_entry_match **match)
{
struct xt_ipv4options_mtinfo1 *info = (void *)(*match)->data;
switch (c) {
case 'a': /* --any */
xtables_param_act(XTF_NO_INVERT, "ipv4options", "--any", invert);
info->flags |= XT_V4OPTS_ANY;
return true;
case 'f': /* --flags */
xtables_param_act(XTF_NO_INVERT, "ipv4options", "--flags", invert);
ipv4options_parse_flagspec(info, optarg);
return true;
}
return false;
}
/* no checking of *flags - no IPv4 options is also valid */
static void ipv4options_print_flags(const struct xt_ipv4options_mtinfo1 *info,
bool numeric)
{
uint32_t tmp = info->map;
unsigned int i;
for (i = 1; i < 32; ++i)
if (tmp & (1 << i)) {
if (info->invert & (1 << i))
printf("!");
if (!numeric && v4opt_names[i] != NULL)
printf("%s", v4opt_names[i]);
else
printf("%u", i);
tmp &= ~(1 << i);
if (tmp)
printf(",");
}
}
static void ipv4options_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
{
const struct xt_ipv4options_mtinfo1 *info = (void *)match->data;
printf("ipv4options %s ",
(info->flags & XT_V4OPTS_ANY) ? "any-of" : "all-of");
ipv4options_print_flags(info, numeric);
printf(" ");
}
static void ipv4options_mt_save(const void *ip,
const struct xt_entry_match *match)
{
const struct xt_ipv4options_mtinfo1 *info = (void *)match->data;
if (info->map != 0) {
printf("--flags ");
ipv4options_print_flags(info, true);
}
if (info->flags & XT_V4OPTS_ANY)
printf(" --any");
printf(" ");
}
static struct xtables_match ipv4options_mt_reg = {
.version = XTABLES_VERSION,
.name = "ipv4options",
.revision = 1,
.family = PF_INET,
.size = XT_ALIGN(sizeof(struct xt_ipv4options_mtinfo1)),
.userspacesize = XT_ALIGN(sizeof(struct xt_ipv4options_mtinfo1)),
.help = ipv4options_mt_help,
.parse = ipv4options_mt_parse,
.print = ipv4options_mt_print,
.save = ipv4options_mt_save,
.extra_opts = ipv4options_mt_opts,
};
static __attribute__((constructor)) void ipv4options_mt_ldr(void)
{
xtables_register_match(&ipv4options_mt_reg);
}

View File

@@ -0,0 +1,47 @@
The "ipv4options" module allows to match against a set of IPv4 header options.
.TP
\fB\-\-flags\fP [\fB!\fP]\fIsymbol\fP[\fB,\fP[\fB!\fP]\fIsymbol...\fP]
Specify the options that shall appear or not appear in the header. Each
symbol specification is delimited by a comma, and a '!' can be prefixed to
a symbol to negate its presence. Symbols are either the name of an IPv4 option
or its number. See examples below.
.TP
\fB\-\-any\fP
By default, all of the flags specified must be present/absent, that is, they
form an AND condition. Use the \-\-any flag instead to use an OR condition
where only at least one symbol spec must be true.
.PP
Known symbol names (and their number):
.PP
1 - \fBnop\fP
.PP
2 - \fBsecurity\fP - RFC 1108
.PP
3 - \fBlsrr\fP - Loose Source Routing, RFC 791
.PP
4 - \fBtimestamp\fP - RFC 781, 791
.PP
7 - \fBrecord\-route\fP - RFC 791
.PP
9 - \fBssrr\fP - Strict Source Routing, RFC 791
.PP
11 - \fBmtu\-probe\fP - RFC 1063
.PP
12 - \fBmtu\-reply\fP - RFC 1063
.PP
18 - \fBtraceroute\fP - RFC 1393
.PP
20 - \fBrouter-alert\fP - RFC 2113
.PP
Examples:
.PP
Match packets that have both Timestamp and NOP:
\-m ipv4options \-\-flags nop,timestamp
.PP
~ that have either of Timestamp or NOP, or both:
\-\-flags nop,timestamp \-\-any
.PP
~ that have Timestamp and no NOP: \-\-flags '!nop,timestamp'
.PP
~ that have either no NOP or a timestamp (or both conditions):
\-\-flags '!nop,timestamp' \-\-any

View File

@@ -0,0 +1,18 @@
This module matches the length of a packet against a specific value or range of
values.
.TP
[\fB!\fR] \fB--length\fR \fIlength\fR[\fB:\fR\fIlength\fR]
Match exact length or length range.
.TP
\fB--layer3\fR
Match the layer3 frame size (e.g. IPv4/v6 header plus payload).
.TP
\fB--layer4\fR
Match the layer4 frame size (e.g. TCP/UDP header plus payload).
.TP
\fB--layer5\fR
Match the layer5 frame size (e.g. TCP/UDP payload, often called layer7).
.PP
If no --layer* option is given, --layer3 is assumed by default. Note that using
--layer5 may not match a packet if it is not one of the recognized types
(currently TCP, UDP, UDPLite, ICMP, AH and ESP) or which has no 5th layer.

173
extensions/libxt_length2.c Normal file
View File

@@ -0,0 +1,173 @@
#include <getopt.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xtables.h>
#include "xt_length2.h"
enum {
F_LAYER = 1 << 0,
F_LENGTH = 1 << 1,
XT_LENGTH_LAYER_MASK = XT_LENGTH_LAYER3 | XT_LENGTH_LAYER4 |
XT_LENGTH_LAYER5 | XT_LENGTH_LAYER7,
};
static void length_mt_help(void)
{
printf(
"length match options:\n"
" --layer3 Match against layer3 size (e.g. L4 + IPv6 header)\n"
" --layer4 Match against layer4 size (e.g. L5 + SCTP header)\n"
" --layer5 Match against layer5 size (e.g. L7 + chunk headers)\n"
" --layer7 Match against layer7 payload (e.g. SCTP payload)\n"
"[!] --length n[:n] Match packet length against value or range\n"
" of values (inclusive)\n"
);
}
static const struct option length_mt_opts[] = {
{.name = "layer3", .has_arg = false, .val = '3'},
{.name = "layer4", .has_arg = false, .val = '4'},
{.name = "layer5", .has_arg = false, .val = '5'},
{.name = "layer7", .has_arg = false, .val = '7'},
{.name = "length", .has_arg = true, .val = '='},
{NULL},
};
static void length_mt_init(struct xt_entry_match *match)
{
struct xt_length_mtinfo2 *info = (void *)match->data;
info->flags = XT_LENGTH_LAYER3;
}
static int length_mt_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
{
struct xt_length_mtinfo2 *info = (void *)(*match)->data;
unsigned int from, to;
char *end;
switch (c) {
case '3': /* --layer3 */
xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER);
info->flags &= ~XT_LENGTH_LAYER_MASK;
info->flags |= XT_LENGTH_LAYER3;
*flags |= F_LAYER;
return true;
case '4': /* --layer4 */
xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER);
info->flags &= ~XT_LENGTH_LAYER_MASK;
info->flags |= XT_LENGTH_LAYER4;
*flags |= F_LAYER;
return true;
case '5': /* --layer5 */
xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER);
info->flags &= ~XT_LENGTH_LAYER_MASK;
info->flags |= XT_LENGTH_LAYER5;
*flags |= F_LAYER;
return true;
case '7': /* --layer7 */
xtables_param_act(XTF_ONLY_ONCE, "length", "--layer*", *flags & F_LAYER);
info->flags &= ~XT_LENGTH_LAYER_MASK;
info->flags |= XT_LENGTH_LAYER7;
*flags |= F_LAYER;
return true;
case '=': /* --length */
xtables_param_act(XTF_ONLY_ONCE, "length", "--length", *flags & F_LENGTH);
if (invert)
info->flags |= XT_LENGTH_INVERT;
if (!xtables_strtoui(optarg, &end, &from, 0, ~0U))
xtables_param_act(XTF_BAD_VALUE, "length", "--length", optarg);
to = from;
if (*end == ':')
if (!xtables_strtoui(end + 1, &end, &to, 0, ~0U))
xtables_param_act(XTF_BAD_VALUE, "length",
"--length", optarg);
if (*end != '\0')
xtables_param_act(XTF_BAD_VALUE, "length", "--length", optarg);
info->min = from;
info->max = to;
*flags |= F_LENGTH;
return true;
}
return false;
}
static void length_mt_check(unsigned int flags)
{
if (!(flags & F_LENGTH))
xtables_error(PARAMETER_PROBLEM,
"length: You must specify \"--length\"");
if (!(flags & F_LAYER))
fprintf(stderr, "iptables: length match: Defaulting to "
"--layer3. Consider specifying it explicitly.\n");
}
static void length_mt_print(const void *ip, const struct xt_entry_match *match,
int numeric)
{
const struct xt_length_mtinfo2 *info = (const void *)match->data;
if (info->flags & XT_LENGTH_LAYER3)
printf("layer3 ");
else if (info->flags & XT_LENGTH_LAYER4)
printf("layer4 ");
else if (info->flags & XT_LENGTH_LAYER5)
printf("layer5 ");
else if (info->flags & XT_LENGTH_LAYER7)
printf("layer7 ");
printf("length ");
if (info->flags & XT_LENGTH_INVERT)
printf("! ");
if (info->min == info->max)
printf("%u ", (unsigned int)info->min);
else
printf("%u-%u ", (unsigned int)info->min,
(unsigned int)info->max);
}
static void length_mt_save(const void *ip, const struct xt_entry_match *match)
{
const struct xt_length_mtinfo2 *info = (const void *)match->data;
if (info->flags & XT_LENGTH_LAYER3)
printf("--layer3 ");
else if (info->flags & XT_LENGTH_LAYER4)
printf("--layer4 ");
else if (info->flags & XT_LENGTH_LAYER5)
printf("--layer5 ");
else if (info->flags & XT_LENGTH_LAYER7)
printf("--layer7 ");
if (info->flags & XT_LENGTH_INVERT)
printf("! ");
printf("--length ");
if (info->min == info->max)
printf("%u ", (unsigned int)info->min);
else
printf("%u:%u ", (unsigned int)info->min,
(unsigned int)info->max);
}
static struct xtables_match length2_mt_reg = {
.version = XTABLES_VERSION,
.name = "length2",
.revision = 2,
.family = PF_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_length_mtinfo2)),
.userspacesize = XT_ALIGN(sizeof(struct xt_length_mtinfo2)),
.init = length_mt_init,
.help = length_mt_help,
.parse = length_mt_parse,
.final_check = length_mt_check,
.print = length_mt_print,
.save = length_mt_save,
.extra_opts = length_mt_opts,
};
static void _init(void)
{
xtables_register_match(&length2_mt_reg);
}

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