diff --git a/extensions/Kbuild b/extensions/Kbuild index f0e018a..54c04ef 100644 --- a/extensions/Kbuild +++ b/extensions/Kbuild @@ -14,6 +14,7 @@ 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_ipp2p} += xt_ipp2p.o obj-${build_ipset} += ipset/ diff --git a/extensions/Mbuild b/extensions/Mbuild index d044733..cf9e51c 100644 --- a/extensions/Mbuild +++ b/extensions/Mbuild @@ -7,6 +7,7 @@ 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_ipp2p} += libxt_ipp2p.so obj-${build_portscan} += libxt_portscan.so diff --git a/extensions/libxt_fuzzy.c b/extensions/libxt_fuzzy.c new file mode 100644 index 0000000..1b42329 --- /dev/null +++ b/extensions/libxt_fuzzy.c @@ -0,0 +1,139 @@ +/* + * "fuzzy" match extension for iptables + * Hime Aguiar e Oliveira Jr. , 2002 - 2003 + * + * 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 +#include +#include +#include +#include +#include +#include "xt_fuzzy.h" + +static void fuzzy_mt_help(void) +{ + printf( +"fuzzy v%s options:\n" +" --lower-limit number (in packets per second)\n" +" --upper-limit number\n" +,XTABLES_VERSION); +}; + +static struct option fuzzy_mt_opts[] = { + { "lower-limit", 1 , 0 , '1' } , + { "upper-limit", 1 , 0 , '2' } , + { 0 } +}; + +/* Initialize data structures */ +static void fuzzy_mt_init(struct xt_entry_match *m) +{ + struct xt_fuzzy_mtinfo *info = (void *)m->data; + + /* + * Default rates (I will improve this very soon with something based + * on real statistics of the running machine). + */ + + info->minimum_rate = 1000; + info->maximum_rate = 2000; +} + +#define IPT_FUZZY_OPT_MINIMUM 0x01 +#define IPT_FUZZY_OPT_MAXIMUM 0x02 + +static int fuzzy_mt_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_fuzzy_mtinfo *info = (void *)(*match)->data; + + uint32_t num; + + switch (c) { + + case '1': + + if (invert) + exit_error(PARAMETER_PROBLEM,"Can't specify ! --lower-limit"); + + if (*flags & IPT_FUZZY_OPT_MINIMUM) + exit_error(PARAMETER_PROBLEM,"Can't specify --lower-limit twice"); + + if (string_to_number(optarg,1,FUZZY_MAX_RATE,&num) == -1 || num < 1) + exit_error(PARAMETER_PROBLEM,"BAD --lower-limit"); + + info->minimum_rate = num; + + *flags |= IPT_FUZZY_OPT_MINIMUM; + + break; + + case '2': + + if (invert) + exit_error(PARAMETER_PROBLEM,"Can't specify ! --upper-limit"); + + if (*flags & IPT_FUZZY_OPT_MAXIMUM) + exit_error(PARAMETER_PROBLEM,"Can't specify --upper-limit twice"); + + if (string_to_number(optarg,1,FUZZY_MAX_RATE,&num) == -1 || num < 1) + exit_error(PARAMETER_PROBLEM,"BAD --upper-limit"); + + info->maximum_rate = num; + + *flags |= IPT_FUZZY_OPT_MAXIMUM; + + break; + + default: + return 0; + } + return 1; +} + +static void fuzzy_mt_check(unsigned int flags) +{ +} + +static void fuzzy_mt_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_fuzzy_mtinfo *info = (const void *)match->data; + + printf(" fuzzy: lower limit = %u pps - upper limit = %u pps ",info->minimum_rate,info->maximum_rate); + +} + +/* Saves the union ipt_targinfo in parsable form to stdout. */ +static void fuzzy_mt_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_fuzzy_mtinfo *info = (const void *)match->data; + + printf("--lower-limit %u ", info->minimum_rate); + printf("--upper-limit %u ", info->maximum_rate); + +} + +static struct xtables_match fuzzy_mt_reg = { + .name = "fuzzy", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_fuzzy_mtinfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_fuzzy_mtinfo)), + .help = fuzzy_mt_help, + .init = fuzzy_mt_init, + .parse = fuzzy_mt_parse, + .final_check = fuzzy_mt_check, + .print = fuzzy_mt_print, + .save = fuzzy_mt_save, + .extra_opts = fuzzy_mt_opts, +}; + +static void _init(void) +{ + xtables_register_match(&fuzzy_mt_reg); +} diff --git a/extensions/libxt_fuzzy.man b/extensions/libxt_fuzzy.man new file mode 100644 index 0000000..c2bed1e --- /dev/null +++ b/extensions/libxt_fuzzy.man @@ -0,0 +1,7 @@ +This module matches a rate limit based on a fuzzy logic controller (FLC). +.TP +\fB--lower-limit\fP \fInumber\fP +Specifies the lower limit, in packets per second. +.TP +\fB--upper-limit\fP \fInumber\fP +Specifies the upper limit, also in packets per second. diff --git a/extensions/xt_fuzzy.Kconfig b/extensions/xt_fuzzy.Kconfig new file mode 100644 index 0000000..7e1232e --- /dev/null +++ b/extensions/xt_fuzzy.Kconfig @@ -0,0 +1,6 @@ +config NETFILTER_XT_MATCH_FUZZY + tristate '"fuzzy" match support' + depends on NETFILTER_XTABLES && NETFILTER_ADVANCED + ---help--- + This extension allows you to match on packets according to a fuzzy + logic based law. diff --git a/extensions/xt_fuzzy.c b/extensions/xt_fuzzy.c new file mode 100644 index 0000000..27c6ca4 --- /dev/null +++ b/extensions/xt_fuzzy.c @@ -0,0 +1,187 @@ +/* + * This module implements a simple TSK FLC (Takagi-Sugeno-Kang Fuzzy Logic + * Controller) that aims to limit, in an adaptive and flexible way, the + * packet rate crossing a given stream. It serves as an initial and very + * simple (but effective) example of how Fuzzy Logic techniques can be + * applied to defeat DoS attacks. + * + * As a matter of fact, Fuzzy Logic can help us to insert any "behavior" + * into our code in a precise, adaptive and efficient manner. + * + * The goal is very similar to that of "limit" match, but using techniques + * of Fuzzy Control, that allow us to shape the transfer functions + * precisely, avoiding over and undershoots - and stuff like that. + * + * 2002-08-10 Hime Aguiar e Oliveira Jr. : Initial version. + * 2002-08-17 : Changed to eliminate floating point operations . + * 2002-08-23 : Coding style changes . + * 2003-04-08 Maciej Soltysiak : IPv6 Port + */ + +#include +#include +#include +#include +#include +#include +#include "xt_fuzzy.h" +#include "compat_xtables.h" + +/* + * Packet Acceptance Rate - LOW and Packet Acceptance Rate - HIGH + * Expressed in percentage. + */ + +#define PAR_LOW 1/100 +#define PAR_HIGH 1 + +static spinlock_t fuzzy_lock = SPIN_LOCK_UNLOCKED; + +MODULE_AUTHOR("Hime Aguiar e Oliveira Junior "); +MODULE_DESCRIPTION("IP tables Fuzzy Logic Controller match module"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_fuzzy"); + +static uint8_t mf_high(uint32_t tx,uint32_t mini,uint32_t maxi) +{ + if (tx >= maxi) return 100; + + if (tx <= mini) return 0; + + return ((100 * (tx-mini)) / (maxi-mini)); +} + +static uint8_t mf_low(uint32_t tx,uint32_t mini,uint32_t maxi) +{ + if (tx <= mini) return 100; + + if (tx >= maxi) return 0; + + return ((100 * (maxi - tx)) / (maxi - mini)); + +} + +static bool +fuzzy_mt(const struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, const struct xt_match *match, + const void *matchinfo, int offset, unsigned int protoff, + bool *hotdrop) +{ + /* From userspace */ + + struct xt_fuzzy_mtinfo *info = (void *)matchinfo; + + unsigned long amount; + uint8_t howhigh, howlow, random_number; + + + spin_lock_bh(&fuzzy_lock); /* Rise the lock */ + + info->bytes_total += skb->len; + ++info->packets_total; + + info->present_time = jiffies; + + if (info->present_time >= info->previous_time) + amount = info->present_time - info->previous_time; + else { + /* + * There was a transition: I choose to re-sample + * and keep the old acceptance rate... + */ + + amount = 0; + info->previous_time = info->present_time; + info->bytes_total = info->packets_total = 0; + }; + + if ( amount > HZ/10) {/* More than 100 ms elapsed ... */ + + info->mean_rate = (uint32_t) ((HZ * info->packets_total) \ + / amount); + + info->previous_time = info->present_time; + info->bytes_total = info->packets_total = 0; + + howhigh = mf_high(info->mean_rate,info->minimum_rate,info->maximum_rate); + howlow = mf_low(info->mean_rate,info->minimum_rate,info->maximum_rate); + + info->acceptance_rate = (uint8_t) \ + (howhigh * PAR_LOW + PAR_HIGH * howlow); + + /* + * In fact, the above defuzzification would require a + * denominator proportional to (howhigh+howlow) but, in this + * particular case, that expression is constant. + * + * An imediate consequence is that it is not necessary to call + * both mf_high and mf_low - but to keep things understandable, + * I did so. + */ + + } + + spin_unlock_bh(&fuzzy_lock); /* Release the lock */ + + + if (info->acceptance_rate < 100) + { + get_random_bytes((void *)(&random_number), 1); + + if (random_number <= (255 * info->acceptance_rate) / 100) + /* + * If within the acceptance, it can pass + * => do not match. + */ + return 0; + else + /* It cannot pass (it matches) */ + return 1; + }; + + /* acceptance_rate == 100 % => Everything passes ... */ + return 0; + +} + +static bool +fuzzy_mt_check(const char *table, const void *ip, const struct xt_match *match, + void *matchinfo, unsigned int hook_mask) +{ + + const struct xt_fuzzy_mtinfo *info = matchinfo; + + if ((info->minimum_rate < FUZZY_MIN_RATE) || (info->maximum_rate > FUZZY_MAX_RATE) + || (info->minimum_rate >= info->maximum_rate)) { + printk("ip6t_fuzzy: BAD limits , please verify !!!\n"); + return 0; + } + + return 1; +} + +static struct xt_match fuzzy_mt_reg = { + .name = "fuzzy", + .revision = 0, + .family = PF_INET, + .match = fuzzy_mt, + .checkentry = fuzzy_mt_check, + .matchsize = XT_ALIGN(sizeof(struct xt_fuzzy_mtinfo)), + .me = THIS_MODULE, +}; + +static int __init fuzzy_mt_init(void) +{ + if (xt_register_match(&fuzzy_mt_reg)) + return -EINVAL; + + return 0; +} + +static void __exit fuzzy_mt_exit(void) +{ + xt_unregister_match(&fuzzy_mt_reg); +} + +module_init(fuzzy_mt_init); +module_exit(fuzzy_mt_exit); diff --git a/extensions/xt_fuzzy.h b/extensions/xt_fuzzy.h new file mode 100644 index 0000000..b3ea394 --- /dev/null +++ b/extensions/xt_fuzzy.h @@ -0,0 +1,20 @@ +#ifndef _LINUX_NETFILTER_XT_FUZZY_H +#define _LINUX_NETFILTER_XT_FUZZY_H 1 + +enum { + FUZZY_MIN_RATE = 3, + FUZZY_MAX_RATE = 10000000, +}; + +struct xt_fuzzy_mtinfo { + uint32_t minimum_rate; + uint32_t maximum_rate; + uint32_t packets_total; + uint32_t bytes_total; + uint32_t previous_time; + uint32_t present_time; + uint32_t mean_rate; + uint8_t acceptance_rate; +}; + +#endif /* _LINUX_NETFILTER_XT_FUZZY_H */ diff --git a/mconfig b/mconfig index 02bc21c..a860284 100644 --- a/mconfig +++ b/mconfig @@ -9,6 +9,7 @@ build_SYSRQ=m build_TARPIT=m build_TEE=m build_condition=m +build_fuzzy=m build_geoip=m build_ipp2p=m build_ipset=m