]>
Commit | Line | Data |
---|---|---|
e00b0090 | 1 | include/linux/netfilter_ipv4/ipt_fuzzy.h | 21 +++ |
2 | include/linux/netfilter_ipv6/ip6t_fuzzy.h | 21 +++ | |
3 | net/ipv4/netfilter/Kconfig | 10 + | |
4 | net/ipv4/netfilter/Makefile | 1 | |
5 | net/ipv4/netfilter/ipt_fuzzy.c | 185 +++++++++++++++++++++++++++++ | |
6 | net/ipv6/netfilter/Kconfig | 10 + | |
7 | net/ipv6/netfilter/Makefile | 1 | |
8 | net/ipv6/netfilter/ip6t_fuzzy.c | 188 ++++++++++++++++++++++++++++++ | |
9 | 8 files changed, 437 insertions(+) | |
10 | ||
11 | diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv4/ipt_fuzzy.h linux/include/linux/netfilter_ipv4/ipt_fuzzy.h | |
12 | --- linux.org/include/linux/netfilter_ipv4/ipt_fuzzy.h 1970-01-01 01:00:00.000000000 +0100 | |
13 | +++ linux/include/linux/netfilter_ipv4/ipt_fuzzy.h 2006-05-04 10:09:04.000000000 +0200 | |
14 | @@ -0,0 +1,21 @@ | |
15 | +#ifndef _IPT_FUZZY_H | |
16 | +#define _IPT_FUZZY_H | |
17 | + | |
18 | +#include <linux/param.h> | |
19 | +#include <linux/types.h> | |
20 | + | |
21 | +#define MAXFUZZYRATE 10000000 | |
22 | +#define MINFUZZYRATE 3 | |
23 | + | |
24 | +struct ipt_fuzzy_info { | |
25 | + u_int32_t minimum_rate; | |
26 | + u_int32_t maximum_rate; | |
27 | + u_int32_t packets_total; | |
28 | + u_int32_t bytes_total; | |
29 | + u_int32_t previous_time; | |
30 | + u_int32_t present_time; | |
31 | + u_int32_t mean_rate; | |
32 | + u_int8_t acceptance_rate; | |
33 | +}; | |
34 | + | |
35 | +#endif /*_IPT_FUZZY_H*/ | |
36 | diff -Nur --exclude '*.orig' linux.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h linux/include/linux/netfilter_ipv6/ip6t_fuzzy.h | |
37 | --- linux.org/include/linux/netfilter_ipv6/ip6t_fuzzy.h 1970-01-01 01:00:00.000000000 +0100 | |
38 | +++ linux/include/linux/netfilter_ipv6/ip6t_fuzzy.h 2006-05-04 10:09:04.000000000 +0200 | |
39 | @@ -0,0 +1,21 @@ | |
40 | +#ifndef _IP6T_FUZZY_H | |
41 | +#define _IP6T_FUZZY_H | |
42 | + | |
43 | +#include <linux/param.h> | |
44 | +#include <linux/types.h> | |
45 | + | |
46 | +#define MAXFUZZYRATE 10000000 | |
47 | +#define MINFUZZYRATE 3 | |
48 | + | |
49 | +struct ip6t_fuzzy_info { | |
50 | + u_int32_t minimum_rate; | |
51 | + u_int32_t maximum_rate; | |
52 | + u_int32_t packets_total; | |
53 | + u_int32_t bytes_total; | |
54 | + u_int32_t previous_time; | |
55 | + u_int32_t present_time; | |
56 | + u_int32_t mean_rate; | |
57 | + u_int8_t acceptance_rate; | |
58 | +}; | |
59 | + | |
60 | +#endif /*_IP6T_FUZZY_H*/ | |
61 | diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Kconfig linux/net/ipv4/netfilter/Kconfig | |
62 | --- linux.org/net/ipv4/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200 | |
63 | +++ linux/net/ipv4/netfilter/Kconfig 2006-05-04 10:09:04.000000000 +0200 | |
64 | @@ -606,5 +606,15 @@ | |
65 | Allows altering the ARP packet payload: source and destination | |
66 | hardware and network addresses. | |
67 | ||
68 | +config IP_NF_MATCH_FUZZY | |
69 | + tristate 'fuzzy match support' | |
70 | + depends on IP_NF_IPTABLES | |
71 | + help | |
72 | + This option adds a `fuzzy' match, which allows you to match | |
73 | + packets according to a fuzzy logic based law. | |
74 | + | |
75 | + If you want to compile it as a module, say M here and read | |
76 | + Documentation/modules.txt. If unsure, say `N'. | |
77 | + | |
78 | endmenu | |
79 | ||
80 | diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/Makefile linux/net/ipv4/netfilter/Makefile | |
81 | --- linux.org/net/ipv4/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200 | |
82 | +++ linux/net/ipv4/netfilter/Makefile 2006-05-04 10:09:04.000000000 +0200 | |
83 | @@ -0,0 +0,1 @@ | |
84 | +obj-$(CONFIG_IP_NF_MATCH_FUZZY) += ipt_fuzzy.o | |
85 | diff -Nur --exclude '*.orig' linux.org/net/ipv4/netfilter/ipt_fuzzy.c linux/net/ipv4/netfilter/ipt_fuzzy.c | |
86 | --- linux.org/net/ipv4/netfilter/ipt_fuzzy.c 1970-01-01 01:00:00.000000000 +0100 | |
87 | +++ linux/net/ipv4/netfilter/ipt_fuzzy.c 2006-05-04 10:09:04.000000000 +0200 | |
88 | @@ -0,0 +1,186 @@ | |
89 | +/* | |
90 | + * This module implements a simple TSK FLC | |
91 | + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims | |
92 | + * to limit , in an adaptive and flexible way , the packet rate crossing | |
93 | + * a given stream . It serves as an initial and very simple (but effective) | |
94 | + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks. | |
95 | + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior" | |
96 | + * into our code in a precise , adaptive and efficient manner. | |
97 | + * The goal is very similar to that of "limit" match , but using techniques of | |
98 | + * Fuzzy Control , that allow us to shape the transfer functions precisely , | |
99 | + * avoiding over and undershoots - and stuff like that . | |
100 | + * | |
101 | + * | |
102 | + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version. | |
103 | + * 2002-08-17 : Changed to eliminate floating point operations . | |
104 | + * 2002-08-23 : Coding style changes . | |
105 | +*/ | |
106 | + | |
107 | +#include <linux/module.h> | |
108 | +#include <linux/skbuff.h> | |
109 | +#include <linux/ip.h> | |
110 | +#include <linux/random.h> | |
111 | +#include <net/tcp.h> | |
112 | +#include <linux/spinlock.h> | |
113 | +#include <linux/netfilter_ipv4/ip_tables.h> | |
114 | +#include <linux/netfilter_ipv4/ipt_fuzzy.h> | |
115 | + | |
116 | +/* | |
117 | + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH | |
118 | + Expressed in percentage | |
119 | +*/ | |
120 | + | |
121 | +#define PAR_LOW 1/100 | |
122 | +#define PAR_HIGH 1 | |
123 | + | |
124 | +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED ; | |
125 | + | |
126 | +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>"); | |
127 | +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); | |
128 | +MODULE_LICENSE("GPL"); | |
129 | + | |
130 | +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi) | |
131 | +{ | |
132 | + if (tx >= maxi) | |
133 | + return 100; | |
134 | + | |
135 | + if (tx <= mini) | |
136 | + return 0; | |
137 | + | |
138 | + return ( (100*(tx-mini)) / (maxi-mini) ); | |
139 | +} | |
140 | + | |
141 | +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi) | |
142 | +{ | |
143 | + if (tx <= mini) | |
144 | + return 100; | |
145 | + | |
146 | + if (tx >= maxi) | |
147 | + return 0; | |
148 | + | |
149 | + return ( (100*( maxi - tx )) / ( maxi - mini ) ); | |
150 | +} | |
151 | + | |
152 | +static int | |
153 | +ipt_fuzzy_match(const struct sk_buff *pskb, | |
154 | + const struct net_device *in, | |
155 | + const struct net_device *out, | |
156 | + const void *matchinfo, | |
157 | + int offset, | |
158 | + unsigned int protoff, | |
159 | + int *hotdrop) | |
160 | +{ | |
161 | + /* From userspace */ | |
162 | + | |
163 | + struct ipt_fuzzy_info *info = (struct ipt_fuzzy_info *) matchinfo; | |
164 | + | |
165 | + u_int8_t random_number; | |
166 | + unsigned long amount; | |
167 | + u_int8_t howhigh, howlow; | |
168 | + | |
169 | + | |
170 | + spin_lock_bh(&fuzzy_lock); /* Rise the lock */ | |
171 | + | |
172 | + info->bytes_total += pskb->len; | |
173 | + info->packets_total++; | |
174 | + | |
175 | + info->present_time = jiffies; | |
176 | + | |
177 | + if (info->present_time >= info->previous_time) | |
178 | + amount = info->present_time - info->previous_time; | |
179 | + else { | |
180 | + /* There was a transition : I choose to re-sample | |
181 | + and keep the old acceptance rate... | |
182 | + */ | |
183 | + | |
184 | + amount = 0; | |
185 | + info->previous_time = info->present_time; | |
186 | + info->bytes_total = info->packets_total = 0; | |
187 | + }; | |
188 | + | |
189 | + if (amount > HZ/10) /* More than 100 ms elapsed ... */ | |
190 | + { | |
191 | + | |
192 | + info->mean_rate = (u_int32_t) ((HZ*info->packets_total) \ | |
193 | + / amount ); | |
194 | + | |
195 | + info->previous_time = info->present_time; | |
196 | + info->bytes_total = info->packets_total = 0; | |
197 | + | |
198 | + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); | |
199 | + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); | |
200 | + | |
201 | + info->acceptance_rate = (u_int8_t) \ | |
202 | + (howhigh*PAR_LOW + PAR_HIGH*howlow); | |
203 | + | |
204 | + /* In fact , the above defuzzification would require a denominator | |
205 | + proportional to (howhigh+howlow) but , in this particular case , | |
206 | + that expression is constant . | |
207 | + An imediate consequence is that it isn't necessary to call | |
208 | + both mf_high and mf_low - but to keep things understandable , | |
209 | + I did so . */ | |
210 | + | |
211 | + } | |
212 | + | |
213 | + spin_unlock_bh(&fuzzy_lock); /* Release the lock */ | |
214 | + | |
215 | + | |
216 | + if ( info->acceptance_rate < 100 ) | |
217 | + { | |
218 | + get_random_bytes((void *)(&random_number), 1); | |
219 | + | |
220 | + /* If within the acceptance , it can pass => don't match */ | |
221 | + if (random_number <= (255 * info->acceptance_rate) / 100) | |
222 | + return 0; | |
223 | + else | |
224 | + return 1; /* It can't pass ( It matches ) */ | |
225 | + } ; | |
226 | + | |
227 | + return 0; /* acceptance_rate == 100 % => Everything passes ... */ | |
228 | + | |
229 | +} | |
230 | + | |
231 | +static int | |
232 | +ipt_fuzzy_checkentry(const char *tablename, | |
233 | + const struct ipt_ip *e, | |
234 | + void *matchinfo, | |
235 | + unsigned int matchsize, | |
236 | + unsigned int hook_mask) | |
237 | +{ | |
238 | + | |
239 | + const struct ipt_fuzzy_info *info = matchinfo; | |
240 | + | |
241 | + if (matchsize != IPT_ALIGN(sizeof(struct ipt_fuzzy_info))) { | |
242 | + printk("ipt_fuzzy: matchsize %u != %zu\n", matchsize, | |
243 | + IPT_ALIGN(sizeof(struct ipt_fuzzy_info))); | |
244 | + return 0; | |
245 | + } | |
246 | + | |
247 | + if ((info->minimum_rate < MINFUZZYRATE ) || (info->maximum_rate > MAXFUZZYRATE) | |
248 | + || (info->minimum_rate >= info->maximum_rate )) { | |
249 | + printk("ipt_fuzzy: BAD limits , please verify !!!\n"); | |
250 | + return 0; | |
251 | + } | |
252 | + | |
253 | + return 1; | |
254 | +} | |
255 | + | |
256 | +static struct ipt_match ipt_fuzzy_reg = { | |
257 | + .name = "fuzzy", | |
258 | + .match = ipt_fuzzy_match, | |
259 | + .checkentry = ipt_fuzzy_checkentry, | |
260 | + .me = THIS_MODULE | |
261 | +}; | |
262 | + | |
263 | +static int __init init(void) | |
264 | +{ | |
265 | + return ipt_register_match(&ipt_fuzzy_reg); | |
266 | +} | |
267 | + | |
268 | +static void __exit fini(void) | |
269 | +{ | |
270 | + ipt_unregister_match(&ipt_fuzzy_reg); | |
271 | +} | |
272 | + | |
273 | +module_init(init); | |
274 | +module_exit(fini); | |
275 | diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Kconfig linux/net/ipv6/netfilter/Kconfig | |
276 | --- linux.org/net/ipv6/netfilter/Kconfig 2006-05-02 23:38:44.000000000 +0200 | |
277 | +++ linux/net/ipv6/netfilter/Kconfig 2006-05-04 10:09:04.000000000 +0200 | |
278 | @@ -210,5 +210,15 @@ | |
279 | If you want to compile it as a module, say M here and read | |
280 | <file:Documentation/modules.txt>. If unsure, say `N'. | |
281 | ||
282 | +config IP6_NF_MATCH_FUZZY | |
283 | + tristate 'Fuzzy match support' | |
284 | + depends on IP6_NF_FILTER | |
285 | + help | |
286 | + This option adds a `fuzzy' match, which allows you to match | |
287 | + packets according to a fuzzy logic based law. | |
288 | + | |
289 | + If you want to compile it as a module, say M here and read | |
290 | + Documentation/modules.txt. If unsure, say `N'. | |
291 | + | |
292 | endmenu | |
293 | ||
294 | diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/Makefile linux/net/ipv6/netfilter/Makefile | |
295 | --- linux.org/net/ipv6/netfilter/Makefile 2006-05-02 23:38:44.000000000 +0200 | |
296 | +++ linux/net/ipv6/netfilter/Makefile 2006-05-04 10:09:04.000000000 +0200 | |
297 | @@ -0,0 +0,1 @@ | |
298 | +obj-$(CONFIG_IP6_NF_MATCH_FUZZY) += ip6t_fuzzy.o | |
299 | diff -Nur --exclude '*.orig' linux.org/net/ipv6/netfilter/ip6t_fuzzy.c linux/net/ipv6/netfilter/ip6t_fuzzy.c | |
300 | --- linux.org/net/ipv6/netfilter/ip6t_fuzzy.c 1970-01-01 01:00:00.000000000 +0100 | |
301 | +++ linux/net/ipv6/netfilter/ip6t_fuzzy.c 2006-05-04 10:09:04.000000000 +0200 | |
302 | @@ -0,0 +1,186 @@ | |
303 | +/* | |
304 | + * This module implements a simple TSK FLC | |
305 | + * (Takagi-Sugeno-Kang Fuzzy Logic Controller) that aims | |
306 | + * to limit , in an adaptive and flexible way , the packet rate crossing | |
307 | + * a given stream . It serves as an initial and very simple (but effective) | |
308 | + * example of how Fuzzy Logic techniques can be applied to defeat DoS attacks. | |
309 | + * As a matter of fact , Fuzzy Logic can help us to insert any "behavior" | |
310 | + * into our code in a precise , adaptive and efficient manner. | |
311 | + * The goal is very similar to that of "limit" match , but using techniques of | |
312 | + * Fuzzy Control , that allow us to shape the transfer functions precisely , | |
313 | + * avoiding over and undershoots - and stuff like that . | |
314 | + * | |
315 | + * | |
316 | + * 2002-08-10 Hime Aguiar e Oliveira Jr. <hime@engineer.com> : Initial version. | |
317 | + * 2002-08-17 : Changed to eliminate floating point operations . | |
318 | + * 2002-08-23 : Coding style changes . | |
319 | + * 2003-04-08 Maciej Soltysiak <solt@dns.toxicilms.tv> : IPv6 Port | |
320 | + */ | |
321 | + | |
322 | +#include <linux/module.h> | |
323 | +#include <linux/skbuff.h> | |
324 | +#include <linux/ipv6.h> | |
325 | +#include <linux/random.h> | |
326 | +#include <net/tcp.h> | |
327 | +#include <linux/spinlock.h> | |
328 | +#include <linux/netfilter_ipv6/ip6_tables.h> | |
329 | +#include <linux/netfilter_ipv6/ip6t_fuzzy.h> | |
330 | + | |
331 | +/* | |
332 | + Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH | |
333 | + Expressed in percentage | |
334 | +*/ | |
335 | + | |
336 | +#define PAR_LOW 1/100 | |
337 | +#define PAR_HIGH 1 | |
338 | + | |
339 | +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED; | |
340 | + | |
341 | +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior <hime@engineer.com>"); | |
342 | +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); | |
343 | +MODULE_LICENSE("GPL"); | |
344 | + | |
345 | +static u_int8_t mf_high(u_int32_t tx,u_int32_t mini,u_int32_t maxi) | |
346 | +{ | |
347 | + if (tx >= maxi) return 100; | |
348 | + | |
349 | + if (tx <= mini) return 0; | |
350 | + | |
351 | + return ((100 * (tx-mini)) / (maxi-mini)); | |
352 | +} | |
353 | + | |
354 | +static u_int8_t mf_low(u_int32_t tx,u_int32_t mini,u_int32_t maxi) | |
355 | +{ | |
356 | + if (tx <= mini) return 100; | |
357 | + | |
358 | + if (tx >= maxi) return 0; | |
359 | + | |
360 | + return ((100 * (maxi - tx)) / (maxi - mini)); | |
361 | + | |
362 | +} | |
363 | + | |
364 | +static int | |
365 | +ip6t_fuzzy_match(const struct sk_buff *pskb, | |
366 | + const struct net_device *in, | |
367 | + const struct net_device *out, | |
368 | + const void *matchinfo, | |
369 | + int offset, | |
370 | + unsigned int protoff, | |
371 | + int *hotdrop) | |
372 | +{ | |
373 | + /* From userspace */ | |
374 | + | |
375 | + struct ip6t_fuzzy_info *info = (struct ip6t_fuzzy_info *) matchinfo; | |
376 | + | |
377 | + u_int8_t random_number; | |
378 | + unsigned long amount; | |
379 | + u_int8_t howhigh, howlow; | |
380 | + | |
381 | + | |
382 | + spin_lock_bh(&fuzzy_lock); /* Rise the lock */ | |
383 | + | |
384 | + info->bytes_total += pskb->len; | |
385 | + info->packets_total++; | |
386 | + | |
387 | + info->present_time = jiffies; | |
388 | + | |
389 | + if (info->present_time >= info->previous_time) | |
390 | + amount = info->present_time - info->previous_time; | |
391 | + else { | |
392 | + /* There was a transition : I choose to re-sample | |
393 | + and keep the old acceptance rate... | |
394 | + */ | |
395 | + | |
396 | + amount = 0; | |
397 | + info->previous_time = info->present_time; | |
398 | + info->bytes_total = info->packets_total = 0; | |
399 | + }; | |
400 | + | |
401 | + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */ | |
402 | + | |
403 | + info->mean_rate = (u_int32_t) ((HZ * info->packets_total) \ | |
404 | + / amount); | |
405 | + | |
406 | + info->previous_time = info->present_time; | |
407 | + info->bytes_total = info->packets_total = 0; | |
408 | + | |
409 | + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); | |
410 | + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); | |
411 | + | |
412 | + info->acceptance_rate = (u_int8_t) \ | |
413 | + (howhigh * PAR_LOW + PAR_HIGH * howlow); | |
414 | + | |
415 | + /* In fact, the above defuzzification would require a denominator | |
416 | + * proportional to (howhigh+howlow) but, in this particular case, | |
417 | + * that expression is constant. | |
418 | + * An imediate consequence is that it is not necessary to call | |
419 | + * both mf_high and mf_low - but to keep things understandable, | |
420 | + * I did so. | |
421 | + */ | |
422 | + | |
423 | + } | |
424 | + | |
425 | + spin_unlock_bh(&fuzzy_lock); /* Release the lock */ | |
426 | + | |
427 | + | |
428 | + if (info->acceptance_rate < 100) | |
429 | + { | |
430 | + get_random_bytes((void *)(&random_number), 1); | |
431 | + | |
432 | + /* If within the acceptance , it can pass => don't match */ | |
433 | + if (random_number <= (255 * info->acceptance_rate) / 100) | |
434 | + return 0; | |
435 | + else | |
436 | + return 1; /* It can't pass (It matches) */ | |
437 | + }; | |
438 | + | |
439 | + return 0; /* acceptance_rate == 100 % => Everything passes ... */ | |
440 | + | |
441 | +} | |
442 | + | |
443 | +static int | |
444 | +ip6t_fuzzy_checkentry(const char *tablename, | |
445 | + const struct ip6t_ip6 *ip, | |
446 | + void *matchinfo, | |
447 | + unsigned int matchsize, | |
448 | + unsigned int hook_mask) | |
449 | +{ | |
450 | + | |
451 | + const struct ip6t_fuzzy_info *info = matchinfo; | |
452 | + | |
453 | + if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))) { | |
454 | + printk("ip6t_fuzzy: matchsize %u != %zu\n", matchsize, | |
455 | + IP6T_ALIGN(sizeof(struct ip6t_fuzzy_info))); | |
456 | + return 0; | |
457 | + } | |
458 | + | |
459 | + if ((info->minimum_rate < MINFUZZYRATE) || (info->maximum_rate > MAXFUZZYRATE) | |
460 | + || (info->minimum_rate >= info->maximum_rate)) { | |
461 | + printk("ip6t_fuzzy: BAD limits , please verify !!!\n"); | |
462 | + return 0; | |
463 | + } | |
464 | + | |
465 | + return 1; | |
466 | +} | |
467 | + | |
468 | +static struct ip6t_match ip6t_fuzzy_reg = { | |
469 | + .name = "fuzzy", | |
470 | + .match = ip6t_fuzzy_match, | |
471 | + .checkentry = ip6t_fuzzy_checkentry, | |
472 | + .me = THIS_MODULE }; | |
473 | + | |
474 | +static int __init init(void) | |
475 | +{ | |
476 | + if (ip6t_register_match(&ip6t_fuzzy_reg)) | |
477 | + return -EINVAL; | |
478 | + | |
479 | + return 0; | |
480 | +} | |
481 | + | |
482 | +static void __exit fini(void) | |
483 | +{ | |
484 | + ip6t_unregister_match(&ip6t_fuzzy_reg); | |
485 | +} | |
486 | + | |
487 | +module_init(init); | |
488 | +module_exit(fini); |