mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2026-04-21 03:19:40 +02:00
Compare commits
882 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
061fc794b5 | ||
|
|
bf1ca298ae | ||
|
|
6e5edc8372 | ||
|
|
7ad14b7150 | ||
|
|
0cc51e6b35 | ||
|
|
fa7bcbfb9b | ||
|
|
d86101e470 | ||
|
|
00114dea3d | ||
|
|
d4c2aac5f8 | ||
|
|
5622c5f024 | ||
|
|
358991306c | ||
|
|
2bbdcb1d58 | ||
|
|
b14728691d | ||
|
|
708f883635 | ||
|
|
f822b8bc1b | ||
|
|
4205900d9b | ||
|
|
266638e41e | ||
|
|
ebcd176822 | ||
|
|
6b47d09a36 | ||
|
|
1849c47ae8 | ||
|
|
68d895f75c | ||
|
|
53b6b862cc | ||
|
|
ed10cb9c17 | ||
|
|
5903f4bcfc | ||
|
|
5e19871613 | ||
|
|
30fb410003 | ||
|
|
3ea761a1ed | ||
|
|
4603d3e0f4 | ||
|
|
b0b2b5a74c | ||
|
|
082d42fb21 | ||
|
|
b1f0e118a0 | ||
|
|
56fba3ecff | ||
|
|
9057fb48f3 | ||
|
|
e19f91ddb4 | ||
|
|
256ac1a4f6 | ||
|
|
b91dbd03c7 | ||
|
|
254c6926d3 | ||
|
|
2e78cf03a4 | ||
|
|
bf63a25a64 | ||
|
|
94656621ed | ||
|
|
95d4f9e113 | ||
|
|
123e1a14e9 | ||
|
|
f4f3f98609 | ||
|
|
9b1c7c1c04 | ||
|
|
ed8e496750 | ||
|
|
5339fcc65b | ||
|
|
2265c1b854 | ||
|
|
2c574f992d | ||
|
|
3a24468a68 | ||
|
|
7682cc8c34 | ||
|
|
215b3c5b12 | ||
|
|
4dbb36b723 | ||
|
|
10f951e61d | ||
|
|
a4c50ae405 | ||
|
|
38d89983ca | ||
|
|
25985650a9 | ||
|
|
4de9ff1505 | ||
|
|
46b7cf206b | ||
|
|
29d10e11fa | ||
|
|
60a26f1dea | ||
|
|
cdf90737be | ||
|
|
5713415014 | ||
|
|
230bc1f327 | ||
|
|
d360f5578c | ||
|
|
dd32060f6a | ||
|
|
d5eb4e586c | ||
|
|
1b4b4347c5 | ||
|
|
2f37af43c5 | ||
|
|
56e5970c64 | ||
|
|
2b76b68c65 | ||
|
|
d2eeac4c32 | ||
|
|
0e9037b000 | ||
|
|
0a6091b64a | ||
|
|
b565a85fb6 | ||
|
|
425a035959 | ||
|
|
89c80f5981 | ||
|
|
8579fd2b3b | ||
|
|
0a836e9677 | ||
|
|
90b0f3a51f | ||
|
|
89d1b808b9 | ||
|
|
c839e87bbb | ||
|
|
a587f9526d | ||
|
|
1874fcd519 | ||
|
|
21ea7b76ec | ||
|
|
ee8da2b1ac | ||
|
|
19a4359368 | ||
|
|
1b379667d3 | ||
|
|
cd410aefe7 | ||
|
|
e4b5cef8f0 | ||
|
|
a8af97b8fa | ||
|
|
db234c30cd | ||
|
|
2e6fb73e85 | ||
|
|
6024758b28 | ||
|
|
69f3f21a32 | ||
|
|
7af1b9737c | ||
|
|
f5e95f35a7 | ||
|
|
80bed0655f | ||
|
|
bc6aaf74d8 | ||
|
|
192243483a | ||
|
|
e3114d60d5 | ||
|
|
e6f20befad | ||
|
|
5038e160f8 | ||
|
|
a6289ec3ff | ||
|
|
01e7128a80 | ||
|
|
1dc2a1c2de | ||
|
|
60b6b1dbef | ||
|
|
fcb19403bc | ||
|
|
f89f10bbe9 | ||
|
|
a9358542fe | ||
|
|
237fe7c660 | ||
|
|
939fc901c1 | ||
|
|
a4a077ff86 | ||
|
|
bccf64d820 | ||
|
|
7e3e156d92 | ||
|
|
8f70b9a99d | ||
|
|
e277360bcd | ||
|
|
672f12b2a6 | ||
|
|
8788b6c096 | ||
|
|
96ce5ec488 | ||
|
|
5e22c9c592 | ||
|
|
01f97bfdd1 | ||
|
|
1324442bce | ||
|
|
a576f4d43e | ||
|
|
cc17e1d0fe | ||
|
|
c08835d65c | ||
|
|
4c21811919 | ||
|
|
431062c6ec | ||
|
|
87adf3461f | ||
|
|
f2e21e67a5 | ||
|
|
ae307c0bf3 | ||
|
|
ec8c6b8732 | ||
|
|
7916b74a42 | ||
|
|
7fbbd0401e | ||
|
|
991c0cf4cf | ||
|
|
b58e78968e | ||
|
|
02eb0e5df9 | ||
|
|
98ea6c538b | ||
|
|
7cf7250e07 | ||
|
|
f9b0ee7533 | ||
|
|
a82d0ba517 | ||
|
|
bc2bcc383c | ||
|
|
c6c70ab30b | ||
|
|
a0a8fbc091 | ||
|
|
9414a5df34 | ||
|
|
f28cfff138 | ||
|
|
a8d7ec5ad6 | ||
|
|
29f293743a | ||
|
|
3bf7ebc48c | ||
|
|
172bc7e306 | ||
|
|
db45bbcb9e | ||
|
|
b2cd0ab65b | ||
|
|
b5a2f9aa14 | ||
|
|
6fbb35d686 | ||
|
|
e1d9825475 | ||
|
|
efa8b9670a | ||
|
|
2b38d081a5 | ||
|
|
fda591dba4 | ||
|
|
9de3027c02 | ||
|
|
2dc8f21476 | ||
|
|
e027089782 | ||
|
|
fe7a30c746 | ||
|
|
d582cc04df | ||
|
|
13db8d78c9 | ||
|
|
6a60b5ab75 | ||
|
|
d48a5fe0f4 | ||
|
|
b70905e7cb | ||
|
|
3f04148501 | ||
|
|
d96fff8893 | ||
|
|
aceca54912 | ||
|
|
cb1cdb190f | ||
|
|
48ebf55444 | ||
|
|
57c3cc1722 | ||
|
|
29141b6e95 | ||
|
|
cdac8506c3 | ||
|
|
5494bc40f4 | ||
|
|
bcdb7ed4e9 | ||
|
|
1ed86c6bbd | ||
|
|
2a5f1099c8 | ||
|
|
c243c78af4 | ||
|
|
91da2a0dbd | ||
|
|
a160a2aa36 | ||
|
|
b25e96fd49 | ||
|
|
6d74f76a29 | ||
|
|
78e47758c6 | ||
|
|
bcdd42f556 | ||
|
|
acf92ff914 | ||
|
|
0e845bf23f | ||
|
|
158e6a26eb | ||
|
|
693c32f414 | ||
|
|
3e337562d7 | ||
|
|
bb25bc08c4 | ||
|
|
ea3e4b2ed5 | ||
|
|
557af2177f | ||
|
|
60f5239630 | ||
|
|
3ba7d8c3a9 | ||
|
|
28d12faba8 | ||
|
|
cf7a3d4342 | ||
|
|
fabad77f8f | ||
|
|
5e020d380c | ||
|
|
a7fbf4f4de | ||
|
|
4137f6c111 | ||
|
|
04d8ebe31c | ||
|
|
6ab4c02a54 | ||
|
|
a66e4510b8 | ||
|
|
31aebc134e | ||
|
|
e640a15ec9 | ||
|
|
66f213e324 | ||
|
|
0dcc56bc62 | ||
|
|
8db01220fd | ||
|
|
95ff9a2de3 | ||
|
|
2f1e094125 | ||
|
|
37b000182f | ||
|
|
255a310536 | ||
|
|
3a6e73e986 | ||
|
|
0a97126f5b | ||
|
|
2ba833fe47 | ||
|
|
77240e0918 | ||
|
|
651e60f8d7 | ||
|
|
54ac2a899a | ||
|
|
61d2be172d | ||
|
|
093f3b0a97 | ||
|
|
57d25f22f1 | ||
|
|
2f18ab31ec | ||
|
|
12d0a8702c | ||
|
|
35ce1adf5e | ||
|
|
e5fe0b9c14 | ||
|
|
cd7fc84b29 | ||
|
|
4ff5a8fbf6 | ||
|
|
37e3a543a9 | ||
|
|
5f6cbbc663 | ||
|
|
a2676585da | ||
|
|
4a8aab6aed | ||
|
|
dec7d7fc4d | ||
|
|
5c615a3c73 | ||
|
|
0c1375414d | ||
|
|
7e5a8b0501 | ||
|
|
cb8050172a | ||
|
|
5be4ac8b2b | ||
|
|
8d5b7c5b7d | ||
|
|
f9aca7621c | ||
|
|
af940bcbae | ||
|
|
06b82c649d | ||
|
|
e5093b61cd | ||
|
|
7cd01e0b14 | ||
|
|
4eb97c7a01 | ||
|
|
48fbc6783e | ||
|
|
a9f383daf8 | ||
|
|
cbe58f55d0 | ||
|
|
d11218815f | ||
|
|
911d3d146a | ||
|
|
e2ecff2071 | ||
|
|
b2bcedd1ef | ||
|
|
36c349054e | ||
|
|
95da880d39 | ||
|
|
3be26a731b | ||
|
|
38db58adc1 | ||
|
|
0f302b7b2f | ||
|
|
d66d07d01d | ||
|
|
3736a265d8 | ||
|
|
5b2649b1a2 | ||
|
|
f6b8767228 | ||
|
|
ac58f2e94b | ||
|
|
7cc774641a | ||
|
|
492236f931 | ||
|
|
1e8da7c31c | ||
|
|
3f1202c211 | ||
|
|
759546f8d0 | ||
|
|
72b1421783 | ||
|
|
0b3d1bc4f0 | ||
|
|
3679e0efa6 | ||
|
|
517b8c66b5 | ||
|
|
7ee9feb20e | ||
|
|
f830dbd34e | ||
|
|
916013cd89 | ||
|
|
a6b06502ca | ||
|
|
aee5aedc63 | ||
|
|
54d784ffdf | ||
|
|
076610e3af | ||
|
|
7a1ad32d1a | ||
|
|
40094379dd | ||
|
|
ce37dd6984 | ||
|
|
31fdd86247 | ||
|
|
36df60c940 | ||
|
|
2b671829d8 | ||
|
|
9ab6a0ee0d | ||
|
|
365d5edfb3 | ||
|
|
75cd1d7d6a | ||
|
|
b0dc0e6f4c | ||
|
|
bc1c37618a | ||
|
|
d7aeb7da4b | ||
|
|
487da26146 | ||
|
|
434dea2b53 | ||
|
|
30d227135b | ||
|
|
a508ec048c | ||
|
|
3069c9a3a2 | ||
|
|
5245220246 | ||
|
|
ec97cd6d89 | ||
|
|
dc58126e37 | ||
|
|
d509951fcf | ||
|
|
6ef91897b2 | ||
|
|
c7f60a33c5 | ||
|
|
65b75fc19c | ||
|
|
bac406bff5 | ||
|
|
aa53733851 | ||
|
|
9ccd32d840 | ||
|
|
939d3c8b27 | ||
|
|
c2d93e16fd | ||
|
|
04aed87cb6 | ||
|
|
5ef3a7c436 | ||
|
|
27a77b62f5 | ||
|
|
c10e974bd6 | ||
|
|
01d864f4fc | ||
|
|
071c95b750 | ||
|
|
a141cc311c | ||
|
|
7e92ce7ce6 | ||
|
|
21da1dfea5 | ||
|
|
6c17eb46b5 | ||
|
|
74ea647303 | ||
|
|
e0154bfa4c | ||
|
|
cd18e2479c | ||
|
|
d2f3541cda | ||
|
|
1fed8bbf09 | ||
|
|
6e8fb7f231 | ||
|
|
eceaee3431 | ||
|
|
77b29a62ee | ||
|
|
33db992c39 | ||
|
|
85d8f98dd7 | ||
|
|
e84391ce66 | ||
|
|
ef7fb0db7f | ||
|
|
4203259e5a | ||
|
|
e3956498ac | ||
|
|
6f730f3ab2 | ||
|
|
2b590a35fd | ||
|
|
3dd33dfe93 | ||
|
|
d417077816 | ||
|
|
d057f6d6f0 | ||
|
|
b2fc85c589 | ||
|
|
fa1348455d | ||
|
|
1a5c079e6b | ||
|
|
75b3762ef4 | ||
|
|
cfb72bf468 | ||
|
|
1b0790d151 | ||
|
|
a5355e74ea | ||
|
|
757bf0e993 | ||
|
|
cea4817a46 | ||
|
|
2dc79fe008 | ||
|
|
b60f8f1de2 | ||
|
|
499c6db75e | ||
|
|
509953daec | ||
|
|
c53a86874d | ||
|
|
309b960012 | ||
|
|
f4882ca029 | ||
|
|
8fd3eb56eb | ||
|
|
94574fb829 | ||
|
|
32871bad39 | ||
|
|
0ba44bd461 | ||
|
|
d4e6e3d155 | ||
|
|
18043f3e3a | ||
|
|
ff27f61477 | ||
|
|
9f59f21614 | ||
|
|
7a8bfed52c | ||
|
|
1edc9b943b | ||
|
|
ebfa77795a | ||
|
|
4a8aa505c4 | ||
|
|
4654ee127f | ||
|
|
a7a77d7146 | ||
|
|
2a61ca7d4b | ||
|
|
39de351a91 | ||
|
|
07bf41a294 | ||
|
|
07cd29d9ce | ||
|
|
eb9634aee6 | ||
|
|
19f241a09c | ||
|
|
0a29c1d32f | ||
|
|
93a17fdde0 | ||
|
|
80444b0d31 | ||
|
|
f180c0e5c6 | ||
|
|
ca8ebe4467 | ||
|
|
e82410735a | ||
|
|
89e72bb0f4 | ||
|
|
77b9f2024c | ||
|
|
0edb572f6e | ||
|
|
8b1ff64b8b | ||
|
|
ebb61aa3c9 | ||
|
|
bd2e6108f3 | ||
|
|
288492c820 | ||
|
|
e425c8f277 | ||
|
|
e3e88827fb | ||
|
|
6c709fd682 | ||
|
|
1b53724a61 | ||
|
|
983b28fe8e | ||
|
|
3141b2ff86 | ||
|
|
980a53348f | ||
|
|
8ea781e257 | ||
|
|
7e39ee66e0 | ||
|
|
65e97a66e6 | ||
|
|
d82b20ead7 | ||
|
|
c5d4dd0bcf | ||
|
|
0168f8e8a2 | ||
|
|
dc22ec7bd1 | ||
|
|
80ded69d77 | ||
|
|
af1bfd7684 | ||
|
|
b05712a14d | ||
|
|
7d8ffffd85 | ||
|
|
75212f3972 | ||
|
|
77027ff8d3 | ||
|
|
e9a70bbf15 | ||
|
|
25bf680ead | ||
|
|
4d547c2bfc | ||
|
|
f7c7264a65 | ||
|
|
0f42828fd6 | ||
|
|
e2da87230a | ||
|
|
1dc1ae3ec5 | ||
|
|
3bbea41b30 | ||
|
|
549508499c | ||
|
|
748498038a | ||
|
|
3ee2b5fb93 | ||
|
|
5bcdf7f10e | ||
|
|
6599996ccc | ||
|
|
bf8d44cca4 | ||
|
|
1721b76a0f | ||
|
|
81ad2519a9 | ||
|
|
f65ea59795 | ||
|
|
baf7b1091a | ||
|
|
2ae0413e31 | ||
|
|
db76ea9a5c | ||
|
|
3ed1a3cbf0 | ||
|
|
9c4c76f9e2 | ||
|
|
7f33590df8 | ||
|
|
6733265358 | ||
|
|
f757049112 | ||
|
|
21cdf786f7 | ||
|
|
7c248871f8 | ||
|
|
3500a38767 | ||
|
|
cf9b60a57e | ||
|
|
e5eedb25c2 | ||
|
|
e3ae8dcb81 | ||
|
|
aca381d3b6 | ||
|
|
bb15becc88 | ||
|
|
14458b3a7e | ||
|
|
2d36632d4a | ||
|
|
b5e2c7255a | ||
|
|
376a89e7d1 | ||
|
|
03ec8a7696 | ||
|
|
442982f04e | ||
|
|
98b853cea3 | ||
|
|
59401339b8 | ||
|
|
121836ce80 | ||
|
|
c23df41f6e | ||
|
|
fb2eea69af | ||
|
|
4815e3a8a6 | ||
|
|
f9922c6f85 | ||
|
|
24491d55d7 | ||
|
|
7ab69a17fa | ||
|
|
d2339410b2 | ||
|
|
649caf61e8 | ||
|
|
922a9be87d | ||
|
|
4d48511f01 | ||
|
|
6dedbef3d4 | ||
|
|
fe49f9b6a4 | ||
|
|
283974cbbe | ||
|
|
7deca86132 | ||
|
|
7d6435f422 | ||
|
|
748f5cfdd0 | ||
|
|
d402cec807 | ||
|
|
b42190c04b | ||
|
|
4dcefe4b95 | ||
|
|
a2662b0121 | ||
|
|
03354eed44 | ||
|
|
ddda6972a4 | ||
|
|
8e7359bb92 | ||
|
|
40786af1c0 | ||
|
|
f6e2fb815e | ||
|
|
f171a0f07e | ||
|
|
d17ddb9c94 | ||
|
|
54d80a73b4 | ||
|
|
43921c5834 | ||
|
|
9a18a05d02 | ||
|
|
5b472be9bb | ||
|
|
4dd35fb564 | ||
|
|
b32d6dad90 | ||
|
|
5b2cb97c06 | ||
|
|
ca894d6687 | ||
|
|
db717ec479 | ||
|
|
a46ca95078 | ||
|
|
8b2a266db0 | ||
|
|
03e10ff544 | ||
|
|
37986fd785 | ||
|
|
8ff64f4ef4 | ||
|
|
93f6c1a312 | ||
|
|
b535abce2e | ||
|
|
5db988626f | ||
|
|
c6f8f72bf1 | ||
|
|
47cbb07162 | ||
|
|
79c55ab325 | ||
|
|
11ab4d0acc | ||
|
|
8ae9ac5433 | ||
|
|
2060a58912 | ||
|
|
e1eed2b05e | ||
|
|
7b077c7459 | ||
|
|
ad146dbeef | ||
|
|
fb4c49d794 | ||
|
|
a17203e036 | ||
|
|
987402dc61 | ||
|
|
295b6b6d73 | ||
|
|
7338a2a400 | ||
|
|
ba35636718 | ||
|
|
fd19a40dbe | ||
|
|
937571bb9d | ||
|
|
346fc1a376 | ||
|
|
56535551b3 | ||
|
|
dd8fdd09c8 | ||
|
|
beb3358297 | ||
|
|
02d8bdc3d9 | ||
|
|
42b77a386a | ||
|
|
6340363394 | ||
|
|
c9b4e9c518 | ||
|
|
8dd316ed56 | ||
|
|
48327605c6 | ||
|
|
414e95ffb1 | ||
|
|
749e0b788a | ||
|
|
7512101bca | ||
|
|
1a17ed6a45 | ||
|
|
1aeaadd740 | ||
|
|
0acbe528ac | ||
|
|
f5fe2dc801 | ||
|
|
524201adcc | ||
|
|
7cfd3b1dbb | ||
|
|
ab13e58f96 | ||
|
|
548922388c | ||
|
|
43864ac6f1 | ||
|
|
2ef714cc93 | ||
|
|
8b71d90002 | ||
|
|
457e86b908 | ||
|
|
9b99211326 | ||
|
|
c96845a311 | ||
|
|
01e4bace4d | ||
|
|
84704346e7 | ||
|
|
77bd7953fb | ||
|
|
8c02b00a33 | ||
|
|
1f8b91ce53 | ||
|
|
dac1b7d506 | ||
|
|
40d0345f1e | ||
|
|
3e70d6289d | ||
|
|
d99c8570f3 | ||
|
|
cf7a40fbe7 | ||
|
|
0de9f38412 | ||
|
|
b4b0ab9ef4 | ||
|
|
b20e02869e | ||
|
|
ebd603b8fb | ||
|
|
1945c545dd | ||
|
|
7952a7d253 | ||
|
|
c82da14d2b | ||
|
|
9f1af79901 | ||
|
|
50c4ee1a5e | ||
|
|
351b040f4a | ||
|
|
6ed735a810 | ||
|
|
d643fc4b6c | ||
|
|
0fe32e7443 | ||
|
|
3c0397867b | ||
|
|
16e4968343 | ||
|
|
8c910aa82b | ||
|
|
6340d999d7 | ||
|
|
11af976e8b | ||
|
|
a4afc4159e | ||
|
|
24bb655130 | ||
|
|
2eaa5c5606 | ||
|
|
0593b96c2c | ||
|
|
6f1c1ef0ce | ||
|
|
d5ff452ea5 | ||
|
|
c012379e0b | ||
|
|
15de3beb63 | ||
|
|
160e04d13e | ||
|
|
359ecc7a8c | ||
|
|
6ee71ed485 | ||
|
|
7bd0157a9a | ||
|
|
6f8582eb5e | ||
|
|
df7168bb4d | ||
|
|
0aa7be2f1d | ||
|
|
d9cd40e9fa | ||
|
|
8bd6ef78f9 | ||
|
|
578af6f726 | ||
|
|
22edc7a24d | ||
|
|
304e5e52ca | ||
|
|
3f7288abfe | ||
|
|
aad0cafd19 | ||
|
|
17a0312848 | ||
|
|
c66d291eb8 | ||
|
|
cb407ce7c4 | ||
|
|
3f426f3b43 | ||
|
|
0b3ae22673 | ||
|
|
bc5a7d8e3a | ||
|
|
0628857068 | ||
|
|
de4f6e8994 | ||
|
|
439dd913f1 | ||
|
|
9568747d94 | ||
|
|
20365cf762 | ||
|
|
fa601c0fa7 | ||
|
|
00573d0172 | ||
|
|
c7036a88f1 | ||
|
|
af21c1d369 | ||
|
|
b132101b63 | ||
|
|
71beab548d | ||
|
|
6de54e5fcd | ||
|
|
a921427746 | ||
|
|
2b2b6246f0 | ||
|
|
98e5dfd6ef | ||
|
|
9e5c2e7ee9 | ||
|
|
284c0e9493 | ||
|
|
5284b5db92 | ||
|
|
36035d52d3 | ||
|
|
4d94687c15 | ||
|
|
7070678ab4 | ||
|
|
f6281d498c | ||
|
|
2cab32596a | ||
|
|
08f6a82bdc | ||
|
|
82a8524f1a | ||
|
|
6bb354d3f0 | ||
|
|
5184176c3b | ||
|
|
430723ece1 | ||
|
|
f1dc7f960c | ||
|
|
370f47b000 | ||
|
|
8e812620f0 | ||
|
|
204b612e23 | ||
|
|
c2c86f4b3d | ||
|
|
379e685b0f | ||
|
|
69dd0686e2 | ||
|
|
48325a209e | ||
|
|
96f501ab89 | ||
|
|
3c1bf73e8e | ||
|
|
e0276b4875 | ||
|
|
1bc7f1be67 | ||
|
|
3c3adcbd07 | ||
|
|
da6a9b932c | ||
|
|
5f290cd4a0 | ||
|
|
181a9cab43 | ||
|
|
a819458cba | ||
|
|
654862af21 | ||
|
|
0d8ae29a60 | ||
|
|
e05a4d9586 | ||
|
|
0541154a5e | ||
|
|
00199427ac | ||
|
|
35b00f8c3f | ||
|
|
1f3150bdf9 | ||
|
|
13c73af796 | ||
|
|
ba9a3efec1 | ||
|
|
f474c7d4d4 | ||
|
|
4a350ddd03 | ||
|
|
628d137f12 | ||
|
|
28ecf45548 | ||
|
|
58839b9b86 | ||
|
|
e436948ebd | ||
|
|
79d54ebd7c | ||
|
|
0b64b27172 | ||
|
|
d116000784 | ||
|
|
4b5f0b12d9 | ||
|
|
c8dde526f2 | ||
|
|
3058e42a21 | ||
|
|
40b30f7f27 | ||
|
|
aaad5f53ac | ||
|
|
db1057158f | ||
|
|
713c31e8f7 | ||
|
|
e5ffb39750 | ||
|
|
19067393b6 | ||
|
|
1de82a88a1 | ||
|
|
9928c864ab | ||
|
|
45515a0afd | ||
|
|
75f80fa8f8 | ||
|
|
d8dc72d151 | ||
|
|
cee3d25d49 | ||
|
|
afbeb2fb47 | ||
|
|
c0dc0858de | ||
|
|
b04317576b | ||
|
|
af2bbf0352 | ||
|
|
db9bb2778d | ||
|
|
674560d2d9 | ||
|
|
7ab033e64c | ||
|
|
3131448443 | ||
|
|
71322e614c | ||
|
|
d3fdfe08dd | ||
|
|
46f9ddbf59 | ||
|
|
e37985b527 | ||
|
|
0ccd55abd9 | ||
|
|
60123a8c07 | ||
|
|
504f1089fb | ||
|
|
e119350000 | ||
|
|
a260e3349f | ||
|
|
5cb36ed213 | ||
|
|
1a5b9f0e02 | ||
|
|
2c53605084 | ||
|
|
537f25dbad | ||
|
|
63a1e5329f | ||
|
|
b0a6111054 | ||
|
|
b07434386b | ||
|
|
0c963dee06 | ||
|
|
09bfb8496e | ||
|
|
9d1afc4268 | ||
|
|
342ccf62b2 | ||
|
|
adabd647b1 | ||
|
|
26f25a43a9 | ||
|
|
bcda21a2b0 | ||
|
|
4e6bc8af95 | ||
|
|
bd4be0d991 | ||
|
|
1f736c8203 | ||
|
|
90fa3ab9e2 | ||
|
|
fd82a312d6 | ||
|
|
27c1676821 | ||
|
|
3e26335cbd | ||
|
|
f4b96672ef | ||
|
|
c3d080f21a | ||
|
|
cb268031b7 | ||
|
|
ac44a5a1fe | ||
|
|
a3baa78ae2 | ||
|
|
47e002127c | ||
|
|
03363a528a | ||
|
|
58b016f0af | ||
|
|
8d64e7bd50 | ||
|
|
dd6cb27da4 | ||
|
|
06c01131e8 | ||
|
|
a44c4e4b1d | ||
|
|
1fb6f187d3 | ||
|
|
83e474f9ab | ||
|
|
efd4c91557 | ||
|
|
65a257a67d | ||
|
|
5b07e04600 | ||
|
|
6b175b40cb | ||
|
|
0887365f8b | ||
|
|
cebadbfcd7 | ||
|
|
380b1b6997 | ||
|
|
8e5219636a | ||
|
|
760edd3db6 | ||
|
|
502c1c05aa | ||
|
|
a7ceccc0f4 | ||
|
|
10bd08d0f3 | ||
|
|
1e5315d338 | ||
|
|
579484ed70 | ||
|
|
2aa32d4bce | ||
|
|
5aee8738ed | ||
|
|
1111edfd85 | ||
|
|
0d47cb8b37 | ||
|
|
1c55aec64a | ||
|
|
dd26ab476c | ||
|
|
4bf667d8eb | ||
|
|
0a88bd3435 | ||
|
|
62fb261265 | ||
|
|
d97f77a8f5 | ||
|
|
822c6bebe2 | ||
|
|
fdf42a3a50 | ||
|
|
6b2ca78af7 | ||
|
|
ee24cd1ac1 | ||
|
|
71812a2053 | ||
|
|
31e4e18998 | ||
|
|
9fb2ffe1d3 | ||
|
|
23e83aa04c | ||
|
|
77ee63ba8b | ||
|
|
49e59a6dce | ||
|
|
137ecb9814 | ||
|
|
7e25254e93 | ||
|
|
0c9ae3cb1b | ||
|
|
471e747fc0 | ||
|
|
fe7a66f3cb | ||
|
|
a13650f94d | ||
|
|
73e7b5ead1 | ||
|
|
e5920cc577 | ||
|
|
39655fe83b | ||
|
|
9df309a14a | ||
|
|
5e2085a45f | ||
|
|
4bcb7077c0 | ||
|
|
000c2d73fd | ||
|
|
e89c5d976a | ||
|
|
f5ed98fbf5 | ||
|
|
60c4162087 | ||
|
|
074a7d6cb7 | ||
|
|
a6ba463c43 | ||
|
|
be2061c520 | ||
|
|
3f96deb0f0 | ||
|
|
6d8ce3acae | ||
|
|
f6c317710f | ||
|
|
6799806300 | ||
|
|
0d36136f54 | ||
|
|
e1fc5f2086 | ||
|
|
9d5f4bf468 | ||
|
|
637516f2d4 | ||
|
|
b427c930f2 | ||
|
|
34f39756ec | ||
|
|
e36c7575fc | ||
|
|
0a23bd2580 | ||
|
|
03aeed615d | ||
|
|
49018e2ff7 | ||
|
|
50d14a33c0 | ||
|
|
c64a78ffcc | ||
|
|
1aae519356 | ||
|
|
af5823b407 | ||
|
|
9b198fe6e7 | ||
|
|
4997b326f6 | ||
|
|
c288ecdb9c | ||
|
|
f21e372402 | ||
|
|
927dd88dc4 | ||
|
|
7dd96ec357 | ||
|
|
ba6aa51f91 | ||
|
|
beb7546e20 | ||
|
|
67579079e0 | ||
|
|
3a632a9bc5 | ||
|
|
45b2e64d82 | ||
|
|
538d74b5d8 | ||
|
|
e3988b50b5 | ||
|
|
f4b8440fba | ||
|
|
d3ee3a0c3c | ||
|
|
f96bc08f35 | ||
|
|
a0c791dc88 | ||
|
|
f717a91bc5 | ||
|
|
8bd5fc14ba | ||
|
|
a51b16097b | ||
|
|
0bb538ba69 | ||
|
|
e11a07b230 | ||
|
|
d263cfbd50 | ||
|
|
36f80be2f7 | ||
|
|
7b9ca945d4 | ||
|
|
ffeb1da7d7 | ||
|
|
d2d8712980 | ||
|
|
621cef39f5 | ||
|
|
08e6f23655 | ||
|
|
4a25321191 | ||
|
|
8c322a0119 | ||
|
|
bd39e4671e | ||
|
|
3d6bb5f86f | ||
|
|
ce03d0ee8e | ||
|
|
bca90ca2a7 | ||
|
|
08cb9e5584 | ||
|
|
1a8cc305af | ||
|
|
47a34e0ccf | ||
|
|
36dab67658 | ||
|
|
7bb2957e47 | ||
|
|
c168a2f142 | ||
|
|
68af6989b1 | ||
|
|
446c67018a | ||
|
|
0fe8e180c4 | ||
|
|
7cdfc0ac3d | ||
|
|
85cab10371 | ||
|
|
61d8425cb6 | ||
|
|
d49b6244c1 | ||
|
|
10c2b97786 | ||
|
|
9ed364ed36 | ||
|
|
b95e5f6417 | ||
|
|
4afebf88eb | ||
|
|
d523158e92 | ||
|
|
1fd1787a1c | ||
|
|
fbbca68790 | ||
|
|
4cdfd49637 | ||
|
|
31c01cf107 | ||
|
|
879e964f60 | ||
|
|
019c9de291 | ||
|
|
af370f81f0 | ||
|
|
598c7ede37 | ||
|
|
2f66755226 | ||
|
|
d01a5f3d17 | ||
|
|
bbda3e53da | ||
|
|
22e73ea31f | ||
|
|
6b37f201d7 | ||
|
|
94ecf3847b | ||
|
|
ee968691d7 | ||
|
|
22db3bcb9c | ||
|
|
7da803e908 | ||
|
|
4aad07bdc4 | ||
|
|
7a3f874753 | ||
|
|
f77a8e2eda | ||
|
|
bd99e950f5 | ||
|
|
fdb7f34bc8 | ||
|
|
85e3c24167 | ||
|
|
aab8dd360f | ||
|
|
a8f60d0d4b | ||
|
|
5b1bfedb82 | ||
|
|
ee7e4f5a42 | ||
|
|
d20d1922db | ||
|
|
be6fbee56a | ||
|
|
3c0b26c4b9 | ||
|
|
25e2fbdf7d | ||
|
|
5bd67db123 | ||
|
|
f3737502bd | ||
|
|
74e7eb283a | ||
|
|
f3f0741469 | ||
|
|
9c43965a86 | ||
|
|
3a4e719b8c |
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1,24 +1,29 @@
|
||||
*.gcno
|
||||
*.la
|
||||
*.lo
|
||||
*.loT
|
||||
*.mod
|
||||
*.o
|
||||
.deps
|
||||
.libs
|
||||
.cache.mk
|
||||
.deps/
|
||||
.dirstamp
|
||||
.libs/
|
||||
Makefile
|
||||
Makefile.in
|
||||
GNUmakefile
|
||||
|
||||
/downloads
|
||||
|
||||
/Makefile.iptrules
|
||||
/Makefile.mans
|
||||
/.*.lst
|
||||
/matches.man
|
||||
/targets.man
|
||||
|
||||
/aclocal.m4
|
||||
/autom4te*.cache
|
||||
/compile
|
||||
/autom4te.cache/
|
||||
/build-aux/
|
||||
/config.*
|
||||
/configure
|
||||
/depcomp
|
||||
/install-sh
|
||||
/libtool
|
||||
/ltmain.sh
|
||||
/missing
|
||||
/stamp-h1
|
||||
/xtables-addons.8
|
||||
|
||||
80
INSTALL
80
INSTALL
@@ -9,19 +9,20 @@ in combination with the kernel's Kbuild system.
|
||||
# make install
|
||||
|
||||
|
||||
Prerequirements
|
||||
===============
|
||||
Supported configurations for this release
|
||||
=========================================
|
||||
|
||||
* a recent iptables snapshot
|
||||
- from the "xtables" git repository at dev.medozas.de
|
||||
(minimum as per git-describe: v1.4.0-77)
|
||||
- or the subversion repository at netfilter.org (minimum: r7502)
|
||||
- or the xtables-combined tarball that is currently distributed
|
||||
* iptables >= 1.6.0
|
||||
|
||||
* kernel-source >= 2.6.18.5 with prepared build/output directory
|
||||
- CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK
|
||||
- CONFIG_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_MARK
|
||||
enabled =y or as module (=m)
|
||||
* kernel-devel >= 4.15
|
||||
with prepared build/output directory
|
||||
- CONFIG_NF_CONNTRACK
|
||||
- CONFIG_NF_CONNTRACK_MARK enabled =y or as module (=m)
|
||||
- CONFIG_CONNECTOR y/m if you wish to receive userspace
|
||||
notifications from pknock through netlink/connector
|
||||
|
||||
(Use xtables-addons-1.x if you need support for Linux < 3.7.
|
||||
Use xtables-addons-2.x if you need support for Linux < 4.15.)
|
||||
|
||||
|
||||
Selecting extensions
|
||||
@@ -36,6 +37,10 @@ Configuring and compiling
|
||||
|
||||
./configure [options]
|
||||
|
||||
--without-kbuild
|
||||
|
||||
Deactivate building kernel modules, and just do userspace parts.
|
||||
|
||||
--with-kbuild=
|
||||
|
||||
Specifies the path to the kernel build output directory. We need
|
||||
@@ -43,23 +48,18 @@ Configuring and compiling
|
||||
/lib/modules/$(running version)/build, which usually points to
|
||||
the right directory. (If not, you need to install something.)
|
||||
|
||||
--with-xtables=
|
||||
For RPM building, it should be /usr/src/linux-obj/...
|
||||
or whatever location the distro makes use of.
|
||||
|
||||
Specifies the path to the directory where we may find
|
||||
xtables.h, should it not be within the standard C compiler
|
||||
include path (/usr/include), or if you want to override it.
|
||||
The directory will be checked for xtables.h and
|
||||
include/xtables.h. (This is to support the following specs:)
|
||||
|
||||
--with-xtables=/usr/src/xtables
|
||||
--with-xtables=/usr/src/xtables/include
|
||||
--with-xtables=/opt/xtables/include
|
||||
|
||||
--with-libxtdir=
|
||||
--with-xtlibdir=
|
||||
|
||||
Specifies the path to where the newly built extensions should
|
||||
be installed when `make install` is run. It uses the same
|
||||
default as the Xtables package, ${libexecdir}/xtables.
|
||||
be installed when `make install` is run. The default is to
|
||||
use the same path that Xtables/iptables modules use, as
|
||||
determined by `pkg-config xtables --variable xtlibdir`.
|
||||
Thus, this option normally does NOT need to be specified
|
||||
anymore, even if your distribution put modules in a strange
|
||||
location.
|
||||
|
||||
If you want to enable debugging, use
|
||||
|
||||
@@ -68,6 +68,33 @@ If you want to enable debugging, use
|
||||
(-O0 is used to turn off instruction reordering, which makes debugging
|
||||
much easier.)
|
||||
|
||||
To make use of a libxtables that is not in the default path, either
|
||||
|
||||
a) append the location of the pkg-config files like:
|
||||
|
||||
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
|
||||
|
||||
(Assuming that files have been installed)
|
||||
or,
|
||||
|
||||
b) override the pkg-config variables, for example:
|
||||
|
||||
./configure libxtables_CFLAGS="-I../iptables/include" \
|
||||
libxtables_LIBS="-L../iptables/.libs \
|
||||
-Wl,-rpath,../iptables/.libs -lxtables"
|
||||
|
||||
(Use this in case you wish to use it without having to
|
||||
run `make install`. This is because the libxtables.pc pkgconfig
|
||||
file in ../iptables would already point to e.g. /usr/local.)
|
||||
|
||||
|
||||
Build-time options
|
||||
==================
|
||||
|
||||
V= controls the verbosity of make commands.
|
||||
V=0 "silent" (output filename)
|
||||
V=1 "verbose" (entire gcc command line)
|
||||
|
||||
|
||||
Note to distribution packagers
|
||||
==============================
|
||||
@@ -76,4 +103,5 @@ Except for --with-kbuild, distributions should not have a need to
|
||||
supply any other flags (besides --prefix=/usr and perhaps
|
||||
--libdir=/usr/lib64, etc.) to configure when all prerequired packages
|
||||
are installed. If iptables-devel is installed, necessary headers should
|
||||
be in /usr/include, so --with-xtables is not needed.
|
||||
already be in /usr/include, so that overriding PKG_CONFIG_PATH,
|
||||
libxtables_CFLAGS and libxtables_LIBS variables should not be needed.
|
||||
|
||||
35
Makefile.am
35
Makefile.am
@@ -1,23 +1,32 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||
SUBDIRS = extensions extensions/ipset
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
SUBDIRS = extensions geoip
|
||||
|
||||
man_MANS := xtables-addons.8
|
||||
|
||||
xtables-addons.8: ${srcdir}/xtables-addons.8.in extensions/matches.man extensions/targets.man
|
||||
${AM_VERBOSE_GEN} sed -e '/@MATCHES@/ r extensions/matches.man' -e '/@TARGET@/ r extensions/targets.man' $< >$@;
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
||||
extensions/%:
|
||||
${MAKE} ${AM_MAKEFLAGS} -C $(@D) $(@F)
|
||||
xtables-addons.8: FORCE
|
||||
${MAKE} -f Makefile.mans all;
|
||||
|
||||
install-exec-local:
|
||||
depmod -a || :;
|
||||
clean-local-mans:
|
||||
${MAKE} -f Makefile.mans clean;
|
||||
|
||||
clean-local: clean-local-mans
|
||||
|
||||
config.status: Makefile.iptrules.in
|
||||
|
||||
tmpdir := $(shell mktemp -dtu)
|
||||
packer = xz
|
||||
packext = .tar.xz
|
||||
|
||||
.PHONY: tarball
|
||||
tarball:
|
||||
rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION};
|
||||
pushd ${top_srcdir} && git archive --prefix=xtables-addons-${PACKAGE_VERSION}/ HEAD | tar -C /tmp -x && popd;
|
||||
pushd /tmp/xtables-addons-${PACKAGE_VERSION} && ./autogen.sh && popd;
|
||||
tar -C /tmp -cjf xtables-addons-${PACKAGE_VERSION}.tar.bz2 --owner=root --group=root xtables-addons-${PACKAGE_VERSION}/;
|
||||
rm -Rf /tmp/xtables-addons-${PACKAGE_VERSION};
|
||||
# do not use mkdir_p here.
|
||||
mkdir ${tmpdir}
|
||||
pushd ${top_srcdir} && git archive --prefix=${PACKAGE_NAME}-${PACKAGE_VERSION}/ HEAD | tar -C ${tmpdir} -x && popd;
|
||||
pushd ${tmpdir}/${PACKAGE_NAME}-${PACKAGE_VERSION} && ./autogen.sh && popd;
|
||||
tar --use=${packer} -C ${tmpdir} -cf ${PACKAGE_NAME}-${PACKAGE_VERSION}${packext} --owner=root --group=root ${PACKAGE_NAME}-${PACKAGE_VERSION}/;
|
||||
rm -Rf ${tmpdir};
|
||||
|
||||
31
Makefile.extra
Normal file
31
Makefile.extra
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- Makefile -*-
|
||||
# AUTOMAKE
|
||||
|
||||
export AM_CPPFLAGS
|
||||
export AM_CFLAGS
|
||||
XA_SRCDIR = ${srcdir}
|
||||
XA_TOPSRCDIR = ${top_srcdir}
|
||||
XA_ABSTOPSRCDIR = ${abs_top_srcdir}
|
||||
export XA_SRCDIR
|
||||
export XA_TOPSRCDIR
|
||||
export XA_ABSTOPSRCDIR
|
||||
|
||||
_mcall = -f ${top_builddir}/Makefile.iptrules
|
||||
|
||||
all-local: user-all-local
|
||||
|
||||
install-exec-local: user-install-local
|
||||
|
||||
clean-local: user-clean-local
|
||||
|
||||
user-all-local:
|
||||
${MAKE} ${_mcall} all;
|
||||
|
||||
# Have no user-install-data-local ATM
|
||||
user-install-local: user-install-exec-local
|
||||
|
||||
user-install-exec-local:
|
||||
${MAKE} ${_mcall} install;
|
||||
|
||||
user-clean-local:
|
||||
${MAKE} ${_mcall} clean;
|
||||
62
Makefile.iptrules.in
Normal file
62
Makefile.iptrules.in
Normal file
@@ -0,0 +1,62 @@
|
||||
# -*- Makefile -*-
|
||||
# MANUAL
|
||||
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
libexecdir = @libexecdir@
|
||||
xtlibdir = @xtlibdir@
|
||||
|
||||
CC = @CC@
|
||||
CCLD = ${CC}
|
||||
CFLAGS = @CFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
libxtables_CFLAGS = @libxtables_CFLAGS@
|
||||
libxtables_LIBS = @libxtables_LIBS@
|
||||
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
|
||||
|
||||
AM_DEFAULT_VERBOSITY = 0
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_SILENT_0 = @
|
||||
am__v_CC_ = ${am__v_CC_${AM_DEFAULT_VERBOSITY}}
|
||||
am__v_CCLD_ = ${am__v_CCLD_${AM_DEFAULT_VERBOSITY}}
|
||||
am__v_GEN_ = ${am__v_GEN_${AM_DEFAULT_VERBOSITY}}
|
||||
am__v_SILENT_ = ${am__v_SILENT_${AM_DEFAULT_VERBOSITY}}
|
||||
AM_V_CC = ${am__v_CC_${V}}
|
||||
AM_V_CCLD = ${am__v_CCLD_${V}}
|
||||
AM_V_GEN = ${am__v_GEN_${V}}
|
||||
AM_V_silent = ${am__v_GEN_${V}}
|
||||
|
||||
include ${XA_TOPSRCDIR}/mconfig
|
||||
-include ${XA_TOPSRCDIR}/mconfig.*
|
||||
include ${XA_SRCDIR}/Mbuild
|
||||
-include ${XA_SRCDIR}/Mbuild.*
|
||||
|
||||
targets := $(filter-out %/,${obj-m})
|
||||
subdirs_list := $(filter %/,${obj-m})
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
.PHONY: all install clean
|
||||
|
||||
all: ${targets}
|
||||
@for i in ${subdirs_list}; do ${MAKE} -C $$i || exit $$?; done;
|
||||
|
||||
install: ${targets}
|
||||
@for i in ${subdirs_list}; do ${MAKE} -C $$i $@ || exit $$?; done;
|
||||
install -dm0755 "${DESTDIR}/${xtlibdir}";
|
||||
@for i in $^; do install -pm0755 $$i "${DESTDIR}/${xtlibdir}"; done;
|
||||
|
||||
clean:
|
||||
@for i in ${subdirs_list}; do ${MAKE} -C $$i $@ || exit $$?; done;
|
||||
rm -f *.oo *.so;
|
||||
|
||||
lib%.so: lib%.oo
|
||||
${AM_V_CCLD}${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $< ${libxtables_LIBS} ${LDLIBS};
|
||||
|
||||
%.oo: ${XA_SRCDIR}/%.c
|
||||
${AM_V_CC}${CC} ${AM_DEPFLAGS} ${AM_CPPFLAGS} ${AM_CFLAGS} -DPIC -fPIC ${CPPFLAGS} ${CFLAGS} -o $@ -c $<;
|
||||
43
Makefile.mans.in
Normal file
43
Makefile.mans.in
Normal file
@@ -0,0 +1,43 @@
|
||||
# -*- Makefile -*-
|
||||
# MANUAL
|
||||
|
||||
srcdir := @srcdir@
|
||||
|
||||
wcman_matches := $(shell find "${srcdir}/extensions" -name 'libxt_[a-z]*.man' -print | sort)
|
||||
wcman_targets := $(shell find "${srcdir}/extensions" -name 'libxt_[A-Z]*.man' -print | sort)
|
||||
wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches})
|
||||
wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
|
||||
|
||||
.PHONY: FORCE
|
||||
|
||||
FORCE:
|
||||
|
||||
.manpages.lst: FORCE
|
||||
@echo "${wlist_targets} ${wlist_matches}" >$@.tmp; \
|
||||
cmp -s $@ $@.tmp || mv $@.tmp $@; \
|
||||
rm -f $@.tmp;
|
||||
|
||||
man_run = \
|
||||
${AM_V_GEN}for ext in $(1); do \
|
||||
name="$${ext%.man}"; \
|
||||
name="$${name\#\#*/libxt_}"; \
|
||||
if [ -f "$$ext" ]; then \
|
||||
echo ".SS $$name"; \
|
||||
cat "$$ext" || exit $$?; \
|
||||
continue; \
|
||||
fi; \
|
||||
done >$@;
|
||||
|
||||
all: xtables-addons.8
|
||||
|
||||
xtables-addons.8: ${srcdir}/xtables-addons.8.in matches.man targets.man
|
||||
${AM_V_GEN}sed -e '/@MATCHES@/ r matches.man' -e '/@TARGET@/ r targets.man' $< >$@;
|
||||
|
||||
matches.man: .manpages.lst ${wcman_matches}
|
||||
$(call man_run,${wlist_matches})
|
||||
|
||||
targets.man: .manpages.lst ${wcman_targets}
|
||||
$(call man_run,${wlist_targets})
|
||||
|
||||
clean:
|
||||
rm -f xtables-addons.8 matches.man targets.man
|
||||
55
README
55
README
@@ -1,52 +1,15 @@
|
||||
Xtables-addons
|
||||
==============
|
||||
|
||||
Xtables-addons is the proclaimed successor to patch-o-matic(-ng). It
|
||||
contains extensions that were not accepted in the main Xtables
|
||||
package.
|
||||
Xtables-addons is a set of extensions that were not accepted in the
|
||||
Linux kernel and/or main Xtables/iptables package.
|
||||
|
||||
Xtables-addons is different from patch-o-matic in that you do not
|
||||
have to patch or recompile either kernel or Xtables(iptables). But
|
||||
please see the INSTALL file for the minimum requirements of this
|
||||
package.
|
||||
|
||||
All code imported from patch-o-matic has been reviewed and all
|
||||
apparent bugs like binary stability across multiarches, missing
|
||||
sanity checks and incorrect endianess handling have been fixed,
|
||||
simplified, and sped up.
|
||||
It superseded the earlier patch-o-matic(-ng) package in that no
|
||||
patching and/or recompilation of either the kernel or
|
||||
Xtables/iptables is required. However, do see the INSTALL file for
|
||||
the minimum requirements of Xtables-addons.
|
||||
|
||||
|
||||
Inclusion into a kernel tree
|
||||
============================
|
||||
|
||||
|
||||
|
||||
|
||||
External extensions
|
||||
===================
|
||||
|
||||
The program "xa-download-more" can be used to download more
|
||||
extensions from 3rd parties into the source tree. The URLs are listed
|
||||
in the "sources" file. If the "sources" file contains an entry like
|
||||
|
||||
http://foobar.org/xa/
|
||||
|
||||
xa-download-more will inspect http://foobar.org/xa/xa-index.txt for
|
||||
files to download. That file may contain
|
||||
|
||||
foobar.tar.bz2
|
||||
|
||||
and xa-download-more will then retrieve and unpack
|
||||
http://foobar.org/xa/foobar.tar.bz2.
|
||||
|
||||
Files that should be contained in the tarball are an mconfig and
|
||||
Kbuild files to control building the extension, libxt_foobar.c for
|
||||
the userspace extension and xt_foobar.c for the kernel extension.
|
||||
|
||||
mconfig.foobar
|
||||
extensions/Kbuild.foobar
|
||||
extensions/Mbuild.foobar
|
||||
extensions/libxt_foobar.c
|
||||
extensions/libxt_foobar.man
|
||||
extensions/xt_foobar.c
|
||||
extensions/xt_foobar.h
|
||||
Included in this package
|
||||
========================
|
||||
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
|
||||
|
||||
109
configure.ac
109
configure.ac
@@ -1,66 +1,79 @@
|
||||
|
||||
AC_INIT([xtables-addons], [1.5.7])
|
||||
AC_INIT([xtables-addons], [3.7])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_INSTALL
|
||||
AM_INIT_AUTOMAKE
|
||||
AM_INIT_AUTOMAKE([1.10b -Wall foreign subdir-objects])
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
AC_DISABLE_STATIC
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
kbuilddir="/lib/modules/$(uname -r)/build";
|
||||
AC_ARG_WITH([kbuild],
|
||||
AS_HELP_STRING([--with-kbuild=PATH],
|
||||
[Path to kernel build directory [[/lib/modules/CURRENT/build]]]),
|
||||
[kbuilddir="$withval"])
|
||||
AC_ARG_WITH([ksource],
|
||||
AS_HELP_STRING([--with-ksource=PATH],
|
||||
[Path to kernel source directory [[/lib/modules/CURRENT/source]]]),
|
||||
[ksourcedir="$withval"])
|
||||
AC_ARG_WITH([xtables],
|
||||
AS_HELP_STRING([--with-xtables=PATH],
|
||||
[Path to the Xtables includes [[none]]]),
|
||||
[xtables_location="$withval"])
|
||||
[Path to kernel build directory [[/lib/modules/CURRENT/build]]])
|
||||
AS_HELP_STRING([--without-kbuild],
|
||||
[Build only userspace tools]),
|
||||
[kbuilddir="$withval"],
|
||||
[kbuilddir="/lib/modules/$(uname -r)/build"])
|
||||
#
|
||||
# check for --without-kbuild
|
||||
#
|
||||
if [[ "$kbuilddir" == no ]]; then
|
||||
kbuilddir="";
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS([linux/netfilter/x_tables.h], [],
|
||||
[AC_MSG_ERROR([You need to have linux/netfilter/x_tables.h, see INSTALL file for details])])
|
||||
PKG_CHECK_MODULES([libxtables], [xtables >= 1.6.0])
|
||||
xtlibdir="$(pkg-config --variable=xtlibdir xtables)"
|
||||
|
||||
AC_ARG_WITH([xtlibdir],
|
||||
AS_HELP_STRING([--with-xtlibdir=PATH],
|
||||
[Path where to install Xtables extensions [[LIBEXECDIR/xtables]]]),
|
||||
[xtlibdir="$withval"],
|
||||
[xtlibdir='${libexecdir}/xtables'])
|
||||
[Path where to install Xtables extensions [[autodetect]]]),
|
||||
[xtlibdir="$withval"])
|
||||
AC_MSG_CHECKING([Xtables module directory])
|
||||
AC_MSG_RESULT([$xtlibdir])
|
||||
|
||||
AC_MSG_CHECKING([xtables.h presence])
|
||||
if [[ -n "$xtables_location" ]]; then
|
||||
if [[ -f "$xtables_location/xtables.h" ]]; then
|
||||
AC_MSG_RESULT([$xtables_location/xtables.h])
|
||||
xtables_CFLAGS="-I $xtables_location";
|
||||
elif [[ -f "$xtables_location/include/xtables.h" ]]; then
|
||||
AC_MSG_RESULT([$xtables_location/include/xtables.h])
|
||||
xtables_CFLAGS="-I $xtables_location/include";
|
||||
fi;
|
||||
fi;
|
||||
if [[ -z "$xtables_CFLAGS" ]]; then
|
||||
if [[ -f "$includedir/xtables.h" ]]; then
|
||||
AC_MSG_RESULT([$includedir/xtables.h])
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi;
|
||||
fi;
|
||||
|
||||
regular_CFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \
|
||||
-D_REENTRANT -Wall -Waggregate-return -Wmissing-declarations \
|
||||
regular_CPPFLAGS="-D_LARGEFILE_SOURCE=1 -D_LARGE_FILES -D_FILE_OFFSET_BITS=64 \
|
||||
-D_REENTRANT -I\${XA_TOPSRCDIR}/include"
|
||||
regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
|
||||
-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
|
||||
-Winline -pipe -DXTABLES_LIBDIR=\\\"\${xtlibdir}\\\"";
|
||||
kinclude_CFLAGS="";
|
||||
if [[ -n "$kbuilddir" ]]; then
|
||||
kinclude_CFLAGS="$kinclude_CFLAGS -I $kbuilddir/include";
|
||||
fi;
|
||||
if [[ -n "$ksourcedir" ]]; then
|
||||
kinclude_CFLAGS="$kinclude_CFLAGS -I $ksourcedir/include";
|
||||
-Winline -pipe";
|
||||
|
||||
if test -n "$kbuilddir"; then
|
||||
AC_MSG_CHECKING([kernel version that we will build against])
|
||||
krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease | $AWK -v 'FS=[[^0-9.]]' '{print $1; exit}')"
|
||||
save_IFS="$IFS"
|
||||
IFS='.'
|
||||
set x $krel
|
||||
IFS="$save_IFS"
|
||||
kmajor="$(($2+0))"
|
||||
kminor="$(($3+0))"
|
||||
kmicro="$(($4+0))"
|
||||
kstable="$(($5+0))"
|
||||
if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then
|
||||
echo "WARNING: Version detection did not succeed. Continue at own luck.";
|
||||
else
|
||||
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
|
||||
if test "$kmajor" -gt 5 -o "$kmajor" -eq 5 -a "$kminor" -gt 4; then
|
||||
echo "WARNING: That kernel version is not officially supported yet. Continue at own luck.";
|
||||
elif test "$kmajor" -eq 5 -a "$kminor" -ge 0; then
|
||||
:
|
||||
elif test "$kmajor" -eq 4 -a "$kminor" -ge 18; then
|
||||
:
|
||||
else
|
||||
echo "WARNING: That kernel version is not officially supported.";
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
AC_SUBST([regular_CPPFLAGS])
|
||||
AC_SUBST([regular_CFLAGS])
|
||||
AC_SUBST([xtables_CFLAGS])
|
||||
AC_SUBST([kinclude_CFLAGS])
|
||||
AC_SUBST([kbuilddir])
|
||||
AC_SUBST([ksourcedir])
|
||||
AC_SUBST([xtlibdir])
|
||||
AC_OUTPUT([Makefile extensions/GNUmakefile extensions/ipset/GNUmakefile])
|
||||
AC_CONFIG_FILES([Makefile Makefile.iptrules Makefile.mans geoip/Makefile
|
||||
extensions/Makefile extensions/ACCOUNT/Makefile
|
||||
extensions/pknock/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
4
doc/README.psd
Normal file
4
doc/README.psd
Normal 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: "
|
||||
39
doc/api/2.6.35.c
Normal file
39
doc/api/2.6.35.c
Normal file
@@ -0,0 +1,39 @@
|
||||
match:
|
||||
|
||||
/* true/false */
|
||||
bool
|
||||
(*match)(
|
||||
const struct sk_buff *skb,
|
||||
struct xt_action_param *,
|
||||
);
|
||||
|
||||
/* error code */
|
||||
int
|
||||
(*checkentry)(
|
||||
const struct xt_mtchk_param *,
|
||||
);
|
||||
|
||||
void
|
||||
(*destroy)(
|
||||
const struct xt_mtdtor_param *,
|
||||
);
|
||||
|
||||
target:
|
||||
|
||||
/* verdict */
|
||||
unsigned int
|
||||
(*target)(
|
||||
struct sk_buff *skb,
|
||||
const struct xt_action_param *,
|
||||
);
|
||||
|
||||
/* error code */
|
||||
int
|
||||
(*checkentry)(
|
||||
const struct xt_tgchk_param *,
|
||||
);
|
||||
|
||||
void
|
||||
(*destroy)(
|
||||
const struct xt_tgdtor_param *,
|
||||
);
|
||||
39
doc/api/xt-a.c
Normal file
39
doc/api/xt-a.c
Normal file
@@ -0,0 +1,39 @@
|
||||
match:
|
||||
|
||||
/* true/false */
|
||||
bool
|
||||
(*match)(
|
||||
const struct sk_buff *skb,
|
||||
struct xt_action_param *,
|
||||
);
|
||||
|
||||
/* error code */
|
||||
int
|
||||
(*checkentry)(
|
||||
const struct xt_mtchk_param *,
|
||||
);
|
||||
|
||||
void
|
||||
(*destroy)(
|
||||
const struct xt_mtdtor_param *,
|
||||
);
|
||||
|
||||
target:
|
||||
|
||||
/* verdict */
|
||||
unsigned int
|
||||
(*target)(
|
||||
struct sk_buff **pskb,
|
||||
const struct xt_action_param *,
|
||||
);
|
||||
|
||||
/* error code */
|
||||
int
|
||||
(*checkentry)(
|
||||
const struct xt_tgchk_param *,
|
||||
);
|
||||
|
||||
void
|
||||
(*destroy)(
|
||||
const struct xt_tgdtor_param *,
|
||||
);
|
||||
180
doc/changelog.txt
Normal file
180
doc/changelog.txt
Normal file
@@ -0,0 +1,180 @@
|
||||
|
||||
v3.7 (2019-12-01)
|
||||
=================
|
||||
Fixes:
|
||||
- xt_geoip: fix in6_addr little-endian byte swapping
|
||||
|
||||
|
||||
v3.6 (2019-11-20)
|
||||
=================
|
||||
Enhancements:
|
||||
- support for up to Linux 5.4
|
||||
|
||||
|
||||
v3.5 (2019-09-10)
|
||||
=================
|
||||
Enhancements:
|
||||
- xt_DELUDE, xt_TARPIT: added additional code needed to work with
|
||||
bridges from Linux 5.0 onwards.
|
||||
|
||||
|
||||
v3.4 (2019-09-06)
|
||||
=================
|
||||
Enhancements:
|
||||
- support for up to Linux 5.3
|
||||
- xt_PROTO module
|
||||
|
||||
|
||||
v3.3 (2019-03-07)
|
||||
=================
|
||||
Enhancements:
|
||||
- support for Linux 5.0
|
||||
|
||||
|
||||
v3.2 (2018-09-07)
|
||||
=================
|
||||
Changes:
|
||||
- rework xt_geoip_build to scan the immediate directory for .csv,
|
||||
not to scan for GeoLite2-Country-CSV_\d+.
|
||||
|
||||
|
||||
v3.1 (2018-08-14)
|
||||
=================
|
||||
Enhancements:
|
||||
- support for Linux 4.17, 4.18
|
||||
|
||||
|
||||
v3.0 (2018-02-12)
|
||||
=================
|
||||
Enhancements:
|
||||
- support for Linux 4.15, 4.16
|
||||
Changes:
|
||||
- remove support for Linux 3.7--4.14
|
||||
|
||||
|
||||
v2.14 (2017-11-22)
|
||||
==================
|
||||
Enhancements:
|
||||
- support for Linux up to 4.14
|
||||
Fixes:
|
||||
- xt_DNETMAP: fix some reports from PVSStudio (a static checker)
|
||||
|
||||
|
||||
v2.13 (2017-06-29)
|
||||
==================
|
||||
Enhancements:
|
||||
- support for Linux up to 4.12
|
||||
- xt_condition: namespace support
|
||||
Fixes:
|
||||
- xt_geoip: check for allocation overflow
|
||||
- xt_DNETMAP: fix a buffer overflow
|
||||
|
||||
|
||||
v2.12 (2017-01-11)
|
||||
==================
|
||||
Enhancements:
|
||||
- support for Linux up to 4.10
|
||||
|
||||
|
||||
v2.11 (2016-05-20)
|
||||
==================
|
||||
Enhancements:
|
||||
- support for Linux 4.5, 4.6
|
||||
- xt_ECHO: tentatively support responding to fragments
|
||||
|
||||
|
||||
v2.10 (2015-11-20)
|
||||
==================
|
||||
Enhancements:
|
||||
- Support for Linux 4.4
|
||||
Fixes:
|
||||
- xt_ACCOUNT: call free_page with the right amount of pages
|
||||
|
||||
|
||||
v2.9 (2015-10-12)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux 4.3
|
||||
|
||||
|
||||
v2.8 (2015-08-19)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux 4.2
|
||||
- Enable xt_ECHO for Linux 4.0+
|
||||
|
||||
|
||||
v2.7 (2015-07-06)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux up to 4.1
|
||||
|
||||
|
||||
v2.6 (2014-09-29)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux up to 3.17
|
||||
Fixes:
|
||||
- xt_pknock: UDP SPA mode erroneously returned an error saying
|
||||
crypto was unavailable
|
||||
|
||||
|
||||
v2.5 (2014-04-18)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux up to 3.15
|
||||
- xt_quota2: introduce support for network namespaces
|
||||
|
||||
|
||||
v2.4 (2014-01-09)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux up to 3.13
|
||||
Changes:
|
||||
- remove unmaintained RAWSNAT/RAWDNAT code
|
||||
- remove unused parts of compat_xtables that served Linux <3.7
|
||||
Fixes:
|
||||
- xt_quota2: --no-change should not alter quota to zero ever
|
||||
- xt_quota2: --packet should not be set to zero based on skb->len
|
||||
|
||||
|
||||
v2.3 (2013-06-18)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux 3.10
|
||||
Fixes:
|
||||
- xt_DNETMAP, xt_condition, xt_quota2: resolve compile error when
|
||||
CONFIG_UIDGID_STRICT_TYPE_CHECKS=y
|
||||
- xt_RAWNAT: ensure correct operation in the presence of IPv4 options
|
||||
- xt_geoip: do not throw a warnings when country database is size 0
|
||||
- xt_quota2: print "!" at the correct position during iptables-save
|
||||
Changes:
|
||||
- Make print (iptables -L) output the same as save (-S)
|
||||
|
||||
|
||||
v2.2 (2013-03-31)
|
||||
=================
|
||||
Enhancements:
|
||||
- Support for Linux 3.9
|
||||
- iptaccount: fix entire program being erroneously optimized away on PPC
|
||||
|
||||
|
||||
v2.1 (2012-11-27)
|
||||
=================
|
||||
Fixes:
|
||||
- DNETMAP: fix compile error with Linux 3.7
|
||||
Enhancements:
|
||||
- Support for Linux 3.8
|
||||
|
||||
|
||||
v2.0 (2012-11-12)
|
||||
=================
|
||||
Changes:
|
||||
- remove support for Linux 2.6.17–3.6
|
||||
- remove xt_TEE (this is available upstream since 2.6.35)
|
||||
- remove xt_CHECKSUM (this is available upstream since 2.6.36)
|
||||
Enhancements:
|
||||
- Support for Linux 3.7
|
||||
|
||||
If you want to use Xtables-addons with kernels older than 4.15,
|
||||
use the addons 2.x series.
|
||||
11
extensions/.gitignore
vendored
11
extensions/.gitignore
vendored
@@ -1,13 +1,12 @@
|
||||
.*.cmd
|
||||
.*.d
|
||||
.tmp_versions
|
||||
.tmp_versions/
|
||||
*.ko
|
||||
*.mod.c
|
||||
Module.markers
|
||||
Module.symvers
|
||||
Modules.symvers
|
||||
modules.order
|
||||
|
||||
/*.so
|
||||
/*.oo
|
||||
/matches.man
|
||||
/targets.man
|
||||
/.manpages.lst
|
||||
*.so
|
||||
*.oo
|
||||
|
||||
1
extensions/ACCOUNT/.gitignore
vendored
Normal file
1
extensions/ACCOUNT/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/iptaccount
|
||||
5
extensions/ACCOUNT/Kbuild
Normal file
5
extensions/ACCOUNT/Kbuild
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
EXTRA_CFLAGS = -I${src}/..
|
||||
|
||||
obj-m += xt_ACCOUNT.o
|
||||
13
extensions/ACCOUNT/Makefile.am
Normal file
13
extensions/ACCOUNT/Makefile.am
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${abs_top_srcdir}/extensions
|
||||
AM_CFLAGS = ${regular_CFLAGS} ${libxtables_CFLAGS}
|
||||
|
||||
include ../../Makefile.extra
|
||||
|
||||
sbin_PROGRAMS = iptaccount
|
||||
iptaccount_LDADD = libxt_ACCOUNT_cl.la
|
||||
|
||||
lib_LTLIBRARIES = libxt_ACCOUNT_cl.la
|
||||
|
||||
man_MANS = iptaccount.8
|
||||
3
extensions/ACCOUNT/Mbuild
Normal file
3
extensions/ACCOUNT/Mbuild
Normal file
@@ -0,0 +1,3 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
obj-${build_ACCOUNT} += libxt_ACCOUNT.so
|
||||
1
extensions/ACCOUNT/VERSION.txt
Normal file
1
extensions/ACCOUNT/VERSION.txt
Normal file
@@ -0,0 +1 @@
|
||||
1.16
|
||||
26
extensions/ACCOUNT/iptaccount.8
Normal file
26
extensions/ACCOUNT/iptaccount.8
Normal file
@@ -0,0 +1,26 @@
|
||||
.TH iptaccount 8 "v1.16" "" "v1.16"
|
||||
.SH Name
|
||||
iptaccount \(em administrative utility to access xt_ACCOUNT statistics
|
||||
.SH Syntax
|
||||
\fBiptaccount\fP [\fB\-acfhu\fP] [\fB\-l\fP \fIname\fP]
|
||||
.SH Options
|
||||
.PP
|
||||
\fB\-a\fP
|
||||
List all (accounting) table names.
|
||||
.PP
|
||||
\fB\-c\fP
|
||||
Loop every second (abort with CTRL+C).
|
||||
.PP
|
||||
\fB\-f\fP
|
||||
Flush data after display.
|
||||
.PP
|
||||
\fB\-h\fP
|
||||
Free all kernel handles. (Experts only!)
|
||||
.PP
|
||||
\fB\-l\fP \fIname\fP
|
||||
Show data in accounting table called by \fIname\fP.
|
||||
.TP
|
||||
\fB\-u\fP
|
||||
Show kernel handle usage.
|
||||
.SH "See also"
|
||||
\fBxtables-addons\fP(8)
|
||||
230
extensions/ACCOUNT/iptaccount.c
Normal file
230
extensions/ACCOUNT/iptaccount.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2004-2006 by Intra2net AG *
|
||||
* opensource@intra2net.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License *
|
||||
* version 2.1 as published by the Free Software Foundation; *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/types.h>
|
||||
#include <libxt_ACCOUNT_cl.h>
|
||||
|
||||
bool exit_now;
|
||||
static void sig_term(int signr)
|
||||
{
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGQUIT, SIG_IGN);
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
exit_now = true;
|
||||
}
|
||||
|
||||
static char *addr_to_dotted(unsigned int addr)
|
||||
{
|
||||
static char buf[16];
|
||||
const unsigned char *bytep;
|
||||
|
||||
addr = htonl(addr);
|
||||
bytep = (const unsigned char *)&addr;
|
||||
snprintf(buf, sizeof(buf), "%u.%u.%u.%u", bytep[0], bytep[1], bytep[2], bytep[3]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void show_usage(void)
|
||||
{
|
||||
printf("Unknown command line option. Try: [-u] [-h] [-a] [-f] [-c] [-s] [-l name]\n");
|
||||
printf("[-u] show kernel handle usage\n");
|
||||
printf("[-h] free all kernel handles (experts only!)\n\n");
|
||||
printf("[-a] list all table names\n");
|
||||
printf("[-l name] show data in table <name>\n");
|
||||
printf("[-f] flush data after showing\n");
|
||||
printf("[-c] loop every second (abort with CTRL+C)\n");
|
||||
printf("[-s] CSV output (for spreadsheet import)\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct ipt_ACCOUNT_context ctx;
|
||||
struct ipt_acc_handle_ip *entry;
|
||||
int i;
|
||||
int optchar;
|
||||
bool doHandleUsage = false, doHandleFree = false, doTableNames = false;
|
||||
bool doFlush = false, doContinue = false, doCSV = false;
|
||||
|
||||
char *table_name = NULL;
|
||||
const char *name;
|
||||
|
||||
printf("\nlibxt_ACCOUNT_cl userspace accounting tool v%s\n\n",
|
||||
LIBXT_ACCOUNT_VERSION);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
show_usage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
while ((optchar = getopt(argc, argv, "uhacfsl:")) != -1)
|
||||
{
|
||||
switch (optchar)
|
||||
{
|
||||
case 'u':
|
||||
doHandleUsage = true;
|
||||
break;
|
||||
case 'h':
|
||||
doHandleFree = true;
|
||||
break;
|
||||
case 'a':
|
||||
doTableNames = true;
|
||||
break;
|
||||
case 'f':
|
||||
doFlush = true;
|
||||
break;
|
||||
case 'c':
|
||||
doContinue = true;
|
||||
break;
|
||||
case 's':
|
||||
doCSV = true;
|
||||
break;
|
||||
case 'l':
|
||||
table_name = strdup(optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
show_usage();
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// install exit handler
|
||||
if (signal(SIGTERM, sig_term) == SIG_ERR)
|
||||
{
|
||||
printf("can't install signal handler for SIGTERM\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (signal(SIGINT, sig_term) == SIG_ERR)
|
||||
{
|
||||
printf("can't install signal handler for SIGINT\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (signal(SIGQUIT, sig_term) == SIG_ERR)
|
||||
{
|
||||
printf("can't install signal handler for SIGQUIT\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (ipt_ACCOUNT_init(&ctx))
|
||||
{
|
||||
printf("Init failed: %s\n", ctx.error_str);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Get handle usage?
|
||||
if (doHandleUsage)
|
||||
{
|
||||
int rtn = ipt_ACCOUNT_get_handle_usage(&ctx);
|
||||
if (rtn < 0)
|
||||
{
|
||||
printf("get_handle_usage failed: %s\n", ctx.error_str);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Current kernel handle usage: %d\n", ctx.handle.itemcount);
|
||||
}
|
||||
|
||||
if (doHandleFree)
|
||||
{
|
||||
int rtn = ipt_ACCOUNT_free_all_handles(&ctx);
|
||||
if (rtn < 0)
|
||||
{
|
||||
printf("handle_free_all failed: %s\n", ctx.error_str);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Freed all handles in kernel space\n");
|
||||
}
|
||||
|
||||
if (doTableNames)
|
||||
{
|
||||
int rtn = ipt_ACCOUNT_get_table_names(&ctx);
|
||||
if (rtn < 0)
|
||||
{
|
||||
printf("get_table_names failed: %s\n", ctx.error_str);
|
||||
exit(-1);
|
||||
}
|
||||
while ((name = ipt_ACCOUNT_get_next_name(&ctx)) != 0)
|
||||
printf("Found table: %s\n", name);
|
||||
}
|
||||
|
||||
if (table_name)
|
||||
{
|
||||
// Read out data
|
||||
if (doCSV)
|
||||
printf("IP;SRC packets;SRC bytes;DST packets;DST bytes\n");
|
||||
else
|
||||
printf("Showing table: %s\n", table_name);
|
||||
|
||||
i = 0;
|
||||
while (!exit_now)
|
||||
{
|
||||
// Get entries from table test
|
||||
if (ipt_ACCOUNT_read_entries(&ctx, table_name, !doFlush))
|
||||
{
|
||||
printf("Read failed: %s\n", ctx.error_str);
|
||||
ipt_ACCOUNT_deinit(&ctx);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!doCSV)
|
||||
printf("Run #%d - %u %s found\n", i, ctx.handle.itemcount,
|
||||
ctx.handle.itemcount == 1 ? "item" : "items");
|
||||
|
||||
// Output and free entries
|
||||
while ((entry = ipt_ACCOUNT_get_next_entry(&ctx)) != NULL)
|
||||
{
|
||||
if (doCSV)
|
||||
printf("%s;%llu;%llu;%llu;%llu\n",
|
||||
addr_to_dotted(entry->ip),
|
||||
(unsigned long long)entry->src_packets,
|
||||
(unsigned long long)entry->src_bytes,
|
||||
(unsigned long long)entry->dst_packets,
|
||||
(unsigned long long)entry->dst_bytes);
|
||||
else
|
||||
printf("IP: %s SRC packets: %llu bytes: %llu DST packets: %llu bytes: %llu\n",
|
||||
addr_to_dotted(entry->ip),
|
||||
(unsigned long long)entry->src_packets,
|
||||
(unsigned long long)entry->src_bytes,
|
||||
(unsigned long long)entry->dst_packets,
|
||||
(unsigned long long)entry->dst_bytes);
|
||||
}
|
||||
|
||||
if (doContinue)
|
||||
{
|
||||
sleep(1);
|
||||
i++;
|
||||
} else
|
||||
exit_now = true;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Finished.\n");
|
||||
ipt_ACCOUNT_deinit(&ctx);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
162
extensions/ACCOUNT/libxt_ACCOUNT.c
Normal file
162
extensions/ACCOUNT/libxt_ACCOUNT.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/* Shared library add-on to iptables to add ACCOUNT(ing) support.
|
||||
Author: Intra2net AG <opensource@intra2net.com>
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#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"
|
||||
#include "compat_user.h"
|
||||
|
||||
static struct option account_tg_opts[] = {
|
||||
{.name = "addr", .has_arg = true, .val = 'a'},
|
||||
{.name = "tname", .has_arg = true, .val = 't'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* 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);
|
||||
|
||||
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 (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, bool 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, false);
|
||||
}
|
||||
|
||||
/* 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, true);
|
||||
}
|
||||
|
||||
static struct xtables_target account_tg_reg = {
|
||||
.name = "ACCOUNT",
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPV4,
|
||||
.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);
|
||||
}
|
||||
60
extensions/ACCOUNT/libxt_ACCOUNT.man
Normal file
60
extensions/ACCOUNT/libxt_ACCOUNT.man
Normal file
@@ -0,0 +1,60 @@
|
||||
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.
|
||||
.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/
|
||||
199
extensions/ACCOUNT/libxt_ACCOUNT_cl.c
Normal file
199
extensions/ACCOUNT/libxt_ACCOUNT_cl.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2004 by Intra2net AG *
|
||||
* opensource@intra2net.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License *
|
||||
* version 2.1 as published by the Free Software Foundation; *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <linux/if.h>
|
||||
|
||||
#include <libxt_ACCOUNT_cl.h>
|
||||
|
||||
int ipt_ACCOUNT_init(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
memset(ctx, 0, sizeof(struct ipt_ACCOUNT_context));
|
||||
ctx->handle.handle_nr = -1;
|
||||
|
||||
ctx->sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
|
||||
if (ctx->sockfd < 0) {
|
||||
ctx->sockfd = -1;
|
||||
ctx->error_str = "Can't open socket to kernel. "
|
||||
"Permission denied or ipt_ACCOUNT module not loaded";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 4096 bytes default buffer should save us from reallocations
|
||||
// as it fits 200 concurrent active clients
|
||||
if ((ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE)) == NULL) {
|
||||
close(ctx->sockfd);
|
||||
ctx->sockfd = -1;
|
||||
ctx->error_str = "Out of memory for data buffer";
|
||||
return -1;
|
||||
}
|
||||
ctx->data_size = IPT_ACCOUNT_MIN_BUFSIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ipt_ACCOUNT_free_entries(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
if (ctx->handle.handle_nr != -1) {
|
||||
setsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_SET_ACCOUNT_HANDLE_FREE,
|
||||
&ctx->handle, sizeof(struct ipt_acc_handle_sockopt));
|
||||
ctx->handle.handle_nr = -1;
|
||||
}
|
||||
|
||||
ctx->handle.itemcount = 0;
|
||||
ctx->pos = 0;
|
||||
}
|
||||
|
||||
void ipt_ACCOUNT_deinit(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
free(ctx->data);
|
||||
ctx->data = NULL;
|
||||
|
||||
ipt_ACCOUNT_free_entries(ctx);
|
||||
|
||||
close(ctx->sockfd);
|
||||
ctx->sockfd = -1;
|
||||
}
|
||||
|
||||
int ipt_ACCOUNT_read_entries(struct ipt_ACCOUNT_context *ctx,
|
||||
const char *table, char dont_flush)
|
||||
{
|
||||
unsigned int s = sizeof(struct ipt_acc_handle_sockopt);
|
||||
unsigned int new_size;
|
||||
int rtn;
|
||||
|
||||
strncpy(ctx->handle.name, table, ACCOUNT_TABLE_NAME_LEN-1);
|
||||
|
||||
// Get table information
|
||||
if (!dont_flush)
|
||||
rtn = getsockopt(ctx->sockfd, IPPROTO_IP,
|
||||
IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH, &ctx->handle, &s);
|
||||
else
|
||||
rtn = getsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_GET_ACCOUNT_PREPARE_READ,
|
||||
&ctx->handle, &s);
|
||||
|
||||
if (rtn < 0) {
|
||||
ctx->error_str = "Can't get table information from kernel. "
|
||||
"Does it exist?";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check data buffer size
|
||||
ctx->pos = 0;
|
||||
new_size = ctx->handle.itemcount * sizeof(struct ipt_acc_handle_ip);
|
||||
// We want to prevent reallocations all the time
|
||||
if (new_size < IPT_ACCOUNT_MIN_BUFSIZE)
|
||||
new_size = IPT_ACCOUNT_MIN_BUFSIZE;
|
||||
|
||||
// Reallocate if it's too small or twice as big
|
||||
if (ctx->data_size < new_size || ctx->data_size > new_size * 2) {
|
||||
// Free old buffer
|
||||
free(ctx->data);
|
||||
ctx->data_size = 0;
|
||||
|
||||
if ((ctx->data = malloc(new_size)) == NULL) {
|
||||
ctx->error_str = "Out of memory for data buffer";
|
||||
ipt_ACCOUNT_free_entries(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->data_size = new_size;
|
||||
}
|
||||
|
||||
// Copy data from kernel
|
||||
memcpy(ctx->data, &ctx->handle, sizeof(struct ipt_acc_handle_sockopt));
|
||||
rtn = getsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_GET_ACCOUNT_GET_DATA,
|
||||
ctx->data, &ctx->data_size);
|
||||
if (rtn < 0) {
|
||||
ctx->error_str = "Can't get data from kernel. "
|
||||
"Check /var/log/messages for details.";
|
||||
ipt_ACCOUNT_free_entries(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Free kernel handle but don't reset pos/itemcount
|
||||
setsockopt(ctx->sockfd, IPPROTO_IP, IPT_SO_SET_ACCOUNT_HANDLE_FREE,
|
||||
&ctx->handle, sizeof(struct ipt_acc_handle_sockopt));
|
||||
ctx->handle.handle_nr = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ipt_acc_handle_ip *ipt_ACCOUNT_get_next_entry(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
struct ipt_acc_handle_ip *rtn;
|
||||
|
||||
// Empty or no more items left to return?
|
||||
if (!ctx->handle.itemcount || ctx->pos >= ctx->handle.itemcount)
|
||||
return NULL;
|
||||
|
||||
// Get next entry
|
||||
rtn = (struct ipt_acc_handle_ip *)(ctx->data + ctx->pos
|
||||
* sizeof(struct ipt_acc_handle_ip));
|
||||
ctx->pos++;
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int ipt_ACCOUNT_get_handle_usage(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
unsigned int s = sizeof(struct ipt_acc_handle_sockopt);
|
||||
if (getsockopt(ctx->sockfd, IPPROTO_IP,
|
||||
IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE, &ctx->handle, &s) < 0) {
|
||||
ctx->error_str = "Can't get handle usage information from kernel";
|
||||
return -1;
|
||||
}
|
||||
ctx->handle.handle_nr = -1;
|
||||
|
||||
return ctx->handle.itemcount;
|
||||
}
|
||||
|
||||
int ipt_ACCOUNT_free_all_handles(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
if (setsockopt(ctx->sockfd, IPPROTO_IP,
|
||||
IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL, NULL, 0) < 0) {
|
||||
ctx->error_str = "Can't free all kernel handles";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipt_ACCOUNT_get_table_names(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
int rtn = getsockopt(ctx->sockfd, IPPROTO_IP,
|
||||
IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES,
|
||||
ctx->data, &ctx->data_size);
|
||||
if (rtn < 0) {
|
||||
ctx->error_str = "Can't get table names from kernel. Out of memory, "
|
||||
"MINBUFISZE too small?";
|
||||
return -1;
|
||||
}
|
||||
ctx->pos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *ipt_ACCOUNT_get_next_name(struct ipt_ACCOUNT_context *ctx)
|
||||
{
|
||||
const char *rtn;
|
||||
if (((char *)ctx->data)[ctx->pos] == 0)
|
||||
return 0;
|
||||
|
||||
rtn = ctx->data + ctx->pos;
|
||||
ctx->pos += strlen(ctx->data + ctx->pos) + 1;
|
||||
|
||||
return rtn;
|
||||
}
|
||||
60
extensions/ACCOUNT/libxt_ACCOUNT_cl.h
Normal file
60
extensions/ACCOUNT/libxt_ACCOUNT_cl.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2004 by Intra2net AG *
|
||||
* opensource@intra2net.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Lesser General Public License *
|
||||
* version 2.1 as published by the Free Software Foundation; *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _xt_ACCOUNT_cl_H
|
||||
#define _xt_ACCOUNT_cl_H
|
||||
|
||||
#include <xt_ACCOUNT.h>
|
||||
|
||||
#define LIBXT_ACCOUNT_VERSION "1.3"
|
||||
|
||||
/* Don't set this below the size of struct ipt_account_handle_sockopt */
|
||||
#define IPT_ACCOUNT_MIN_BUFSIZE 4096
|
||||
|
||||
struct ipt_ACCOUNT_context
|
||||
{
|
||||
int sockfd;
|
||||
struct ipt_acc_handle_sockopt handle;
|
||||
|
||||
unsigned int data_size;
|
||||
void *data;
|
||||
unsigned int pos;
|
||||
|
||||
char *error_str;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int ipt_ACCOUNT_init(struct ipt_ACCOUNT_context *ctx);
|
||||
void ipt_ACCOUNT_deinit(struct ipt_ACCOUNT_context *ctx);
|
||||
|
||||
void ipt_ACCOUNT_free_entries(struct ipt_ACCOUNT_context *ctx);
|
||||
int ipt_ACCOUNT_read_entries(struct ipt_ACCOUNT_context *ctx,
|
||||
const char *table, char dont_flush);
|
||||
struct ipt_acc_handle_ip *ipt_ACCOUNT_get_next_entry(
|
||||
struct ipt_ACCOUNT_context *ctx);
|
||||
|
||||
/* ipt_ACCOUNT_free_entries is for internal use only function as this library
|
||||
is constructed to be used in a loop -> Don't allocate memory all the time.
|
||||
The data buffer is freed on deinit() */
|
||||
|
||||
int ipt_ACCOUNT_get_handle_usage(struct ipt_ACCOUNT_context *ctx);
|
||||
int ipt_ACCOUNT_free_all_handles(struct ipt_ACCOUNT_context *ctx);
|
||||
int ipt_ACCOUNT_get_table_names(struct ipt_ACCOUNT_context *ctx);
|
||||
const char *ipt_ACCOUNT_get_next_name(struct ipt_ACCOUNT_context *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
1217
extensions/ACCOUNT/xt_ACCOUNT.c
Normal file
1217
extensions/ACCOUNT/xt_ACCOUNT.c
Normal file
File diff suppressed because it is too large
Load Diff
68
extensions/ACCOUNT/xt_ACCOUNT.h
Normal file
68
extensions/ACCOUNT/xt_ACCOUNT.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2004-2006 by Intra2net AG *
|
||||
* opensource@intra2net.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License *
|
||||
* version 2 as published by the Free Software Foundation; *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _IPT_ACCOUNT_H
|
||||
#define _IPT_ACCOUNT_H
|
||||
|
||||
/*
|
||||
* Socket option interface shared between kernel (xt_ACCOUNT) and userspace
|
||||
* library (libxt_ACCOUNT_cl). Hopefully we are unique at least within our
|
||||
* kernel & xtables-addons space.
|
||||
*
|
||||
* Turned out often enough we are not.
|
||||
* 64-67 used by ip_tables, ip6_tables
|
||||
* 96-100 used by arp_tables
|
||||
* 128-131 used by ebtables
|
||||
*/
|
||||
#define SO_ACCOUNT_BASE_CTL 70
|
||||
|
||||
#define IPT_SO_SET_ACCOUNT_HANDLE_FREE (SO_ACCOUNT_BASE_CTL + 1)
|
||||
#define IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL (SO_ACCOUNT_BASE_CTL + 2)
|
||||
#define IPT_SO_SET_ACCOUNT_MAX IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL
|
||||
|
||||
#define IPT_SO_GET_ACCOUNT_PREPARE_READ (SO_ACCOUNT_BASE_CTL + 4)
|
||||
#define IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH (SO_ACCOUNT_BASE_CTL + 5)
|
||||
#define IPT_SO_GET_ACCOUNT_GET_DATA (SO_ACCOUNT_BASE_CTL + 6)
|
||||
#define IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE (SO_ACCOUNT_BASE_CTL + 7)
|
||||
#define IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES (SO_ACCOUNT_BASE_CTL + 8)
|
||||
#define IPT_SO_GET_ACCOUNT_MAX IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES
|
||||
|
||||
#define ACCOUNT_TABLE_NAME_LEN 32
|
||||
#define ACCOUNT_MAX_HANDLES 10
|
||||
|
||||
/* Structure for the userspace part of ipt_ACCOUNT */
|
||||
struct ipt_acc_info {
|
||||
__be32 net_ip;
|
||||
__be32 net_mask;
|
||||
char table_name[ACCOUNT_TABLE_NAME_LEN];
|
||||
int32_t table_nr;
|
||||
};
|
||||
|
||||
/* Handle structure for communication with the userspace library */
|
||||
struct ipt_acc_handle_sockopt {
|
||||
uint32_t handle_nr; /* Used for HANDLE_FREE */
|
||||
char name[ACCOUNT_TABLE_NAME_LEN]; /* Used for HANDLE_PREPARE_READ/
|
||||
HANDLE_READ_FLUSH */
|
||||
uint32_t itemcount; /* Used for HANDLE_PREPARE_READ/
|
||||
HANDLE_READ_FLUSH */
|
||||
};
|
||||
|
||||
/*
|
||||
Used for every IP when returning data
|
||||
*/
|
||||
struct ipt_acc_handle_ip {
|
||||
__be32 ip, __dummy;
|
||||
uint64_t src_packets;
|
||||
uint64_t src_bytes;
|
||||
uint64_t dst_packets;
|
||||
uint64_t dst_bytes;
|
||||
};
|
||||
|
||||
#endif /* _IPT_ACCOUNT_H */
|
||||
@@ -1,133 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
top_srcdir := @top_srcdir@
|
||||
srcdir := @srcdir@
|
||||
abstop_srcdir := $(shell readlink -e ${top_srcdir})
|
||||
abssrcdir := $(shell readlink -e ${srcdir})
|
||||
|
||||
ifeq (${abstop_srcdir},)
|
||||
$(error Path resolution of ${top_srcdir} failed)
|
||||
endif
|
||||
ifeq (${abssrcdir},)
|
||||
$(error Path resolution of ${srcdir} failed)
|
||||
endif
|
||||
|
||||
prefix := @prefix@
|
||||
exec_prefix := @exec_prefix@
|
||||
libdir := @libdir@
|
||||
libexecdir := @libexecdir@
|
||||
xtlibdir := @xtlibdir@
|
||||
kbuilddir := @kbuilddir@
|
||||
|
||||
CC := @CC@
|
||||
CCLD := ${CC}
|
||||
CFLAGS := @CFLAGS@
|
||||
LDFLAGS := @LDFLAGS@
|
||||
regular_CFLAGS := @regular_CFLAGS@
|
||||
kinclude_CFLAGS := @kinclude_CFLAGS@
|
||||
xtables_CFLAGS := @xtables_CFLAGS@
|
||||
|
||||
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS}
|
||||
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
|
||||
|
||||
ifeq (${V},)
|
||||
AM_LIBTOOL_SILENT = --silent
|
||||
AM_VERBOSE_CC = @echo " CC " $@;
|
||||
AM_VERBOSE_CCLD = @echo " CCLD " $@;
|
||||
AM_VERBOSE_CXX = @echo " CXX " $@;
|
||||
AM_VERBOSE_CXXLD = @echo " CXXLD " $@;
|
||||
AM_VERBOSE_AR = @echo " AR " $@;
|
||||
AM_VERBOSE_GEN = @echo " GEN " $@;
|
||||
endif
|
||||
|
||||
#
|
||||
# Wildcard module list
|
||||
#
|
||||
include ${top_srcdir}/mconfig
|
||||
-include ${top_srcdir}/mconfig.*
|
||||
include ${srcdir}/Mbuild
|
||||
-include ${srcdir}/Mbuild.*
|
||||
-include ${srcdir}/*.Mbuild
|
||||
|
||||
|
||||
#
|
||||
# Building blocks
|
||||
#
|
||||
targets := ${obj-m}
|
||||
targets_install := ${obj-m}
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
.PHONY: all install clean distclean FORCE
|
||||
|
||||
all: modules user matches.man targets.man
|
||||
|
||||
user: ${targets}
|
||||
|
||||
install: modules_install ${targets_install}
|
||||
@mkdir -p "${DESTDIR}${xtlibdir}";
|
||||
install -pm0755 ${targets_install} "${DESTDIR}${xtlibdir}/";
|
||||
|
||||
clean: clean_modules
|
||||
rm -f *.oo *.so;
|
||||
|
||||
distclean: clean
|
||||
rm -f .*.d .manpages.lst;
|
||||
|
||||
-include .*.d
|
||||
|
||||
|
||||
#
|
||||
# Call out to kbuild
|
||||
#
|
||||
.PHONY: modules modules_install clean_modules
|
||||
|
||||
modules:
|
||||
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} modules;
|
||||
|
||||
modules_install:
|
||||
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} INSTALL_MOD_PATH=${DESTDIR} modules_install;
|
||||
|
||||
clean_modules:
|
||||
make -C ${kbuilddir} M=${abssrcdir} XA_TOPSRCDIR=${abstop_srcdir} clean;
|
||||
|
||||
|
||||
#
|
||||
# Shared libraries
|
||||
#
|
||||
lib%.so: lib%.oo
|
||||
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
|
||||
|
||||
lib%.oo: ${srcdir}/lib%.c
|
||||
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
|
||||
|
||||
|
||||
#
|
||||
# Manpages
|
||||
#
|
||||
wcman_matches := $(wildcard ${srcdir}/libxt_[a-z]*.man)
|
||||
wcman_targets := $(wildcard ${srcdir}/libxt_[A-Z]*.man)
|
||||
wlist_matches := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_matches})
|
||||
wlist_targets := $(patsubst ${srcdir}/libxt_%.man,%,${wcman_targets})
|
||||
|
||||
.manpages.lst: FORCE
|
||||
@echo "${wlist_targets} ${wlist_matches}" >$@.tmp; \
|
||||
cmp -s $@ $@.tmp || mv $@.tmp $@; \
|
||||
rm -f $@.tmp;
|
||||
|
||||
man_run = \
|
||||
${AM_VERBOSE_GEN} \
|
||||
for ext in $(1); do \
|
||||
f="${srcdir}/libxt_$$ext.man"; \
|
||||
if [ -f "$$f" ]; then \
|
||||
echo ".SS $$ext"; \
|
||||
cat "$$f"; \
|
||||
continue; \
|
||||
fi; \
|
||||
done >$@;
|
||||
|
||||
matches.man: .manpages.lst ${wcman_matches}
|
||||
$(call man_run,${wlist_matches})
|
||||
|
||||
targets.man: .manpages.lst ${wcman_targets}
|
||||
$(call man_run,${wlist_targets})
|
||||
@@ -1,25 +1,31 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
include ${XA_TOPSRCDIR}/mconfig
|
||||
-include ${XA_TOPSRCDIR}/mconfig.*
|
||||
include ${XA_ABSTOPSRCDIR}/mconfig
|
||||
-include ${XA_ABSTOPSRCDIR}/mconfig.*
|
||||
|
||||
obj-m += compat_xtables.o
|
||||
|
||||
obj-${build_ACCOUNT} += ACCOUNT/
|
||||
obj-${build_CHAOS} += xt_CHAOS.o
|
||||
obj-${build_DELUDE} += xt_DELUDE.o
|
||||
obj-${build_DHCPADDR} += xt_DHCPADDR.o
|
||||
obj-${build_DHCPMAC} += xt_DHCPMAC.o
|
||||
obj-${build_DNETMAP} += xt_DNETMAP.o
|
||||
obj-${build_ECHO} += xt_ECHO.o
|
||||
obj-${build_IPMARK} += xt_IPMARK.o
|
||||
obj-${build_LOGMARK} += xt_LOGMARK.o
|
||||
obj-${build_PROTO} += xt_PROTO.o
|
||||
obj-${build_SYSRQ} += xt_SYSRQ.o
|
||||
obj-${build_TARPIT} += xt_TARPIT.o
|
||||
obj-${build_TEE} += xt_TEE.o
|
||||
obj-${build_condition} += xt_condition.o
|
||||
obj-${build_fuzzy} += xt_fuzzy.o
|
||||
obj-${build_geoip} += xt_geoip.o
|
||||
obj-${build_iface} += xt_iface.o
|
||||
obj-${build_ipp2p} += xt_ipp2p.o
|
||||
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_pknock} += pknock/
|
||||
obj-${build_psd} += xt_psd.o
|
||||
obj-${build_quota2} += xt_quota2.o
|
||||
|
||||
-include ${M}/*.Kbuild
|
||||
|
||||
29
extensions/Makefile.am
Normal file
29
extensions/Makefile.am
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- Makefile -*-
|
||||
# AUTOMAKE
|
||||
|
||||
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${abs_top_srcdir}/extensions
|
||||
AM_CFLAGS = ${regular_CFLAGS} ${libxtables_CFLAGS}
|
||||
|
||||
# Not having Kbuild in Makefile.extra because it will already recurse
|
||||
.PHONY: modules modules_install clean_modules
|
||||
|
||||
_kcall = -C ${kbuilddir} M=${abs_srcdir}
|
||||
|
||||
modules:
|
||||
@echo -n "Xtables-addons ${PACKAGE_VERSION} - Linux "
|
||||
@if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} --no-print-directory -s kernelrelease; fi;
|
||||
${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} modules; fi;
|
||||
|
||||
modules_install:
|
||||
${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} INSTALL_MOD_PATH=${DESTDIR} ext-mod-dir='$${INSTALL_MOD_DIR}' modules_install; fi;
|
||||
|
||||
clean_modules:
|
||||
${AM_V_silent}if [ -n "${kbuilddir}" ]; then ${MAKE} ${_kcall} clean; fi;
|
||||
|
||||
all-local: modules
|
||||
|
||||
install-exec-local: modules_install
|
||||
|
||||
clean-local: clean_modules
|
||||
|
||||
include ../Makefile.extra
|
||||
@@ -1,15 +1,25 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
obj-${build_ACCOUNT} += ACCOUNT/
|
||||
obj-${build_CHAOS} += libxt_CHAOS.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_DNETMAP} += libxt_DNETMAP.so
|
||||
obj-${build_ECHO} += libxt_ECHO.so
|
||||
obj-${build_IPMARK} += libxt_IPMARK.so
|
||||
obj-${build_LOGMARK} += libxt_LOGMARK.so
|
||||
obj-${build_PROTO} += libxt_PROTO.so
|
||||
obj-${build_SYSRQ} += libxt_SYSRQ.so
|
||||
obj-${build_TARPIT} += libxt_TARPIT.so
|
||||
obj-${build_TEE} += libxt_TEE.so
|
||||
obj-${build_condition} += libxt_condition.so
|
||||
obj-${build_fuzzy} += libxt_fuzzy.so
|
||||
obj-${build_geoip} += libxt_geoip.so
|
||||
obj-${build_iface} += libxt_iface.so
|
||||
obj-${build_ipp2p} += libxt_ipp2p.so
|
||||
obj-${build_portscan} += libxt_portscan.so
|
||||
obj-${build_ipv4options} += libxt_ipv4options.so
|
||||
obj-${build_length2} += libxt_length2.so
|
||||
obj-${build_lscan} += libxt_lscan.so
|
||||
obj-${build_pknock} += pknock/
|
||||
obj-${build_psd} += libxt_psd.so
|
||||
obj-${build_quota2} += libxt_quota2.so
|
||||
obj-${build_gradm} += libxt_gradm.so
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#ifndef _COMPAT_NFINETADDR_H
|
||||
#define _COMPAT_NFINETADDR_H 1
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
|
||||
union nf_inet_addr {
|
||||
__be32 ip;
|
||||
__be32 ip6[4];
|
||||
struct in_addr in;
|
||||
struct in6_addr in6;
|
||||
};
|
||||
|
||||
#endif /* _COMPAT_NFINETADDR_H */
|
||||
@@ -4,11 +4,8 @@
|
||||
struct tcphdr;
|
||||
struct udphdr;
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->nfmark)
|
||||
#else
|
||||
# define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
|
||||
#endif
|
||||
#define skb_ifindex(skb) (skb)->skb_iif
|
||||
#define skb_nfmark(skb) (((struct sk_buff *)(skb))->mark)
|
||||
|
||||
#ifdef CONFIG_NETWORK_SECMARK
|
||||
# define skb_secmark(skb) ((skb)->secmark)
|
||||
@@ -16,24 +13,4 @@ struct udphdr;
|
||||
# define skb_secmark(skb) 0
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 21)
|
||||
# define ip_hdr(skb) ((skb)->nh.iph)
|
||||
# define ip_hdrlen(skb) (ip_hdr(skb)->ihl * 4)
|
||||
# define ipv6_hdr(skb) ((skb)->nh.ipv6h)
|
||||
# define skb_network_header(skb) ((skb)->nh.raw)
|
||||
# define skb_transport_header(skb) ((skb)->h.raw)
|
||||
static inline void skb_reset_network_header(struct sk_buff *skb)
|
||||
{
|
||||
skb->nh.raw = skb->data;
|
||||
}
|
||||
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (void *)skb_transport_header(skb);
|
||||
}
|
||||
static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (void *)skb_transport_header(skb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* COMPAT_SKBUFF_H */
|
||||
|
||||
12
extensions/compat_user.h
Normal file
12
extensions/compat_user.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Userspace-level compat hacks
|
||||
*/
|
||||
#ifndef _XTABLES_COMPAT_USER_H
|
||||
#define _XTABLES_COMPAT_USER_H 1
|
||||
|
||||
/* linux-glibc-devel 2.6.34 header screwup */
|
||||
#ifndef ALIGN
|
||||
# define ALIGN(s, n) (((s) + ((n) - 1)) & ~((n) - 1))
|
||||
#endif
|
||||
|
||||
#endif /* _XTABLES_COMPAT_USER_H */
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* API compat layer
|
||||
* written by Jan Engelhardt <jengelh [at] medozas de>, 2008
|
||||
* written by Jan Engelhardt, 2008 - 2010
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License, either
|
||||
@@ -8,394 +8,38 @@
|
||||
*/
|
||||
#include <linux/ip.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <linux/netfilter_arp.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/route.h>
|
||||
#include <linux/export.h>
|
||||
#include "compat_skbuff.h"
|
||||
#include "compat_xtnu.h"
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_match_run(const struct sk_buff *skb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
const struct xt_match *cm, const void *matchinfo, int offset,
|
||||
unsigned int protoff, int *hotdrop)
|
||||
{
|
||||
struct xtnu_match *nm = xtcompat_numatch(cm);
|
||||
bool lo_drop = false, lo_ret;
|
||||
|
||||
if (nm == NULL || nm->match == NULL)
|
||||
return false;
|
||||
lo_ret = nm->match(skb, in, out, nm, matchinfo,
|
||||
offset, protoff, &lo_drop);
|
||||
*hotdrop = lo_drop;
|
||||
return lo_ret;
|
||||
}
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
# define WITH_IPV6 1
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static int xtnu_match_check(const char *table, const void *entry,
|
||||
const struct xt_match *cm, void *matchinfo, unsigned int matchinfosize,
|
||||
unsigned int hook_mask)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_match_check(const char *table, const void *entry,
|
||||
const struct xt_match *cm, void *matchinfo, unsigned int hook_mask)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
void *HX_memmem(const void *space, size_t spacesize,
|
||||
const void *point, size_t pointsize)
|
||||
{
|
||||
struct xtnu_match *nm = xtcompat_numatch(cm);
|
||||
size_t i;
|
||||
|
||||
if (nm == NULL)
|
||||
return false;
|
||||
if (nm->checkentry == NULL)
|
||||
return true;
|
||||
return nm->checkentry(table, entry, nm, matchinfo, hook_mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo,
|
||||
unsigned int matchinfosize)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static void xtnu_match_destroy(const struct xt_match *cm, void *matchinfo)
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
{
|
||||
struct xtnu_match *nm = xtcompat_numatch(cm);
|
||||
|
||||
if (nm != NULL && nm->destroy != NULL)
|
||||
nm->destroy(nm, matchinfo);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
int xtnu_register_match(struct xtnu_match *nt)
|
||||
{
|
||||
struct xt_match *ct;
|
||||
char *tmp;
|
||||
int ret;
|
||||
|
||||
ct = kzalloc(sizeof(struct xt_match), GFP_KERNEL);
|
||||
if (ct == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp = (char *)ct->name;
|
||||
memcpy(tmp, nt->name, sizeof(nt->name));
|
||||
tmp = (char *)(ct->name + sizeof(ct->name) - sizeof(void *));
|
||||
*(tmp-1) = '\0';
|
||||
memcpy(tmp, &nt, sizeof(void *));
|
||||
|
||||
ct->revision = nt->revision;
|
||||
ct->family = nt->family;
|
||||
ct->table = (char *)nt->table;
|
||||
ct->hooks = nt->hooks;
|
||||
ct->proto = nt->proto;
|
||||
ct->match = xtnu_match_run;
|
||||
ct->checkentry = xtnu_match_check;
|
||||
ct->destroy = xtnu_match_destroy;
|
||||
ct->matchsize = nt->matchsize;
|
||||
ct->me = nt->me;
|
||||
|
||||
nt->__compat_match = ct;
|
||||
ret = xt_register_match(ct);
|
||||
if (ret != 0)
|
||||
kfree(ct);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_register_match);
|
||||
|
||||
int xtnu_register_matches(struct xtnu_match *nt, unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
ret = xtnu_register_match(&nt[i]);
|
||||
if (ret < 0) {
|
||||
if (i > 0)
|
||||
xtnu_unregister_matches(nt, i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_register_matches);
|
||||
|
||||
void xtnu_unregister_match(struct xtnu_match *nt)
|
||||
{
|
||||
xt_unregister_match(nt->__compat_match);
|
||||
kfree(nt->__compat_match);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_unregister_match);
|
||||
|
||||
void xtnu_unregister_matches(struct xtnu_match *nt, unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; ++i)
|
||||
xtnu_unregister_match(&nt[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_unregister_matches);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static unsigned int xtnu_target_run(struct sk_buff **pskb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
unsigned int hooknum, const struct xt_target *ct, const void *targinfo,
|
||||
void *userdata)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
static unsigned int xtnu_target_run(struct sk_buff **pskb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
unsigned int hooknum, const struct xt_target *ct, const void *targinfo)
|
||||
#else
|
||||
static unsigned int xtnu_target_run(struct sk_buff *skb,
|
||||
const struct net_device *in, const struct net_device *out,
|
||||
unsigned int hooknum, const struct xt_target *ct, const void *targinfo)
|
||||
#endif
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt != NULL && nt->target != NULL)
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
return nt->target(pskb, in, out, hooknum, nt, targinfo);
|
||||
#else
|
||||
return nt->target(&skb, in, out, hooknum, nt, targinfo);
|
||||
#endif
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static int xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo,
|
||||
unsigned int targinfosize, unsigned int hook_mask)
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
static int xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
|
||||
#else
|
||||
static bool xtnu_target_check(const char *table, const void *entry,
|
||||
const struct xt_target *ct, void *targinfo, unsigned int hook_mask)
|
||||
#endif
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt == NULL)
|
||||
return false;
|
||||
if (nt->checkentry == NULL)
|
||||
/* this is valid, just like if there was no function */
|
||||
return true;
|
||||
return nt->checkentry(table, entry, nt, targinfo, hook_mask);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo,
|
||||
unsigned int targinfosize)
|
||||
#else
|
||||
static void xtnu_target_destroy(const struct xt_target *ct, void *targinfo)
|
||||
#endif
|
||||
{
|
||||
struct xtnu_target *nt = xtcompat_nutarget(ct);
|
||||
if (nt != NULL && nt->destroy != NULL)
|
||||
nt->destroy(nt, targinfo);
|
||||
}
|
||||
|
||||
int xtnu_register_target(struct xtnu_target *nt)
|
||||
{
|
||||
struct xt_target *ct;
|
||||
char *tmp;
|
||||
int ret;
|
||||
|
||||
ct = kzalloc(sizeof(struct xt_target), GFP_KERNEL);
|
||||
if (ct == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp = (char *)ct->name;
|
||||
memcpy(tmp, nt->name, sizeof(nt->name));
|
||||
tmp = (char *)(ct->name + sizeof(ct->name) - sizeof(void *));
|
||||
*(tmp-1) = '\0';
|
||||
memcpy(tmp, &nt, sizeof(void *));
|
||||
|
||||
ct->revision = nt->revision;
|
||||
ct->family = nt->family;
|
||||
ct->table = (char *)nt->table;
|
||||
ct->hooks = nt->hooks;
|
||||
ct->proto = nt->proto;
|
||||
ct->target = xtnu_target_run;
|
||||
ct->checkentry = xtnu_target_check;
|
||||
ct->destroy = xtnu_target_destroy;
|
||||
ct->targetsize = nt->targetsize;
|
||||
ct->me = nt->me;
|
||||
|
||||
nt->__compat_target = ct;
|
||||
ret = xt_register_target(ct);
|
||||
if (ret != 0)
|
||||
kfree(ct);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_register_target);
|
||||
|
||||
int xtnu_register_targets(struct xtnu_target *nt, unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < num; ++i) {
|
||||
ret = xtnu_register_target(&nt[i]);
|
||||
if (ret < 0) {
|
||||
if (i > 0)
|
||||
xtnu_unregister_targets(nt, i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_register_targets);
|
||||
|
||||
void xtnu_unregister_target(struct xtnu_target *nt)
|
||||
{
|
||||
xt_unregister_target(nt->__compat_target);
|
||||
kfree(nt->__compat_target);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_unregister_target);
|
||||
|
||||
void xtnu_unregister_targets(struct xtnu_target *nt, unsigned int num)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; ++i)
|
||||
xtnu_unregister_target(&nt[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_unregister_targets);
|
||||
|
||||
struct xt_match *xtnu_request_find_match(unsigned int af, const char *name,
|
||||
uint8_t revision)
|
||||
{
|
||||
static const char *const xt_prefix[] = {
|
||||
[AF_UNSPEC] = "x",
|
||||
[AF_INET] = "ip",
|
||||
[AF_INET6] = "ip6",
|
||||
#ifdef AF_ARP
|
||||
[AF_ARP] = "arp",
|
||||
#elif defined(NF_ARP) && NF_ARP != AF_UNSPEC
|
||||
[NF_ARP] = "arp",
|
||||
#endif
|
||||
};
|
||||
struct xt_match *match;
|
||||
|
||||
match = try_then_request_module(xt_find_match(af, name, revision),
|
||||
"%st_%s", xt_prefix[af], name);
|
||||
if (IS_ERR(match) || match == NULL)
|
||||
if (pointsize > spacesize)
|
||||
return NULL;
|
||||
|
||||
return match;
|
||||
for (i = 0; i <= spacesize - pointsize; ++i)
|
||||
if (memcmp(space + i, point, pointsize) == 0)
|
||||
return (void *)space + i;
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_request_find_match);
|
||||
|
||||
int xtnu_ip_route_me_harder(struct sk_buff **pskb, unsigned int addr_type)
|
||||
{
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
|
||||
/* Actually this one is valid up to 2.6.18.4, but changed in 2.6.18.5 */
|
||||
return ip_route_me_harder(pskb);
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
return ip_route_me_harder(pskb, addr_type);
|
||||
#else
|
||||
return ip_route_me_harder(*pskb, addr_type);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_route_me_harder);
|
||||
|
||||
int xtnu_skb_make_writable(struct sk_buff **pskb, unsigned int len)
|
||||
{
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
return skb_make_writable(pskb, len);
|
||||
#else
|
||||
return skb_make_writable(*pskb, len);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_skb_make_writable);
|
||||
|
||||
#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 24)
|
||||
static int __xtnu_ip_local_out(struct sk_buff *skb)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
iph->tot_len = htons(skb->len);
|
||||
ip_send_check(iph);
|
||||
return nf_hook(PF_INET, NF_IP_LOCAL_OUT, skb, NULL,
|
||||
skb->dst->dev, dst_output);
|
||||
}
|
||||
|
||||
int xtnu_ip_local_out(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __xtnu_ip_local_out(skb);
|
||||
if (likely(err == 1))
|
||||
err = dst_output(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_local_out);
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
static int __xtnu_ip_local_out(struct sk_buff **pskb)
|
||||
{
|
||||
struct iphdr *iph = ip_hdr(*pskb);
|
||||
|
||||
iph->tot_len = htons((*pskb)->len);
|
||||
ip_send_check(iph);
|
||||
return nf_hook(PF_INET, NF_IP_LOCAL_OUT, pskb, NULL,
|
||||
(*pskb)->dst->dev, dst_output);
|
||||
}
|
||||
|
||||
int xtnu_ip_local_out(struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = __xtnu_ip_local_out(&skb);
|
||||
if (likely(err == 1))
|
||||
err = dst_output(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_local_out);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
||||
int xtnu_ip_route_output_key(void *net, struct rtable **rp, struct flowi *flp)
|
||||
{
|
||||
return ip_route_output_flow(rp, flp, NULL, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_ip_route_output_key);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
int xtnu_neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
|
||||
{
|
||||
unsigned int hh_alen;
|
||||
|
||||
read_lock_bh(&hh->hh_lock);
|
||||
hh_alen = HH_DATA_ALIGN(hh->hh_len);
|
||||
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
|
||||
read_unlock_bh(&hh->hh_lock);
|
||||
skb_push(skb, hh->hh_len);
|
||||
return hh->hh_output(skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_neigh_hh_output);
|
||||
|
||||
static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to)
|
||||
{
|
||||
__be32 diff[] = {~from, to};
|
||||
*sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
|
||||
~csum_unfold(*sum)));
|
||||
}
|
||||
|
||||
void xtnu_csum_replace2(__sum16 *sum, __be16 from, __be16 to)
|
||||
{
|
||||
csum_replace4(sum, (__force __be32)from, (__force __be32)to);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xtnu_csum_replace2);
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(HX_memmem);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#ifndef _XTABLES_COMPAT_H
|
||||
#define _XTABLES_COMPAT_H 1
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/version.h>
|
||||
#include "compat_skbuff.h"
|
||||
#include "compat_xtnu.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
|
||||
# warning Kernels below 2.6.18.5 not supported.
|
||||
#define DEBUGP Use__pr_debug__instead
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
|
||||
# warning Kernels below 4.15 not supported.
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
||||
@@ -14,65 +17,38 @@
|
||||
# warning You have CONFIG_NF_CONNTRACK enabled, but CONFIG_NF_CONNTRACK_MARK is not (please enable).
|
||||
# endif
|
||||
# include <net/netfilter/nf_conntrack.h>
|
||||
#elif defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
|
||||
# if !defined(CONFIG_IP_NF_CONNTRACK_MARK)
|
||||
# warning You have CONFIG_IP_NF_CONNTRACK enabled, but CONFIG_IP_NF_CONNTRACK_MARK is not (please enable).
|
||||
# endif
|
||||
# include <linux/netfilter_ipv4/ip_conntrack.h>
|
||||
# define nf_conn ip_conntrack
|
||||
# define nf_ct_get ip_conntrack_get
|
||||
# define nf_conntrack_untracked ip_conntrack_untracked
|
||||
#else
|
||||
# warning You need either CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK.
|
||||
# warning You need CONFIG_NF_CONNTRACK.
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
# define neigh_hh_output xtnu_neigh_hh_output
|
||||
# define IPPROTO_UDPLITE 136
|
||||
#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 "%04hx:%04hx:%04hx:%04hx:%04hx:%04hx:%04hx:%04hx"
|
||||
#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 "%hhu.%hhu.%hhu.%hhu"
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
||||
# define NF_INET_PRE_ROUTING NF_IP_PRE_ROUTING
|
||||
# define NF_INET_LOCAL_IN NF_IP_LOCAL_IN
|
||||
# define NF_INET_FORWARD NF_IP_FORWARD
|
||||
# define NF_INET_LOCAL_OUT NF_IP_LOCAL_OUT
|
||||
# define NF_INET_POST_ROUTING NF_IP_POST_ROUTING
|
||||
# define ip_local_out xtnu_ip_local_out
|
||||
# define ip_route_output_key xtnu_ip_route_output_key
|
||||
# include "compat_nfinetaddr.h"
|
||||
static inline struct net *par_net(const struct xt_action_param *par)
|
||||
{
|
||||
return par->state->net;
|
||||
}
|
||||
|
||||
#ifndef NF_CT_ASSERT
|
||||
# define NF_CT_ASSERT(x) WARN_ON(!(x))
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23)
|
||||
# define init_net xtnu_ip_route_output_key /* yes */
|
||||
# define init_net__loopback_dev (&loopback_dev)
|
||||
# define init_net__proc_net proc_net
|
||||
#else
|
||||
# define init_net__loopback_dev init_net.loopback_dev
|
||||
# define init_net__proc_net init_net.proc_net
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 22)
|
||||
# define xt_match xtnu_match
|
||||
# define xt_register_match xtnu_register_match
|
||||
# define xt_unregister_match xtnu_unregister_match
|
||||
# define xt_register_matches xtnu_register_matches
|
||||
# define xt_unregister_matches xtnu_unregister_matches
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19)
|
||||
# define csum_replace2 xtnu_csum_replace2
|
||||
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 24)
|
||||
# define csum_replace2 nf_csum_replace2
|
||||
#endif
|
||||
|
||||
#define ip_route_me_harder xtnu_ip_route_me_harder
|
||||
#define skb_make_writable xtnu_skb_make_writable
|
||||
#define xt_target xtnu_target
|
||||
#define xt_register_target xtnu_register_target
|
||||
#define xt_unregister_target xtnu_unregister_target
|
||||
#define xt_register_targets xtnu_register_targets
|
||||
#define xt_unregister_targets xtnu_unregister_targets
|
||||
|
||||
#define xt_request_find_match xtnu_request_find_match
|
||||
|
||||
#endif /* _XTABLES_COMPAT_H */
|
||||
|
||||
@@ -1,54 +1,40 @@
|
||||
#ifndef _COMPAT_XTNU_H
|
||||
#define _COMPAT_XTNU_H 1
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
|
||||
typedef _Bool bool;
|
||||
enum { false = 0, true = 1, };
|
||||
#endif
|
||||
|
||||
struct flowi;
|
||||
struct hh_cache;
|
||||
struct module;
|
||||
struct net_device;
|
||||
struct rtable;
|
||||
struct sk_buff;
|
||||
|
||||
struct xtnu_match {
|
||||
struct list_head list;
|
||||
char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)];
|
||||
bool (*match)(const struct sk_buff *, const struct net_device *,
|
||||
const struct net_device *, const struct xtnu_match *,
|
||||
const void *, int, unsigned int, bool *);
|
||||
bool (*checkentry)(const char *, const void *,
|
||||
const struct xtnu_match *, void *, unsigned int);
|
||||
void (*destroy)(const struct xtnu_match *, void *);
|
||||
/*
|
||||
* Making it smaller by sizeof(void *) on purpose to catch
|
||||
* lossy translation, if any.
|
||||
*/
|
||||
char name[sizeof(((struct xt_match *)NULL)->name) - 1 - sizeof(void *)];
|
||||
uint8_t revision;
|
||||
bool (*match)(const struct sk_buff *, struct xt_action_param *);
|
||||
int (*checkentry)(const struct xt_mtchk_param *);
|
||||
void (*destroy)(const struct xt_mtdtor_param *);
|
||||
struct module *me;
|
||||
const char *table;
|
||||
unsigned int matchsize, hooks;
|
||||
unsigned short proto, family;
|
||||
uint8_t revision;
|
||||
|
||||
void *__compat_match;
|
||||
};
|
||||
|
||||
struct xtnu_target {
|
||||
struct list_head list;
|
||||
char name[XT_FUNCTION_MAXNAMELEN - 1 - sizeof(void *)];
|
||||
unsigned int (*target)(struct sk_buff **, const struct net_device *,
|
||||
const struct net_device *, unsigned int,
|
||||
const struct xtnu_target *, const void *);
|
||||
bool (*checkentry)(const char *, const void *,
|
||||
const struct xtnu_target *, void *, unsigned int);
|
||||
void (*destroy)(const struct xtnu_target *, void *);
|
||||
char name[sizeof(((struct xt_target *)NULL)->name) - 1 - sizeof(void *)];
|
||||
uint8_t revision;
|
||||
unsigned int (*target)(struct sk_buff **,
|
||||
const struct xt_action_param *);
|
||||
int (*checkentry)(const struct xt_tgchk_param *);
|
||||
void (*destroy)(const struct xt_tgdtor_param *);
|
||||
struct module *me;
|
||||
const char *table;
|
||||
unsigned int targetsize, hooks;
|
||||
unsigned short proto, family;
|
||||
uint8_t revision;
|
||||
|
||||
void *__compat_target;
|
||||
};
|
||||
@@ -67,11 +53,7 @@ static inline struct xtnu_target *xtcompat_nutarget(const struct xt_target *t)
|
||||
return q;
|
||||
}
|
||||
|
||||
extern int xtnu_ip_local_out(struct sk_buff *);
|
||||
extern int xtnu_ip_route_me_harder(struct sk_buff **, unsigned int);
|
||||
extern int xtnu_skb_make_writable(struct sk_buff **, unsigned int);
|
||||
extern int xtnu_register_match(struct xtnu_match *);
|
||||
extern int xtnu_ip_route_output_key(void *, struct rtable **, struct flowi *);
|
||||
extern void xtnu_unregister_match(struct xtnu_match *);
|
||||
extern int xtnu_register_matches(struct xtnu_match *, unsigned int);
|
||||
extern void xtnu_unregister_matches(struct xtnu_match *, unsigned int);
|
||||
@@ -79,8 +61,7 @@ extern int xtnu_register_target(struct xtnu_target *);
|
||||
extern void xtnu_unregister_target(struct xtnu_target *);
|
||||
extern int xtnu_register_targets(struct xtnu_target *, unsigned int);
|
||||
extern void xtnu_unregister_targets(struct xtnu_target *, unsigned int);
|
||||
extern struct xt_match *xtnu_request_find_match(unsigned int,
|
||||
const char *, uint8_t);
|
||||
extern int xtnu_neigh_hh_output(struct hh_cache *, struct sk_buff *);
|
||||
|
||||
extern void *HX_memmem(const void *, size_t, const void *, size_t);
|
||||
|
||||
#endif /* _COMPAT_XTNU_H */
|
||||
|
||||
3
extensions/ipset/.gitignore
vendored
3
extensions/ipset/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
*.oo
|
||||
*.so
|
||||
/ipset
|
||||
@@ -1,84 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
top_srcdir := @top_srcdir@
|
||||
srcdir := @srcdir@
|
||||
abstop_srcdir := $(shell readlink -e ${top_srcdir})
|
||||
abssrcdir := $(shell readlink -e ${srcdir})
|
||||
|
||||
ifeq (${abstop_srcdir},)
|
||||
$(error Path resolution of ${top_srcdir} failed)
|
||||
endif
|
||||
ifeq (${abssrcdir},)
|
||||
$(error Path resolution of ${srcdir} failed)
|
||||
endif
|
||||
|
||||
prefix := @prefix@
|
||||
exec_prefix := @exec_prefix@
|
||||
sbindir := @sbindir@
|
||||
libdir := @libdir@
|
||||
libexecdir := @libexecdir@
|
||||
xtlibdir := @xtlibdir@
|
||||
kbuilddir := @kbuilddir@
|
||||
man8dir := @mandir@/man8
|
||||
|
||||
CC := @CC@
|
||||
CCLD := ${CC}
|
||||
CFLAGS := @CFLAGS@
|
||||
LDFLAGS := @LDFLAGS@
|
||||
regular_CFLAGS := @regular_CFLAGS@
|
||||
kinclude_CFLAGS := @kinclude_CFLAGS@
|
||||
xtables_CFLAGS := @xtables_CFLAGS@
|
||||
|
||||
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS} -DXTABLES_LIBDIR=\"${xtlibdir}\"
|
||||
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
|
||||
|
||||
ifeq (${V},)
|
||||
AM_LIBTOOL_SILENT = --silent
|
||||
AM_VERBOSE_CC = @echo " CC " $@;
|
||||
AM_VERBOSE_CCLD = @echo " CCLD " $@;
|
||||
AM_VERBOSE_CXX = @echo " CXX " $@;
|
||||
AM_VERBOSE_CXXLD = @echo " CXXLD " $@;
|
||||
AM_VERBOSE_AR = @echo " AR " $@;
|
||||
AM_VERBOSE_GEN = @echo " GEN " $@;
|
||||
endif
|
||||
|
||||
#
|
||||
# Building blocks
|
||||
#
|
||||
targets := $(addsuffix .so,$(addprefix libipset_,iphash ipmap ipporthash iptree iptreemap macipmap nethash portmap))
|
||||
|
||||
.SECONDARY:
|
||||
|
||||
.PHONY: all install clean distclean FORCE
|
||||
|
||||
all: ipset ${targets}
|
||||
|
||||
install: all
|
||||
@mkdir -p "${DESTDIR}${sbindir}" "${DESTDIR}${xtlibdir}" "${DESTDIR}${man8dir}";
|
||||
install -pm0755 ipset "${DESTDIR}${sbindir}/";
|
||||
install -pm0755 ${targets} "${DESTDIR}${xtlibdir}/";
|
||||
install -pm0644 ipset.8 "${DESTDIR}${man8dir}/";
|
||||
|
||||
clean:
|
||||
rm -f *.oo *.so *.o ipset;
|
||||
|
||||
distclean: clean
|
||||
rm -f .*.d;
|
||||
|
||||
-include .*.d
|
||||
|
||||
|
||||
ipset: ipset.o
|
||||
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -o $@ $< -ldl -rdynamic;
|
||||
|
||||
#
|
||||
# Shared libraries
|
||||
#
|
||||
lib%.so: lib%.oo
|
||||
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
|
||||
|
||||
libipset_%.oo: ${srcdir}/ipset_%.c
|
||||
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
|
||||
|
||||
%.o: %.c
|
||||
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} ${CFLAGS} -o $@ -c $<;
|
||||
@@ -1,6 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
obj-m += ipt_set.o ipt_SET.o
|
||||
obj-m += ip_set.o ip_set_ipmap.o ip_set_portmap.o ip_set_macipmap.o
|
||||
obj-m += ip_set_iphash.o ip_set_nethash.o ip_set_ipporthash.o
|
||||
obj-m += ip_set_iptree.o ip_set_iptreemap.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,506 +0,0 @@
|
||||
#ifndef _IP_SET_H
|
||||
#define _IP_SET_H
|
||||
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2004 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.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_IP_NF_SET_MAX
|
||||
/* from 2 to 65534 */
|
||||
# define CONFIG_IP_NF_SET_MAX 256
|
||||
#endif
|
||||
#ifndef CONFIG_IP_NF_SET_HASHSIZE
|
||||
# define CONFIG_IP_NF_SET_HASHSIZE 1024
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define IP_SET_DEBUG
|
||||
#endif
|
||||
|
||||
/*
|
||||
* A sockopt of such quality has hardly ever been seen before on the open
|
||||
* market! This little beauty, hardly ever used: above 64, so it's
|
||||
* traditionally used for firewalling, not touched (even once!) by the
|
||||
* 2.0, 2.2 and 2.4 kernels!
|
||||
*
|
||||
* Comes with its own certificate of authenticity, valid anywhere in the
|
||||
* Free world!
|
||||
*
|
||||
* Rusty, 19.4.2000
|
||||
*/
|
||||
#define SO_IP_SET 83
|
||||
|
||||
/*
|
||||
* Heavily modify by Joakim Axelsson 08.03.2002
|
||||
* - Made it more modulebased
|
||||
*
|
||||
* Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
|
||||
* - bindings added
|
||||
* - in order to "deal with" backward compatibility, renamed to ipset
|
||||
*/
|
||||
|
||||
/*
|
||||
* Used so that the kernel module and ipset-binary can match their versions
|
||||
*/
|
||||
#define IP_SET_PROTOCOL_VERSION 2
|
||||
|
||||
#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
|
||||
|
||||
/* Lets work with our own typedef for representing an IP address.
|
||||
* We hope to make the code more portable, possibly to IPv6...
|
||||
*
|
||||
* The representation works in HOST byte order, because most set types
|
||||
* will perform arithmetic operations and compare operations.
|
||||
*
|
||||
* For now the type is an uint32_t.
|
||||
*
|
||||
* Make sure to ONLY use the functions when translating and parsing
|
||||
* in order to keep the host byte order and make it more portable:
|
||||
* parse_ip()
|
||||
* parse_mask()
|
||||
* parse_ipandmask()
|
||||
* ip_tostring()
|
||||
* (Joakim: where are they???)
|
||||
*/
|
||||
|
||||
typedef uint32_t ip_set_ip_t;
|
||||
|
||||
/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
|
||||
* and IP_SET_INVALID_ID if you want to increase the max number of sets.
|
||||
*/
|
||||
typedef uint16_t ip_set_id_t;
|
||||
|
||||
#define IP_SET_INVALID_ID 65535
|
||||
|
||||
/* How deep we follow bindings */
|
||||
#define IP_SET_MAX_BINDINGS 6
|
||||
|
||||
/*
|
||||
* Option flags for kernel operations (ipt_set_info)
|
||||
*/
|
||||
#define IPSET_SRC 0x01 /* Source match/add */
|
||||
#define IPSET_DST 0x02 /* Destination match/add */
|
||||
#define IPSET_MATCH_INV 0x04 /* Inverse matching */
|
||||
|
||||
/*
|
||||
* Set features
|
||||
*/
|
||||
#define IPSET_TYPE_IP 0x01 /* IP address type of set */
|
||||
#define IPSET_TYPE_PORT 0x02 /* Port type of set */
|
||||
#define IPSET_DATA_SINGLE 0x04 /* Single data storage */
|
||||
#define IPSET_DATA_DOUBLE 0x08 /* Double data storage */
|
||||
|
||||
/* Reserved keywords */
|
||||
#define IPSET_TOKEN_DEFAULT ":default:"
|
||||
#define IPSET_TOKEN_ALL ":all:"
|
||||
|
||||
/* SO_IP_SET operation constants, and their request struct types.
|
||||
*
|
||||
* Operation ids:
|
||||
* 0-99: commands with version checking
|
||||
* 100-199: add/del/test/bind/unbind
|
||||
* 200-299: list, save, restore
|
||||
*/
|
||||
|
||||
/* Single shot operations:
|
||||
* version, create, destroy, flush, rename and swap
|
||||
*
|
||||
* Sets are identified by name.
|
||||
*/
|
||||
|
||||
#define IP_SET_REQ_STD \
|
||||
unsigned op; \
|
||||
unsigned version; \
|
||||
char name[IP_SET_MAXNAMELEN]
|
||||
|
||||
#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */
|
||||
struct ip_set_req_create {
|
||||
IP_SET_REQ_STD;
|
||||
char typename[IP_SET_MAXNAMELEN];
|
||||
};
|
||||
|
||||
#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */
|
||||
struct ip_set_req_std {
|
||||
IP_SET_REQ_STD;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */
|
||||
/* Uses ip_set_req_std */
|
||||
|
||||
#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */
|
||||
/* Uses ip_set_req_create */
|
||||
|
||||
#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */
|
||||
/* Uses ip_set_req_create */
|
||||
|
||||
union ip_set_name_index {
|
||||
char name[IP_SET_MAXNAMELEN];
|
||||
ip_set_id_t index;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
|
||||
struct ip_set_req_get_set {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
union ip_set_name_index set;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
|
||||
/* Uses ip_set_req_get_set */
|
||||
|
||||
#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
|
||||
struct ip_set_req_version {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
};
|
||||
|
||||
/* Double shots operations:
|
||||
* add, del, test, bind and unbind.
|
||||
*
|
||||
* First we query the kernel to get the index and type of the target set,
|
||||
* then issue the command. Validity of IP is checked in kernel in order
|
||||
* to minimalize sockopt operations.
|
||||
*/
|
||||
|
||||
/* Get minimal set data for add/del/test/bind/unbind IP */
|
||||
#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */
|
||||
struct ip_set_req_adt_get {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
union ip_set_name_index set;
|
||||
char typename[IP_SET_MAXNAMELEN];
|
||||
};
|
||||
|
||||
#define IP_SET_REQ_BYINDEX \
|
||||
unsigned op; \
|
||||
ip_set_id_t index;
|
||||
|
||||
struct ip_set_req_adt {
|
||||
IP_SET_REQ_BYINDEX;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */
|
||||
/* Uses ip_set_req_adt, with type specific addage */
|
||||
|
||||
#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */
|
||||
/* Uses ip_set_req_adt, with type specific addage */
|
||||
|
||||
#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */
|
||||
/* Uses ip_set_req_adt, with type specific addage */
|
||||
|
||||
#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */
|
||||
/* Uses ip_set_req_bind, with type specific addage */
|
||||
struct ip_set_req_bind {
|
||||
IP_SET_REQ_BYINDEX;
|
||||
char binding[IP_SET_MAXNAMELEN];
|
||||
};
|
||||
|
||||
#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
|
||||
/* Uses ip_set_req_bind, with type speficic addage
|
||||
* index = 0 means unbinding for all sets */
|
||||
|
||||
#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
|
||||
/* Uses ip_set_req_bind, with type specific addage */
|
||||
|
||||
/* Multiple shots operations: list, save, restore.
|
||||
*
|
||||
* - check kernel version and query the max number of sets
|
||||
* - get the basic information on all sets
|
||||
* and size required for the next step
|
||||
* - get actual set data: header, data, bindings
|
||||
*/
|
||||
|
||||
/* Get max_sets and the index of a queried set
|
||||
*/
|
||||
#define IP_SET_OP_MAX_SETS 0x00000020
|
||||
struct ip_set_req_max_sets {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
ip_set_id_t max_sets; /* max_sets */
|
||||
ip_set_id_t sets; /* real number of sets */
|
||||
union ip_set_name_index set; /* index of set if name used */
|
||||
};
|
||||
|
||||
/* Get the id and name of the sets plus size for next step */
|
||||
#define IP_SET_OP_LIST_SIZE 0x00000201
|
||||
#define IP_SET_OP_SAVE_SIZE 0x00000202
|
||||
struct ip_set_req_setnames {
|
||||
unsigned op;
|
||||
ip_set_id_t index; /* set to list/save */
|
||||
size_t size; /* size to get setdata/bindings */
|
||||
/* followed by sets number of struct ip_set_name_list */
|
||||
};
|
||||
|
||||
struct ip_set_name_list {
|
||||
char name[IP_SET_MAXNAMELEN];
|
||||
char typename[IP_SET_MAXNAMELEN];
|
||||
ip_set_id_t index;
|
||||
ip_set_id_t id;
|
||||
};
|
||||
|
||||
/* The actual list operation */
|
||||
#define IP_SET_OP_LIST 0x00000203
|
||||
struct ip_set_req_list {
|
||||
IP_SET_REQ_BYINDEX;
|
||||
/* sets number of struct ip_set_list in reply */
|
||||
};
|
||||
|
||||
struct ip_set_list {
|
||||
ip_set_id_t index;
|
||||
ip_set_id_t binding;
|
||||
u_int32_t ref;
|
||||
size_t header_size; /* Set header data of header_size */
|
||||
size_t members_size; /* Set members data of members_size */
|
||||
size_t bindings_size; /* Set bindings data of bindings_size */
|
||||
};
|
||||
|
||||
struct ip_set_hash_list {
|
||||
ip_set_ip_t ip;
|
||||
ip_set_id_t binding;
|
||||
};
|
||||
|
||||
/* The save operation */
|
||||
#define IP_SET_OP_SAVE 0x00000204
|
||||
/* Uses ip_set_req_list, in the reply replaced by
|
||||
* sets number of struct ip_set_save plus a marker
|
||||
* ip_set_save followed by ip_set_hash_save structures.
|
||||
*/
|
||||
struct ip_set_save {
|
||||
ip_set_id_t index;
|
||||
ip_set_id_t binding;
|
||||
size_t header_size; /* Set header data of header_size */
|
||||
size_t members_size; /* Set members data of members_size */
|
||||
};
|
||||
|
||||
/* At restoring, ip == 0 means default binding for the given set: */
|
||||
struct ip_set_hash_save {
|
||||
ip_set_ip_t ip;
|
||||
ip_set_id_t id;
|
||||
ip_set_id_t binding;
|
||||
};
|
||||
|
||||
/* The restore operation */
|
||||
#define IP_SET_OP_RESTORE 0x00000205
|
||||
/* Uses ip_set_req_setnames followed by ip_set_restore structures
|
||||
* plus a marker ip_set_restore, followed by ip_set_hash_save
|
||||
* structures.
|
||||
*/
|
||||
struct ip_set_restore {
|
||||
char name[IP_SET_MAXNAMELEN];
|
||||
char typename[IP_SET_MAXNAMELEN];
|
||||
ip_set_id_t index;
|
||||
size_t header_size; /* Create data of header_size */
|
||||
size_t members_size; /* Set members data of members_size */
|
||||
};
|
||||
|
||||
static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
|
||||
{
|
||||
return 4 * ((((b - a + 8) / 8) + 3) / 4);
|
||||
}
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define ip_set_printk(format, args...) \
|
||||
do { \
|
||||
printk("%s: %s: ", __FILE__, __FUNCTION__); \
|
||||
printk(format "\n" , ## args); \
|
||||
} while (0)
|
||||
|
||||
#if defined(IP_SET_DEBUG)
|
||||
#define DP(format, args...) \
|
||||
do { \
|
||||
printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
|
||||
printk(format "\n" , ## args); \
|
||||
} while (0)
|
||||
#define IP_SET_ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) \
|
||||
printk("IP_SET_ASSERT: %s:%i(%s)\n", \
|
||||
__FILE__, __LINE__, __FUNCTION__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DP(format, args...)
|
||||
#define IP_SET_ASSERT(x)
|
||||
#endif
|
||||
|
||||
struct ip_set;
|
||||
|
||||
/*
|
||||
* The ip_set_type definition - one per set type, e.g. "ipmap".
|
||||
*
|
||||
* Each individual set has a pointer, set->type, going to one
|
||||
* of these structures. Function pointers inside the structure implement
|
||||
* the real behaviour of the sets.
|
||||
*
|
||||
* If not mentioned differently, the implementation behind the function
|
||||
* pointers of a set_type, is expected to return 0 if ok, and a negative
|
||||
* errno (e.g. -EINVAL) on error.
|
||||
*/
|
||||
struct ip_set_type {
|
||||
struct list_head list; /* next in list of set types */
|
||||
|
||||
/* test for IP in set (kernel: iptables -m set src|dst)
|
||||
* return 0 if not in set, 1 if in set.
|
||||
*/
|
||||
int (*testip_kernel) (struct ip_set *set,
|
||||
const struct sk_buff * skb,
|
||||
ip_set_ip_t *ip,
|
||||
const u_int32_t *flags,
|
||||
unsigned char index);
|
||||
|
||||
/* test for IP in set (userspace: ipset -T set IP)
|
||||
* return 0 if not in set, 1 if in set.
|
||||
*/
|
||||
int (*testip) (struct ip_set *set,
|
||||
const void *data, size_t size,
|
||||
ip_set_ip_t *ip);
|
||||
|
||||
/*
|
||||
* Size of the data structure passed by when
|
||||
* adding/deletin/testing an entry.
|
||||
*/
|
||||
size_t reqsize;
|
||||
|
||||
/* Add IP into set (userspace: ipset -A set IP)
|
||||
* Return -EEXIST if the address is already in the set,
|
||||
* and -ERANGE if the address lies outside the set bounds.
|
||||
* If the address was not already in the set, 0 is returned.
|
||||
*/
|
||||
int (*addip) (struct ip_set *set,
|
||||
const void *data, size_t size,
|
||||
ip_set_ip_t *ip);
|
||||
|
||||
/* Add IP into set (kernel: iptables ... -j SET set src|dst)
|
||||
* Return -EEXIST if the address is already in the set,
|
||||
* and -ERANGE if the address lies outside the set bounds.
|
||||
* If the address was not already in the set, 0 is returned.
|
||||
*/
|
||||
int (*addip_kernel) (struct ip_set *set,
|
||||
const struct sk_buff * skb,
|
||||
ip_set_ip_t *ip,
|
||||
const u_int32_t *flags,
|
||||
unsigned char index);
|
||||
|
||||
/* remove IP from set (userspace: ipset -D set --entry x)
|
||||
* Return -EEXIST if the address is NOT in the set,
|
||||
* and -ERANGE if the address lies outside the set bounds.
|
||||
* If the address really was in the set, 0 is returned.
|
||||
*/
|
||||
int (*delip) (struct ip_set *set,
|
||||
const void *data, size_t size,
|
||||
ip_set_ip_t *ip);
|
||||
|
||||
/* remove IP from set (kernel: iptables ... -j SET --entry x)
|
||||
* Return -EEXIST if the address is NOT in the set,
|
||||
* and -ERANGE if the address lies outside the set bounds.
|
||||
* If the address really was in the set, 0 is returned.
|
||||
*/
|
||||
int (*delip_kernel) (struct ip_set *set,
|
||||
const struct sk_buff * skb,
|
||||
ip_set_ip_t *ip,
|
||||
const u_int32_t *flags,
|
||||
unsigned char index);
|
||||
|
||||
/* new set creation - allocated type specific items
|
||||
*/
|
||||
int (*create) (struct ip_set *set,
|
||||
const void *data, size_t size);
|
||||
|
||||
/* retry the operation after successfully tweaking the set
|
||||
*/
|
||||
int (*retry) (struct ip_set *set);
|
||||
|
||||
/* set destruction - free type specific items
|
||||
* There is no return value.
|
||||
* Can be called only when child sets are destroyed.
|
||||
*/
|
||||
void (*destroy) (struct ip_set *set);
|
||||
|
||||
/* set flushing - reset all bits in the set, or something similar.
|
||||
* There is no return value.
|
||||
*/
|
||||
void (*flush) (struct ip_set *set);
|
||||
|
||||
/* Listing: size needed for header
|
||||
*/
|
||||
size_t header_size;
|
||||
|
||||
/* Listing: Get the header
|
||||
*
|
||||
* Fill in the information in "data".
|
||||
* This function is always run after list_header_size() under a
|
||||
* writelock on the set. Therefor is the length of "data" always
|
||||
* correct.
|
||||
*/
|
||||
void (*list_header) (const struct ip_set *set,
|
||||
void *data);
|
||||
|
||||
/* Listing: Get the size for the set members
|
||||
*/
|
||||
int (*list_members_size) (const struct ip_set *set);
|
||||
|
||||
/* Listing: Get the set members
|
||||
*
|
||||
* Fill in the information in "data".
|
||||
* This function is always run after list_member_size() under a
|
||||
* writelock on the set. Therefor is the length of "data" always
|
||||
* correct.
|
||||
*/
|
||||
void (*list_members) (const struct ip_set *set,
|
||||
void *data);
|
||||
|
||||
char typename[IP_SET_MAXNAMELEN];
|
||||
unsigned char features;
|
||||
int protocol_version;
|
||||
|
||||
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
|
||||
struct module *me;
|
||||
};
|
||||
|
||||
extern int ip_set_register_set_type(struct ip_set_type *set_type);
|
||||
extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
|
||||
|
||||
/* A generic ipset */
|
||||
struct ip_set {
|
||||
char name[IP_SET_MAXNAMELEN]; /* the name of the set */
|
||||
rwlock_t lock; /* lock for concurrency control */
|
||||
ip_set_id_t id; /* set id for swapping */
|
||||
ip_set_id_t binding; /* default binding for the set */
|
||||
atomic_t ref; /* in kernel and in hash references */
|
||||
struct ip_set_type *type; /* the set types */
|
||||
void *data; /* pooltype specific data */
|
||||
};
|
||||
|
||||
/* Structure to bind set elements to sets */
|
||||
struct ip_set_hash {
|
||||
struct list_head list; /* list of clashing entries in hash */
|
||||
ip_set_ip_t ip; /* ip from set */
|
||||
ip_set_id_t id; /* set id */
|
||||
ip_set_id_t binding; /* set we bind the element to */
|
||||
};
|
||||
|
||||
/* 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_byindex(ip_set_id_t id);
|
||||
extern void ip_set_put(ip_set_id_t id);
|
||||
|
||||
/* API for iptables set match, and SET target */
|
||||
extern void ip_set_addip_kernel(ip_set_id_t id,
|
||||
const struct sk_buff *skb,
|
||||
const u_int32_t *flags);
|
||||
extern void ip_set_delip_kernel(ip_set_id_t id,
|
||||
const struct sk_buff *skb,
|
||||
const u_int32_t *flags);
|
||||
extern int ip_set_testip_kernel(ip_set_id_t id,
|
||||
const struct sk_buff *skb,
|
||||
const u_int32_t *flags);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /*_IP_SET_H*/
|
||||
@@ -1,425 +0,0 @@
|
||||
/* Copyright (C) 2003-2004 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 hash set */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ip_set.h"
|
||||
#include <linux/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "ip_set_malloc.h"
|
||||
#include "ip_set_iphash.h"
|
||||
|
||||
static int limit = MAX_RANGE;
|
||||
|
||||
static inline __u32
|
||||
jhash_ip(const struct ip_set_iphash *map, uint16_t i, 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;
|
||||
__u32 id;
|
||||
u_int16_t i;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
*hash_ip = ip & map->netmask;
|
||||
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
|
||||
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
|
||||
|
||||
for (i = 0; i < map->probes; i++) {
|
||||
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||
DP("hash key: %u", id);
|
||||
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||
if (*elem == *hash_ip)
|
||||
return id;
|
||||
/* No shortcut at testing - there can be deleted
|
||||
* entries. */
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
|
||||
}
|
||||
|
||||
static int
|
||||
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)) {
|
||||
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||
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
|
||||
__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
__u32 probe;
|
||||
u_int16_t i;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
if (!ip || map->elements >= limit)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip & map->netmask;
|
||||
|
||||
for (i = 0; i < map->probes; i++) {
|
||||
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
|
||||
addip(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)) {
|
||||
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;
|
||||
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! */
|
||||
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
|
||||
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_iphash *map = set->data;
|
||||
ip_set_ip_t id, *elem;
|
||||
|
||||
if (!ip)
|
||||
return -ERANGE;
|
||||
|
||||
id = hash_id(set, ip, hash_ip);
|
||||
if (id == UINT_MAX)
|
||||
return -EEXIST;
|
||||
|
||||
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||
*elem = 0;
|
||||
map->elements--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(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)) {
|
||||
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->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;
|
||||
}
|
||||
|
||||
static void destroy(struct ip_set *set)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int list_members_size(const struct ip_set *set)
|
||||
{
|
||||
const struct ip_set_iphash *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_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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("iphash type of IP sets");
|
||||
module_param(limit, int, 0600);
|
||||
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||
|
||||
static int __init ip_set_iphash_init(void)
|
||||
{
|
||||
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);
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef __IP_SET_IPHASH_H
|
||||
#define __IP_SET_IPHASH_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "iphash"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
|
||||
struct ip_set_iphash {
|
||||
ip_set_ip_t *members; /* the iphash 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 netmask; /* netmask */
|
||||
void *initval[0]; /* initvals for jhash_1word */
|
||||
};
|
||||
|
||||
struct ip_set_req_iphash_create {
|
||||
uint32_t hashsize;
|
||||
uint16_t probes;
|
||||
uint16_t resize;
|
||||
ip_set_ip_t netmask;
|
||||
};
|
||||
|
||||
struct ip_set_req_iphash {
|
||||
ip_set_ip_t ip;
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_IPHASH_H */
|
||||
@@ -1,331 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Copyright (C) 2003-2004 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 single bitmap type */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.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 <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "ip_set_ipmap.h"
|
||||
|
||||
static inline ip_set_ip_t
|
||||
ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
|
||||
{
|
||||
return (ip - map->first_ip)/map->hosts;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_ipmap *map = set->data;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip & map->netmask;
|
||||
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
|
||||
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||
return !!test_bit(ip_to_id(map, *hash_ip), map->members);
|
||||
}
|
||||
|
||||
static int
|
||||
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)) {
|
||||
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||
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
|
||||
__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_ipmap *map = set->data;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip & map->netmask;
|
||||
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||
if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
|
||||
return -EEXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
addip(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)) {
|
||||
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
|
||||
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_ipmap *map = set->data;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip & map->netmask;
|
||||
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||
if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
|
||||
return -EEXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(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)) {
|
||||
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;
|
||||
|
||||
if (req->netmask == 0xFFFFFFFF) {
|
||||
map->hosts = 1;
|
||||
map->sizeid = map->last_ip - map->first_ip + 1;
|
||||
} else {
|
||||
unsigned int mask_bits, netmask_bits;
|
||||
ip_set_ip_t mask;
|
||||
|
||||
map->first_ip &= map->netmask; /* Should we better bark? */
|
||||
|
||||
mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
|
||||
netmask_bits = mask_to_bits(map->netmask);
|
||||
|
||||
if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
|
||||
|| netmask_bits <= mask_bits)
|
||||
return -ENOEXEC;
|
||||
|
||||
DP("mask_bits %u, netmask_bits %u",
|
||||
mask_bits, netmask_bits);
|
||||
map->hosts = 2 << (32 - netmask_bits - 1);
|
||||
map->sizeid = 2 << (netmask_bits - mask_bits - 1);
|
||||
}
|
||||
if (map->sizeid > MAX_RANGE + 1) {
|
||||
ip_set_printk("range too big (max %d addresses)",
|
||||
MAX_RANGE+1);
|
||||
kfree(map);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
static void list_members(const struct ip_set *set, void *data)
|
||||
{
|
||||
const struct ip_set_ipmap *map = set->data;
|
||||
int bytes = bitmap_bytes(0, map->sizeid - 1);
|
||||
|
||||
memcpy(data, map->members, bytes);
|
||||
}
|
||||
|
||||
static struct ip_set_type ip_set_ipmap = {
|
||||
.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_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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("ipmap type of IP sets");
|
||||
|
||||
static int __init ip_set_ipmap_init(void)
|
||||
{
|
||||
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);
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef __IP_SET_IPMAP_H
|
||||
#define __IP_SET_IPMAP_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "ipmap"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
|
||||
struct ip_set_ipmap {
|
||||
void *members; /* the ipmap proper */
|
||||
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 netmask; /* subnet netmask */
|
||||
ip_set_ip_t sizeid; /* size of set in IPs */
|
||||
ip_set_ip_t hosts; /* number of hosts in a subnet */
|
||||
};
|
||||
|
||||
struct ip_set_req_ipmap_create {
|
||||
ip_set_ip_t from;
|
||||
ip_set_ip_t to;
|
||||
ip_set_ip_t netmask;
|
||||
};
|
||||
|
||||
struct ip_set_req_ipmap {
|
||||
ip_set_ip_t ip;
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
mask_to_bits(ip_set_ip_t mask)
|
||||
{
|
||||
unsigned int bits = 32;
|
||||
ip_set_ip_t maskaddr;
|
||||
|
||||
if (mask == 0xFFFFFFFF)
|
||||
return bits;
|
||||
|
||||
maskaddr = 0xFFFFFFFE;
|
||||
while (--bits >= 0 && maskaddr != mask)
|
||||
maskaddr <<= 1;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static ip_set_ip_t
|
||||
range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
|
||||
{
|
||||
ip_set_ip_t mask = 0xFFFFFFFE;
|
||||
|
||||
*bits = 32;
|
||||
while (--(*bits) >= 0 && mask && (to & mask) != from)
|
||||
mask <<= 1;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
#endif /* __IP_SET_IPMAP_H */
|
||||
@@ -1,575 +0,0 @@
|
||||
/* Copyright (C) 2003-2004 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 hash set */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ip_set.h"
|
||||
#include <linux/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "ip_set_malloc.h"
|
||||
#include "ip_set_ipporthash.h"
|
||||
|
||||
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
|
||||
jhash_ip(const struct ip_set_ipporthash *map, uint16_t i, ip_set_ip_t ip)
|
||||
{
|
||||
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;
|
||||
__u32 id;
|
||||
u_int16_t i;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
*hash_ip = HASH_IP(map, ip, port);
|
||||
DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
|
||||
set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
|
||||
|
||||
for (i = 0; i < map->probes; i++) {
|
||||
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||
DP("hash key: %u", id);
|
||||
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||
if (*elem == *hash_ip)
|
||||
return id;
|
||||
/* No shortcut at testing - there can be deleted
|
||||
* entries. */
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__testip(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;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
|
||||
return (hash_id(set, ip, port, hash_ip) != UINT_MAX);
|
||||
}
|
||||
|
||||
static int
|
||||
testip(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 __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;
|
||||
|
||||
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 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
|
||||
__add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip)
|
||||
{
|
||||
__u32 probe;
|
||||
u_int16_t i;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
for (i = 0; i < map->probes; i++) {
|
||||
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 inline int
|
||||
__addip(struct ip_set_ipporthash *map, ip_set_ip_t ip, ip_set_ip_t port,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
if (map->elements > limit)
|
||||
return -ERANGE;
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = HASH_IP(map, ip, port);
|
||||
|
||||
return __add_haship(map, *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;
|
||||
|
||||
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_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) {
|
||||
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->first_ip = map->first_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! */
|
||||
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
|
||||
__delip(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;
|
||||
ip_set_ip_t id;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
|
||||
id = hash_id(set, ip, port, hash_ip);
|
||||
|
||||
if (id == UINT_MAX)
|
||||
return -EEXIST;
|
||||
|
||||
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||
*elem = 0;
|
||||
map->elements--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(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 __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;
|
||||
}
|
||||
|
||||
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->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;
|
||||
}
|
||||
|
||||
static void destroy(struct ip_set *set)
|
||||
{
|
||||
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->to = map->last_ip;
|
||||
}
|
||||
|
||||
static int list_members_size(const struct ip_set *set)
|
||||
{
|
||||
const struct ip_set_ipporthash *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_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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("ipporthash type of IP sets");
|
||||
module_param(limit, int, 0600);
|
||||
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||
|
||||
static int __init ip_set_ipporthash_init(void)
|
||||
{
|
||||
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);
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef __IP_SET_IPPORTHASH_H
|
||||
#define __IP_SET_IPPORTHASH_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "ipporthash"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
#define INVALID_PORT (MAX_RANGE + 1)
|
||||
|
||||
struct ip_set_ipporthash {
|
||||
ip_set_ip_t *members; /* the ipporthash 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 */
|
||||
void *initval[0]; /* initvals for jhash_1word */
|
||||
};
|
||||
|
||||
struct ip_set_req_ipporthash_create {
|
||||
uint32_t hashsize;
|
||||
uint16_t probes;
|
||||
uint16_t resize;
|
||||
ip_set_ip_t from;
|
||||
ip_set_ip_t to;
|
||||
};
|
||||
|
||||
struct ip_set_req_ipporthash {
|
||||
ip_set_ip_t ip;
|
||||
ip_set_ip_t port;
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_IPPORTHASH_H */
|
||||
@@ -1,607 +0,0 @@
|
||||
/* Copyright (C) 2005 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 iptree type */
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ip_set.h"
|
||||
#include <linux/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
/* Backward compatibility */
|
||||
#ifndef __nocast
|
||||
#define __nocast
|
||||
#endif
|
||||
|
||||
#include "ip_set_iptree.h"
|
||||
|
||||
static int limit = MAX_RANGE;
|
||||
|
||||
/* Garbage collection interval in seconds: */
|
||||
#define IPTREE_GC_TIME 5*60
|
||||
/* Sleep so many milliseconds before trying again
|
||||
* to delete the gc timer at destroying/flushing a set */
|
||||
#define IPTREE_DESTROY_SLEEP 100
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
|
||||
static struct kmem_cache *branch_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)
|
||||
#define ABCD(a,b,c,d,addrp) do { \
|
||||
a = ((unsigned char *)addrp)[3]; \
|
||||
b = ((unsigned char *)addrp)[2]; \
|
||||
c = ((unsigned char *)addrp)[1]; \
|
||||
d = ((unsigned char *)addrp)[0]; \
|
||||
} while (0)
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
#define ABCD(a,b,c,d,addrp) do { \
|
||||
a = ((unsigned char *)addrp)[0]; \
|
||||
b = ((unsigned char *)addrp)[1]; \
|
||||
c = ((unsigned char *)addrp)[2]; \
|
||||
d = ((unsigned char *)addrp)[3]; \
|
||||
} while (0)
|
||||
#else
|
||||
#error "Please fix asm/byteorder.h"
|
||||
#endif /* __LITTLE_ENDIAN */
|
||||
|
||||
#define TESTIP_WALK(map, elem, branch) do { \
|
||||
if ((map)->tree[elem]) { \
|
||||
branch = (map)->tree[elem]; \
|
||||
} else \
|
||||
return 0; \
|
||||
} while (0)
|
||||
|
||||
static inline int
|
||||
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned char a,b,c,d;
|
||||
|
||||
if (!ip)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip;
|
||||
ABCD(a, b, c, d, hash_ip);
|
||||
DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
|
||||
TESTIP_WALK(map, a, btree);
|
||||
TESTIP_WALK(btree, b, ctree);
|
||||
TESTIP_WALK(ctree, c, dtree);
|
||||
DP("%lu %lu", dtree->expires[d], jiffies);
|
||||
return dtree->expires[d]
|
||||
&& (!map->timeout
|
||||
|| time_after(dtree->expires[d], jiffies));
|
||||
}
|
||||
|
||||
static int
|
||||
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)) {
|
||||
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||
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 { \
|
||||
if ((map)->tree[elem]) { \
|
||||
DP("found %u", elem); \
|
||||
branch = (map)->tree[elem]; \
|
||||
} else { \
|
||||
branch = (type *) \
|
||||
kmem_cache_alloc(cachep, GFP_ATOMIC); \
|
||||
if (branch == NULL) \
|
||||
return -ENOMEM; \
|
||||
memset(branch, 0, sizeof(*branch)); \
|
||||
(map)->tree[elem] = branch; \
|
||||
DP("alloc %u", elem); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static inline int
|
||||
__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned char a,b,c,d;
|
||||
int ret = 0;
|
||||
|
||||
if (!ip || map->elements >= limit)
|
||||
/* We could call the garbage collector
|
||||
* but it's probably overkill */
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip;
|
||||
ABCD(a, b, c, d, hash_ip);
|
||||
DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
|
||||
ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
|
||||
ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
|
||||
ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
|
||||
if (dtree->expires[d]
|
||||
&& (!map->timeout || time_after(dtree->expires[d], jiffies)))
|
||||
ret = -EEXIST;
|
||||
dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
|
||||
/* Lottery: I won! */
|
||||
if (dtree->expires[d] == 0)
|
||||
dtree->expires[d] = 1;
|
||||
DP("%u %lu", d, dtree->expires[d]);
|
||||
if (ret == 0)
|
||||
map->elements++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
addip(struct ip_set *set, const void *data, size_t size,
|
||||
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 { \
|
||||
if ((map)->tree[elem]) { \
|
||||
branch = (map)->tree[elem]; \
|
||||
} else \
|
||||
return -EEXIST; \
|
||||
} while (0)
|
||||
|
||||
static inline int
|
||||
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned char a,b,c,d;
|
||||
|
||||
if (!ip)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = ip;
|
||||
ABCD(a, b, c, d, hash_ip);
|
||||
DELIP_WALK(map, a, btree);
|
||||
DELIP_WALK(btree, b, ctree);
|
||||
DELIP_WALK(ctree, c, dtree);
|
||||
|
||||
if (dtree->expires[d]) {
|
||||
dtree->expires[d] = 0;
|
||||
map->elements--;
|
||||
return 0;
|
||||
}
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(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)) {
|
||||
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) \
|
||||
for (i = 0; i < 256; i++) { \
|
||||
if (!(map)->tree[i]) \
|
||||
continue; \
|
||||
branch = (map)->tree[i]
|
||||
|
||||
#define LOOP_WALK_END }
|
||||
|
||||
static void ip_tree_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned int a,b,c,d;
|
||||
unsigned char i,j,k;
|
||||
|
||||
i = j = k = 0;
|
||||
DP("gc: %s", set->name);
|
||||
write_lock_bh(&set->lock);
|
||||
LOOP_WALK_BEGIN(map, a, btree);
|
||||
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||
for (d = 0; d < 256; d++) {
|
||||
if (dtree->expires[d]) {
|
||||
DP("gc: %u %u %u %u: expires %lu jiffies %lu",
|
||||
a, b, c, d,
|
||||
dtree->expires[d], jiffies);
|
||||
if (map->timeout
|
||||
&& time_before(dtree->expires[d], jiffies)) {
|
||||
dtree->expires[d] = 0;
|
||||
map->elements--;
|
||||
} else
|
||||
k = 1;
|
||||
}
|
||||
}
|
||||
if (k == 0) {
|
||||
DP("gc: %s: leaf %u %u %u empty",
|
||||
set->name, a, b, c);
|
||||
kmem_cache_free(leaf_cachep, dtree);
|
||||
ctree->tree[c] = NULL;
|
||||
} else {
|
||||
DP("gc: %s: leaf %u %u %u not empty",
|
||||
set->name, a, b, c);
|
||||
j = 1;
|
||||
k = 0;
|
||||
}
|
||||
LOOP_WALK_END;
|
||||
if (j == 0) {
|
||||
DP("gc: %s: branch %u %u empty",
|
||||
set->name, a, b);
|
||||
kmem_cache_free(branch_cachep, ctree);
|
||||
btree->tree[b] = NULL;
|
||||
} else {
|
||||
DP("gc: %s: branch %u %u not empty",
|
||||
set->name, a, b);
|
||||
i = 1;
|
||||
j = k = 0;
|
||||
}
|
||||
LOOP_WALK_END;
|
||||
if (i == 0) {
|
||||
DP("gc: %s: branch %u empty",
|
||||
set->name, a);
|
||||
kmem_cache_free(branch_cachep, btree);
|
||||
map->tree[a] = NULL;
|
||||
} else {
|
||||
DP("gc: %s: branch %u not empty",
|
||||
set->name, a);
|
||||
i = j = k = 0;
|
||||
}
|
||||
LOOP_WALK_END;
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static inline void init_gc_timer(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptree *map = set->data;
|
||||
|
||||
/* Even if there is no timeout for the entries,
|
||||
* we still have to call gc because delete
|
||||
* do not clean up empty branches */
|
||||
map->gc_interval = IPTREE_GC_TIME;
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = ip_tree_gc;
|
||||
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static int create(struct ip_set *set, const void *data, size_t size)
|
||||
{
|
||||
const struct ip_set_req_iptree_create *req = data;
|
||||
struct ip_set_iptree *map;
|
||||
|
||||
if (size != sizeof(struct ip_set_req_iptree_create)) {
|
||||
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||
sizeof(struct ip_set_req_iptree_create),
|
||||
size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
|
||||
if (!map) {
|
||||
DP("out of memory for %d bytes",
|
||||
sizeof(struct ip_set_iptree));
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(map, 0, sizeof(*map));
|
||||
map->timeout = req->timeout;
|
||||
map->elements = 0;
|
||||
set->data = map;
|
||||
|
||||
init_gc_timer(set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __flush(struct ip_set_iptree *map)
|
||||
{
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned int a,b,c;
|
||||
|
||||
LOOP_WALK_BEGIN(map, a, btree);
|
||||
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||
kmem_cache_free(leaf_cachep, dtree);
|
||||
LOOP_WALK_END;
|
||||
kmem_cache_free(branch_cachep, ctree);
|
||||
LOOP_WALK_END;
|
||||
kmem_cache_free(branch_cachep, btree);
|
||||
LOOP_WALK_END;
|
||||
map->elements = 0;
|
||||
}
|
||||
|
||||
static void destroy(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptree *map = set->data;
|
||||
|
||||
/* gc might be running */
|
||||
while (!del_timer(&map->gc))
|
||||
msleep(IPTREE_DESTROY_SLEEP);
|
||||
__flush(map);
|
||||
kfree(map);
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void flush(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptree *map = set->data;
|
||||
unsigned int timeout = map->timeout;
|
||||
|
||||
/* gc might be running */
|
||||
while (!del_timer(&map->gc))
|
||||
msleep(IPTREE_DESTROY_SLEEP);
|
||||
__flush(map);
|
||||
memset(map, 0, sizeof(*map));
|
||||
map->timeout = timeout;
|
||||
|
||||
init_gc_timer(set);
|
||||
}
|
||||
|
||||
static void list_header(const struct ip_set *set, void *data)
|
||||
{
|
||||
const struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_req_iptree_create *header = data;
|
||||
|
||||
header->timeout = map->timeout;
|
||||
}
|
||||
|
||||
static int list_members_size(const struct ip_set *set)
|
||||
{
|
||||
const struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned int a,b,c,d;
|
||||
unsigned int count = 0;
|
||||
|
||||
LOOP_WALK_BEGIN(map, a, btree);
|
||||
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||
for (d = 0; d < 256; d++) {
|
||||
if (dtree->expires[d]
|
||||
&& (!map->timeout || time_after(dtree->expires[d], jiffies)))
|
||||
count++;
|
||||
}
|
||||
LOOP_WALK_END;
|
||||
LOOP_WALK_END;
|
||||
LOOP_WALK_END;
|
||||
|
||||
DP("members %u", count);
|
||||
return (count * sizeof(struct ip_set_req_iptree));
|
||||
}
|
||||
|
||||
static void list_members(const struct ip_set *set, void *data)
|
||||
{
|
||||
const struct ip_set_iptree *map = set->data;
|
||||
struct ip_set_iptreeb *btree;
|
||||
struct ip_set_iptreec *ctree;
|
||||
struct ip_set_iptreed *dtree;
|
||||
unsigned int a,b,c,d;
|
||||
size_t offset = 0;
|
||||
struct ip_set_req_iptree *entry;
|
||||
|
||||
LOOP_WALK_BEGIN(map, a, btree);
|
||||
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||
for (d = 0; d < 256; d++) {
|
||||
if (dtree->expires[d]
|
||||
&& (!map->timeout || time_after(dtree->expires[d], jiffies))) {
|
||||
entry = data + offset;
|
||||
entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
|
||||
entry->timeout = !map->timeout ? 0
|
||||
: (dtree->expires[d] - jiffies)/HZ;
|
||||
offset += sizeof(struct ip_set_req_iptree);
|
||||
}
|
||||
}
|
||||
LOOP_WALK_END;
|
||||
LOOP_WALK_END;
|
||||
LOOP_WALK_END;
|
||||
}
|
||||
|
||||
static struct ip_set_type ip_set_iptree = {
|
||||
.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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("iptree type of IP sets");
|
||||
module_param(limit, int, 0600);
|
||||
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||
|
||||
static int __init ip_set_iptree_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
branch_cachep = kmem_cache_create("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) {
|
||||
printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
leaf_cachep = kmem_cache_create("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) {
|
||||
printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_branch;
|
||||
}
|
||||
ret = ip_set_register_set_type(&ip_set_iptree);
|
||||
if (ret == 0)
|
||||
goto out;
|
||||
|
||||
kmem_cache_destroy(leaf_cachep);
|
||||
free_branch:
|
||||
kmem_cache_destroy(branch_cachep);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_set_iptree_fini(void)
|
||||
{
|
||||
/* FIXME: possible race with ip_set_create() */
|
||||
ip_set_unregister_set_type(&ip_set_iptree);
|
||||
kmem_cache_destroy(leaf_cachep);
|
||||
kmem_cache_destroy(branch_cachep);
|
||||
}
|
||||
|
||||
module_init(ip_set_iptree_init);
|
||||
module_exit(ip_set_iptree_fini);
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef __IP_SET_IPTREE_H
|
||||
#define __IP_SET_IPTREE_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "iptree"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
|
||||
struct ip_set_iptreed {
|
||||
unsigned long expires[256]; /* x.x.x.ADDR */
|
||||
};
|
||||
|
||||
struct ip_set_iptreec {
|
||||
struct ip_set_iptreed *tree[256]; /* x.x.ADDR.* */
|
||||
};
|
||||
|
||||
struct ip_set_iptreeb {
|
||||
struct ip_set_iptreec *tree[256]; /* x.ADDR.*.* */
|
||||
};
|
||||
|
||||
struct ip_set_iptree {
|
||||
unsigned int timeout;
|
||||
unsigned int gc_interval;
|
||||
#ifdef __KERNEL__
|
||||
uint32_t elements; /* number of elements */
|
||||
struct timer_list gc;
|
||||
struct ip_set_iptreeb *tree[256]; /* ADDR.*.*.* */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ip_set_req_iptree_create {
|
||||
unsigned int timeout;
|
||||
};
|
||||
|
||||
struct ip_set_req_iptree {
|
||||
ip_set_ip_t ip;
|
||||
unsigned int timeout;
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_IPTREE_H */
|
||||
@@ -1,827 +0,0 @@
|
||||
/* Copyright (C) 2007 Sven Wegener <sven.wegener@stealer.net>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* This modules implements the iptreemap ipset type. It uses bitmaps to
|
||||
* represent every single IPv4 address as a bit. The bitmaps are managed in a
|
||||
* tree structure, where the first three octets of an address are used as an
|
||||
* 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/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ip_set.h"
|
||||
#include <linux/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include "ip_set_iptreemap.h"
|
||||
|
||||
#define IPTREEMAP_DEFAULT_GC_TIME (5 * 60)
|
||||
#define IPTREEMAP_DESTROY_SLEEP (100)
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
|
||||
static struct kmem_cache *cachep_b;
|
||||
static struct kmem_cache *cachep_c;
|
||||
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_c *fullbitmap_c;
|
||||
static struct ip_set_iptreemap_b *fullbitmap_b;
|
||||
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
#define ABCD(a, b, c, d, addr) \
|
||||
do { \
|
||||
a = ((unsigned char *)addr)[3]; \
|
||||
b = ((unsigned char *)addr)[2]; \
|
||||
c = ((unsigned char *)addr)[1]; \
|
||||
d = ((unsigned char *)addr)[0]; \
|
||||
} while (0)
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
#define ABCD(a,b,c,d,addrp) do { \
|
||||
a = ((unsigned char *)addrp)[0]; \
|
||||
b = ((unsigned char *)addrp)[1]; \
|
||||
c = ((unsigned char *)addrp)[2]; \
|
||||
d = ((unsigned char *)addrp)[3]; \
|
||||
} while (0)
|
||||
#else
|
||||
#error "Please fix asm/byteorder.h"
|
||||
#endif /* __LITTLE_ENDIAN */
|
||||
|
||||
#define TESTIP_WALK(map, elem, branch, full) \
|
||||
do { \
|
||||
branch = (map)->tree[elem]; \
|
||||
if (!branch) \
|
||||
return 0; \
|
||||
else if (branch == full) \
|
||||
return 1; \
|
||||
} while (0)
|
||||
|
||||
#define ADDIP_WALK(map, elem, branch, type, cachep, full) \
|
||||
do { \
|
||||
branch = (map)->tree[elem]; \
|
||||
if (!branch) { \
|
||||
branch = (type *) kmem_cache_alloc(cachep, GFP_ATOMIC); \
|
||||
if (!branch) \
|
||||
return -ENOMEM; \
|
||||
memset(branch, 0, sizeof(*branch)); \
|
||||
(map)->tree[elem] = branch; \
|
||||
} else if (branch == full) { \
|
||||
return -EEXIST; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ADDIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free) \
|
||||
for (a = a1; a <= a2; a++) { \
|
||||
branch = (map)->tree[a]; \
|
||||
if (branch != full) { \
|
||||
if ((a > a1 && a < a2) || (hint)) { \
|
||||
if (branch) \
|
||||
free(branch); \
|
||||
(map)->tree[a] = full; \
|
||||
continue; \
|
||||
} else if (!branch) { \
|
||||
branch = kmem_cache_alloc(cachep, GFP_ATOMIC); \
|
||||
if (!branch) \
|
||||
return -ENOMEM; \
|
||||
memset(branch, 0, sizeof(*branch)); \
|
||||
(map)->tree[a] = branch; \
|
||||
}
|
||||
|
||||
#define ADDIP_RANGE_LOOP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DELIP_WALK(map, elem, branch, cachep, full, flags) \
|
||||
do { \
|
||||
branch = (map)->tree[elem]; \
|
||||
if (!branch) { \
|
||||
return -EEXIST; \
|
||||
} else if (branch == full) { \
|
||||
branch = kmem_cache_alloc(cachep, flags); \
|
||||
if (!branch) \
|
||||
return -ENOMEM; \
|
||||
memcpy(branch, full, sizeof(*full)); \
|
||||
(map)->tree[elem] = branch; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define DELIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free, flags) \
|
||||
for (a = a1; a <= a2; a++) { \
|
||||
branch = (map)->tree[a]; \
|
||||
if (branch) { \
|
||||
if ((a > a1 && a < a2) || (hint)) { \
|
||||
if (branch != full) \
|
||||
free(branch); \
|
||||
(map)->tree[a] = NULL; \
|
||||
continue; \
|
||||
} else if (branch == full) { \
|
||||
branch = kmem_cache_alloc(cachep, flags); \
|
||||
if (!branch) \
|
||||
return -ENOMEM; \
|
||||
memcpy(branch, full, sizeof(*branch)); \
|
||||
(map)->tree[a] = branch; \
|
||||
}
|
||||
|
||||
#define DELIP_RANGE_LOOP_END() \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LOOP_WALK_BEGIN(map, i, branch) \
|
||||
for (i = 0; i < 256; i++) { \
|
||||
branch = (map)->tree[i]; \
|
||||
if (likely(!branch)) \
|
||||
continue;
|
||||
|
||||
#define LOOP_WALK_END() \
|
||||
}
|
||||
|
||||
#define LOOP_WALK_BEGIN_GC(map, i, branch, full, cachep, count) \
|
||||
count = -256; \
|
||||
for (i = 0; i < 256; i++) { \
|
||||
branch = (map)->tree[i]; \
|
||||
if (likely(!branch)) \
|
||||
continue; \
|
||||
count++; \
|
||||
if (branch == full) { \
|
||||
count++; \
|
||||
continue; \
|
||||
}
|
||||
|
||||
#define LOOP_WALK_END_GC(map, i, branch, full, cachep, count) \
|
||||
if (-256 == count) { \
|
||||
kmem_cache_free(cachep, branch); \
|
||||
(map)->tree[i] = NULL; \
|
||||
} else if (256 == count) { \
|
||||
kmem_cache_free(cachep, branch); \
|
||||
(map)->tree[i] = full; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LOOP_WALK_BEGIN_COUNT(map, i, branch, inrange, count) \
|
||||
for (i = 0; i < 256; i++) { \
|
||||
if (!(map)->tree[i]) { \
|
||||
if (inrange) { \
|
||||
count++; \
|
||||
inrange = 0; \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
branch = (map)->tree[i];
|
||||
|
||||
#define LOOP_WALK_END_COUNT() \
|
||||
}
|
||||
|
||||
#define GETVALUE1(a, a1, b1, r) \
|
||||
(a == a1 ? b1 : r)
|
||||
|
||||
#define GETVALUE2(a, b, a1, b1, c1, r) \
|
||||
(a == a1 && b == b1 ? c1 : r)
|
||||
|
||||
#define GETVALUE3(a, b, c, a1, b1, c1, d1, r) \
|
||||
(a == a1 && b == b1 && c == c1 ? d1 : r)
|
||||
|
||||
#define CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2) \
|
||||
( \
|
||||
GETVALUE1(a, a1, b1, 0) == 0 \
|
||||
&& GETVALUE1(a, a2, b2, 255) == 255 \
|
||||
&& c1 == 0 \
|
||||
&& c2 == 255 \
|
||||
&& d1 == 0 \
|
||||
&& d2 == 255 \
|
||||
)
|
||||
|
||||
#define CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2) \
|
||||
( \
|
||||
GETVALUE2(a, b, a1, b1, c1, 0) == 0 \
|
||||
&& GETVALUE2(a, b, a2, b2, c2, 255) == 255 \
|
||||
&& d1 == 0 \
|
||||
&& d2 == 255 \
|
||||
)
|
||||
|
||||
#define CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2) \
|
||||
( \
|
||||
GETVALUE3(a, b, c, a1, b1, c1, d1, 0) == 0 \
|
||||
&& GETVALUE3(a, b, c, a2, b2, c2, d2, 255) == 255 \
|
||||
)
|
||||
|
||||
|
||||
static inline void
|
||||
free_d(struct ip_set_iptreemap_d *map)
|
||||
{
|
||||
kmem_cache_free(cachep_d, map);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_c(struct ip_set_iptreemap_c *map)
|
||||
{
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned int i;
|
||||
|
||||
LOOP_WALK_BEGIN(map, i, dtree) {
|
||||
if (dtree != fullbitmap_d)
|
||||
free_d(dtree);
|
||||
} LOOP_WALK_END();
|
||||
|
||||
kmem_cache_free(cachep_c, map);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_b(struct ip_set_iptreemap_b *map)
|
||||
{
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
unsigned int i;
|
||||
|
||||
LOOP_WALK_BEGIN(map, i, ctree) {
|
||||
if (ctree != fullbitmap_c)
|
||||
free_c(ctree);
|
||||
} LOOP_WALK_END();
|
||||
|
||||
kmem_cache_free(cachep_b, map);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned char a, b, c, d;
|
||||
|
||||
*hash_ip = ip;
|
||||
|
||||
ABCD(a, b, c, d, hash_ip);
|
||||
|
||||
TESTIP_WALK(map, a, btree, fullbitmap_b);
|
||||
TESTIP_WALK(btree, b, ctree, fullbitmap_c);
|
||||
TESTIP_WALK(ctree, c, dtree, fullbitmap_d);
|
||||
|
||||
return !!test_bit(d, (void *) dtree->bitmap);
|
||||
}
|
||||
|
||||
static int
|
||||
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)) {
|
||||
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
|
||||
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
|
||||
__addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned char a, b, c, d;
|
||||
|
||||
*hash_ip = ip;
|
||||
|
||||
ABCD(a, b, c, d, hash_ip);
|
||||
|
||||
ADDIP_WALK(map, a, btree, struct ip_set_iptreemap_b, cachep_b, fullbitmap_b);
|
||||
ADDIP_WALK(btree, b, ctree, struct ip_set_iptreemap_c, cachep_c, fullbitmap_c);
|
||||
ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreemap_d, cachep_d, fullbitmap_d);
|
||||
|
||||
if (__test_and_set_bit(d, (void *) dtree->bitmap))
|
||||
return -EEXIST;
|
||||
|
||||
__set_bit(b, (void *) btree->dirty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned int a, b, c, d;
|
||||
unsigned char a1, b1, c1, d1;
|
||||
unsigned char a2, b2, c2, d2;
|
||||
|
||||
if (start == end)
|
||||
return __addip_single(set, start, hash_ip);
|
||||
|
||||
*hash_ip = start;
|
||||
|
||||
ABCD(a1, b1, c1, d1, &start);
|
||||
ABCD(a2, b2, c2, d2, &end);
|
||||
|
||||
/* This is sooo ugly... */
|
||||
ADDIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b) {
|
||||
ADDIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c) {
|
||||
ADDIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d) {
|
||||
for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
|
||||
__set_bit(d, (void *) dtree->bitmap);
|
||||
__set_bit(b, (void *) btree->dirty);
|
||||
} ADDIP_RANGE_LOOP_END();
|
||||
} ADDIP_RANGE_LOOP_END();
|
||||
} ADDIP_RANGE_LOOP_END();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
addip(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)) {
|
||||
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
|
||||
__delip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned char a,b,c,d;
|
||||
|
||||
*hash_ip = ip;
|
||||
|
||||
ABCD(a, b, c, d, hash_ip);
|
||||
|
||||
DELIP_WALK(map, a, btree, cachep_b, fullbitmap_b, flags);
|
||||
DELIP_WALK(btree, b, ctree, cachep_c, fullbitmap_c, flags);
|
||||
DELIP_WALK(ctree, c, dtree, cachep_d, fullbitmap_d, flags);
|
||||
|
||||
if (!__test_and_clear_bit(d, (void *) dtree->bitmap))
|
||||
return -EEXIST;
|
||||
|
||||
__set_bit(b, (void *) btree->dirty);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned int a, b, c, d;
|
||||
unsigned char a1, b1, c1, d1;
|
||||
unsigned char a2, b2, c2, d2;
|
||||
|
||||
if (start == end)
|
||||
return __delip_single(set, start, hash_ip, flags);
|
||||
|
||||
*hash_ip = start;
|
||||
|
||||
ABCD(a1, b1, c1, d1, &start);
|
||||
ABCD(a2, b2, c2, d2, &end);
|
||||
|
||||
/* This is sooo ugly... */
|
||||
DELIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b, flags) {
|
||||
DELIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c, flags) {
|
||||
DELIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d, flags) {
|
||||
for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
|
||||
__clear_bit(d, (void *) dtree->bitmap);
|
||||
__set_bit(b, (void *) btree->dirty);
|
||||
} DELIP_RANGE_LOOP_END();
|
||||
} DELIP_RANGE_LOOP_END();
|
||||
} DELIP_RANGE_LOOP_END();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(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)) {
|
||||
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
|
||||
* -1 == all bits cleared
|
||||
* 1 == all bits set
|
||||
* 0 == anything else
|
||||
*/
|
||||
static inline int
|
||||
bitmap_status(struct ip_set_iptreemap_d *dtree)
|
||||
{
|
||||
unsigned char first = dtree->bitmap[0];
|
||||
int a;
|
||||
|
||||
for (a = 1; a < 32; a++)
|
||||
if (dtree->bitmap[a] != first)
|
||||
return 0;
|
||||
|
||||
return (first == 0 ? -1 : (first == 255 ? 1 : 0));
|
||||
}
|
||||
|
||||
static void
|
||||
gc(unsigned long addr)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) addr;
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned int a, b, c;
|
||||
int i, j, k;
|
||||
|
||||
write_lock_bh(&set->lock);
|
||||
|
||||
LOOP_WALK_BEGIN_GC(map, a, btree, fullbitmap_b, cachep_b, i) {
|
||||
LOOP_WALK_BEGIN_GC(btree, b, ctree, fullbitmap_c, cachep_c, j) {
|
||||
if (!__test_and_clear_bit(b, (void *) btree->dirty))
|
||||
continue;
|
||||
LOOP_WALK_BEGIN_GC(ctree, c, dtree, fullbitmap_d, cachep_d, k) {
|
||||
switch (bitmap_status(dtree)) {
|
||||
case -1:
|
||||
kmem_cache_free(cachep_d, dtree);
|
||||
ctree->tree[c] = NULL;
|
||||
k--;
|
||||
break;
|
||||
case 1:
|
||||
kmem_cache_free(cachep_d, dtree);
|
||||
ctree->tree[c] = fullbitmap_d;
|
||||
k++;
|
||||
break;
|
||||
}
|
||||
} LOOP_WALK_END();
|
||||
} LOOP_WALK_END_GC(btree, b, ctree, fullbitmap_c, cachep_c, k);
|
||||
} LOOP_WALK_END_GC(map, a, btree, fullbitmap_b, cachep_b, j);
|
||||
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_gc_timer(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = gc;
|
||||
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static int create(struct ip_set *set, const void *data, size_t size)
|
||||
{
|
||||
const struct ip_set_req_iptreemap_create *req = data;
|
||||
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);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
map->gc_interval = req->gc_interval ? req->gc_interval : IPTREEMAP_DEFAULT_GC_TIME;
|
||||
set->data = map;
|
||||
|
||||
init_gc_timer(set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void __flush(struct ip_set_iptreemap *map)
|
||||
{
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
unsigned int a;
|
||||
|
||||
LOOP_WALK_BEGIN(map, a, btree);
|
||||
if (btree != fullbitmap_b)
|
||||
free_b(btree);
|
||||
LOOP_WALK_END();
|
||||
}
|
||||
|
||||
static void destroy(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
|
||||
while (!del_timer(&map->gc))
|
||||
msleep(IPTREEMAP_DESTROY_SLEEP);
|
||||
|
||||
__flush(map);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void flush(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
|
||||
while (!del_timer(&map->gc))
|
||||
msleep(IPTREEMAP_DESTROY_SLEEP);
|
||||
|
||||
__flush(map);
|
||||
|
||||
memset(map, 0, sizeof(*map));
|
||||
|
||||
init_gc_timer(set);
|
||||
}
|
||||
|
||||
static void list_header(const struct ip_set *set, void *data)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_req_iptreemap_create *header = data;
|
||||
|
||||
header->gc_interval = map->gc_interval;
|
||||
}
|
||||
|
||||
static int list_members_size(const struct ip_set *set)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned int a, b, c, d, inrange = 0, count = 0;
|
||||
|
||||
LOOP_WALK_BEGIN_COUNT(map, a, btree, inrange, count) {
|
||||
LOOP_WALK_BEGIN_COUNT(btree, b, ctree, inrange, count) {
|
||||
LOOP_WALK_BEGIN_COUNT(ctree, c, dtree, inrange, count) {
|
||||
for (d = 0; d < 256; d++) {
|
||||
if (test_bit(d, (void *) dtree->bitmap)) {
|
||||
inrange = 1;
|
||||
} else if (inrange) {
|
||||
count++;
|
||||
inrange = 0;
|
||||
}
|
||||
}
|
||||
} LOOP_WALK_END_COUNT();
|
||||
} LOOP_WALK_END_COUNT();
|
||||
} LOOP_WALK_END_COUNT();
|
||||
|
||||
if (inrange)
|
||||
count++;
|
||||
|
||||
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)
|
||||
{
|
||||
struct ip_set_req_iptreemap *entry = data + offset;
|
||||
|
||||
entry->start = start;
|
||||
entry->end = end;
|
||||
|
||||
return sizeof(*entry);
|
||||
}
|
||||
|
||||
static void list_members(const struct ip_set *set, void *data)
|
||||
{
|
||||
struct ip_set_iptreemap *map = set->data;
|
||||
struct ip_set_iptreemap_b *btree;
|
||||
struct ip_set_iptreemap_c *ctree;
|
||||
struct ip_set_iptreemap_d *dtree;
|
||||
unsigned int a, b, c, d, inrange = 0;
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t start = 0, end = 0, ip;
|
||||
|
||||
LOOP_WALK_BEGIN(map, a, btree) {
|
||||
LOOP_WALK_BEGIN(btree, b, ctree) {
|
||||
LOOP_WALK_BEGIN(ctree, c, dtree) {
|
||||
for (d = 0; d < 256; d++) {
|
||||
if (test_bit(d, (void *) dtree->bitmap)) {
|
||||
ip = ((a << 24) | (b << 16) | (c << 8) | d);
|
||||
if (!inrange) {
|
||||
inrange = 1;
|
||||
start = ip;
|
||||
} else if (end < ip - 1) {
|
||||
offset += add_member(data, offset, start, end);
|
||||
start = ip;
|
||||
}
|
||||
end = ip;
|
||||
} else if (inrange) {
|
||||
offset += add_member(data, offset, start, end);
|
||||
inrange = 0;
|
||||
}
|
||||
}
|
||||
} LOOP_WALK_END();
|
||||
} LOOP_WALK_END();
|
||||
} LOOP_WALK_END();
|
||||
|
||||
if (inrange)
|
||||
add_member(data, offset, start, end);
|
||||
}
|
||||
|
||||
static struct ip_set_type ip_set_iptreemap = {
|
||||
.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_AUTHOR("Sven Wegener <sven.wegener@stealer.net>");
|
||||
MODULE_DESCRIPTION("iptreemap type of IP sets");
|
||||
|
||||
static int __init ip_set_iptreemap_init(void)
|
||||
{
|
||||
int ret = -ENOMEM;
|
||||
int a;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
cachep_b = kmem_cache_create("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) {
|
||||
ip_set_printk("Unable to create ip_set_iptreemap_b slab cache");
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
cachep_c = kmem_cache_create("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) {
|
||||
ip_set_printk("Unable to create ip_set_iptreemap_c slab cache");
|
||||
goto outb;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
cachep_d = kmem_cache_create("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) {
|
||||
ip_set_printk("Unable to create ip_set_iptreemap_d slab cache");
|
||||
goto outc;
|
||||
}
|
||||
|
||||
fullbitmap_d = kmem_cache_alloc(cachep_d, GFP_KERNEL);
|
||||
if (!fullbitmap_d)
|
||||
goto outd;
|
||||
|
||||
fullbitmap_c = kmem_cache_alloc(cachep_c, GFP_KERNEL);
|
||||
if (!fullbitmap_c)
|
||||
goto outbitmapd;
|
||||
|
||||
fullbitmap_b = kmem_cache_alloc(cachep_b, GFP_KERNEL);
|
||||
if (!fullbitmap_b)
|
||||
goto outbitmapc;
|
||||
|
||||
ret = ip_set_register_set_type(&ip_set_iptreemap);
|
||||
if (0 > ret)
|
||||
goto outbitmapb;
|
||||
|
||||
/* Now init our global bitmaps */
|
||||
memset(fullbitmap_d->bitmap, 0xff, sizeof(fullbitmap_d->bitmap));
|
||||
|
||||
for (a = 0; a < 256; a++)
|
||||
fullbitmap_c->tree[a] = fullbitmap_d;
|
||||
|
||||
for (a = 0; a < 256; a++)
|
||||
fullbitmap_b->tree[a] = fullbitmap_c;
|
||||
memset(fullbitmap_b->dirty, 0, sizeof(fullbitmap_b->dirty));
|
||||
|
||||
return 0;
|
||||
|
||||
outbitmapb:
|
||||
kmem_cache_free(cachep_b, fullbitmap_b);
|
||||
outbitmapc:
|
||||
kmem_cache_free(cachep_c, fullbitmap_c);
|
||||
outbitmapd:
|
||||
kmem_cache_free(cachep_d, fullbitmap_d);
|
||||
outd:
|
||||
kmem_cache_destroy(cachep_d);
|
||||
outc:
|
||||
kmem_cache_destroy(cachep_c);
|
||||
outb:
|
||||
kmem_cache_destroy(cachep_b);
|
||||
out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit ip_set_iptreemap_fini(void)
|
||||
{
|
||||
ip_set_unregister_set_type(&ip_set_iptreemap);
|
||||
kmem_cache_free(cachep_d, fullbitmap_d);
|
||||
kmem_cache_free(cachep_c, fullbitmap_c);
|
||||
kmem_cache_free(cachep_b, fullbitmap_b);
|
||||
kmem_cache_destroy(cachep_d);
|
||||
kmem_cache_destroy(cachep_c);
|
||||
kmem_cache_destroy(cachep_b);
|
||||
}
|
||||
|
||||
module_init(ip_set_iptreemap_init);
|
||||
module_exit(ip_set_iptreemap_fini);
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef __IP_SET_IPTREEMAP_H
|
||||
#define __IP_SET_IPTREEMAP_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "iptreemap"
|
||||
|
||||
#ifdef __KERNEL__
|
||||
struct ip_set_iptreemap_d {
|
||||
unsigned char bitmap[32]; /* x.x.x.y */
|
||||
};
|
||||
|
||||
struct ip_set_iptreemap_c {
|
||||
struct ip_set_iptreemap_d *tree[256]; /* x.x.y.x */
|
||||
};
|
||||
|
||||
struct ip_set_iptreemap_b {
|
||||
struct ip_set_iptreemap_c *tree[256]; /* x.y.x.x */
|
||||
unsigned char dirty[32];
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ip_set_iptreemap {
|
||||
unsigned int gc_interval;
|
||||
#ifdef __KERNEL__
|
||||
struct timer_list gc;
|
||||
struct ip_set_iptreemap_b *tree[256]; /* y.x.x.x */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ip_set_req_iptreemap_create {
|
||||
unsigned int gc_interval;
|
||||
};
|
||||
|
||||
struct ip_set_req_iptreemap {
|
||||
ip_set_ip_t start;
|
||||
ip_set_ip_t end;
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_IPTREEMAP_H */
|
||||
@@ -1,148 +0,0 @@
|
||||
#ifndef _LINUX_IPSET_JHASH_H
|
||||
#define _LINUX_IPSET_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.
|
||||
*
|
||||
* Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
|
||||
*
|
||||
* http://burtleburtle.net/bob/hash/
|
||||
*
|
||||
* These are the credits from Bob's sources:
|
||||
*
|
||||
* lookup2.c, by Bob Jenkins, December 1996, 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)
|
||||
*
|
||||
* I've modified Bob's hash to be useful in the Linux kernel, and
|
||||
* any bugs present are surely my fault. -DaveM
|
||||
*/
|
||||
|
||||
/* NOTE: Arguments are modified. */
|
||||
#define __jhash_mix(a, b, c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c>>13); \
|
||||
b -= c; b -= a; b ^= (a<<8); \
|
||||
c -= a; c -= b; c ^= (b>>13); \
|
||||
a -= b; a -= c; a ^= (c>>12); \
|
||||
b -= c; b -= a; b ^= (a<<16); \
|
||||
c -= a; c -= b; c ^= (b>>5); \
|
||||
a -= b; a -= c; a ^= (c>>3); \
|
||||
b -= c; b -= a; b ^= (a<<10); \
|
||||
c -= a; c -= b; c ^= (b>>15); \
|
||||
}
|
||||
|
||||
/* The golden ration: an arbitrary value */
|
||||
#define JHASH_GOLDEN_RATIO 0x9e3779b9
|
||||
|
||||
/* The most generic version, hashes an arbitrary sequence
|
||||
* of bytes. No alignment or length assumptions are made about
|
||||
* the input key.
|
||||
*/
|
||||
static inline __u32 jhash(void *key, __u32 length, __u32 initval)
|
||||
{
|
||||
__u32 a, b, c, len;
|
||||
__u8 *k = key;
|
||||
|
||||
len = length;
|
||||
a = b = JHASH_GOLDEN_RATIO;
|
||||
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));
|
||||
|
||||
__jhash_mix(a,b,c);
|
||||
|
||||
k += 12;
|
||||
len -= 12;
|
||||
}
|
||||
|
||||
c += length;
|
||||
switch (len) {
|
||||
case 11: c += ((__u32)k[10]<<24);
|
||||
case 10: c += ((__u32)k[9]<<16);
|
||||
case 9 : c += ((__u32)k[8]<<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 4 : a += ((__u32)k[3]<<24);
|
||||
case 3 : a += ((__u32)k[2]<<16);
|
||||
case 2 : a += ((__u32)k[1]<<8);
|
||||
case 1 : a += k[0];
|
||||
};
|
||||
|
||||
__jhash_mix(a,b,c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* A special optimized version that handles 1 or more of __u32s.
|
||||
* The length parameter here is the number of __u32s in the key.
|
||||
*/
|
||||
static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval)
|
||||
{
|
||||
__u32 a, b, c, len;
|
||||
|
||||
a = b = JHASH_GOLDEN_RATIO;
|
||||
c = initval;
|
||||
len = length;
|
||||
|
||||
while (len >= 3) {
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
__jhash_mix(a, b, c);
|
||||
k += 3; len -= 3;
|
||||
}
|
||||
|
||||
c += length * 4;
|
||||
|
||||
switch (len) {
|
||||
case 2 : b += k[1];
|
||||
case 1 : a += k[0];
|
||||
};
|
||||
|
||||
__jhash_mix(a,b,c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/* A special ultra-optimized versions that knows they are hashing exactly
|
||||
* 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)
|
||||
{
|
||||
a += JHASH_GOLDEN_RATIO;
|
||||
b += JHASH_GOLDEN_RATIO;
|
||||
c += initval;
|
||||
|
||||
__jhash_mix(a, b, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval)
|
||||
{
|
||||
return jhash_3words(a, b, 0, initval);
|
||||
}
|
||||
|
||||
static inline __u32 jhash_1word(__u32 a, __u32 initval)
|
||||
{
|
||||
return jhash_3words(a, 0, 0, initval);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_IPSET_JHASH_H */
|
||||
@@ -1,360 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2004 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 macipmap type */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.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 <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "ip_set_malloc.h"
|
||||
#include "ip_set_macipmap.h"
|
||||
|
||||
static int
|
||||
testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_macipmap *map = set->data;
|
||||
struct ip_set_macip *table = map->members;
|
||||
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)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_ip = req->ip;
|
||||
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
|
||||
set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
|
||||
if (test_bit(IPSET_MACIP_ISSET,
|
||||
(void *) &table[req->ip - map->first_ip].flags)) {
|
||||
return (memcmp(req->ethernet,
|
||||
&table[req->ip - map->first_ip].ethernet,
|
||||
ETH_ALEN) == 0);
|
||||
} else {
|
||||
return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ip_set_macipmap *map = set->data;
|
||||
struct ip_set_macip *table = map->members;
|
||||
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 (ip < map->first_ip || ip > map->last_ip)
|
||||
return 0;
|
||||
|
||||
*hash_ip = ip;
|
||||
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
|
||||
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||
if (test_bit(IPSET_MACIP_ISSET,
|
||||
(void *) &table[ip - map->first_ip].flags)) {
|
||||
/* Is mac pointer valid?
|
||||
* If so, compare... */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||
return (skb_mac_header(skb) >= skb->head
|
||||
&& (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,
|
||||
&table[ip - map->first_ip].ethernet,
|
||||
ETH_ALEN) == 0));
|
||||
} else {
|
||||
return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* returns 0 on success */
|
||||
static inline int
|
||||
__addip(struct ip_set *set,
|
||||
ip_set_ip_t ip, const unsigned char *ethernet, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_macipmap *map = set->data;
|
||||
struct ip_set_macip *table = map->members;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
if (test_and_set_bit(IPSET_MACIP_ISSET,
|
||||
(void *) &table[ip - map->first_ip].flags))
|
||||
return -EEXIST;
|
||||
|
||||
*hash_ip = 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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
addip(struct ip_set *set, const void *data, size_t size,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
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 __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_macipmap *map = set->data;
|
||||
struct ip_set_macip *table = map->members;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -ERANGE;
|
||||
if (!test_and_clear_bit(IPSET_MACIP_ISSET,
|
||||
(void *)&table[ip - map->first_ip].flags))
|
||||
return -EEXIST;
|
||||
|
||||
*hash_ip = ip;
|
||||
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(struct ip_set *set, const void *data, size_t size,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
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) {
|
||||
ip_set_printk("range too big (max %d addresses)",
|
||||
MAX_RANGE+1);
|
||||
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->first_ip = req->from;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static int list_members_size(const struct ip_set *set)
|
||||
{
|
||||
const struct ip_set_macipmap *map = set->data;
|
||||
|
||||
DP("%u", members_size(map->first_ip, map->last_ip));
|
||||
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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("macipmap type of IP sets");
|
||||
|
||||
static int __init ip_set_macipmap_init(void)
|
||||
{
|
||||
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);
|
||||
@@ -1,38 +0,0 @@
|
||||
#ifndef __IP_SET_MACIPMAP_H
|
||||
#define __IP_SET_MACIPMAP_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "macipmap"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
|
||||
/* general flags */
|
||||
#define IPSET_MACIP_MATCHUNSET 1
|
||||
|
||||
/* per ip flags */
|
||||
#define IPSET_MACIP_ISSET 1
|
||||
|
||||
struct ip_set_macipmap {
|
||||
void *members; /* the macipmap proper */
|
||||
ip_set_ip_t first_ip; /* host byte order, included in range */
|
||||
ip_set_ip_t last_ip; /* host byte order, included in range */
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
struct ip_set_req_macipmap_create {
|
||||
ip_set_ip_t from;
|
||||
ip_set_ip_t to;
|
||||
u_int32_t flags;
|
||||
};
|
||||
|
||||
struct ip_set_req_macipmap {
|
||||
ip_set_ip_t ip;
|
||||
unsigned char ethernet[ETH_ALEN];
|
||||
};
|
||||
|
||||
struct ip_set_macip {
|
||||
unsigned short flags;
|
||||
unsigned char ethernet[ETH_ALEN];
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_MACIPMAP_H */
|
||||
@@ -1,143 +0,0 @@
|
||||
#ifndef _IP_SET_MALLOC_H
|
||||
#define _IP_SET_MALLOC_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
static size_t max_malloc_size = 0, max_page_size = 0;
|
||||
|
||||
static inline unsigned int init_max_page_size(void)
|
||||
{
|
||||
size_t page_size = 0;
|
||||
|
||||
#define CACHE(x) if (max_page_size == 0 || x < max_page_size) \
|
||||
page_size = x;
|
||||
#include <linux/kmalloc_sizes.h>
|
||||
#undef CACHE
|
||||
if (page_size) {
|
||||
if (max_malloc_size == 0)
|
||||
max_malloc_size = page_size;
|
||||
|
||||
max_page_size = page_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct harray {
|
||||
size_t max_elements;
|
||||
void *arrays[0];
|
||||
};
|
||||
|
||||
static inline void *
|
||||
__harray_malloc(size_t hashsize, size_t typesize, int flags)
|
||||
{
|
||||
struct harray *harray;
|
||||
size_t max_elements, size, i, j;
|
||||
|
||||
BUG_ON(max_page_size == 0);
|
||||
|
||||
if (typesize > max_page_size)
|
||||
return NULL;
|
||||
|
||||
max_elements = max_page_size/typesize;
|
||||
size = hashsize/max_elements;
|
||||
if (hashsize % max_elements)
|
||||
size++;
|
||||
|
||||
/* Last pointer signals end of arrays */
|
||||
harray = kmalloc(sizeof(struct harray) + (size + 1) * sizeof(void *),
|
||||
flags);
|
||||
|
||||
if (!harray)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < size - 1; i++) {
|
||||
harray->arrays[i] = kmalloc(max_elements * typesize, flags);
|
||||
if (!harray->arrays[i])
|
||||
goto undo;
|
||||
memset(harray->arrays[i], 0, max_elements * typesize);
|
||||
}
|
||||
harray->arrays[i] = kmalloc((hashsize - i * max_elements) * typesize,
|
||||
flags);
|
||||
if (!harray->arrays[i])
|
||||
goto undo;
|
||||
memset(harray->arrays[i], 0, (hashsize - i * max_elements) * typesize);
|
||||
|
||||
harray->max_elements = max_elements;
|
||||
harray->arrays[size] = NULL;
|
||||
|
||||
return (void *)harray;
|
||||
|
||||
undo:
|
||||
for (j = 0; j < i; j++) {
|
||||
kfree(harray->arrays[j]);
|
||||
}
|
||||
kfree(harray);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
harray_malloc(size_t hashsize, size_t typesize, int flags)
|
||||
{
|
||||
void *harray;
|
||||
|
||||
do {
|
||||
harray = __harray_malloc(hashsize, typesize, flags|__GFP_NOWARN);
|
||||
} while (harray == NULL && init_max_page_size());
|
||||
|
||||
return harray;
|
||||
}
|
||||
|
||||
static inline void harray_free(void *h)
|
||||
{
|
||||
struct harray *harray = (struct harray *) h;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; harray->arrays[i] != NULL; i++)
|
||||
kfree(harray->arrays[i]);
|
||||
kfree(harray);
|
||||
}
|
||||
|
||||
static inline void harray_flush(void *h, size_t hashsize, size_t typesize)
|
||||
{
|
||||
struct harray *harray = (struct harray *) h;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; harray->arrays[i+1] != NULL; i++)
|
||||
memset(harray->arrays[i], 0, harray->max_elements * typesize);
|
||||
memset(harray->arrays[i], 0,
|
||||
(hashsize - i * harray->max_elements) * typesize);
|
||||
}
|
||||
|
||||
#define HARRAY_ELEM(h, type, which) \
|
||||
({ \
|
||||
struct harray *__h = (struct harray *)(h); \
|
||||
((type)((__h)->arrays[(which)/(__h)->max_elements]) \
|
||||
+ (which)%(__h)->max_elements); \
|
||||
})
|
||||
|
||||
/* General memory allocation and deallocation */
|
||||
static inline void * ip_set_malloc(size_t bytes)
|
||||
{
|
||||
BUG_ON(max_malloc_size == 0);
|
||||
|
||||
if (bytes > max_malloc_size)
|
||||
return vmalloc(bytes);
|
||||
else
|
||||
return kmalloc(bytes, GFP_KERNEL | __GFP_NOWARN);
|
||||
}
|
||||
|
||||
static inline void ip_set_free(void * data, size_t bytes)
|
||||
{
|
||||
BUG_ON(max_malloc_size == 0);
|
||||
|
||||
if (bytes > max_malloc_size)
|
||||
vfree(data);
|
||||
else
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /*_IP_SET_MALLOC_H*/
|
||||
@@ -1,490 +0,0 @@
|
||||
/* Copyright (C) 2003-2004 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 a cidr nethash set */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ip_set.h"
|
||||
#include <linux/errno.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "ip_set_malloc.h"
|
||||
#include "ip_set_nethash.h"
|
||||
|
||||
static int limit = MAX_RANGE;
|
||||
|
||||
static inline __u32
|
||||
jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t 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,
|
||||
unsigned char cidr,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
__u32 id;
|
||||
u_int16_t i;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
*hash_ip = pack(ip, cidr);
|
||||
|
||||
for (i = 0; i < map->probes; i++) {
|
||||
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||
DP("hash key: %u", id);
|
||||
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||
if (*elem == *hash_ip)
|
||||
return id;
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
static inline __u32
|
||||
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_nethash *map = set->data;
|
||||
__u32 id = UINT_MAX;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 30 && map->cidr[i]; i++) {
|
||||
id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
|
||||
if (id != UINT_MAX)
|
||||
break;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
struct ip_set_nethash *map = set->data;
|
||||
|
||||
return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||
{
|
||||
return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
|
||||
}
|
||||
|
||||
static int
|
||||
testip(struct ip_set *set, const void *data, size_t size,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
const struct ip_set_req_nethash *req = data;
|
||||
|
||||
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;
|
||||
}
|
||||
return (req->cidr == 32 ? __testip(set, req->ip, hash_ip)
|
||||
: __testip_cidr(set, req->ip, req->cidr, 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
|
||||
__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
|
||||
{
|
||||
__u32 probe;
|
||||
u_int16_t i;
|
||||
ip_set_ip_t *elem;
|
||||
|
||||
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 (!*elem) {
|
||||
*elem = ip;
|
||||
map->elements++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Trigger rehashing */
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
if (!ip || map->elements >= limit)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
ret = __addip(set->data, req->ip, req->cidr, hash_ip);
|
||||
|
||||
if (ret == 0)
|
||||
update_cidr_sizes(set->data, req->cidr);
|
||||
|
||||
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;
|
||||
|
||||
again:
|
||||
res = 0;
|
||||
|
||||
/* Calculate new parameters */
|
||||
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_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! */
|
||||
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
|
||||
__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
ip_set_ip_t id, *elem;
|
||||
|
||||
if (!ip)
|
||||
return -ERANGE;
|
||||
|
||||
id = hash_id_cidr(map, ip, cidr, hash_ip);
|
||||
if (id == UINT_MAX)
|
||||
return -EEXIST;
|
||||
|
||||
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||
*elem = 0;
|
||||
map->elements--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delip(struct ip_set *set, const void *data, size_t size,
|
||||
ip_set_ip_t *hash_ip)
|
||||
{
|
||||
const struct ip_set_req_nethash *req = data;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void destroy(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_nethash *map = set->data;
|
||||
|
||||
harray_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void flush(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_nethash *map = set->data;
|
||||
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)
|
||||
{
|
||||
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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("nethash type of IP sets");
|
||||
module_param(limit, int, 0600);
|
||||
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||
|
||||
static int __init ip_set_nethash_init(void)
|
||||
{
|
||||
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);
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef __IP_SET_NETHASH_H
|
||||
#define __IP_SET_NETHASH_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "nethash"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
|
||||
struct ip_set_nethash {
|
||||
ip_set_ip_t *members; /* the nethash 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 */
|
||||
unsigned char cidr[30]; /* CIDR sizes */
|
||||
void *initval[0]; /* initvals for jhash_1word */
|
||||
};
|
||||
|
||||
struct ip_set_req_nethash_create {
|
||||
uint32_t hashsize;
|
||||
uint16_t probes;
|
||||
uint16_t resize;
|
||||
};
|
||||
|
||||
struct ip_set_req_nethash {
|
||||
ip_set_ip_t ip;
|
||||
unsigned char 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 */
|
||||
@@ -1,341 +0,0 @@
|
||||
/* Copyright (C) 2003-2004 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 a port set type as a bitmap */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.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 <asm/uaccess.h>
|
||||
#include <asm/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#include <net/ip.h>
|
||||
|
||||
#include "ip_set_portmap.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
|
||||
__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
|
||||
{
|
||||
struct ip_set_portmap *map = set->data;
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -ERANGE;
|
||||
|
||||
*hash_port = port;
|
||||
DP("set: %s, port:%u, %u", set->name, port, *hash_port);
|
||||
return !!test_bit(port - map->first_port, map->members);
|
||||
}
|
||||
|
||||
static int
|
||||
testport(struct ip_set *set, const void *data, size_t size,
|
||||
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;
|
||||
|
||||
res = __testport(set, port, hash_port);
|
||||
|
||||
return (res < 0 ? 0 : res);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
|
||||
{
|
||||
struct ip_set_portmap *map = set->data;
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -ERANGE;
|
||||
if (test_and_set_bit(port - map->first_port, map->members))
|
||||
return -EEXIST;
|
||||
|
||||
*hash_port = port;
|
||||
DP("port %u", port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
addport(struct ip_set *set, const void *data, size_t size,
|
||||
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
|
||||
__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
|
||||
{
|
||||
struct ip_set_portmap *map = set->data;
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -ERANGE;
|
||||
if (!test_and_clear_bit(port - map->first_port, map->members))
|
||||
return -EEXIST;
|
||||
|
||||
*hash_port = port;
|
||||
DP("port %u", port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
delport(struct ip_set *set, const void *data, size_t size,
|
||||
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 __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) {
|
||||
ip_set_printk("range too big (max %d ports)",
|
||||
MAX_RANGE+1);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ip_set_portmap *map = set->data;
|
||||
|
||||
kfree(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void flush(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_portmap *map = set->data;
|
||||
memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
|
||||
}
|
||||
|
||||
static void list_header(const struct ip_set *set, void *data)
|
||||
{
|
||||
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_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("portmap type of IP sets");
|
||||
|
||||
static int __init ip_set_portmap_init(void)
|
||||
{
|
||||
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);
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef __IP_SET_PORTMAP_H
|
||||
#define __IP_SET_PORTMAP_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define SETTYPE_NAME "portmap"
|
||||
#define MAX_RANGE 0x0000FFFF
|
||||
#define INVALID_PORT (MAX_RANGE + 1)
|
||||
|
||||
struct ip_set_portmap {
|
||||
void *members; /* the portmap proper */
|
||||
ip_set_ip_t first_port; /* host byte order, included in range */
|
||||
ip_set_ip_t last_port; /* host byte order, included in range */
|
||||
};
|
||||
|
||||
struct ip_set_req_portmap_create {
|
||||
ip_set_ip_t from;
|
||||
ip_set_ip_t to;
|
||||
};
|
||||
|
||||
struct ip_set_req_portmap {
|
||||
ip_set_ip_t port;
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_PORTMAP_H */
|
||||
@@ -1,470 +0,0 @@
|
||||
.TH IPSET 8 "Feb 05, 2004" "" ""
|
||||
.\"
|
||||
.\" Man page written by 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
.\"
|
||||
.\"
|
||||
.SH NAME
|
||||
ipset \- administration tool for IP sets
|
||||
.SH SYNOPSIS
|
||||
.BR "ipset -N " "set type-specification [options]"
|
||||
.br
|
||||
.BR "ipset -[XFLSHh] " "[set] [options]"
|
||||
.br
|
||||
.BR "ipset -[EW] " "from-set to-set"
|
||||
.br
|
||||
.BR "ipset -[ADU] " "set entry"
|
||||
.br
|
||||
.BR "ipset -B " "set entry -b binding"
|
||||
.br
|
||||
.BR "ipset -T " "set entry [-b binding]"
|
||||
.br
|
||||
.BR "ipset -R "
|
||||
.SH DESCRIPTION
|
||||
.B ipset
|
||||
is used to set up, maintain and inspect so called IP sets in the Linux
|
||||
kernel. Depending on the type, an IP set may store IP addresses, (TCP/UDP)
|
||||
port numbers or additional informations besides IP addresses: the word IP
|
||||
means a general term here. See the set type definitions below.
|
||||
.P
|
||||
Any entry in a set can be bound to another set, which forms a relationship
|
||||
between a set element and the set it is bound to. In order to define a
|
||||
binding it is not required that the entry be already added to the set.
|
||||
The sets may have a default binding, which is valid for every set element
|
||||
for which there is no binding defined at all.
|
||||
.P
|
||||
IP set bindings pointing to sets and iptables matches and targets
|
||||
referring to sets creates references, which protects the given sets in
|
||||
the kernel. A set cannot be removed (destroyed) while there is a single
|
||||
reference pointing to it.
|
||||
.SH OPTIONS
|
||||
The options that are recognized by
|
||||
.B ipset
|
||||
can be divided into several different groups.
|
||||
.SS COMMANDS
|
||||
These options specify the specific action to perform. Only one of them
|
||||
can be specified on the command line unless otherwise specified
|
||||
below. For all the long versions of the command and option names, you
|
||||
need to use only enough letters to ensure that
|
||||
.B ipset
|
||||
can differentiate it from all other options.
|
||||
.TP
|
||||
.BI "-N, --create " "\fIsetname\fP type type-specific-options"
|
||||
Create a set identified with setname and specified type.
|
||||
Type-specific options must be supplied.
|
||||
.TP
|
||||
.BI "-X, --destroy " "[\fIsetname\fP]"
|
||||
Destroy the specified set, or all sets if none or the keyword
|
||||
.B
|
||||
:all:
|
||||
is specified.
|
||||
Before destroying the set, all bindings belonging to the
|
||||
set elements and the default binding of the set are removed.
|
||||
|
||||
If the set has got references, nothing is done.
|
||||
.TP
|
||||
.BI "-F, --flush " "[\fIsetname\fP]"
|
||||
Delete all entries from the specified set, or flush
|
||||
all sets if none or the keyword
|
||||
.B
|
||||
:all:
|
||||
is given. Bindings are not affected by the flush operation.
|
||||
.TP
|
||||
.BI "-E, --rename " "\fIfrom-setname\fP \fIto-setname\fP"
|
||||
Rename a set. Set identified by to-setname must not exist.
|
||||
.TP
|
||||
.BI "-W, --swap " "\fIfrom-setname\fP \fIto-setname\fP"
|
||||
Swap two sets as they referenced in the Linux kernel.
|
||||
.B
|
||||
iptables
|
||||
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
|
||||
.BI "-L, --list " "[\fIsetname\fP]"
|
||||
List the entries and bindings for the specified set, or for
|
||||
all sets if none or the keyword
|
||||
.B
|
||||
:all:
|
||||
is given. The
|
||||
.B "-n, --numeric"
|
||||
option can be used to suppress name lookups and generate numeric
|
||||
output. When the
|
||||
.B "-s, --sorted"
|
||||
option is given, the entries are listed sorted (if the given set
|
||||
type supports the operation).
|
||||
.TP
|
||||
.BI "-S, --save " "[\fIsetname\fP]"
|
||||
Save the given set, or all sets if none or the keyword
|
||||
.B
|
||||
:all:
|
||||
is specified to stdout in a format that --restore can read.
|
||||
.TP
|
||||
.BI "-R, --restore "
|
||||
Restore a saved session generated by --save. The saved session
|
||||
can be fed from stdin.
|
||||
|
||||
When generating a session file please note that the supported commands
|
||||
(create set, add element, bind) must appear in a strict order: first create
|
||||
the set, then add all elements. Then create the next set, add all its elements
|
||||
and so on. Finally you can list all binding commands. Also, it is a restore
|
||||
operation, so the sets being restored must not exist.
|
||||
.TP
|
||||
.BI "-A, --add " "\fIsetname\fP \fIIP\fP"
|
||||
Add an IP to a set.
|
||||
.TP
|
||||
.BI "-D, --del " "\fIsetname\fP \fIIP\fP"
|
||||
Delete an IP from a set.
|
||||
.TP
|
||||
.BI "-T, --test " "\fIsetname\fP \fIIP
|
||||
Test wether an IP is in a set or not. Exit status number is zero
|
||||
if the tested IP is in the set and nonzero if it is missing from
|
||||
the set.
|
||||
.TP
|
||||
.BI "-T, --test " "\fIsetname\fP \fIIP\fP \fI--binding\fP \fIto-setname\fP"
|
||||
Test wether the IP belonging to the set points to the specified binding.
|
||||
Exit status number is zero if the binding points to the specified set,
|
||||
otherwise it is nonzero. The keyword
|
||||
.B
|
||||
:default:
|
||||
can be used to test the default binding of the set.
|
||||
.TP
|
||||
.BI "-B, --bind " "\fIsetname\fP \fIIP\fP \fI--binding\fP \fIto-setname\fP"
|
||||
Bind the IP in setname to to-setname.
|
||||
.TP
|
||||
.BI "-U, --unbind " "\fIsetname\fP \fIIP\fP"
|
||||
Delete the binding belonging to IP in set setname.
|
||||
.TP
|
||||
.BI "-H, --help " "[settype]"
|
||||
Print help and settype specific help if settype specified.
|
||||
.P
|
||||
At the
|
||||
.B
|
||||
-B, -U
|
||||
and
|
||||
.B
|
||||
-T
|
||||
commands you can use the token
|
||||
.B
|
||||
:default:
|
||||
to bind, unbind or test the default binding of a set instead
|
||||
of an IP. At the
|
||||
.B
|
||||
-U
|
||||
command you can use the token
|
||||
.B
|
||||
:all:
|
||||
to destroy the bindings of all elements of a set.
|
||||
.SS "OTHER OPTIONS"
|
||||
The following additional options can be specified:
|
||||
.TP
|
||||
.B "-b, --binding setname"
|
||||
The option specifies the value of the binding for the
|
||||
.B "-B"
|
||||
binding command, for which it is a mandatory option.
|
||||
You can use it in the
|
||||
.B "-T"
|
||||
test command as well to test bindings.
|
||||
.TP
|
||||
.B "-s, --sorted"
|
||||
Sorted output. When listing sets, entries are listed sorted.
|
||||
.TP
|
||||
.B "-n, --numeric"
|
||||
Numeric output. When listing sets, bindings, IP addresses and
|
||||
port numbers will be printed in numeric format. By default the
|
||||
program will try to display them as host names, network names
|
||||
or services (whenever applicable), which can trigger
|
||||
.B
|
||||
slow
|
||||
DNS
|
||||
lookups.
|
||||
.TP
|
||||
.B "-q, --quiet"
|
||||
Suppress any output to stdout and stderr. ipset will still return
|
||||
possible errors.
|
||||
.SH SET TYPES
|
||||
ipset supports the following set types:
|
||||
.SS ipmap
|
||||
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)
|
||||
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
|
||||
.B "--netmask"
|
||||
option with a CIDR netmask value between 0-32 when creating an ipmap
|
||||
set, you will be able to store and match network addresses: i.e an
|
||||
IP address will be in the set if the value resulted by masking the address
|
||||
with the specified netmask can be found in the set.
|
||||
.P
|
||||
Options to use when creating an ipmap set:
|
||||
.TP
|
||||
.BR "--from " from-IP
|
||||
.TP
|
||||
.BR "--to " to-IP
|
||||
Create an ipmap set from the specified range.
|
||||
.TP
|
||||
.BR "--network " IP/mask
|
||||
Create an ipmap set from the specified network.
|
||||
.TP
|
||||
.BR "--netmask " CIDR-netmask
|
||||
When the optional
|
||||
.B "--netmask"
|
||||
parameter specified, network addresses will be
|
||||
stored in the set instead of IP addresses, and the from-IP parameter
|
||||
must be a network address.
|
||||
.SS macipmap
|
||||
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
|
||||
up to 65536 (B-class network) IP addresses with MAC.
|
||||
When adding an entry to a macipmap set, you must specify the entry as
|
||||
.I IP:MAC.
|
||||
When deleting or testing macipmap entries, the
|
||||
.I :MAC
|
||||
part is not mandatory. (The old "%" separation token instead of ":", i.e
|
||||
IP%MAC is accepted as well.)
|
||||
.P
|
||||
Options to use when creating an macipmap set:
|
||||
.TP
|
||||
.BR "--from " from-IP
|
||||
.TP
|
||||
.BR "--to " to-IP
|
||||
Create a macipmap set from the specified range.
|
||||
.TP
|
||||
.BR "--network " IP/mask
|
||||
Create a macipmap set from the specified network.
|
||||
.TP
|
||||
.BR "--matchunset"
|
||||
When the optional
|
||||
.B "--matchunset"
|
||||
parameter specified, IP addresses which could be stored
|
||||
in the set but not set yet, will always match.
|
||||
.P
|
||||
Please note, the
|
||||
.I
|
||||
set
|
||||
and
|
||||
.I
|
||||
SET
|
||||
netfilter kernel modules
|
||||
.B
|
||||
always
|
||||
use the source MAC address from the packet to match, add or delete
|
||||
entries from a macipmap type of set.
|
||||
.SS portmap
|
||||
The portmap set type uses a memory range, where each bit represents
|
||||
one port. A portmap set type can store up to 65536 ports.
|
||||
The portmap set type is very fast and memory cheap.
|
||||
.P
|
||||
Options to use when creating an portmap set:
|
||||
.TP
|
||||
.BR "--from " from-port
|
||||
.TP
|
||||
.BR "--to " to-port
|
||||
Create a portmap set from the specified range.
|
||||
.SS iphash
|
||||
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
|
||||
resort, dynamic growing of the hash performed. The iphash set type is
|
||||
great to store random addresses. By supplyig the
|
||||
.B "--netmask"
|
||||
option with a CIDR netmask value between 0-32 at creating the set,
|
||||
you will be able to store and match network addresses instead: i.e
|
||||
an IP address will be in the set if the value of the address
|
||||
masked with the specified netmask can be found in the set.
|
||||
.P
|
||||
Options to use when creating an iphash set:
|
||||
.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.
|
||||
.TP
|
||||
.BR "--netmask " CIDR-netmask
|
||||
When the optional
|
||||
.B "--netmask"
|
||||
parameter specified, network addresses will be
|
||||
stored in the set instead of IP addresses.
|
||||
.P
|
||||
The iphash type of sets can store up to 65536 entries. If a set is full,
|
||||
no new entries can be added to it.
|
||||
.P
|
||||
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 value of the
|
||||
.B
|
||||
probes
|
||||
parameter. At the same time higher
|
||||
.B
|
||||
probes
|
||||
values result a better utilized hash while smaller values
|
||||
produce a larger, sparse hash.
|
||||
.SS nethash
|
||||
The nethash set type uses a hash to store different size of
|
||||
network addresses. The
|
||||
.I
|
||||
IP
|
||||
"address" used in the ipset commands must be in the form
|
||||
.I
|
||||
IP-address/cidr-size
|
||||
where the CIDR block size must be in the inclusive range of 1-31.
|
||||
In order to avoid clashes in the hash
|
||||
double-hashing, and as a last resort, dynamic growing of the hash performed.
|
||||
.P
|
||||
Options to use when creating an nethash set:
|
||||
.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 4).
|
||||
.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
|
||||
.P
|
||||
The nethash type of sets can store up to 65536 entries. If a set is full,
|
||||
no new entries can be added to it.
|
||||
.P
|
||||
An IP address will be in a nethash type of set if it is in any of the
|
||||
netblocks added to the set and the matching always start from the smallest
|
||||
size of netblock (most specific netmask) to the biggest ones (least
|
||||
specific netmasks). When adding/deleting IP addresses
|
||||
to a nethash set by the
|
||||
.I
|
||||
SET
|
||||
netfilter kernel module, it will be added/deleted by the smallest
|
||||
netblock size which can be found in the set.
|
||||
.P
|
||||
The lookup time in a nethash type of set is approximately linearly
|
||||
grows with the times of the
|
||||
.B
|
||||
probes
|
||||
parameter and the number of different mask parameters in the hash.
|
||||
Otherwise the same speed and memory efficiency comments applies here
|
||||
as at the iphash type.
|
||||
.SS ipporthash
|
||||
The ipporthash set type uses a hash to store IP address and port pairs.
|
||||
In order to avoid clashes in the hash double-hashing, and as a last
|
||||
resort, dynamic growing of the hash performed. An ipporthash set can
|
||||
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
|
||||
set, the entries must be specified as
|
||||
.B
|
||||
"IP:port".
|
||||
(Old "IP%port" format accepted as well.)
|
||||
.P
|
||||
The ipporthash types of sets evaluates two src/dst parameters of the
|
||||
.I
|
||||
set
|
||||
match and
|
||||
.I
|
||||
SET
|
||||
target.
|
||||
.P
|
||||
Options to use when creating an ipporthash 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
|
||||
The iptree set type uses a tree to store IP addresses, optionally
|
||||
with timeout values.
|
||||
.P
|
||||
Options to use when creating an iptree set:
|
||||
.TP
|
||||
.BR "--timeout " value
|
||||
The timeout value for the entries in seconds (default 0)
|
||||
.P
|
||||
If a set was created with a nonzero valued
|
||||
.B "--timeout"
|
||||
parameter then one may add IP addresses to the set with a specific
|
||||
timeout value using the syntax
|
||||
.I IP:timeout-value.
|
||||
Similarly to the hash types, the iptree type of sets can store up to 65536
|
||||
entries.
|
||||
.SS iptreemap
|
||||
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.
|
||||
As input entry, you can add IP addresses, CIDR blocks or network ranges
|
||||
to the set. Network ranges can be specified in the format
|
||||
.I IP1:IP2
|
||||
.P
|
||||
Options to use when creating an iptreemap set:
|
||||
.TP
|
||||
.BR "--gc " value
|
||||
How often the garbage collection should be called, in seconds (default 300)
|
||||
.SH GENERAL RESTRICTIONS
|
||||
Setnames starting with colon (:) cannot be defined. Zero valued set
|
||||
entries cannot be used with hash type of sets.
|
||||
.SH COMMENTS
|
||||
If you want to store same size subnets from a given network
|
||||
(say /24 blocks from a /8 network), use the ipmap set type.
|
||||
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 nethash.
|
||||
.SH DIAGNOSTICS
|
||||
Various error messages are printed to standard error. The exit code
|
||||
is 0 for correct functioning. Errors which appear to be caused by
|
||||
invalid or abused command line parameters cause an exit code of 2, and
|
||||
other errors cause an exit code of 1.
|
||||
.SH BUGS
|
||||
Bugs? No, just funny features. :-)
|
||||
OK, just kidding...
|
||||
.SH SEE ALSO
|
||||
.BR iptables (8),
|
||||
.SH AUTHORS
|
||||
Jozsef Kadlecsik wrote ipset, which is based on ippool by
|
||||
Joakim Axelsson, Patrick Schaaf and Martin Josefsson.
|
||||
.P
|
||||
Sven Wegener wrote the iptreemap type.
|
||||
.SH LAST REMARK
|
||||
.BR "I stand on the shoulder of giants."
|
||||
.\" .. and did I mention that we are incredibly cool people?
|
||||
.\" .. sexy, too ..
|
||||
.\" .. witty, charming, powerful ..
|
||||
.\" .. and most of all, modest ..
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,191 +0,0 @@
|
||||
#ifndef __IPSET_H
|
||||
#define __IPSET_H
|
||||
|
||||
/* Copyright 2000-2004 Joakim Axelsson (gozem@linux.nu)
|
||||
* Patrick Schaaf (bof@bof.de)
|
||||
* 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 <getopt.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
|
||||
|
||||
#define LIST_TRIES 5
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
extern int option_debug;
|
||||
#define DP(format, args...) if (option_debug) \
|
||||
do { \
|
||||
fprintf(stderr, "%s: %s (DBG): ", __FILE__, __FUNCTION__);\
|
||||
fprintf(stderr, format "\n" , ## args); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DP(format, args...)
|
||||
#endif
|
||||
|
||||
/* Commands */
|
||||
enum set_commands {
|
||||
CMD_NONE,
|
||||
CMD_CREATE, /* -N */
|
||||
CMD_DESTROY, /* -X */
|
||||
CMD_FLUSH, /* -F */
|
||||
CMD_RENAME, /* -E */
|
||||
CMD_SWAP, /* -W */
|
||||
CMD_LIST, /* -L */
|
||||
CMD_SAVE, /* -S */
|
||||
CMD_RESTORE, /* -R */
|
||||
CMD_ADD, /* -A */
|
||||
CMD_DEL, /* -D */
|
||||
CMD_TEST, /* -T */
|
||||
CMD_BIND, /* -B */
|
||||
CMD_UNBIND, /* -U */
|
||||
CMD_HELP, /* -H */
|
||||
CMD_VERSION, /* -V */
|
||||
NUMBER_OF_CMD = CMD_VERSION,
|
||||
/* Internal commands */
|
||||
CMD_MAX_SETS,
|
||||
CMD_LIST_SIZE,
|
||||
CMD_SAVE_SIZE,
|
||||
CMD_ADT_GET,
|
||||
};
|
||||
|
||||
enum exittype {
|
||||
OTHER_PROBLEM = 1,
|
||||
PARAMETER_PROBLEM,
|
||||
VERSION_PROBLEM
|
||||
};
|
||||
|
||||
/* The view of an ipset in userspace */
|
||||
struct set {
|
||||
char name[IP_SET_MAXNAMELEN]; /* Name of the set */
|
||||
ip_set_id_t id; /* Unique set id */
|
||||
ip_set_id_t index; /* Array index */
|
||||
unsigned ref; /* References in kernel */
|
||||
struct settype *settype; /* Pointer to set type functions */
|
||||
};
|
||||
|
||||
struct settype {
|
||||
struct settype *next;
|
||||
|
||||
char typename[IP_SET_MAXNAMELEN];
|
||||
|
||||
int protocol_version;
|
||||
|
||||
/*
|
||||
* Create set
|
||||
*/
|
||||
|
||||
/* Size of create data. Will be sent to kernel */
|
||||
size_t create_size;
|
||||
|
||||
/* Initialize the create. */
|
||||
void (*create_init) (void *data);
|
||||
|
||||
/* Function which parses command options; returns true if it ate an option */
|
||||
int (*create_parse) (int c, char *argv[], void *data,
|
||||
unsigned *flags);
|
||||
|
||||
/* Final check; exit if not ok. */
|
||||
void (*create_final) (void *data, unsigned int flags);
|
||||
|
||||
/* Pointer to list of extra command-line options for create */
|
||||
const struct option *create_opts;
|
||||
|
||||
/*
|
||||
* Add/del/test IP
|
||||
*/
|
||||
|
||||
/* Size of data. Will be sent to kernel */
|
||||
size_t adt_size;
|
||||
|
||||
/* Function which parses command options */
|
||||
ip_set_ip_t (*adt_parser) (unsigned cmd, const char *optarg, void *data);
|
||||
|
||||
/*
|
||||
* Printing
|
||||
*/
|
||||
|
||||
/* Size of header. */
|
||||
size_t header_size;
|
||||
|
||||
/* Initialize the type-header */
|
||||
void (*initheader) (struct set *set, const void *data);
|
||||
|
||||
/* Pretty print the type-header */
|
||||
void (*printheader) (struct set *set, unsigned options);
|
||||
|
||||
/* Pretty print all IPs */
|
||||
void (*printips) (struct set *set, void *data, size_t len, unsigned options);
|
||||
|
||||
/* Pretty print all IPs sorted */
|
||||
void (*printips_sorted) (struct set *set, void *data, size_t len, unsigned options);
|
||||
|
||||
/* Print save arguments for creating the set */
|
||||
void (*saveheader) (struct set *set, unsigned options);
|
||||
|
||||
/* Print save for all IPs */
|
||||
void (*saveips) (struct set *set, void *data, size_t len, unsigned options);
|
||||
|
||||
/* Conver a single IP (binding) to string */
|
||||
char * (*bindip_tostring)(struct set *set, ip_set_ip_t ip, unsigned options);
|
||||
|
||||
/* Parse an IP at restoring bindings. FIXME */
|
||||
void (*bindip_parse) (const char *str, ip_set_ip_t * ip);
|
||||
|
||||
/* Print usage */
|
||||
void (*usage) (void);
|
||||
|
||||
/* Internal data */
|
||||
void *header;
|
||||
void *data;
|
||||
unsigned int option_offset;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
extern void settype_register(struct settype *settype);
|
||||
|
||||
/* extern void unregister_settype(set_type_t *set_type); */
|
||||
|
||||
extern void exit_error(enum exittype status, const char *msg, ...);
|
||||
|
||||
extern char *binding_ip_tostring(struct set *set,
|
||||
ip_set_ip_t ip, unsigned options);
|
||||
extern char *ip_tostring(ip_set_ip_t ip, unsigned options);
|
||||
extern char *ip_tostring_numeric(ip_set_ip_t ip);
|
||||
extern void parse_ip(const char *str, ip_set_ip_t * ip);
|
||||
extern void parse_mask(const char *str, ip_set_ip_t * mask);
|
||||
extern void parse_ipandmask(const char *str, ip_set_ip_t * ip,
|
||||
ip_set_ip_t * mask);
|
||||
extern char *port_tostring(ip_set_ip_t port, unsigned options);
|
||||
extern void parse_port(const char *str, ip_set_ip_t * port);
|
||||
extern int string_to_number(const char *str, unsigned int min, unsigned int max,
|
||||
ip_set_ip_t *port);
|
||||
|
||||
extern void *ipset_malloc(size_t size);
|
||||
extern char *ipset_strdup(const char *);
|
||||
extern void ipset_free(void **data);
|
||||
|
||||
#define BITSPERBYTE (8*sizeof(char))
|
||||
#define ID2BYTE(id) ((id)/BITSPERBYTE)
|
||||
#define ID2MASK(id) (1 << ((id)%BITSPERBYTE))
|
||||
#define test_bit(id, heap) ((((char *)(heap))[ID2BYTE(id)] & ID2MASK(id)) != 0)
|
||||
|
||||
#endif /* __IPSET_H */
|
||||
@@ -1,299 +0,0 @@
|
||||
/* Copyright 2004 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 <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#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"
|
||||
|
||||
#define BUFLEN 30;
|
||||
|
||||
#define OPT_CREATE_HASHSIZE 0x01U
|
||||
#define OPT_CREATE_PROBES 0x02U
|
||||
#define OPT_CREATE_RESIZE 0x04U
|
||||
#define OPT_CREATE_NETMASK 0x08U
|
||||
|
||||
/* Initialize the create. */
|
||||
static void create_init(void *data)
|
||||
{
|
||||
struct ip_set_req_iphash_create *mydata =
|
||||
(struct ip_set_req_iphash_create *) data;
|
||||
|
||||
DP("create INIT");
|
||||
|
||||
/* Default create parameters */
|
||||
mydata->hashsize = 1024;
|
||||
mydata->probes = 8;
|
||||
mydata->resize = 50;
|
||||
|
||||
mydata->netmask = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ip_set_req_iphash_create *mydata =
|
||||
(struct ip_set_req_iphash_create *) data;
|
||||
unsigned int bits;
|
||||
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':
|
||||
|
||||
if (string_to_number(optarg, 0, 32, &bits))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Invalid netmask `%s' specified", optarg);
|
||||
|
||||
if (bits != 0)
|
||||
mydata->netmask = 0xFFFFFFFF << (32 - bits);
|
||||
|
||||
*flags |= OPT_CREATE_NETMASK;
|
||||
|
||||
DP("--netmask %x", mydata->netmask);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Final check; exit if not ok. */
|
||||
static void create_final(void *data, unsigned int flags)
|
||||
{
|
||||
#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 */
|
||||
static const struct option create_opts[] = {
|
||||
{"hashsize", 1, 0, '1'},
|
||||
{"probes", 1, 0, '2'},
|
||||
{"resize", 1, 0, '3'},
|
||||
{"netmask", 1, 0, '4'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_iphash *mydata =
|
||||
(struct ip_set_req_iphash *) data;
|
||||
|
||||
parse_ip(arg, &mydata->ip);
|
||||
if (!mydata->ip)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Zero valued IP address `%s' specified", arg);
|
||||
|
||||
return mydata->ip;
|
||||
};
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_iphash_create *header =
|
||||
(struct ip_set_req_iphash_create *) data;
|
||||
struct ip_set_iphash *map =
|
||||
(struct ip_set_iphash *) set->settype->header;
|
||||
|
||||
memset(map, 0, sizeof(struct ip_set_iphash));
|
||||
map->hashsize = header->hashsize;
|
||||
map->probes = header->probes;
|
||||
map->resize = header->resize;
|
||||
map->netmask = header->netmask;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
mask_to_bits(ip_set_ip_t mask)
|
||||
{
|
||||
unsigned int bits = 32;
|
||||
ip_set_ip_t maskaddr;
|
||||
|
||||
if (mask == 0xFFFFFFFF)
|
||||
return bits;
|
||||
|
||||
maskaddr = 0xFFFFFFFE;
|
||||
while (--bits >= 0 && maskaddr != mask)
|
||||
maskaddr <<= 1;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
static void printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_iphash *mysetdata =
|
||||
(struct ip_set_iphash *) set->settype->header;
|
||||
|
||||
printf(" hashsize: %u", mysetdata->hashsize);
|
||||
printf(" probes: %u", mysetdata->probes);
|
||||
printf(" resize: %u", mysetdata->resize);
|
||||
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
|
||||
}
|
||||
|
||||
static void printips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t *ip;
|
||||
|
||||
while (offset < len) {
|
||||
ip = data + offset;
|
||||
if (*ip)
|
||||
printf("%s\n", ip_tostring(*ip, options));
|
||||
offset += sizeof(ip_set_ip_t);
|
||||
}
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_iphash *mysetdata =
|
||||
(struct ip_set_iphash *) set->settype->header;
|
||||
|
||||
printf("-N %s %s --hashsize %u --probes %u --resize %u",
|
||||
set->name, set->settype->typename,
|
||||
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
|
||||
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" --netmask %d\n", mask_to_bits(mysetdata->netmask));
|
||||
}
|
||||
|
||||
/* Print save for an IP */
|
||||
static void saveips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t *ip;
|
||||
|
||||
while (offset < len) {
|
||||
ip = data + offset;
|
||||
if (*ip)
|
||||
printf("-A %s %s\n", set->name,
|
||||
ip_tostring(*ip, options));
|
||||
offset += sizeof(ip_set_ip_t);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set iphash [--hashsize hashsize] [--probes probes ]\n"
|
||||
" [--resize resize] [--netmask CIDR-netmask]\n"
|
||||
"-A set IP\n"
|
||||
"-D set IP\n"
|
||||
"-T set IP\n");
|
||||
}
|
||||
|
||||
static struct settype settype_iphash = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_iphash_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_iphash),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_iphash),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips, /* We only have the unsorted version */
|
||||
.printips_sorted = &printips,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &binding_ip_tostring,
|
||||
.bindip_parse = &parse_ip,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void iphash_init(void)
|
||||
{
|
||||
settype_register(&settype_iphash);
|
||||
|
||||
}
|
||||
@@ -1,362 +0,0 @@
|
||||
/* Copyright 2000-2004 Joakim Axelsson (gozem@linux.nu)
|
||||
* Patrick Schaaf (bof@bof.de)
|
||||
* 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 <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
/* #include <asm/bitops.h> */
|
||||
|
||||
#include "ip_set_ipmap.h"
|
||||
#include "ipset.h"
|
||||
|
||||
#define BUFLEN 30;
|
||||
|
||||
#define OPT_CREATE_FROM 0x01U
|
||||
#define OPT_CREATE_TO 0x02U
|
||||
#define OPT_CREATE_NETWORK 0x04U
|
||||
#define OPT_CREATE_NETMASK 0x08U
|
||||
|
||||
#define OPT_ADDDEL_IP 0x01U
|
||||
|
||||
/* Initialize the create. */
|
||||
static void create_init(void *data)
|
||||
{
|
||||
struct ip_set_req_ipmap_create *mydata =
|
||||
(struct ip_set_req_ipmap_create *) data;
|
||||
|
||||
DP("create INIT");
|
||||
mydata->netmask = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ip_set_req_ipmap_create *mydata =
|
||||
(struct ip_set_req_ipmap_create *) data;
|
||||
unsigned int bits;
|
||||
|
||||
DP("create_parse");
|
||||
|
||||
switch (c) {
|
||||
case '1':
|
||||
parse_ip(optarg, &mydata->from);
|
||||
|
||||
*flags |= OPT_CREATE_FROM;
|
||||
|
||||
DP("--from %x (%s)", mydata->from,
|
||||
ip_tostring_numeric(mydata->from));
|
||||
|
||||
break;
|
||||
|
||||
case '2':
|
||||
parse_ip(optarg, &mydata->to);
|
||||
|
||||
*flags |= OPT_CREATE_TO;
|
||||
|
||||
DP("--to %x (%s)", mydata->to,
|
||||
ip_tostring_numeric(mydata->to));
|
||||
|
||||
break;
|
||||
|
||||
case '3':
|
||||
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;
|
||||
|
||||
case '4':
|
||||
if (string_to_number(optarg, 0, 32, &bits))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Invalid netmask `%s' specified", optarg);
|
||||
|
||||
if (bits != 0)
|
||||
mydata->netmask = 0xFFFFFFFF << (32 - bits);
|
||||
|
||||
*flags |= OPT_CREATE_NETMASK;
|
||||
|
||||
DP("--netmask %x", mydata->netmask);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define ERRSTRLEN 256
|
||||
|
||||
/* Final check; exit if not ok. */
|
||||
static void create_final(void *data, unsigned int flags)
|
||||
{
|
||||
struct ip_set_req_ipmap_create *mydata =
|
||||
(struct ip_set_req_ipmap_create *) data;
|
||||
ip_set_ip_t range;
|
||||
char errstr[ERRSTRLEN];
|
||||
|
||||
if (flags == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Need to specify --from and --to, or --network\n");
|
||||
|
||||
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 {
|
||||
/* --from --to */
|
||||
if ((flags & OPT_CREATE_FROM) == 0
|
||||
|| (flags & OPT_CREATE_TO) == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Need to specify both --from and --to\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 lower than to.\n");
|
||||
|
||||
if (flags & OPT_CREATE_NETMASK) {
|
||||
unsigned int mask_bits, netmask_bits;
|
||||
ip_set_ip_t mask;
|
||||
|
||||
if ((mydata->from & mydata->netmask) != mydata->from)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"%s is not a network address according to netmask %d\n",
|
||||
ip_tostring_numeric(mydata->from),
|
||||
mask_to_bits(mydata->netmask));
|
||||
|
||||
mask = range_to_mask(mydata->from, mydata->to, &mask_bits);
|
||||
if (!mask
|
||||
&& (mydata->from || mydata->to != 0xFFFFFFFF)) {
|
||||
strncpy(errstr, ip_tostring_numeric(mydata->from),
|
||||
ERRSTRLEN-2);
|
||||
errstr[ERRSTRLEN-1] = '\0';
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"%s-%s is not a full network (%x)\n",
|
||||
errstr,
|
||||
ip_tostring_numeric(mydata->to), mask);
|
||||
}
|
||||
netmask_bits = mask_to_bits(mydata->netmask);
|
||||
|
||||
if (netmask_bits <= mask_bits) {
|
||||
strncpy(errstr, ip_tostring_numeric(mydata->from),
|
||||
ERRSTRLEN-2);
|
||||
errstr[ERRSTRLEN-1] = '\0';
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"%d netmask specifies larger or equal netblock than %s-%s (%d)\n",
|
||||
netmask_bits,
|
||||
errstr,
|
||||
ip_tostring_numeric(mydata->to),
|
||||
mask_bits);
|
||||
}
|
||||
range = (1<<(netmask_bits - mask_bits)) - 1;
|
||||
} else {
|
||||
range = mydata->to - mydata->from;
|
||||
}
|
||||
if (range > 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[] = {
|
||||
{"from", 1, 0, '1'},
|
||||
{"to", 1, 0, '2'},
|
||||
{"network", 1, 0, '3'},
|
||||
{"netmask", 1, 0, '4'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_ipmap *mydata =
|
||||
(struct ip_set_req_ipmap *) data;
|
||||
|
||||
DP("ipmap: %p %p", arg, data);
|
||||
|
||||
parse_ip(arg, &mydata->ip);
|
||||
DP("%s", ip_tostring_numeric(mydata->ip));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_ipmap_create *header =
|
||||
(struct ip_set_req_ipmap_create *) data;
|
||||
struct ip_set_ipmap *map =
|
||||
(struct ip_set_ipmap *) set->settype->header;
|
||||
|
||||
memset(map, 0, sizeof(struct ip_set_ipmap));
|
||||
map->first_ip = header->from;
|
||||
map->last_ip = header->to;
|
||||
map->netmask = header->netmask;
|
||||
|
||||
if (map->netmask == 0xFFFFFFFF) {
|
||||
map->hosts = 1;
|
||||
map->sizeid = map->last_ip - map->first_ip + 1;
|
||||
} else {
|
||||
unsigned int mask_bits, netmask_bits;
|
||||
ip_set_ip_t mask;
|
||||
|
||||
mask = range_to_mask(header->from, header->to, &mask_bits);
|
||||
netmask_bits = mask_to_bits(header->netmask);
|
||||
|
||||
DP("bits: %i %i", mask_bits, netmask_bits);
|
||||
map->hosts = 2 << (32 - netmask_bits - 1);
|
||||
map->sizeid = 2 << (netmask_bits - mask_bits - 1);
|
||||
}
|
||||
|
||||
DP("%i %i", map->hosts, map->sizeid );
|
||||
}
|
||||
|
||||
static void printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_ipmap *mysetdata =
|
||||
(struct ip_set_ipmap *) set->settype->header;
|
||||
|
||||
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
|
||||
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
|
||||
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
|
||||
}
|
||||
|
||||
static void printips_sorted(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_ipmap *mysetdata =
|
||||
(struct ip_set_ipmap *) set->settype->header;
|
||||
ip_set_ip_t id;
|
||||
|
||||
for (id = 0; id < mysetdata->sizeid; id++)
|
||||
if (test_bit(id, data))
|
||||
printf("%s\n",
|
||||
ip_tostring(mysetdata->first_ip
|
||||
+ id * mysetdata->hosts,
|
||||
options));
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_ipmap *mysetdata =
|
||||
(struct ip_set_ipmap *) 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));
|
||||
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||
printf("\n");
|
||||
else
|
||||
printf(" --netmask %d\n",
|
||||
mask_to_bits(mysetdata->netmask));
|
||||
}
|
||||
|
||||
static void saveips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_ipmap *mysetdata =
|
||||
(struct ip_set_ipmap *) set->settype->header;
|
||||
ip_set_ip_t id;
|
||||
|
||||
DP("%s", set->name);
|
||||
for (id = 0; id < mysetdata->sizeid; id++)
|
||||
if (test_bit(id, data))
|
||||
printf("-A %s %s\n",
|
||||
set->name,
|
||||
ip_tostring(mysetdata->first_ip
|
||||
+ id * mysetdata->hosts,
|
||||
options));
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set ipmap --from IP --to IP [--netmask CIDR-netmask]\n"
|
||||
"-N set ipmap --network IP/mask [--netmask CIDR-netmask]\n"
|
||||
"-A set IP\n"
|
||||
"-D set IP\n"
|
||||
"-T set IP\n");
|
||||
}
|
||||
|
||||
static struct settype settype_ipmap = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_ipmap_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_ipmap),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_ipmap),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips_sorted, /* We only have sorted version */
|
||||
.printips_sorted = &printips_sorted,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &binding_ip_tostring,
|
||||
.bindip_parse = &parse_ip,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void ipmap_init(void)
|
||||
{
|
||||
settype_register(&settype_ipmap);
|
||||
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
/* Copyright 2004 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 <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#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"
|
||||
|
||||
#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_ipporthash_create *mydata =
|
||||
(struct ip_set_req_ipporthash_create *) 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[], void *data, unsigned int *flags)
|
||||
{
|
||||
struct ip_set_req_ipporthash_create *mydata =
|
||||
(struct ip_set_req_ipporthash_create *) 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_ipporthash_create *mydata =
|
||||
(struct ip_set_req_ipporthash_create *) 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[] = {
|
||||
{"hashsize", 1, 0, '1'},
|
||||
{"probes", 1, 0, '2'},
|
||||
{"resize", 1, 0, '3'},
|
||||
{"from", 1, 0, '4'},
|
||||
{"to", 1, 0, '5'},
|
||||
{"network", 1, 0, '6'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_ipporthash *mydata =
|
||||
(struct ip_set_req_ipporthash *) data;
|
||||
char *saved = ipset_strdup(arg);
|
||||
char *ptr, *tmp = saved;
|
||||
|
||||
DP("ipporthash: %p %p", arg, data);
|
||||
|
||||
ptr = strsep(&tmp, ":%");
|
||||
parse_ip(ptr, &mydata->ip);
|
||||
|
||||
if (tmp)
|
||||
parse_port(tmp, &mydata->port);
|
||||
else
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"IP address and port must be specified: ip%%port");
|
||||
free(saved);
|
||||
return 1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_ipporthash_create *header =
|
||||
(struct ip_set_req_ipporthash_create *) data;
|
||||
struct ip_set_ipporthash *map =
|
||||
(struct ip_set_ipporthash *) set->settype->header;
|
||||
|
||||
memset(map, 0, sizeof(struct ip_set_ipporthash));
|
||||
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 int options)
|
||||
{
|
||||
struct ip_set_ipporthash *mysetdata =
|
||||
(struct ip_set_ipporthash *) 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, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_ipporthash *mysetdata =
|
||||
(struct ip_set_ipporthash *) set->settype->header;
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t *ipptr, ip;
|
||||
uint16_t port;
|
||||
|
||||
while (offset < len) {
|
||||
ipptr = data + offset;
|
||||
if (*ipptr) {
|
||||
ip = (*ipptr>>16) + mysetdata->first_ip;
|
||||
port = (uint16_t) *ipptr;
|
||||
printf("%s:%s\n",
|
||||
ip_tostring(ip, options),
|
||||
port_tostring(port, options));
|
||||
}
|
||||
offset += sizeof(ip_set_ip_t);
|
||||
}
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_ipporthash *mysetdata =
|
||||
(struct ip_set_ipporthash *) 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, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_ipporthash *mysetdata =
|
||||
(struct ip_set_ipporthash *) set->settype->header;
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t *ipptr, ip;
|
||||
uint16_t port;
|
||||
|
||||
while (offset < len) {
|
||||
ipptr = data + offset;
|
||||
if (*ipptr) {
|
||||
ip = (*ipptr>>16) + mysetdata->first_ip;
|
||||
port = (uint16_t) *ipptr;
|
||||
printf("-A %s %s:%s\n", set->name,
|
||||
ip_tostring(ip, options),
|
||||
port_tostring(port, options));
|
||||
}
|
||||
offset += sizeof(ip_set_ip_t);
|
||||
}
|
||||
}
|
||||
|
||||
static char buffer[22];
|
||||
|
||||
static char * unpack_ipport_tostring(struct set *set, ip_set_ip_t bip, unsigned options)
|
||||
{
|
||||
struct ip_set_ipporthash *mysetdata =
|
||||
(struct ip_set_ipporthash *) set->settype->header;
|
||||
ip_set_ip_t ip, port;
|
||||
|
||||
ip = (bip>>16) + mysetdata->first_ip;
|
||||
port = (uint16_t) bip;
|
||||
sprintf(buffer, "%s:%s",
|
||||
ip_tostring(ip, options), port_tostring(port, options));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set ipporthash --from IP --to IP\n"
|
||||
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
|
||||
"-N set ipporthash --network IP/mask\n"
|
||||
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
|
||||
"-A set IP:port\n"
|
||||
"-D set IP:port\n"
|
||||
"-T set IP:port\n");
|
||||
}
|
||||
|
||||
static struct settype settype_ipporthash = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_ipporthash_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_ipporthash),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_ipporthash),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips, /* We only have the unsorted version */
|
||||
.printips_sorted = &printips,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &unpack_ipport_tostring,
|
||||
.bindip_parse = &parse_ip,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void ipporthash_init(void)
|
||||
{
|
||||
settype_register(&settype_ipporthash);
|
||||
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
/* Copyright 2005 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>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "ip_set_iptree.h"
|
||||
#include "ipset.h"
|
||||
|
||||
#define BUFLEN 30;
|
||||
|
||||
#define OPT_CREATE_TIMEOUT 0x01U
|
||||
|
||||
/* Initialize the create. */
|
||||
static void create_init(void *data)
|
||||
{
|
||||
struct ip_set_req_iptree_create *mydata =
|
||||
(struct ip_set_req_iptree_create *) data;
|
||||
|
||||
DP("create INIT");
|
||||
mydata->timeout = 0;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ip_set_req_iptree_create *mydata =
|
||||
(struct ip_set_req_iptree_create *) data;
|
||||
|
||||
DP("create_parse");
|
||||
|
||||
switch (c) {
|
||||
case '1':
|
||||
string_to_number(optarg, 0, UINT_MAX, &mydata->timeout);
|
||||
|
||||
*flags |= OPT_CREATE_TIMEOUT;
|
||||
|
||||
DP("--timeout %u", mydata->timeout);
|
||||
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Final check; exit if not ok. */
|
||||
static void create_final(void *data, unsigned int flags)
|
||||
{
|
||||
}
|
||||
|
||||
/* Create commandline options */
|
||||
static const struct option create_opts[] = {
|
||||
{"timeout", 1, 0, '1'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_iptree *mydata =
|
||||
(struct ip_set_req_iptree *) data;
|
||||
char *saved = ipset_strdup(arg);
|
||||
char *ptr, *tmp = saved;
|
||||
|
||||
DP("iptree: %p %p", arg, data);
|
||||
|
||||
ptr = strsep(&tmp, ":%");
|
||||
parse_ip(ptr, &mydata->ip);
|
||||
|
||||
if (tmp)
|
||||
string_to_number(tmp, 0, UINT_MAX, &mydata->timeout);
|
||||
else
|
||||
mydata->timeout = 0;
|
||||
|
||||
free(saved);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_iptree_create *header =
|
||||
(struct ip_set_req_iptree_create *) data;
|
||||
struct ip_set_iptree *map =
|
||||
(struct ip_set_iptree *) set->settype->header;
|
||||
|
||||
map->timeout = header->timeout;
|
||||
}
|
||||
|
||||
static void printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_iptree *mysetdata =
|
||||
(struct ip_set_iptree *) set->settype->header;
|
||||
|
||||
if (mysetdata->timeout)
|
||||
printf(" timeout: %u", mysetdata->timeout);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void printips_sorted(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_iptree *mysetdata =
|
||||
(struct ip_set_iptree *) set->settype->header;
|
||||
struct ip_set_req_iptree *req;
|
||||
size_t offset = 0;
|
||||
|
||||
while (len >= offset + sizeof(struct ip_set_req_iptree)) {
|
||||
req = (struct ip_set_req_iptree *)(data + offset);
|
||||
if (mysetdata->timeout)
|
||||
printf("%s:%u\n", ip_tostring(req->ip, options),
|
||||
req->timeout);
|
||||
else
|
||||
printf("%s\n", ip_tostring(req->ip, options));
|
||||
offset += sizeof(struct ip_set_req_iptree);
|
||||
}
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_iptree *mysetdata =
|
||||
(struct ip_set_iptree *) set->settype->header;
|
||||
|
||||
if (mysetdata->timeout)
|
||||
printf("-N %s %s --timeout %u\n",
|
||||
set->name, set->settype->typename,
|
||||
mysetdata->timeout);
|
||||
else
|
||||
printf("-N %s %s\n",
|
||||
set->name, set->settype->typename);
|
||||
}
|
||||
|
||||
static void saveips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_iptree *mysetdata =
|
||||
(struct ip_set_iptree *) set->settype->header;
|
||||
struct ip_set_req_iptree *req;
|
||||
size_t offset = 0;
|
||||
|
||||
DP("%s", set->name);
|
||||
|
||||
while (len >= offset + sizeof(struct ip_set_req_iptree)) {
|
||||
req = (struct ip_set_req_iptree *)(data + offset);
|
||||
if (mysetdata->timeout)
|
||||
printf("-A %s %s:%u\n",
|
||||
set->name,
|
||||
ip_tostring(req->ip, options),
|
||||
req->timeout);
|
||||
else
|
||||
printf("-A %s %s\n",
|
||||
set->name,
|
||||
ip_tostring(req->ip, options));
|
||||
offset += sizeof(struct ip_set_req_iptree);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set iptree [--timeout value]\n"
|
||||
"-A set IP[:timeout]\n"
|
||||
"-D set IP\n"
|
||||
"-T set IP\n");
|
||||
}
|
||||
|
||||
static struct settype settype_iptree = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_iptree_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_iptree),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_iptree),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips_sorted, /* We only have sorted version */
|
||||
.printips_sorted = &printips_sorted,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &binding_ip_tostring,
|
||||
.bindip_parse = &parse_ip,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void iptree_init(void)
|
||||
{
|
||||
settype_register(&settype_iptree);
|
||||
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
/* Copyright 2007 Sven Wegener <sven.wegener@stealer.net>
|
||||
*
|
||||
* 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>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "ip_set_iptreemap.h"
|
||||
|
||||
#include "ipset.h"
|
||||
|
||||
#define OPT_CREATE_GC 0x1
|
||||
|
||||
static void
|
||||
create_init(void *data)
|
||||
{
|
||||
struct ip_set_req_iptreemap_create *mydata = data;
|
||||
|
||||
mydata->gc_interval = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||
{
|
||||
struct ip_set_req_iptreemap_create *mydata = data;
|
||||
|
||||
switch (c) {
|
||||
case 'g':
|
||||
string_to_number(optarg, 0, UINT_MAX, &mydata->gc_interval);
|
||||
|
||||
*flags |= OPT_CREATE_GC;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
create_final(void *data, unsigned int flags)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct option create_opts[] = {
|
||||
{"gc", 1, 0, 'g'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static ip_set_ip_t
|
||||
adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_iptreemap *mydata = data;
|
||||
ip_set_ip_t mask;
|
||||
|
||||
char *saved = ipset_strdup(arg);
|
||||
char *ptr, *tmp = saved;
|
||||
|
||||
if (strchr(tmp, '/')) {
|
||||
parse_ipandmask(tmp, &mydata->start, &mask);
|
||||
mydata->end = mydata->start | ~mask;
|
||||
} else {
|
||||
ptr = strsep(&tmp, ":");
|
||||
parse_ip(ptr, &mydata->start);
|
||||
|
||||
if (tmp) {
|
||||
parse_ip(tmp, &mydata->end);
|
||||
} else {
|
||||
mydata->end = mydata->start;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
initheader(struct set *set, const void *data)
|
||||
{
|
||||
const struct ip_set_req_iptreemap_create *header = data;
|
||||
struct ip_set_iptreemap *map = set->settype->header;
|
||||
|
||||
map->gc_interval = header->gc_interval;
|
||||
}
|
||||
|
||||
static void
|
||||
printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_iptreemap *mysetdata = set->settype->header;
|
||||
|
||||
if (mysetdata->gc_interval)
|
||||
printf(" gc: %u", mysetdata->gc_interval);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
printips_sorted(struct set *set, void *data, size_t len, unsigned int options)
|
||||
{
|
||||
struct ip_set_req_iptreemap *req;
|
||||
size_t offset = 0;
|
||||
|
||||
while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
|
||||
req = data + offset;
|
||||
|
||||
printf("%s", ip_tostring(req->start, options));
|
||||
if (req->start != req->end)
|
||||
printf(":%s", ip_tostring(req->end, options));
|
||||
printf("\n");
|
||||
|
||||
offset += sizeof(struct ip_set_req_iptreemap);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_iptreemap *mysetdata = set->settype->header;
|
||||
|
||||
printf("-N %s %s", set->name, set->settype->typename);
|
||||
|
||||
if (mysetdata->gc_interval)
|
||||
printf(" --gc %u", mysetdata->gc_interval);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
saveips(struct set *set, void *data, size_t len, unsigned int options)
|
||||
{
|
||||
struct ip_set_req_iptreemap *req;
|
||||
size_t offset = 0;
|
||||
|
||||
while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
|
||||
req = data + offset;
|
||||
|
||||
printf("-A %s %s", set->name, ip_tostring(req->start, options));
|
||||
|
||||
if (req->start != req->end)
|
||||
printf(":%s", ip_tostring(req->end, options));
|
||||
|
||||
printf("\n");
|
||||
|
||||
offset += sizeof(struct ip_set_req_iptreemap);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
printf(
|
||||
"-N set iptreemap --gc interval\n"
|
||||
"-A set IP\n"
|
||||
"-D set IP\n"
|
||||
"-T set IP\n"
|
||||
);
|
||||
}
|
||||
|
||||
static struct settype settype_iptreemap = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
.create_size = sizeof(struct ip_set_req_iptreemap_create),
|
||||
.create_init = &create_init,
|
||||
.create_parse = &create_parse,
|
||||
.create_final = &create_final,
|
||||
.create_opts = create_opts,
|
||||
|
||||
.adt_size = sizeof(struct ip_set_req_iptreemap),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
.header_size = sizeof(struct ip_set_iptreemap),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips_sorted,
|
||||
.printips_sorted = &printips_sorted,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
.bindip_tostring = &binding_ip_tostring,
|
||||
.bindip_parse = &parse_ip,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void iptreemap_init(void)
|
||||
{
|
||||
settype_register(&settype_iptreemap);
|
||||
}
|
||||
@@ -1,341 +0,0 @@
|
||||
/* Copyright 2000, 2001, 2002 Joakim Axelsson (gozem@linux.nu)
|
||||
* Patrick Schaaf (bof@bof.de)
|
||||
* Martin Josefsson (gandalf@wlug.westbo.se)
|
||||
*
|
||||
* 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 <linux/if_ether.h>
|
||||
|
||||
#include "ip_set_macipmap.h"
|
||||
#include "ipset.h"
|
||||
|
||||
#define BUFLEN 30;
|
||||
|
||||
#define OPT_CREATE_FROM 0x01U
|
||||
#define OPT_CREATE_TO 0x02U
|
||||
#define OPT_CREATE_NETWORK 0x04U
|
||||
#define OPT_CREATE_MATCHUNSET 0x08U
|
||||
|
||||
#define OPT_ADDDEL_IP 0x01U
|
||||
#define OPT_ADDDEL_MAC 0x02U
|
||||
|
||||
/* Initialize the create. */
|
||||
static void create_init(void *data)
|
||||
{
|
||||
DP("create INIT");
|
||||
/* Nothing */
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ip_set_req_macipmap_create *mydata =
|
||||
(struct ip_set_req_macipmap_create *) data;
|
||||
|
||||
DP("create_parse");
|
||||
|
||||
switch (c) {
|
||||
case '1':
|
||||
parse_ip(optarg, &mydata->from);
|
||||
|
||||
*flags |= OPT_CREATE_FROM;
|
||||
|
||||
DP("--from %x (%s)", mydata->from,
|
||||
ip_tostring_numeric(mydata->from));
|
||||
|
||||
break;
|
||||
|
||||
case '2':
|
||||
parse_ip(optarg, &mydata->to);
|
||||
|
||||
*flags |= OPT_CREATE_TO;
|
||||
|
||||
DP("--to %x (%s)", mydata->to,
|
||||
ip_tostring_numeric(mydata->to));
|
||||
|
||||
break;
|
||||
|
||||
case '3':
|
||||
parse_ipandmask(optarg, &mydata->from, &mydata->to);
|
||||
|
||||
/* Make to the last of from + mask */
|
||||
mydata->to = mydata->from | (~mydata->to);
|
||||
|
||||
*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;
|
||||
|
||||
case '4':
|
||||
mydata->flags |= IPSET_MACIP_MATCHUNSET;
|
||||
|
||||
*flags |= OPT_CREATE_MATCHUNSET;
|
||||
|
||||
DP("--matchunset");
|
||||
|
||||
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_macipmap_create *mydata =
|
||||
(struct ip_set_req_macipmap_create *) data;
|
||||
|
||||
if (flags == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Need to specify --from and --to, or --network\n");
|
||||
|
||||
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 {
|
||||
/* --from --to */
|
||||
if ((flags & OPT_CREATE_FROM) == 0
|
||||
|| (flags & OPT_CREATE_TO) == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Need to specify both --from and --to\n");
|
||||
}
|
||||
|
||||
|
||||
DP("from : %x to: %x diff: %d match unset: %d", mydata->from,
|
||||
mydata->to, mydata->to - mydata->from,
|
||||
flags & OPT_CREATE_MATCHUNSET);
|
||||
|
||||
if (mydata->from > mydata->to)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"From can't be lower 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[] = {
|
||||
{"from", 1, 0, '1'},
|
||||
{"to", 1, 0, '2'},
|
||||
{"network", 1, 0, '3'},
|
||||
{"matchunset", 0, 0, '4'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void parse_mac(const char *mac, unsigned char *ethernet)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
if (strlen(mac) != ETH_ALEN * 3 - 1)
|
||||
exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac);
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
long number;
|
||||
char *end;
|
||||
|
||||
number = strtol(mac + i * 3, &end, 16);
|
||||
|
||||
if (end == mac + i * 3 + 2 && number >= 0 && number <= 255)
|
||||
ethernet[i] = number;
|
||||
else
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Bad mac address `%s'", mac);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_macipmap *mydata =
|
||||
(struct ip_set_req_macipmap *) data;
|
||||
char *saved = ipset_strdup(arg);
|
||||
char *ptr, *tmp = saved;
|
||||
|
||||
DP("macipmap: %p %p", arg, data);
|
||||
|
||||
ptr = strsep(&tmp, ":%");
|
||||
parse_ip(ptr, &mydata->ip);
|
||||
|
||||
if (tmp)
|
||||
parse_mac(tmp, mydata->ethernet);
|
||||
else
|
||||
memset(mydata->ethernet, 0, ETH_ALEN);
|
||||
|
||||
free(saved);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_macipmap_create *header =
|
||||
(struct ip_set_req_macipmap_create *) data;
|
||||
struct ip_set_macipmap *map =
|
||||
(struct ip_set_macipmap *) set->settype->header;
|
||||
|
||||
memset(map, 0, sizeof(struct ip_set_macipmap));
|
||||
map->first_ip = header->from;
|
||||
map->last_ip = header->to;
|
||||
map->flags = header->flags;
|
||||
}
|
||||
|
||||
static void printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_macipmap *mysetdata =
|
||||
(struct ip_set_macipmap *) set->settype->header;
|
||||
|
||||
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
|
||||
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
|
||||
|
||||
if (mysetdata->flags & IPSET_MACIP_MATCHUNSET)
|
||||
printf(" matchunset");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void print_mac(unsigned char macaddress[ETH_ALEN])
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
printf("%02X", macaddress[0]);
|
||||
for (i = 1; i < ETH_ALEN; i++)
|
||||
printf(":%02X", macaddress[i]);
|
||||
}
|
||||
|
||||
static void printips_sorted(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_macipmap *mysetdata =
|
||||
(struct ip_set_macipmap *) set->settype->header;
|
||||
struct ip_set_macip *table =
|
||||
(struct ip_set_macip *) data;
|
||||
u_int32_t addr = mysetdata->first_ip;
|
||||
|
||||
while (addr <= mysetdata->last_ip) {
|
||||
if (test_bit(IPSET_MACIP_ISSET,
|
||||
(void *)&table[addr - mysetdata->first_ip].flags)) {
|
||||
printf("%s:", ip_tostring(addr, options));
|
||||
print_mac(table[addr - mysetdata->first_ip].
|
||||
ethernet);
|
||||
printf("\n");
|
||||
}
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_macipmap *mysetdata =
|
||||
(struct ip_set_macipmap *) 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));
|
||||
|
||||
if (mysetdata->flags & IPSET_MACIP_MATCHUNSET)
|
||||
printf(" --matchunset");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void saveips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_macipmap *mysetdata =
|
||||
(struct ip_set_macipmap *) set->settype->header;
|
||||
struct ip_set_macip *table =
|
||||
(struct ip_set_macip *) data;
|
||||
u_int32_t addr = mysetdata->first_ip;
|
||||
|
||||
while (addr <= mysetdata->last_ip) {
|
||||
if (test_bit(IPSET_MACIP_ISSET,
|
||||
(void *)&table[addr - mysetdata->first_ip].flags)) {
|
||||
printf("-A %s %s:",
|
||||
set->name, ip_tostring(addr, options));
|
||||
print_mac(table[addr - mysetdata->first_ip].
|
||||
ethernet);
|
||||
printf("\n");
|
||||
}
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set macipmap --from IP --to IP [--matchunset]\n"
|
||||
"-N set macipmap --network IP/mask [--matchunset]\n"
|
||||
"-A set IP:MAC\n"
|
||||
"-D set IP[:MAC]\n"
|
||||
"-T set IP[:MAC]\n");
|
||||
}
|
||||
|
||||
static struct settype settype_macipmap = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_macipmap_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_macipmap),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_macipmap),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips_sorted, /* We only have sorted version */
|
||||
.printips_sorted = &printips_sorted,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &binding_ip_tostring,
|
||||
.bindip_parse = &parse_ip,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void macipmap_init(void)
|
||||
{
|
||||
settype_register(&settype_macipmap);
|
||||
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
/* Copyright 2004 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 <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#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"
|
||||
|
||||
#define BUFLEN 30;
|
||||
|
||||
#define OPT_CREATE_HASHSIZE 0x01U
|
||||
#define OPT_CREATE_PROBES 0x02U
|
||||
#define OPT_CREATE_RESIZE 0x04U
|
||||
|
||||
/* Initialize the create. */
|
||||
static void create_init(void *data)
|
||||
{
|
||||
struct ip_set_req_nethash_create *mydata =
|
||||
(struct ip_set_req_nethash_create *) data;
|
||||
|
||||
DP("create INIT");
|
||||
|
||||
/* Default create parameters */
|
||||
mydata->hashsize = 1024;
|
||||
mydata->probes = 4;
|
||||
mydata->resize = 50;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ip_set_req_nethash_create *mydata =
|
||||
(struct ip_set_req_nethash_create *) 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;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Final check; exit if not ok. */
|
||||
static void create_final(void *data, unsigned int flags)
|
||||
{
|
||||
#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 */
|
||||
static const struct option create_opts[] = {
|
||||
{"hashsize", 1, 0, '1'},
|
||||
{"probes", 1, 0, '2'},
|
||||
{"resize", 1, 0, '3'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_nethash *mydata =
|
||||
(struct ip_set_req_nethash *) data;
|
||||
char *saved = ipset_strdup(arg);
|
||||
char *ptr, *tmp = saved;
|
||||
ip_set_ip_t cidr;
|
||||
|
||||
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->ip);
|
||||
if (!mydata->ip)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Zero valued IP address `%s' specified", ptr);
|
||||
free(saved);
|
||||
|
||||
return mydata->ip;
|
||||
};
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_nethash_create *header =
|
||||
(struct ip_set_req_nethash_create *) data;
|
||||
struct ip_set_nethash *map =
|
||||
(struct ip_set_nethash *) set->settype->header;
|
||||
|
||||
memset(map, 0, sizeof(struct ip_set_nethash));
|
||||
map->hashsize = header->hashsize;
|
||||
map->probes = header->probes;
|
||||
map->resize = header->resize;
|
||||
}
|
||||
|
||||
static void printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_nethash *mysetdata =
|
||||
(struct ip_set_nethash *) set->settype->header;
|
||||
|
||||
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)
|
||||
{
|
||||
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), options), buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void printips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t *ip;
|
||||
|
||||
while (offset < len) {
|
||||
ip = data + offset;
|
||||
if (*ip)
|
||||
printf("%s\n", unpack_ip_tostring(*ip, options));
|
||||
offset += sizeof(ip_set_ip_t);
|
||||
}
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_nethash *mysetdata =
|
||||
(struct ip_set_nethash *) set->settype->header;
|
||||
|
||||
printf("-N %s %s --hashsize %u --probes %u --resize %u\n",
|
||||
set->name, set->settype->typename,
|
||||
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
|
||||
}
|
||||
|
||||
/* Print save for an IP */
|
||||
static void saveips(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
size_t offset = 0;
|
||||
ip_set_ip_t *ip;
|
||||
|
||||
while (offset < len) {
|
||||
ip = data + offset;
|
||||
if (*ip)
|
||||
printf("-A %s %s\n", set->name,
|
||||
unpack_ip_tostring(*ip, options));
|
||||
offset += sizeof(ip_set_ip_t);
|
||||
}
|
||||
}
|
||||
|
||||
static char * net_tostring(struct set *set, ip_set_ip_t ip, unsigned options)
|
||||
{
|
||||
return unpack_ip_tostring(ip, options);
|
||||
}
|
||||
|
||||
static void parse_net(const char *str, ip_set_ip_t *ip)
|
||||
{
|
||||
char *saved = strdup(str);
|
||||
char *ptr, *tmp = saved;
|
||||
ip_set_ip_t cidr;
|
||||
|
||||
ptr = strsep(&tmp, "/");
|
||||
|
||||
if (tmp == NULL)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Missing cidr from `%s'", str);
|
||||
|
||||
if (string_to_number(tmp, 1, 31, &cidr))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Out of range cidr `%s' specified", str);
|
||||
|
||||
parse_ip(ptr, ip);
|
||||
free(saved);
|
||||
|
||||
*ip = pack(*ip, cidr);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set nethash [--hashsize hashsize] [--probes probes ]\n"
|
||||
" [--resize resize]\n"
|
||||
"-A set IP/cidr\n"
|
||||
"-D set IP/cidr\n"
|
||||
"-T set IP/cidr\n");
|
||||
}
|
||||
|
||||
static struct settype settype_nethash = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_nethash_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_nethash),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_nethash),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printips, /* We only have the unsorted version */
|
||||
.printips_sorted = &printips,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveips,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &net_tostring,
|
||||
.bindip_parse = &parse_net,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void nethash_init(void)
|
||||
{
|
||||
settype_register(&settype_nethash);
|
||||
|
||||
}
|
||||
@@ -1,247 +0,0 @@
|
||||
/* Copyright 2004 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 <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "ip_set_portmap.h"
|
||||
#include "ipset.h"
|
||||
|
||||
|
||||
#define BUFLEN 30;
|
||||
|
||||
#define OPT_CREATE_FROM 0x01U
|
||||
#define OPT_CREATE_TO 0x02U
|
||||
|
||||
#define OPT_ADDDEL_PORT 0x01U
|
||||
|
||||
/* Initialize the create. */
|
||||
static void create_init(void *data)
|
||||
{
|
||||
DP("create INIT");
|
||||
/* Nothing */
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct ip_set_req_portmap_create *mydata =
|
||||
(struct ip_set_req_portmap_create *) data;
|
||||
|
||||
DP("create_parse");
|
||||
|
||||
switch (c) {
|
||||
case '1':
|
||||
parse_port(optarg, &mydata->from);
|
||||
|
||||
*flags |= OPT_CREATE_FROM;
|
||||
|
||||
DP("--from %x (%s)", mydata->from,
|
||||
port_tostring(mydata->from, 0));
|
||||
|
||||
break;
|
||||
|
||||
case '2':
|
||||
parse_port(optarg, &mydata->to);
|
||||
|
||||
*flags |= OPT_CREATE_TO;
|
||||
|
||||
DP("--to %x (%s)", mydata->to,
|
||||
port_tostring(mydata->to, 0));
|
||||
|
||||
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_portmap_create *mydata =
|
||||
(struct ip_set_req_portmap_create *) data;
|
||||
|
||||
if (flags == 0) {
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Need to specify --from and --to\n");
|
||||
} else {
|
||||
/* --from --to */
|
||||
if ((flags & OPT_CREATE_FROM) == 0
|
||||
|| (flags & OPT_CREATE_TO) == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Need to specify both --from and --to\n");
|
||||
}
|
||||
|
||||
DP("from : %x to: %x diff: %d", mydata->from, mydata->to,
|
||||
mydata->to - mydata->from);
|
||||
|
||||
if (mydata->from > mydata->to)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"From can't be lower than to.\n");
|
||||
|
||||
if (mydata->to - mydata->from > MAX_RANGE)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Range too large. Max is %d ports in range\n",
|
||||
MAX_RANGE+1);
|
||||
}
|
||||
|
||||
/* Create commandline options */
|
||||
static const struct option create_opts[] = {
|
||||
{"from", 1, 0, '1'},
|
||||
{"to", 1, 0, '2'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
/* Add, del, test parser */
|
||||
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||
{
|
||||
struct ip_set_req_portmap *mydata =
|
||||
(struct ip_set_req_portmap *) data;
|
||||
|
||||
parse_port(arg, &mydata->port);
|
||||
DP("%s", port_tostring(mydata->port, 0));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print and save
|
||||
*/
|
||||
|
||||
static void initheader(struct set *set, const void *data)
|
||||
{
|
||||
struct ip_set_req_portmap_create *header =
|
||||
(struct ip_set_req_portmap_create *) data;
|
||||
struct ip_set_portmap *map =
|
||||
(struct ip_set_portmap *) set->settype->header;
|
||||
|
||||
memset(map, 0, sizeof(struct ip_set_portmap));
|
||||
map->first_port = header->from;
|
||||
map->last_port = header->to;
|
||||
}
|
||||
|
||||
static void printheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_portmap *mysetdata =
|
||||
(struct ip_set_portmap *) set->settype->header;
|
||||
|
||||
printf(" from: %s", port_tostring(mysetdata->first_port, options));
|
||||
printf(" to: %s\n", port_tostring(mysetdata->last_port, options));
|
||||
}
|
||||
|
||||
static void printports_sorted(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_portmap *mysetdata =
|
||||
(struct ip_set_portmap *) set->settype->header;
|
||||
u_int32_t addr = mysetdata->first_port;
|
||||
|
||||
DP("%u -- %u", mysetdata->first_port, mysetdata->last_port);
|
||||
while (addr <= mysetdata->last_port) {
|
||||
if (test_bit(addr - mysetdata->first_port, data))
|
||||
printf("%s\n", port_tostring(addr, options));
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
static char *binding_port_tostring(struct set *set, ip_set_ip_t ip,
|
||||
unsigned int options)
|
||||
{
|
||||
return port_tostring(ip, options);
|
||||
}
|
||||
|
||||
static void saveheader(struct set *set, unsigned int options)
|
||||
{
|
||||
struct ip_set_portmap *mysetdata =
|
||||
(struct ip_set_portmap *) set->settype->header;
|
||||
|
||||
printf("-N %s %s --from %s",
|
||||
set->name,
|
||||
set->settype->typename,
|
||||
port_tostring(mysetdata->first_port, options));
|
||||
printf(" --to %s\n",
|
||||
port_tostring(mysetdata->last_port, options));
|
||||
}
|
||||
|
||||
static void saveports(struct set *set, void *data, size_t len,
|
||||
unsigned int options)
|
||||
{
|
||||
struct ip_set_portmap *mysetdata =
|
||||
(struct ip_set_portmap *) set->settype->header;
|
||||
u_int32_t addr = mysetdata->first_port;
|
||||
|
||||
while (addr <= mysetdata->last_port) {
|
||||
if (test_bit(addr - mysetdata->first_port, data))
|
||||
printf("-A %s %s\n",
|
||||
set->name,
|
||||
port_tostring(addr, options));
|
||||
addr++;
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf
|
||||
("-N set portmap --from PORT --to PORT\n"
|
||||
"-A set PORT\n"
|
||||
"-D set PORT\n"
|
||||
"-T set PORT\n");
|
||||
}
|
||||
|
||||
static struct settype settype_portmap = {
|
||||
.typename = SETTYPE_NAME,
|
||||
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||
|
||||
/* Create */
|
||||
.create_size = sizeof(struct ip_set_req_portmap_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_portmap),
|
||||
.adt_parser = &adt_parser,
|
||||
|
||||
/* Printing */
|
||||
.header_size = sizeof(struct ip_set_portmap),
|
||||
.initheader = &initheader,
|
||||
.printheader = &printheader,
|
||||
.printips = &printports_sorted, /* We only have sorted version */
|
||||
.printips_sorted = &printports_sorted,
|
||||
.saveheader = &saveheader,
|
||||
.saveips = &saveports,
|
||||
|
||||
/* Bindings */
|
||||
.bindip_tostring = &binding_port_tostring,
|
||||
.bindip_parse = &parse_port,
|
||||
|
||||
.usage = &usage,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void portmap_init(void)
|
||||
{
|
||||
settype_register(&settype_portmap);
|
||||
|
||||
}
|
||||
@@ -1,179 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2004 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.
|
||||
*/
|
||||
|
||||
/* 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/netfilter.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/checksum.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ipt_set.h"
|
||||
|
||||
static unsigned int
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
|
||||
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;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
||||
struct sk_buff *skb = *pskb;
|
||||
#endif
|
||||
|
||||
|
||||
if (info->add_set.index != IP_SET_INVALID_ID)
|
||||
ip_set_addip_kernel(info->add_set.index,
|
||||
skb,
|
||||
info->add_set.flags);
|
||||
if (info->del_set.index != IP_SET_INVALID_ID)
|
||||
ip_set_delip_kernel(info->del_set.index,
|
||||
skb,
|
||||
info->del_set.flags);
|
||||
|
||||
return IPT_CONTINUE;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
static bool
|
||||
#else
|
||||
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;
|
||||
ip_set_id_t index;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
if (targinfosize != IPT_ALIGN(sizeof(*info))) {
|
||||
DP("bad target info size %u", targinfosize);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info->add_set.index != IP_SET_INVALID_ID) {
|
||||
index = ip_set_get_byindex(info->add_set.index);
|
||||
if (index == IP_SET_INVALID_ID) {
|
||||
ip_set_printk("cannot find add_set index %u as target",
|
||||
info->add_set.index);
|
||||
return 0; /* error */
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IP_SET_INVALID_ID) {
|
||||
index = ip_set_get_byindex(info->del_set.index);
|
||||
if (index == IP_SET_INVALID_ID) {
|
||||
ip_set_printk("cannot find del_set index %u as target",
|
||||
info->del_set.index);
|
||||
return 0; /* error */
|
||||
}
|
||||
}
|
||||
if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
|
||||
|| info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
|
||||
ip_set_printk("That's nasty!");
|
||||
return 0; /* error */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void destroy(
|
||||
#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;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
|
||||
ip_set_printk("invalid targetsize %d", targetsize);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (info->add_set.index != IP_SET_INVALID_ID)
|
||||
ip_set_put(info->add_set.index);
|
||||
if (info->del_set.index != IP_SET_INVALID_ID)
|
||||
ip_set_put(info->del_set.index);
|
||||
}
|
||||
|
||||
static struct ipt_target SET_target = {
|
||||
.name = "SET",
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||
.family = AF_INET,
|
||||
#endif
|
||||
.target = target,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||
.targetsize = sizeof(struct ipt_set_info_target),
|
||||
#endif
|
||||
.checkentry = checkentry,
|
||||
.destroy = destroy,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
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)
|
||||
{
|
||||
return ipt_register_target(&SET_target);
|
||||
}
|
||||
|
||||
static void __exit ipt_SET_fini(void)
|
||||
{
|
||||
ipt_unregister_target(&SET_target);
|
||||
}
|
||||
|
||||
module_init(ipt_SET_init);
|
||||
module_exit(ipt_SET_fini);
|
||||
@@ -1,159 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2004 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 to match an IP set. */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||
#include "ip_set.h"
|
||||
#include "ipt_set.h"
|
||||
|
||||
static inline int
|
||||
match_set(const struct ipt_set_info *info,
|
||||
const struct sk_buff *skb,
|
||||
int inv)
|
||||
{
|
||||
if (ip_set_testip_kernel(info->index, skb, info->flags))
|
||||
inv = !inv;
|
||||
return inv;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
static bool
|
||||
#else
|
||||
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;
|
||||
|
||||
return match_set(&info->match_set,
|
||||
skb,
|
||||
info->match_set.flags[0] & IPSET_MATCH_INV);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||
static bool
|
||||
#else
|
||||
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;
|
||||
ip_set_id_t index;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
|
||||
ip_set_printk("invalid matchsize %d", matchsize);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
index = ip_set_get_byindex(info->match_set.index);
|
||||
|
||||
if (index == IP_SET_INVALID_ID) {
|
||||
ip_set_printk("Cannot find set indentified by id %u to match",
|
||||
info->match_set.index);
|
||||
return 0; /* error */
|
||||
}
|
||||
if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
|
||||
ip_set_printk("That's nasty!");
|
||||
return 0; /* error */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void destroy(
|
||||
#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;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||
if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
|
||||
ip_set_printk("invalid matchsize %d", matchsize);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ip_set_put(info->match_set.index);
|
||||
}
|
||||
|
||||
static struct ipt_match set_match = {
|
||||
.name = "set",
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||
.family = AF_INET,
|
||||
#endif
|
||||
.match = &match,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||
.matchsize = sizeof(struct ipt_set_info_match),
|
||||
#endif
|
||||
.checkentry = &checkentry,
|
||||
.destroy = &destroy,
|
||||
.me = THIS_MODULE
|
||||
};
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
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)
|
||||
{
|
||||
return ipt_register_match(&set_match);
|
||||
}
|
||||
|
||||
static void __exit ipt_ipset_fini(void)
|
||||
{
|
||||
ipt_unregister_match(&set_match);
|
||||
}
|
||||
|
||||
module_init(ipt_ipset_init);
|
||||
module_exit(ipt_ipset_fini);
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef _IPT_SET_H
|
||||
#define _IPT_SET_H
|
||||
|
||||
#include "ip_set.h"
|
||||
|
||||
struct ipt_set_info {
|
||||
ip_set_id_t index;
|
||||
u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
|
||||
};
|
||||
|
||||
/* match info */
|
||||
struct ipt_set_info_match {
|
||||
struct ipt_set_info match_set;
|
||||
};
|
||||
|
||||
struct ipt_set_info_target {
|
||||
struct ipt_set_info add_set;
|
||||
struct ipt_set_info del_set;
|
||||
};
|
||||
|
||||
#endif /*_IPT_SET_H*/
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* "CHAOS" target extension for iptables
|
||||
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2006 - 2008
|
||||
* Copyright © Jan Engelhardt, 2006 - 2008
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License; either
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "xt_CHAOS.h"
|
||||
#include "compat_user.h"
|
||||
|
||||
enum {
|
||||
F_DELUDE = 1 << 0,
|
||||
@@ -25,7 +26,7 @@ enum {
|
||||
static const struct option chaos_tg_opts[] = {
|
||||
{.name = "delude", .has_arg = false, .val = 'd'},
|
||||
{.name = "tarpit", .has_arg = false, .val = 't'},
|
||||
{},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void chaos_tg_help(void)
|
||||
@@ -58,44 +59,36 @@ static void chaos_tg_check(unsigned int flags)
|
||||
{
|
||||
if (flags == (F_DELUDE | F_TARPIT))
|
||||
/* 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 "
|
||||
"may be specified");
|
||||
}
|
||||
|
||||
static void chaos_tg_print(const void *ip,
|
||||
const struct xt_entry_target *target, int numeric)
|
||||
{
|
||||
const struct xt_chaos_tginfo *info = (const void *)target->data;
|
||||
|
||||
switch (info->variant) {
|
||||
case XTCHAOS_DELUDE:
|
||||
printf("DELUDE ");
|
||||
break;
|
||||
case XTCHAOS_TARPIT:
|
||||
printf("TARPIT ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void chaos_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_chaos_tginfo *info = (const void *)target->data;
|
||||
|
||||
switch (info->variant) {
|
||||
case XTCHAOS_DELUDE:
|
||||
printf("--delude ");
|
||||
printf(" --delude ");
|
||||
break;
|
||||
case XTCHAOS_TARPIT:
|
||||
printf("--tarpit ");
|
||||
printf(" --tarpit ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void chaos_tg_print(const void *ip,
|
||||
const struct xt_entry_target *target, int numeric)
|
||||
{
|
||||
printf(" -j CHAOS");
|
||||
chaos_tg_save(ip, target);
|
||||
}
|
||||
|
||||
static struct xtables_target chaos_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "CHAOS",
|
||||
.family = AF_INET,
|
||||
.family = NFPROTO_IPV4,
|
||||
.size = XT_ALIGN(sizeof(struct xt_chaos_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_chaos_tginfo)),
|
||||
.help = chaos_tg_help,
|
||||
@@ -106,8 +99,7 @@ static struct xtables_target chaos_tg_reg = {
|
||||
.extra_opts = chaos_tg_opts,
|
||||
};
|
||||
|
||||
void _init(void);
|
||||
void _init(void)
|
||||
static __attribute__((constructor)) void chaos_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&chaos_tg_reg);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
.PP
|
||||
Causes confusion on the other end by doing odd things with incoming packets.
|
||||
CHAOS will randomly reply (or not) with one of its configurable subtargets:
|
||||
.TP
|
||||
\fB--delude\fP
|
||||
\fB\-\-delude\fP
|
||||
Use the REJECT and DELUDE targets as a base to do a sudden or deferred
|
||||
connection reset, fooling some network scanners to return non-deterministic
|
||||
(randomly open/closed) results, and in case it is deemed open, it is actually
|
||||
closed/filtered.
|
||||
.TP
|
||||
\fB--tarpit\fP
|
||||
\fB\-\-tarpit\fP
|
||||
Use the REJECT and TARPIT target as a base to hold the connection until it
|
||||
times out. This consumes conntrack entries when connection tracking is loaded
|
||||
(which usually is on most machines), and routers inbetween you and the Internet
|
||||
@@ -17,5 +18,5 @@ connections than they can.
|
||||
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.
|
||||
.PP
|
||||
See http://jengelh.medozas.de/projects/chaostables/ for more information
|
||||
about CHAOS, DELUDE and portscan.
|
||||
See http://inai.de/projects/chaostables/ for more information
|
||||
about CHAOS, DELUDE and lscan.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* "DELUDE" target extension for iptables
|
||||
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2006 - 2008
|
||||
* Copyright © Jan Engelhardt, 2006 - 2008
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License; either
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "compat_user.h"
|
||||
|
||||
static void delude_tg_help(void)
|
||||
{
|
||||
@@ -33,16 +34,13 @@ static struct xtables_target delude_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "DELUDE",
|
||||
.revision = 0,
|
||||
.family = AF_INET,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.family = NFPROTO_IPV4,
|
||||
.help = delude_tg_help,
|
||||
.parse = delude_tg_parse,
|
||||
.final_check = delude_tg_check,
|
||||
};
|
||||
|
||||
void _init(void);
|
||||
void _init(void)
|
||||
static __attribute__((constructor)) void delude_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&delude_tg_reg);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.PP
|
||||
The DELUDE target will reply to a SYN packet with SYN-ACK, and to all other
|
||||
packets with an RST. This will terminate the connection much like REJECT, but
|
||||
network scanners doing TCP half-open discovery can be spoofed to make them
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
100
extensions/libxt_DHCPMAC.c
Normal file
100
extensions/libxt_DHCPMAC.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* "DHCPMAC" target extension for iptables
|
||||
* Copyright © Jan Engelhardt, 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"
|
||||
#include "compat_user.h"
|
||||
|
||||
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_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 void dhcpmac_tg_print(const void *ip,
|
||||
const struct xt_entry_target *target, int numeric)
|
||||
{
|
||||
printf(" -j DHCPMAC");
|
||||
dhcpmac_tg_save(ip, target);
|
||||
}
|
||||
|
||||
static struct xtables_target dhcpmac_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "DHCPMAC",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.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);
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
In conjunction with ebtables, DHCPADDR can be used to completely change all MAC
|
||||
.PP
|
||||
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
|
||||
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
|
||||
aa:bb..`).
|
||||
.TP
|
||||
\fB--set-mac\fP \fIaa:bb:cc:dd:ee:ff\fP[\fB/\fP\fImask\fP]
|
||||
\fB\-\-set\-mac\fP \fIaa:bb:cc:dd:ee:ff\fP[\fB/\fP\fImask\fP]
|
||||
Replace the client host MAC address field in the DHCP message with the given
|
||||
MAC address. This option is mandatory. The \fImask\fP parameter specifies the
|
||||
prefix length of bits to change.
|
||||
@@ -12,13 +13,13 @@ prefix length of bits to change.
|
||||
EXAMPLE, replacing all addresses from one of VMware's assigned vendor IDs
|
||||
(00:50:56) addresses with something else:
|
||||
.PP
|
||||
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
|
||||
ab:cd:ef:00:00:00/24
|
||||
iptables \-t mangle \-A FORWARD \-p udp \-\-dport 67 \-m physdev
|
||||
\-\-physdev\-in vmnet1 \-m dhcpmac \-\-mac 00:50:56:00:00:00/24 \-j DHCPMAC
|
||||
\-\-set\-mac ab:cd:ef:00:00:00/24
|
||||
.PP
|
||||
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
|
||||
00:50:56:00:00:00/24
|
||||
iptables \-t mangle \-A FORWARD \-p udp \-\-dport 68 \-m physdev
|
||||
\-\-physdev\-out vmnet1 \-m dhcpmac \-\-mac ab:cd:ef:00:00:00/24 \-j DHCPMAC
|
||||
\-\-set\-mac 00:50:56:00:00:00/24
|
||||
.PP
|
||||
(This assumes there is a bridge interface that has vmnet1 as a port. You will
|
||||
also need to add appropriate ebtables rules to change the MAC address of the
|
||||
245
extensions/libxt_DNETMAP.c
Normal file
245
extensions/libxt_DNETMAP.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/* Shared library add-on to iptables to add DNETMAP support.
|
||||
* (C) 2010 Marek Kierdelewicz <marek@koba.pl>
|
||||
*
|
||||
* uses some code from libipt_NETMAP by:
|
||||
* Svenning Soerensen <svenning@post5.tele.dk>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter/nf_nat.h>
|
||||
#include "xt_DNETMAP.h"
|
||||
|
||||
#define MODULENAME "DNETMAP"
|
||||
|
||||
static const struct option DNETMAP_opts[] = {
|
||||
{"prefix", 1, NULL, 'p'},
|
||||
{"reuse", 0, NULL, 'r'},
|
||||
{"ttl", 1, NULL, 't'},
|
||||
{"static", 0, NULL, 's'},
|
||||
{"persistent", 0, NULL, 'e'},
|
||||
{.name = NULL}
|
||||
};
|
||||
|
||||
static void DNETMAP_help(void)
|
||||
{
|
||||
printf(MODULENAME " target options:\n"
|
||||
" --%s address[/mask]\n"
|
||||
" Network subnet to map to. If not specified, all existing prefixes are used.\n"
|
||||
" --%s\n"
|
||||
" Reuse entry for given prenat-ip from any prefix despite bindings ttl < 0.\n"
|
||||
" --%s seconds\n"
|
||||
" Regenerate bindings ttl value to seconds. If negative value is specified,\n"
|
||||
" bindings ttl is kept unchanged. If not specified then default ttl value (600s)\n"
|
||||
" is used\n"
|
||||
" --%s\n"
|
||||
" Match only static entries for this rule. Dynamic entries won't be created.\n"
|
||||
" --%s\n"
|
||||
" Set prefix persistent. It won't be removed after deleting last iptables rule.\n\n",
|
||||
DNETMAP_opts[0].name, DNETMAP_opts[1].name,
|
||||
DNETMAP_opts[2].name, DNETMAP_opts[3].name,
|
||||
DNETMAP_opts[4].name);
|
||||
}
|
||||
|
||||
static u_int32_t bits2netmask(int bits)
|
||||
{
|
||||
u_int32_t netmask, bm;
|
||||
|
||||
if (bits >= 32 || bits < 0)
|
||||
return ~0;
|
||||
for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
|
||||
netmask |= bm;
|
||||
return htonl(netmask);
|
||||
}
|
||||
|
||||
static int netmask2bits(u_int32_t netmask)
|
||||
{
|
||||
u_int32_t bm;
|
||||
int bits;
|
||||
|
||||
netmask = ntohl(netmask);
|
||||
for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
|
||||
bits++;
|
||||
if (netmask)
|
||||
return -1; /* holes in netmask */
|
||||
return bits;
|
||||
}
|
||||
|
||||
/* Parses network address */
|
||||
static void parse_prefix(char *arg, struct nf_nat_range *range)
|
||||
{
|
||||
char *slash;
|
||||
const struct in_addr *ip;
|
||||
u_int32_t netmask;
|
||||
unsigned int bits;
|
||||
|
||||
range->flags |= NF_NAT_RANGE_MAP_IPS;
|
||||
slash = strchr(arg, '/');
|
||||
if (slash)
|
||||
*slash = '\0';
|
||||
|
||||
ip = xtables_numeric_to_ipaddr(arg);
|
||||
if (ip == NULL)
|
||||
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
|
||||
arg);
|
||||
range->min_addr.in = *ip;
|
||||
if (slash) {
|
||||
if (strchr(slash + 1, '.')) {
|
||||
ip = xtables_numeric_to_ipmask(slash + 1);
|
||||
if (ip == NULL)
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Bad netmask \"%s\"\n",
|
||||
slash + 1);
|
||||
netmask = ip->s_addr;
|
||||
} else {
|
||||
if (!xtables_strtoui(slash + 1, NULL, &bits, 0, 32))
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Bad netmask \"%s\"\n",
|
||||
slash + 1);
|
||||
netmask = bits2netmask(bits);
|
||||
}
|
||||
/* Don't allow /0 (/1 is probably insane, too) */
|
||||
if (netmask == 0)
|
||||
xtables_error(PARAMETER_PROBLEM, "Netmask needed\n");
|
||||
/* Mask should be <= then /16 */
|
||||
if (bits < 16)
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Max netmask size is /16\n");
|
||||
} else
|
||||
netmask = ~0;
|
||||
|
||||
if (range->min_addr.ip & ~netmask) {
|
||||
if (slash)
|
||||
*slash = '/';
|
||||
xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n",
|
||||
arg);
|
||||
}
|
||||
range->max_addr.ip = range->min_addr.ip | ~netmask;
|
||||
}
|
||||
|
||||
static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)(*target)->data;
|
||||
struct nf_nat_range *mr = &tginfo->prefix;
|
||||
char *end;
|
||||
|
||||
switch (c) {
|
||||
case 'p':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--prefix",
|
||||
*flags & XT_DNETMAP_PREFIX);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--prefix",
|
||||
invert);
|
||||
|
||||
/* TO-DO use xtables_ipparse_any instead? */
|
||||
parse_prefix(optarg, mr);
|
||||
*flags |= XT_DNETMAP_PREFIX;
|
||||
tginfo->flags |= XT_DNETMAP_PREFIX;
|
||||
return 1;
|
||||
case 'r':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--reuse",
|
||||
*flags & XT_DNETMAP_REUSE);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--reuse", invert);
|
||||
*flags |= XT_DNETMAP_REUSE;
|
||||
tginfo->flags |= XT_DNETMAP_REUSE;
|
||||
return 1;
|
||||
case 's':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--static",
|
||||
*flags & XT_DNETMAP_STATIC);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--static", invert);
|
||||
*flags |= XT_DNETMAP_STATIC;
|
||||
tginfo->flags |= XT_DNETMAP_STATIC;
|
||||
return 1;
|
||||
case 'e':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--persistent",
|
||||
*flags & XT_DNETMAP_PERSISTENT);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--persistent", invert);
|
||||
*flags |= XT_DNETMAP_PERSISTENT;
|
||||
tginfo->flags |= XT_DNETMAP_PERSISTENT;
|
||||
return 1;
|
||||
case 't':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--ttl",
|
||||
*flags & XT_DNETMAP_TTL);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--ttl", invert);
|
||||
*flags |= XT_DNETMAP_TTL;
|
||||
tginfo->flags |= XT_DNETMAP_TTL;
|
||||
tginfo->ttl = strtol(optarg, &end, 10);
|
||||
if (*end != '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void DNETMAP_print_addr(const void *ip,
|
||||
const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
|
||||
const struct nf_nat_range *r = &tginfo->prefix;
|
||||
struct in_addr a;
|
||||
int bits;
|
||||
|
||||
a = r->min_addr.in;
|
||||
printf("%s", xtables_ipaddr_to_numeric(&a));
|
||||
a.s_addr = ~(r->min_addr.ip ^ r->max_addr.ip);
|
||||
bits = netmask2bits(a.s_addr);
|
||||
if (bits < 0)
|
||||
printf("/%s", xtables_ipaddr_to_numeric(&a));
|
||||
else
|
||||
printf("/%d", bits);
|
||||
}
|
||||
|
||||
static void DNETMAP_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
|
||||
const __u8 *flags = &tginfo->flags;
|
||||
|
||||
if (*flags & XT_DNETMAP_PREFIX) {
|
||||
printf(" --%s ", DNETMAP_opts[0].name);
|
||||
DNETMAP_print_addr(ip, target, 0);
|
||||
}
|
||||
|
||||
if (*flags & XT_DNETMAP_REUSE)
|
||||
printf(" --reuse ");
|
||||
|
||||
if (*flags & XT_DNETMAP_STATIC)
|
||||
printf(" --static ");
|
||||
|
||||
if (*flags & XT_DNETMAP_PERSISTENT)
|
||||
printf(" --persistent ");
|
||||
|
||||
/* ommited because default value can change as kernel mod param */
|
||||
if (*flags & XT_DNETMAP_TTL)
|
||||
printf(" --ttl %i ", tginfo->ttl);
|
||||
}
|
||||
|
||||
static void DNETMAP_print(const void *ip, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
printf(" -j DNETMAP");
|
||||
DNETMAP_save(ip, target);
|
||||
}
|
||||
|
||||
static struct xtables_target dnetmap_tg_reg = {
|
||||
.name = MODULENAME,
|
||||
.version = XTABLES_VERSION,
|
||||
.family = NFPROTO_IPV4,
|
||||
.size = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
|
||||
.help = DNETMAP_help,
|
||||
.parse = DNETMAP_parse,
|
||||
.print = DNETMAP_print,
|
||||
.save = DNETMAP_save,
|
||||
.extra_opts = DNETMAP_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_target(&dnetmap_tg_reg);
|
||||
}
|
||||
179
extensions/libxt_DNETMAP.man
Normal file
179
extensions/libxt_DNETMAP.man
Normal file
@@ -0,0 +1,179 @@
|
||||
.PP
|
||||
The \fBDNETMAP\fR target allows dynamic two-way 1:1 mapping of IPv4 subnets. A
|
||||
single rule can map a private subnet to a shorter public subnet, creating and
|
||||
maintaining unambiguous private-public IP address bindings. The second rule can
|
||||
be used to map new flows to a private subnet according to maintained bindings.
|
||||
The target allows efficient public IPv4 space usage and unambiguous NAT at the
|
||||
same time.
|
||||
.PP
|
||||
The target can be used only in the \fBnat\fR table in \fBPOSTROUTING\fR or
|
||||
\fBOUTPUT\fR chains for SNAT, and in \fBPREROUTING\fR for DNAT. Only flows
|
||||
directed to bound addresses will be DNATed. The packet continues chain
|
||||
traversal if there is no free postnat address to be assigned to the prenat
|
||||
address. The default binding \fBTTL\fR is \fI10 minutes\fR and can be changed
|
||||
using the \fBdefault_ttl\fR module option. The default address hash size is 256
|
||||
and can be changed using the \fBhash_size\fR module option.
|
||||
.TP
|
||||
\fB\-\-prefix\fR \fIaddr\fR\fB/\fR\fImask\fR
|
||||
The network subnet to map to. If not specified, all existing prefixes are used.
|
||||
.TP
|
||||
\fB\-\-reuse\fR
|
||||
Reuse the entry for a given prenat address from any prefix even if the
|
||||
binding's TTL is < 0.
|
||||
.TP
|
||||
\fB\-\-persistent\fR
|
||||
Set the prefix to be persistent. It will not be removed after deleting the last
|
||||
iptables rule. The option is effective only in the first rule for a given
|
||||
prefix. If you need to change persistency for an existing prefix, please use
|
||||
the procfs interface described below.
|
||||
.TP
|
||||
\fB\-\-static\fR
|
||||
Do not create dynamic mappings using this rule. Use static mappings only. Note
|
||||
that you need to create static mappings via the procfs interface for this rule
|
||||
for this option to have any effect.
|
||||
.TP
|
||||
\fB\-\-ttl\fR \fIseconds\fR
|
||||
Reset the binding's TTL value to \fIseconds\fR. If a negative value is
|
||||
specified, the binding's TTL is kept unchanged. If this option is not
|
||||
specified, then the default TTL value (600s) is used.
|
||||
.PP
|
||||
\fB* /proc interface\fR
|
||||
.PP
|
||||
The module creates the following entries for each new specified subnet:
|
||||
.TP
|
||||
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR
|
||||
Contains the binding table for the given \fIsubnet/mask\fP. Each line contains
|
||||
\fBprenat address\fR, \fBpostnat address\fR, \fBttl\fR (seconds until the entry
|
||||
times out), \fBlasthit\fR (last hit to the entry in seconds relative to system
|
||||
boot time). Please note that the \fBttl\fR and \fBlasthit\fR entries contain an
|
||||
'\fBS\fR' in case of a static binding.
|
||||
.TP
|
||||
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
|
||||
Contains statistics for a given \fIsubnet/mask\fP. The line contains four
|
||||
numerical values separated by spaces. The first one is the number of currently
|
||||
used dynamic addresses (bindings with negative TTL excluded), the second one is
|
||||
the number of static assignments, the third one is the number of all usable
|
||||
addresses in the subnet, and the fourth one is the mean \fBTTL\fR value for all
|
||||
active entries. If the prefix has the persistent flag set, it will be noted as
|
||||
fifth entry.
|
||||
.PP
|
||||
The following write operations are supported via the procfs interface:
|
||||
.TP
|
||||
echo "+\fIprenat-address\fR:\fIpostnat-address\fR" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR
|
||||
Adds a static binding between the prenat and postnap address. If
|
||||
postnat_address is already bound, any previous binding will be timed out
|
||||
immediately. A static binding is never timed out.
|
||||
.TP
|
||||
echo "\-\fIaddress\fR" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR
|
||||
Removes the binding with \fIaddress\fR as prenat or postnat address. If the
|
||||
removed binding is currently static, it will make the entry available for
|
||||
dynamic allocation.
|
||||
.TP
|
||||
echo "+persistent" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR
|
||||
Sets the persistent flag for the prefix. It is useful if you do not want
|
||||
bindings to get flushed when the firewall is restarted. You can check if the
|
||||
prefix is persistent by printing the contents of
|
||||
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR.
|
||||
.TP
|
||||
echo "\-persistent" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR
|
||||
Unsets the persistent flag for the prefix. In this mode, the prefix will be
|
||||
deleted if the last iptables rule for that prefix is removed.
|
||||
.TP
|
||||
echo "flush" >\fB/proc/net/xt_DNETMAP/subnet_mask\fR
|
||||
Flushes all bindings for the specific prefix. All static entries are also
|
||||
flushed and become available for dynamic bindings.
|
||||
.PP
|
||||
Note! Entries are removed if the last iptables rule for a specific prefix is
|
||||
deleted unless the persistent flag is set.
|
||||
.PP
|
||||
\fB* Logging\fR
|
||||
.PP
|
||||
The module logs binding add/timeout events to klog. This behaviour can be
|
||||
disabled using the \fBdisable_log\fR module parameter.
|
||||
.PP
|
||||
\fB* Examples\fR
|
||||
.PP
|
||||
\fB1.\fR Map subnet 192.168.0.0/24 to subnets 20.0.0.0/26. SNAT only:
|
||||
.PP
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26
|
||||
.PP
|
||||
Active hosts from the 192.168.0.0/24 subnet are mapped to 20.0.0.0/26. If the
|
||||
packet from a not yet bound prenat address hits the rule and there are no free
|
||||
or timed-out (TTL<0) entries in prefix 20.0.0.0/28, then a notice is logged to
|
||||
klog and chain traversal continues. If packet from an already-bound prenat
|
||||
address hits the rule, the binding's TTL value is reset to default_ttl and SNAT
|
||||
is performed.
|
||||
.PP
|
||||
\fB2.\fR Use of \fB\-\-reuse\fR and \fB\-\-ttl\fR switches, multiple rule
|
||||
interaction:
|
||||
.PP
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix
|
||||
20.0.0.0/26 \-\-reuse \-\-ttl 200
|
||||
.PP
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 30.0.0.0/26
|
||||
.PP
|
||||
Active hosts from 192.168.0.0/24 subnet are mapped to 20.0.0.0/26 with TTL =
|
||||
200 seconds. If there are no free addresses in first prefix, the next one
|
||||
(30.0.0.0/26) is used with the default TTL. It is important to note that the
|
||||
first rule SNATs all flows whose source address is already actively bound
|
||||
(TTL>0) to ANY prefix. The \fB\-\-reuse\fR parameter makes this functionality
|
||||
work even for inactive (TTL<0) entries.
|
||||
.PP
|
||||
If both subnets are exhausted, then chain traversal continues.
|
||||
.PP
|
||||
\fB3.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 in a bidirectional way:
|
||||
.PP
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26
|
||||
.PP
|
||||
iptables \-t nat \-A PREROUTING \-j DNETMAP
|
||||
.PP
|
||||
If the host 192.168.0.10 generates some traffic, it gets bound to first free
|
||||
address in the subnet \(em 20.0.0.0. Now, any traffic directed to 20.0.0.0 gets
|
||||
DNATed to 192.168.0.10 as long as there is an active (TTL>0) binding. There is
|
||||
no need to specify \fB\-\-prefix\fR parameter in a PREROUTING rule, because
|
||||
this way, it DNATs traffic to all active prefixes. You could specify the prefix
|
||||
you would like to make DNAT work for a specific prefix only.
|
||||
.PP
|
||||
\fB4.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 with static assignments
|
||||
only:
|
||||
.PP
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26
|
||||
\-\-static
|
||||
.PP
|
||||
echo "+192.168.0.10:20.0.0.1" >/proc/net/xt_DNETMAP/20.0.0.0_26
|
||||
.br
|
||||
echo "+192.168.0.11:20.0.0.2" >/proc/net/xt_DNETMAP/20.0.0.0_26
|
||||
.br
|
||||
echo "+192.168.0.51:20.0.0.3" >/proc/net/xt_DNETMAP/20.0.0.0_26
|
||||
.PP
|
||||
This configuration will allow only preconfigured static bindings to work due to
|
||||
the \fBstatic\fR rule option. Without this flag, dynamic bindings would be
|
||||
created using non-static entries.
|
||||
.PP
|
||||
\fB5.\fR Persistent prefix:
|
||||
.PP
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26
|
||||
\-\-persistent
|
||||
.br
|
||||
\fBor\fR
|
||||
.br
|
||||
iptables \-t nat \-A POSTROUTING \-s 192.168.0.0/24 \-j DNETMAP \-\-prefix 20.0.0.0/26
|
||||
.br
|
||||
echo "+persistent" >/proc/net/xt_DNETMAP/20.0.0.0_26
|
||||
.PP
|
||||
Now, we can check the persistent flag of the prefix:
|
||||
.br
|
||||
cat /proc/net/xt_DNETMAP/20.0.0.0_26
|
||||
.br
|
||||
0 0 64 0 \fBpersistent\fR
|
||||
.PP
|
||||
Flush the iptables nat table and see that prefix is still in existence:
|
||||
.br
|
||||
iptables \-F \-t nat
|
||||
.br
|
||||
ls \-l /proc/net/xt_DNETMAP
|
||||
.br
|
||||
\-rw\-r\-\-r\-\- 1 root root 0 06\-10 09:01 20.0.0.0_26
|
||||
.br
|
||||
\-rw\-r\-\-r\-\- 1 root root 0 06\-10 09:01 20.0.0.0_26_stat
|
||||
.
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* "ECHO" target extension for iptables
|
||||
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
|
||||
* Copyright © Jan Engelhardt, 2008
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License; either
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
#include "compat_user.h"
|
||||
|
||||
static void echo_tg_help(void)
|
||||
{
|
||||
@@ -29,15 +30,13 @@ static void echo_tg_check(unsigned int flags)
|
||||
static struct xtables_target echo_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "ECHO",
|
||||
.family = AF_UNSPEC,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.help = echo_tg_help,
|
||||
.parse = echo_tg_parse,
|
||||
.final_check = echo_tg_check,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
static __attribute__((constructor)) void echo_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&echo_tg_reg);
|
||||
}
|
||||
|
||||
5
extensions/libxt_ECHO.man
Normal file
5
extensions/libxt_ECHO.man
Normal file
@@ -0,0 +1,5 @@
|
||||
.PP
|
||||
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.
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* "IPMARK" target extension for iptables
|
||||
* Copyright © Grzegorz Janoszka <Grzegorz.Janoszka@pro.onet.pl>, 2003
|
||||
* Jan Engelhardt <jengelh [at] medozas de>, 2008
|
||||
* Jan Engelhardt, 2008
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License; either
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <string.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_IPMARK.h"
|
||||
#include "compat_user.h"
|
||||
|
||||
enum {
|
||||
FL_ADDR_USED = 1 << 0,
|
||||
@@ -58,45 +59,46 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
|
||||
switch (c) {
|
||||
case '1':
|
||||
param_act(P_ONLY_ONCE, "IPMARK", "addr", *flags & FL_ADDR_USED);
|
||||
param_act(P_NO_INVERT, "IPMARK", "addr", invert);
|
||||
xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "addr", *flags & FL_ADDR_USED);
|
||||
xtables_param_act(XTF_NO_INVERT, "IPMARK", "addr", invert);
|
||||
if (strcmp(optarg, "src") == 0)
|
||||
info->selector = XT_IPMARK_SRC;
|
||||
else if (strcmp(optarg, "dst") == 0)
|
||||
info->selector = XT_IPMARK_DST;
|
||||
else
|
||||
exit_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg);
|
||||
xtables_error(PARAMETER_PROBLEM, "Bad addr value `%s' - should be `src' or `dst'", optarg);
|
||||
*flags |= FL_ADDR_USED;
|
||||
return true;
|
||||
|
||||
|
||||
case '2':
|
||||
param_act(P_ONLY_ONCE, "IPMARK", "and-mask", *flags & FL_AND_MASK_USED);
|
||||
param_act(P_NO_INVERT, "IPMARK", "and-mask", invert);
|
||||
if (!strtonum(optarg, NULL, &n, 0, ~0U))
|
||||
param_act(P_BAD_VALUE, "IPMARK", "and-mask", optarg);
|
||||
xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "and-mask", *flags & FL_AND_MASK_USED);
|
||||
xtables_param_act(XTF_NO_INVERT, "IPMARK", "and-mask", invert);
|
||||
if (!xtables_strtoui(optarg, NULL, &n, 0, ~0U))
|
||||
xtables_param_act(XTF_BAD_VALUE, "IPMARK", "and-mask", optarg);
|
||||
info->andmask = n;
|
||||
*flags |= FL_AND_MASK_USED;
|
||||
return true;
|
||||
|
||||
case '3':
|
||||
param_act(P_ONLY_ONCE, "IPMARK", "or-mask", *flags & FL_OR_MASK_USED);
|
||||
param_act(P_NO_INVERT, "IPMARK", "or-mask", invert);
|
||||
if (!strtonum(optarg, NULL, &n, 0, ~0U))
|
||||
param_act(P_BAD_VALUE, "IPMARK", "or-mask", optarg);
|
||||
xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "or-mask", *flags & FL_OR_MASK_USED);
|
||||
xtables_param_act(XTF_NO_INVERT, "IPMARK", "or-mask", invert);
|
||||
if (!xtables_strtoui(optarg, NULL, &n, 0, ~0U))
|
||||
xtables_param_act(XTF_BAD_VALUE, "IPMARK", "or-mask", optarg);
|
||||
info->ormask = n;
|
||||
*flags |= FL_OR_MASK_USED;
|
||||
return true;
|
||||
|
||||
case '4':
|
||||
param_act(P_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT);
|
||||
param_act(P_NO_INVERT, "IPMARK", "--shift", invert);
|
||||
xtables_param_act(XTF_ONLY_ONCE, "IPMARK", "--shift", *flags & FL_SHIFT);
|
||||
xtables_param_act(XTF_NO_INVERT, "IPMARK", "--shift", invert);
|
||||
/*
|
||||
* Anything >31 does not make sense for IPv4, but it still
|
||||
* does the right thing.
|
||||
*/
|
||||
if (!strtonum(optarg, NULL, &n, 0, 128))
|
||||
param_act(P_BAD_VALUE, "IPMARK", "--shift", optarg);
|
||||
if (!xtables_strtoui(optarg, NULL, &n, 0, 128))
|
||||
xtables_param_act(XTF_BAD_VALUE, "IPMARK", "--shift", optarg);
|
||||
info->shift = n;
|
||||
*flags |= FL_SHIFT;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,77 +108,53 @@ static int ipmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
static void ipmark_tg_check(unsigned int flags)
|
||||
{
|
||||
if (!(flags & FL_ADDR_USED))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"IPMARK target: Parameter --addr is required");
|
||||
}
|
||||
|
||||
static void
|
||||
ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
const struct xt_ipmark_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (info->selector == XT_IPMARK_SRC)
|
||||
printf("IPMARK src ip");
|
||||
else
|
||||
printf("IPMARK dst ip");
|
||||
|
||||
if (info->andmask != ~0U)
|
||||
printf(" and 0x%x ", (unsigned int)info->andmask);
|
||||
if (info->ormask != 0)
|
||||
printf(" or 0x%x ", (unsigned int)info->ormask);
|
||||
}
|
||||
|
||||
static void
|
||||
ipmark_tg_save(const void *entry, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_ipmark_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (info->selector == XT_IPMARK_SRC)
|
||||
printf("--addr src ");
|
||||
printf(" --addr src ");
|
||||
else
|
||||
printf("--addr dst ");
|
||||
printf(" --addr dst ");
|
||||
|
||||
if (info->shift != 0)
|
||||
printf(" --shift %u ", (unsigned int)info->shift);
|
||||
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)
|
||||
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 = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "IPMARK",
|
||||
.family = PF_INET,
|
||||
.revision = 0,
|
||||
.size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
|
||||
.help = ipmark_tg_help,
|
||||
.init = ipmark_tg_init,
|
||||
.parse = ipmark_tg_parse,
|
||||
.final_check = ipmark_tg_check,
|
||||
.print = ipmark_tg_print,
|
||||
.save = ipmark_tg_save,
|
||||
.extra_opts = ipmark_tg_opts,
|
||||
};
|
||||
|
||||
static struct xtables_target ipmark_tg6_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "IPMARK",
|
||||
.family = PF_INET6,
|
||||
.revision = 0,
|
||||
.size = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_ipmark_tginfo)),
|
||||
.help = ipmark_tg_help,
|
||||
.init = ipmark_tg_init,
|
||||
.parse = ipmark_tg_parse,
|
||||
.final_check = ipmark_tg_check,
|
||||
.print = ipmark_tg_print,
|
||||
.save = ipmark_tg_save,
|
||||
.extra_opts = ipmark_tg_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
static void
|
||||
ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
xtables_register_target(&ipmark_tg4_reg);
|
||||
xtables_register_target(&ipmark_tg6_reg);
|
||||
printf(" -j IPMARK");
|
||||
ipmark_tg_save(entry, target);
|
||||
}
|
||||
|
||||
static struct xtables_target ipmark_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "IPMARK",
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision = 1,
|
||||
.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 __attribute__((constructor)) void ipmark_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&ipmark_tg_reg);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
.PP
|
||||
Allows you to mark a received packet basing on its IP address. This
|
||||
can replace many mangle/mark entries with only one, if you use
|
||||
firewall based classifier.
|
||||
|
||||
.PP
|
||||
This target is to be used inside the \fBmangle\fP table.
|
||||
.TP
|
||||
\fB--addr\fP {\fBsrc\fP|\fBdst\fP}
|
||||
\fB\-\-addr\fP {\fBsrc\fP|\fBdst\fP}
|
||||
Select source or destination IP address as a basis for the mark.
|
||||
.TP
|
||||
\fB--and-mask\fP \fImask\fP
|
||||
\fB\-\-and\-mask\fP \fImask\fP
|
||||
Perform bitwise AND on the IP address and this bitmask.
|
||||
.TP
|
||||
\fB--or-mask\fP \fImask\fP
|
||||
\fB\-\-or\-mask\fP \fImask\fP
|
||||
Perform bitwise OR on the IP address and this bitmask.
|
||||
.TP
|
||||
\fB--shift\fP \fIvalue\fP
|
||||
\fB\-\-shift\fP \fIvalue\fP
|
||||
Shift addresses to the right by the given number of bits before taking it
|
||||
as a mark. (This is done before ANDing or ORing it.) This option is needed
|
||||
to select part of an IPv6 address, because marks are only 32 bits in size.
|
||||
@@ -34,16 +35,16 @@ tc filter add dev eth3 parent 1:0 protocol ip fw
|
||||
.PP
|
||||
Earlier we had many rules just like below:
|
||||
.IP
|
||||
iptables -t mangle -A POSTROUTING -o eth3 -d 192.168.5.2 -j MARK
|
||||
--set-mark 0x10502
|
||||
iptables \-t mangle \-A POSTROUTING \-o eth3 \-d 192.168.5.2 \-j MARK
|
||||
\-\-set\-mark 0x10502
|
||||
.IP
|
||||
iptables -t mangle -A POSTROUTING -o eth3 -d 192.168.5.3 -j MARK
|
||||
--set-mark 0x10503
|
||||
iptables \-t mangle \-A POSTROUTING \-o eth3 \-d 192.168.5.3 \-j MARK
|
||||
\-\-set\-mark 0x10503
|
||||
.PP
|
||||
Using IPMARK target we can replace all the mangle/mark rules with only one:
|
||||
.IP
|
||||
iptables -t mangle -A POSTROUTING -o eth3 -j IPMARK --addr dst
|
||||
--and-mask 0xffff --or-mask 0x10000
|
||||
iptables \-t mangle \-A POSTROUTING \-o eth3 \-j IPMARK \-\-addr dst
|
||||
\-\-and\-mask 0xffff \-\-or\-mask 0x10000
|
||||
.PP
|
||||
On the routers with hundreds of users there should be significant load
|
||||
decrease (e.g. twice).
|
||||
@@ -52,5 +53,5 @@ decrease (e.g. twice).
|
||||
2001:db8:45:1d:20d:93ff:fe9b:e443 and the resulting mark should be 0x93ff,
|
||||
then a right-shift of 16 is needed first:
|
||||
.IP
|
||||
-t mangle -A PREROUTING -s 2001:db8::/32 -j IPMARK --addr src --shift 16
|
||||
--and-mask 0xFFFF
|
||||
\-t mangle \-A PREROUTING \-s 2001:db8::/32 \-j IPMARK \-\-addr src \-\-shift
|
||||
16 \-\-and\-mask 0xFFFF
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* "LOGMARK" target extension for iptables
|
||||
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008
|
||||
* Copyright © Jan Engelhardt, 2008
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License; either
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_LOGMARK.h"
|
||||
#include "compat_user.h"
|
||||
|
||||
enum {
|
||||
F_LEVEL = 1 << 0,
|
||||
@@ -22,7 +23,7 @@ enum {
|
||||
static const struct option logmark_tg_opts[] = {
|
||||
{.name = "log-level", .has_arg = true, .val = 'l'},
|
||||
{.name = "log-prefix", .has_arg = true, .val = 'p'},
|
||||
{},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void logmark_tg_help(void)
|
||||
@@ -51,23 +52,23 @@ logmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
|
||||
switch (c) {
|
||||
case 'l': /* --log-level */
|
||||
param_act(P_ONLY_ONCE, "LOGMARK", "--log-level", *flags & F_LEVEL);
|
||||
param_act(P_NO_INVERT, "LOGMARK", "--log-level", invert);
|
||||
if (!strtonum(optarg, NULL, &x, 0, 8))
|
||||
param_act(P_BAD_VALUE, "LOGMARK", "--log-level", optarg);
|
||||
xtables_param_act(XTF_ONLY_ONCE, "LOGMARK", "--log-level", *flags & F_LEVEL);
|
||||
xtables_param_act(XTF_NO_INVERT, "LOGMARK", "--log-level", invert);
|
||||
if (!xtables_strtoui(optarg, NULL, &x, 0, 8))
|
||||
xtables_param_act(XTF_BAD_VALUE, "LOGMARK", "--log-level", optarg);
|
||||
info->level = x;
|
||||
*flags |= F_LEVEL;
|
||||
return true;
|
||||
|
||||
case 'p': /* --log-prefix */
|
||||
param_act(P_ONLY_ONCE, "LOGMARK", "--log-prefix", *flags & F_PREFIX);
|
||||
param_act(P_NO_INVERT, "LOGMARK", "--log-prefix", invert);
|
||||
xtables_param_act(XTF_ONLY_ONCE, "LOGMARK", "--log-prefix", *flags & F_PREFIX);
|
||||
xtables_param_act(XTF_NO_INVERT, "LOGMARK", "--log-prefix", invert);
|
||||
if (strlen(optarg) > sizeof(info->prefix))
|
||||
exit_error(PARAMETER_PROBLEM, "LOGMARK: Maximum "
|
||||
xtables_error(PARAMETER_PROBLEM, "LOGMARK: Maximum "
|
||||
"prefix length is %zu",
|
||||
sizeof(info->prefix));
|
||||
if (strchr(optarg, '\n'))
|
||||
exit_error(PARAMETER_PROBLEM, "LOGMARK: Newlines not "
|
||||
xtables_error(PARAMETER_PROBLEM, "LOGMARK: Newlines not "
|
||||
"allowed in log prefix");
|
||||
strncpy(info->prefix, optarg, sizeof(info->prefix));
|
||||
*flags |= F_PREFIX;
|
||||
@@ -76,31 +77,30 @@ logmark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
logmark_tg_print(const void *ip, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
const struct xt_logmark_tginfo *info = (void *)target->data;
|
||||
|
||||
printf("LOGMARK level %u prefix \"%s\" ", info->level, info->prefix);
|
||||
}
|
||||
|
||||
static void
|
||||
logmark_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_logmark_tginfo *info = (void *)target->data;
|
||||
|
||||
if (info->level != 4)
|
||||
printf("--log-level %u ", info->level);
|
||||
printf(" --log-level %u ", info->level);
|
||||
if (*info->prefix != '\0')
|
||||
printf("--log-prefix \"%s\" ", info->prefix);
|
||||
printf(" --log-prefix \"%s\" ", info->prefix);
|
||||
}
|
||||
|
||||
static void
|
||||
logmark_tg_print(const void *ip, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
printf(" -j LOGMARK");
|
||||
logmark_tg_save(ip, target);
|
||||
}
|
||||
|
||||
static struct xtables_target logmark_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "LOGMARK",
|
||||
.revision = 0,
|
||||
.family = AF_UNSPEC,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.size = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_logmark_tginfo)),
|
||||
.help = logmark_tg_help,
|
||||
@@ -111,8 +111,7 @@ static struct xtables_target logmark_tg_reg = {
|
||||
.extra_opts = logmark_tg_opts,
|
||||
};
|
||||
|
||||
void _init(void);
|
||||
void _init(void)
|
||||
static __attribute__((constructor)) void logmark_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&logmark_tg_reg);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
.PP
|
||||
The LOGMARK target will log packet and connection marks to syslog.
|
||||
.TP
|
||||
\fB--log-level\fR \fIlevel\fR
|
||||
\fB\-\-log\-level\fR \fIlevel\fR
|
||||
A logging level between 0 and 8 (inclusive).
|
||||
.TP
|
||||
\fB--log-prefix\fR \fIstring\fR
|
||||
\fB\-\-log\-prefix\fR \fIstring\fR
|
||||
Prefix log messages with the specified prefix; up to 29 bytes long, and useful
|
||||
for distinguishing messages in the logs.
|
||||
.TP
|
||||
\fB--log-nfmark\fR
|
||||
Include the packet mark in the log.
|
||||
.TP
|
||||
\fB--log-ctmark\fR
|
||||
Include the connection mark in the log.
|
||||
.TP
|
||||
\fB--log-secmark\fR
|
||||
Include the packet secmark in the log.
|
||||
|
||||
105
extensions/libxt_PROTO.c
Normal file
105
extensions/libxt_PROTO.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* PROTO Target module
|
||||
* This program is distributed under the terms of GNU GPL
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_PROTO.h"
|
||||
|
||||
enum {
|
||||
O_PROTO_SET = 0,
|
||||
O_PROTO_STOP_AT_FRAG = 1,
|
||||
O_PROTO_STOP_AT_AUTH = 2,
|
||||
F_PROTO_SET = 1 << O_PROTO_SET,
|
||||
F_PROTO_STOP_AT_FRAG = 1 << O_PROTO_STOP_AT_FRAG,
|
||||
F_PROTO_STOP_AT_AUTH = 1 << O_PROTO_STOP_AT_AUTH,
|
||||
};
|
||||
|
||||
#define s struct xt_PROTO_info
|
||||
static const struct xt_option_entry PROTO_opts[] = {
|
||||
{.name = "proto-set", .type = XTTYPE_UINT8, .id = O_PROTO_SET,
|
||||
.flags = XTOPT_PUT | XTOPT_MAND, XTOPT_POINTER(s, proto)},
|
||||
{.name = "stop-at-frag", .type = XTTYPE_NONE, .id = O_PROTO_STOP_AT_FRAG},
|
||||
{.name = "stop-at-auth", .type = XTTYPE_NONE, .id = O_PROTO_STOP_AT_AUTH},
|
||||
XTOPT_TABLEEND,
|
||||
};
|
||||
#undef s
|
||||
|
||||
static void PROTO_help(void)
|
||||
{
|
||||
printf(
|
||||
"PROTO target options\n"
|
||||
" --proto-set value Set protocol to <value 0-255>\n"
|
||||
);
|
||||
}
|
||||
|
||||
static void PROTO_parse(struct xt_option_call *cb)
|
||||
{
|
||||
struct xt_PROTO_info *info = cb->data;
|
||||
|
||||
xtables_option_parse(cb);
|
||||
switch (cb->entry->id) {
|
||||
case O_PROTO_SET:
|
||||
info->mode |= 1 << XT_PROTO_SET;
|
||||
break;
|
||||
case O_PROTO_STOP_AT_FRAG:
|
||||
info->mode |= 1 << XT_PROTO_STOP_AT_FRAG;
|
||||
break;
|
||||
case O_PROTO_STOP_AT_AUTH:
|
||||
info->mode |= 1 << XT_PROTO_STOP_AT_AUTH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void PROTO_check(struct xt_fcheck_call *cb)
|
||||
{
|
||||
if (!(cb->xflags & F_PROTO_SET))
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"PROTO: You must specify the proto to be set");
|
||||
}
|
||||
|
||||
static void PROTO_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_PROTO_info *info = (void *)target->data;
|
||||
|
||||
if (info->mode & (1 << XT_PROTO_SET))
|
||||
printf(" --proto-set %u", info->proto);
|
||||
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
|
||||
printf(" --stop-at-frag");
|
||||
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
|
||||
printf(" --stop-at-auth");
|
||||
}
|
||||
|
||||
static void PROTO_print(const void *ip, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
const struct xt_PROTO_info *info = (void *)target->data;
|
||||
|
||||
printf(" PROTO ");
|
||||
if (info->mode & (1 << XT_PROTO_SET))
|
||||
printf("set to %u", info->proto);
|
||||
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
|
||||
printf(" stop-at-frag");
|
||||
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
|
||||
printf(" stop-at-auth");
|
||||
}
|
||||
|
||||
static struct xtables_target proto_tg_reg = {
|
||||
.name = "PROTO",
|
||||
.version = XTABLES_VERSION,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.size = XT_ALIGN(sizeof(struct xt_PROTO_info)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_PROTO_info)),
|
||||
.help = PROTO_help,
|
||||
.print = PROTO_print,
|
||||
.save = PROTO_save,
|
||||
.x6_parse = PROTO_parse,
|
||||
.x6_fcheck = PROTO_check,
|
||||
.x6_options = PROTO_opts,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void _init(void)
|
||||
{
|
||||
xtables_register_target(&proto_tg_reg);
|
||||
|
||||
}
|
||||
30
extensions/libxt_PROTO.man
Normal file
30
extensions/libxt_PROTO.man
Normal file
@@ -0,0 +1,30 @@
|
||||
.PP
|
||||
The PROTO target modifies the protocol number in IP packet header.
|
||||
.TP
|
||||
\fB\-\-proto-set\fP \fIproto_num\fP
|
||||
This option is mandatory. \fIproto_num\fP is the protocol number to which you want to
|
||||
modify the packets.
|
||||
.TP
|
||||
\fB\-\-stop-at-frag\fP
|
||||
This option is only valid for IPv6 rules. When specifying this option, the
|
||||
fragment extension header will be seen as a non-extension header.
|
||||
.TP
|
||||
\fB\-\-stop-at-auth\fP
|
||||
This option is only valid for IPv6 rules. When specifying this option, the
|
||||
authentication extension header will be seen as a non-extension header.
|
||||
.PP
|
||||
For IPv4 packets, the \fBProtocol\fP field is modified and the checksum is
|
||||
re-calculated.
|
||||
.PP
|
||||
For IPv6 packets, the scenario can be more complex due to the introduction of
|
||||
the extension headers mechanism. By default, the PROTO target will scan the IPv6
|
||||
packet, finding the last extension header and modify its \fBNext-header\fP field.
|
||||
Normally, the following headers will be seen as an extension header:
|
||||
\fINEXTHDR_HOP\fP,
|
||||
\fINEXTHDR_ROUTING\fP,
|
||||
\fINEXTHDR_FRAGMENT\fP,
|
||||
\fINEXTHDR_AUTH\fP,
|
||||
\fINEXTHDR_DEST\fP.
|
||||
.PP
|
||||
For fragmented packets, only the first fragment is processed and other fragments
|
||||
are not touched.
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
#include "compat_user.h"
|
||||
|
||||
static void sysrq_tg_help(void)
|
||||
{
|
||||
@@ -21,30 +22,17 @@ 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,
|
||||
.name = "SYSRQ",
|
||||
.family = PF_INET,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.revision = 1,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.help = sysrq_tg_help,
|
||||
.parse = sysrq_tg_parse,
|
||||
.final_check = sysrq_tg_check,
|
||||
};
|
||||
|
||||
static struct xtables_target sysrq_tg6_reg = {
|
||||
.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)
|
||||
static __attribute__((constructor)) void sysrq_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&sysrq_tg4_reg);
|
||||
xtables_register_target(&sysrq_tg6_reg);
|
||||
xtables_register_target(&sysrq_tg_reg);
|
||||
}
|
||||
|
||||
@@ -1,47 +1,84 @@
|
||||
.PP
|
||||
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
|
||||
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 \(em if still possible, use /proc/sysrq-trigger. Even when
|
||||
processes are stuck, interrupts are likely to be still processed, and as such,
|
||||
sysrq can be triggered through incoming network packets.
|
||||
.PP
|
||||
This xt_SYSRQ implementation does not use any encryption, so you should change
|
||||
the SYSRQ password after use unless you have made sure it was transmitted
|
||||
securely and no one sniffed the network, e.g. by use of an IPsec tunnel whose
|
||||
endpoint is at the machine where you want to trigger the sysrq. Also, you
|
||||
should limit as to who can issue 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:
|
||||
The xt_SYSRQ implementation uses a salted hash and a sequence number to prevent
|
||||
network sniffers from either guessing the password or replaying earlier
|
||||
requests. The initial sequence number comes from the time of day so you will
|
||||
have a small window of vulnerability should time go backwards at a reboot.
|
||||
However, the file /sys/module/xt_SYSREQ/seqno can be used to both query and
|
||||
update the current sequence number. Also, you should limit as to who can issue
|
||||
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
|
||||
-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
|
||||
\-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
|
||||
.IP
|
||||
(with IPsec) -A INPUT -s 10.10.25.1 -d 10.10.25.7 -m policy --dir in --pol
|
||||
ipsec --proto esp --tunnel-src 10.10.25.1 --tunnel-dst 10.10.25.7
|
||||
-p udp --dport 9 -j SYSRQ
|
||||
(with IPsec) \-A INPUT \-s 10.10.25.1 \-d 10.10.25.7 \-m policy \-\-dir in
|
||||
\-\-pol ipsec \-\-proto esp \-\-tunnel\-src 10.10.25.1 \-\-tunnel\-dst
|
||||
10.10.25.7 \-p udp \-\-dport 9 \-j SYSRQ
|
||||
.PP
|
||||
This extension does not take any options. The \fB-p udp\fP options are
|
||||
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
|
||||
required.
|
||||
.PP
|
||||
The SYSRQ password can be changed through
|
||||
/sys/module/xt_SYSRQ/parameters/password; note you need to use `echo -n` to
|
||||
not add a newline to the password, i.e.
|
||||
/sys/module/xt_SYSRQ/parameters/password, for example:
|
||||
.IP
|
||||
echo -n "password" >/sys/.../password
|
||||
echo \-n "password" >/sys/module/xt_SYSRQ/parameters/password
|
||||
.PP
|
||||
The module will not respond to sysrq requests until a password has been set.
|
||||
.PP
|
||||
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
|
||||
line in /etc/modprobe.d/sysrq if it is properly guarded, that is, only readable
|
||||
by root.
|
||||
line in e.g. /etc/modprobe.d/xt_sysrq if it is properly guarded, that is, only
|
||||
readable by root.
|
||||
.IP
|
||||
options xt_SYSRQ password=cookies
|
||||
.PP
|
||||
To trigger SYSRQ from a remote host, just use netcat or socat, specifying the
|
||||
action (only one) as first character, followed by the password:
|
||||
The hash algorithm can also be specified as a module option, for example, to
|
||||
use SHA-256 instead of the default SHA-1:
|
||||
.IP
|
||||
echo -n "scookies" | socat stdin udp-sendto:10.10.25.7:9
|
||||
.IP
|
||||
echo -n "scookies" | netcat -u 10.10.25.7 9
|
||||
options xt_SYSRQ hash=sha256
|
||||
.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.
|
||||
The xt_SYSRQ module is normally silent unless a successful request is received,
|
||||
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 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)"
|
||||
ipaddr="2001:0db8:0000:0000:0000:ff00:0042:8329"
|
||||
req="$sysrq_key,$seqno,$salt"
|
||||
req="$req,$(echo \-n "$req,$ipaddr,$password" | sha1sum | cut \-c1\-40)"
|
||||
|
||||
echo "$req" | socat stdin udp\-sendto:$ipaddr: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
|
||||
An IPv4 address should have no leading zeros, an IPv6 address should
|
||||
be in the full expanded form (as shown above). The debug option will cause
|
||||
output to be emitted in the same form.
|
||||
.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.
|
||||
|
||||
@@ -1,38 +1,112 @@
|
||||
/*
|
||||
* "TARPIT" target extension to iptables
|
||||
* this file is in the Public Domain
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "xt_TARPIT.h"
|
||||
#include "compat_user.h"
|
||||
|
||||
enum {
|
||||
F_TARPIT = 1 << 0,
|
||||
F_HONEYPOT = 1 << 1,
|
||||
F_RESET = 1 << 2,
|
||||
};
|
||||
|
||||
static const struct option tarpit_tg_opts[] = {
|
||||
{.name = "tarpit", .has_arg = false, .val = 't'},
|
||||
{.name = "honeypot", .has_arg = false, .val = 'h'},
|
||||
{.name = "reset", .has_arg = false, .val = 'r'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void tarpit_tg_help(void)
|
||||
{
|
||||
printf("TARPIT takes no options\n\n");
|
||||
printf(
|
||||
"TARPIT target options:\n"
|
||||
" --tarpit Enable classic 0-window tarpit (default)\n"
|
||||
" --honeypot Enable honeypot option\n"
|
||||
" --reset Enable inline resets\n");
|
||||
}
|
||||
|
||||
static int tarpit_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
return 0;
|
||||
struct xt_tarpit_tginfo *info = (void *)(*target)->data;
|
||||
|
||||
switch (c) {
|
||||
case 't':
|
||||
info->variant = XTTARPIT_TARPIT;
|
||||
*flags |= F_TARPIT;
|
||||
return true;
|
||||
case 'h':
|
||||
info->variant = XTTARPIT_HONEYPOT;
|
||||
*flags |= F_HONEYPOT;
|
||||
return true;
|
||||
case 'r':
|
||||
info->variant = XTTARPIT_RESET;
|
||||
*flags |= F_RESET;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tarpit_tg_check(unsigned int flags)
|
||||
{
|
||||
if (flags == (F_TARPIT | F_HONEYPOT | F_RESET))
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"TARPIT: only one action can be used at a time");
|
||||
}
|
||||
|
||||
static void tarpit_tg_save(const void *ip,
|
||||
const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_tarpit_tginfo *info = (const void *)target->data;
|
||||
|
||||
switch (info->variant) {
|
||||
case XTTARPIT_TARPIT:
|
||||
printf(" --tarpit ");
|
||||
break;
|
||||
case XTTARPIT_HONEYPOT:
|
||||
printf(" --honeypot ");
|
||||
break;
|
||||
case XTTARPIT_RESET:
|
||||
printf(" --reset ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tarpit_tg_print(const void *ip,
|
||||
const struct xt_entry_target *target, int numeric)
|
||||
{
|
||||
printf(" -j TARPIT");
|
||||
tarpit_tg_save(ip, target);
|
||||
}
|
||||
|
||||
static struct xtables_target tarpit_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "TARPIT",
|
||||
.family = AF_INET,
|
||||
.size = XT_ALIGN(0),
|
||||
.userspacesize = XT_ALIGN(0),
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.size = XT_ALIGN(sizeof(struct xt_tarpit_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_tarpit_tginfo)),
|
||||
.help = tarpit_tg_help,
|
||||
.parse = tarpit_tg_parse,
|
||||
.final_check = tarpit_tg_check,
|
||||
.print = tarpit_tg_print,
|
||||
.save = tarpit_tg_save,
|
||||
.extra_opts = tarpit_tg_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
static __attribute__((constructor)) void tarpit_tg_ldr(void)
|
||||
{
|
||||
xtables_register_target(&tarpit_tg_reg);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,60 @@
|
||||
.PP
|
||||
Captures and holds incoming TCP connections using no local per-connection
|
||||
resources. Connections are accepted, but immediately switched to the persist
|
||||
state (0 byte window), in which the remote side stops sending data and asks to
|
||||
continue every 60-240 seconds. Attempts to close the connection are ignored,
|
||||
forcing the remote side to time out the connection in 12-24 minutes.
|
||||
|
||||
resources.
|
||||
.PP
|
||||
TARPIT only works at the TCP level, and is totally application agnostic. This
|
||||
module will answer a TCP request and play along like a listening server, but
|
||||
aside from sending an ACK or RST, no data is sent. Incoming packets are ignored
|
||||
and dropped. The attacker will terminate the session eventually. This module
|
||||
allows the initial packets of an attack to be captured by other software for
|
||||
inspection. In most cases this is sufficient to determine the nature of the
|
||||
attack.
|
||||
.PP
|
||||
This offers similar functionality to LaBrea
|
||||
<http://www.hackbusters.net/LaBrea/> but does not require dedicated hardware or
|
||||
IPs. Any TCP port that you would normally DROP or REJECT can instead become a
|
||||
tarpit.
|
||||
|
||||
.TP
|
||||
\fB\-\-tarpit\fP
|
||||
This mode completes a connection with the attacker but limits the window size
|
||||
to 0, thus keeping the attacker waiting long periods of time. While he is
|
||||
maintaining state of the connection and trying to continue every 60-240
|
||||
seconds, we keep none, so it is very lightweight. Attempts to close the
|
||||
connection are ignored, forcing the remote side to time out the connection in
|
||||
12-24 minutes. This mode is the default.
|
||||
.TP
|
||||
\fB\-\-honeypot\fP
|
||||
This mode completes a connection with the attacker, but signals a normal window
|
||||
size, so that the remote side will attempt to send data, often with some very
|
||||
nasty exploit attempts. We can capture these packets for decoding and further
|
||||
analysis. The module does not send any data, so if the remote expects an
|
||||
application level response, the game is up.
|
||||
.TP
|
||||
\fB\-\-reset\fP
|
||||
This mode is handy because we can send an inline RST (reset). It has no other
|
||||
function.
|
||||
.PP
|
||||
To tarpit connections to TCP port 80 destined for the current machine:
|
||||
.IP
|
||||
-A INPUT -p tcp -m tcp --dport 80 -j TARPIT
|
||||
.P
|
||||
\-A INPUT \-p tcp \-m tcp \-\-dport 80 \-j TARPIT
|
||||
.PP
|
||||
To significantly slow down Code Red/Nimda-style scans of unused address space,
|
||||
forward unused ip addresses to a Linux box not acting as a router (e.g. "ip
|
||||
route 10.0.0.0 255.0.0.0 ip.of.linux.box" on a Cisco), enable IP forwarding on
|
||||
the Linux box, and add:
|
||||
.IP
|
||||
-A FORWARD -p tcp -j TARPIT
|
||||
\-A FORWARD \-p tcp \-j TARPIT
|
||||
.IP
|
||||
-A FORWARD -j DROP
|
||||
\-A FORWARD \-j DROP
|
||||
.PP
|
||||
NOTE:
|
||||
If you use the conntrack module while you are using TARPIT, you should also use
|
||||
the NOTRACK target, or the kernel will unnecessarily allocate resources for
|
||||
each TARPITted connection. To TARPIT incoming connections to the standard IRC
|
||||
port while using conntrack, you could:
|
||||
unset tracking on the packet, or the kernel will unnecessarily allocate
|
||||
resources for each TARPITted connection. To TARPIT incoming connections to the
|
||||
standard IRC port while using conntrack, you could:
|
||||
.IP
|
||||
-t raw -A PREROUTING -p tcp --dport 6667 -j NOTRACK
|
||||
\-t raw \-A PREROUTING \-p tcp \-\-dport 6667 \-j CT \-\-notrack
|
||||
.IP
|
||||
-A INPUT -p tcp --dport 6667 -j TARPIT
|
||||
\-A INPUT \-p tcp \-\-dport 6667 \-j NFLOG
|
||||
.IP
|
||||
\-A INPUT \-p tcp \-\-dport 6667 \-j TARPIT
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* "TEE" target extension for iptables
|
||||
* Copyright © Sebastian Claßen <sebastian.classen [at] freenet.ag>, 2007
|
||||
* Jan Engelhardt <jengelh [at] medozas de>, 2007 - 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 <sys/socket.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "xt_TEE.h"
|
||||
|
||||
enum {
|
||||
FLAG_GATEWAY = 1 << 0,
|
||||
};
|
||||
|
||||
static const struct option tee_tg_opts[] = {
|
||||
{.name = "gateway", .has_arg = true, .val = 'g'},
|
||||
{},
|
||||
};
|
||||
|
||||
static void tee_tg_help(void)
|
||||
{
|
||||
printf(
|
||||
"TEE target options:\n"
|
||||
" --gateway IPADDR Route packet via the gateway given by address\n"
|
||||
"\n");
|
||||
}
|
||||
|
||||
static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
struct xt_tee_tginfo *info = (void *)(*target)->data;
|
||||
const struct in_addr *ia;
|
||||
|
||||
switch (c) {
|
||||
case 'g':
|
||||
if (*flags & FLAG_GATEWAY)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Cannot specify --gw more than once");
|
||||
|
||||
if (check_inverse(optarg, &invert, NULL, 0))
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Unexpected \"!\" after --gateway");
|
||||
|
||||
ia = numeric_to_ipaddr(optarg);
|
||||
if (ia == NULL)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Invalid IP address %s", optarg);
|
||||
|
||||
memcpy(&info->gw, ia, sizeof(*ia));
|
||||
*flags |= FLAG_GATEWAY;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tee_tg_check(unsigned int flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
exit_error(PARAMETER_PROBLEM, "TEE target: "
|
||||
"--gateway parameter required");
|
||||
}
|
||||
|
||||
static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (numeric)
|
||||
printf("TEE gw:%s ", ipaddr_to_anyname(&info->gw.in));
|
||||
else
|
||||
printf("TEE gw:%s ", ipaddr_to_numeric(&info->gw.in));
|
||||
}
|
||||
|
||||
static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--gateway %s ", ipaddr_to_numeric(&info->gw.in));
|
||||
}
|
||||
|
||||
static struct xtables_target tee_tg_reg = {
|
||||
.name = "TEE",
|
||||
.version = XTABLES_VERSION,
|
||||
.size = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)),
|
||||
.help = tee_tg_help,
|
||||
.parse = tee_tg_parse,
|
||||
.final_check = tee_tg_check,
|
||||
.print = tee_tg_print,
|
||||
.save = tee_tg_save,
|
||||
.extra_opts = tee_tg_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_target(&tee_tg_reg);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
* "condition" match extension for iptables
|
||||
* Stephane Ouellette <ouellettes [at] videotron ca>, 2002-10-22
|
||||
* Massimiliano Hofer <max [at] nucleus it>, 2006-05-15
|
||||
* Jan Engelhardt <jengelh [at] medozas de>, 2008
|
||||
* Jan Engelhardt, 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
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_condition.h"
|
||||
#include "compat_user.h"
|
||||
|
||||
static void condition_help(void)
|
||||
{
|
||||
@@ -37,13 +38,13 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
|
||||
if (c == 'X') {
|
||||
if (*flags)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Can't specify multiple conditions");
|
||||
|
||||
if (strlen(optarg) < sizeof(info->name))
|
||||
strcpy(info->name, optarg);
|
||||
else
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"File name too long");
|
||||
|
||||
info->invert = invert;
|
||||
@@ -57,30 +58,28 @@ static int condition_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
static void condition_check(unsigned int flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Condition match: must specify --condition");
|
||||
}
|
||||
|
||||
static void condition_print(const void *ip, const struct xt_entry_match *match,
|
||||
int numeric)
|
||||
{
|
||||
const struct xt_condition_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("condition %s%s ", (info->invert) ? "!" : "", info->name);
|
||||
}
|
||||
|
||||
|
||||
static void condition_save(const void *ip, const struct xt_entry_match *match)
|
||||
{
|
||||
const struct xt_condition_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("--condition %s\"%s\" ", (info->invert) ? "! " : "", info->name);
|
||||
printf("%s --condition \"%s\" ", info->invert ? " !" : "", info->name);
|
||||
}
|
||||
|
||||
static void condition_print(const void *ip, const struct xt_entry_match *match,
|
||||
int numeric)
|
||||
{
|
||||
printf(" -m condition");
|
||||
condition_save(ip, match);
|
||||
}
|
||||
|
||||
static struct xtables_match condition_mt_reg = {
|
||||
.name = "condition",
|
||||
.revision = 0,
|
||||
.family = PF_UNSPEC,
|
||||
.revision = 1,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.version = XTABLES_VERSION,
|
||||
.size = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_condition_mtinfo)),
|
||||
@@ -92,7 +91,7 @@ static struct xtables_match condition_mt_reg = {
|
||||
.extra_opts = condition_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
static __attribute__((constructor)) void condition_mt_ldr(void)
|
||||
{
|
||||
xtables_register_match(&condition_mt_reg);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
.PP
|
||||
This matches if a specific condition variable is (un)set.
|
||||
.TP
|
||||
[\fB!\fP] \fB--condition\fP \fIname\fP
|
||||
[\fB!\fP] \fB\-\-condition\fP \fIname\fP
|
||||
Match on boolean value stored in /proc/net/nf_condition/\fIname\fP.
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* "dhcpaddr" match 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_DHCPADDR.h"
|
||||
#include "mac.c"
|
||||
|
||||
enum {
|
||||
F_MAC = 1 << 0,
|
||||
};
|
||||
|
||||
static const struct option dhcpaddr_mt_opts[] = {
|
||||
{.name = "mac", .has_arg = true, .val = 'M'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void dhcpaddr_mt_help(void)
|
||||
{
|
||||
printf(
|
||||
"dhcpaddr match options:\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,
|
||||
unsigned int *flags, const void *entry, struct xt_entry_match **match)
|
||||
{
|
||||
struct dhcpaddr_info *info = (void *)(*match)->data;
|
||||
|
||||
switch (c) {
|
||||
case 'M':
|
||||
param_act(P_ONLY_ONCE, "dhcpaddr", "--mac", *flags & F_MAC);
|
||||
param_act(P_NO_INVERT, "dhcpaddr", "--mac", invert);
|
||||
if (!mac_parse(optarg, info->addr, &info->mask))
|
||||
param_act(P_BAD_VALUE, "dhcpaddr", "--mac", optarg);
|
||||
if (invert)
|
||||
info->invert = true;
|
||||
*flags |= F_MAC;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dhcpaddr_mt_check(unsigned int flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
exit_error(PARAMETER_PROBLEM, "dhcpaddr match: "
|
||||
"--mac parameter required");
|
||||
}
|
||||
|
||||
static void dhcpaddr_mt_print(const void *ip,
|
||||
const struct xt_entry_match *match, int numeric)
|
||||
{
|
||||
const struct dhcpaddr_info *info = (void *)match->data;
|
||||
|
||||
printf("dhcpaddr %s" DH_MAC_FMT "/%u ",
|
||||
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
static void dhcpaddr_mt_save(const void *ip,
|
||||
const struct xt_entry_match *match)
|
||||
{
|
||||
const struct dhcpaddr_info *info = (void *)match->data;
|
||||
|
||||
if (info->invert)
|
||||
printf("! ");
|
||||
printf("--mac " DH_MAC_FMT "/%u ",
|
||||
DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
static struct xtables_match dhcpaddr_mt_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_mt_help,
|
||||
.parse = dhcpaddr_mt_parse,
|
||||
.final_check = dhcpaddr_mt_check,
|
||||
.print = dhcpaddr_mt_print,
|
||||
.save = dhcpaddr_mt_save,
|
||||
.extra_opts = dhcpaddr_mt_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_match(&dhcpaddr_mt_reg);
|
||||
}
|
||||
@@ -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.
|
||||
101
extensions/libxt_dhcpmac.c
Normal file
101
extensions/libxt_dhcpmac.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* "dhcpmac" match extension for iptables
|
||||
* Copyright © Jan Engelhardt, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <netdb.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <xtables.h>
|
||||
#include "xt_DHCPMAC.h"
|
||||
#include "mac.c"
|
||||
#include "compat_user.h"
|
||||
|
||||
enum {
|
||||
F_MAC = 1 << 0,
|
||||
};
|
||||
|
||||
static const struct option dhcpmac_mt_opts[] = {
|
||||
{.name = "mac", .has_arg = true, .val = 'M'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void dhcpmac_mt_help(void)
|
||||
{
|
||||
printf(
|
||||
"dhcpmac match options:\n"
|
||||
"[!] --mac lladdr[/mask] Match on MAC address in DHCP Client Host field\n"
|
||||
);
|
||||
}
|
||||
|
||||
static int dhcpmac_mt_parse(int c, char **argv, int invert,
|
||||
unsigned int *flags, const void *entry, struct xt_entry_match **match)
|
||||
{
|
||||
struct dhcpmac_info *info = (void *)(*match)->data;
|
||||
|
||||
switch (c) {
|
||||
case 'M':
|
||||
xtables_param_act(XTF_ONLY_ONCE, "dhcpmac", "--mac", *flags & F_MAC);
|
||||
xtables_param_act(XTF_NO_INVERT, "dhcpmac", "--mac", invert);
|
||||
if (!mac_parse(optarg, info->addr, &info->mask))
|
||||
xtables_param_act(XTF_BAD_VALUE, "dhcpmac", "--mac", optarg);
|
||||
if (invert)
|
||||
info->invert = true;
|
||||
*flags |= F_MAC;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dhcpmac_mt_check(unsigned int flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
xtables_error(PARAMETER_PROBLEM, "dhcpmac match: "
|
||||
"--mac parameter required");
|
||||
}
|
||||
|
||||
static void dhcpmac_mt_save(const void *ip,
|
||||
const struct xt_entry_match *match)
|
||||
{
|
||||
const struct dhcpmac_info *info = (void *)match->data;
|
||||
|
||||
if (info->invert)
|
||||
printf(" !");
|
||||
printf(" --mac " DH_MAC_FMT "/%u ",
|
||||
DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
static void dhcpmac_mt_print(const void *ip,
|
||||
const struct xt_entry_match *match, int numeric)
|
||||
{
|
||||
printf(" -m dhcpmac");
|
||||
dhcpmac_mt_save(ip, match);
|
||||
}
|
||||
|
||||
static struct xtables_match dhcpmac_mt_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "dhcpmac",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.size = XT_ALIGN(sizeof(struct dhcpmac_info)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct dhcpmac_info)),
|
||||
.help = dhcpmac_mt_help,
|
||||
.parse = dhcpmac_mt_parse,
|
||||
.final_check = dhcpmac_mt_check,
|
||||
.print = dhcpmac_mt_print,
|
||||
.save = dhcpmac_mt_save,
|
||||
.extra_opts = dhcpmac_mt_opts,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void dhcpmac_mt_ldr(void)
|
||||
{
|
||||
xtables_register_match(&dhcpmac_mt_reg);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user