diff options
author | Marc Boucher <marc@mbsi.ca> | 2000-03-20 06:03:29 +0000 |
---|---|---|
committer | Marc Boucher <marc@mbsi.ca> | 2000-03-20 06:03:29 +0000 |
commit | e6869a8f59d779ff4d5a0984c86d80db70784962 (patch) | |
tree | cbaf2a4e3f8249de3967b959a214c27ff5fdee2a /extensions/libipt_limit.c |
reorganized tree after kernel merge
Diffstat (limited to 'extensions/libipt_limit.c')
-rw-r--r-- | extensions/libipt_limit.c | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/extensions/libipt_limit.c b/extensions/libipt_limit.c new file mode 100644 index 00000000..aed63059 --- /dev/null +++ b/extensions/libipt_limit.c @@ -0,0 +1,196 @@ +/* Shared library add-on to iptables to add limit support. + * + * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> + * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr> + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <iptables.h> +#include <linux/netfilter_ipv4/ip_tables.h> +#include <linux/netfilter_ipv4/ipt_limit.h> + +#define IPT_LIMIT_AVG "3/hour" +#define IPT_LIMIT_BURST 5 + +/* Function which prints out usage message. */ +static void +help(void) +{ + printf( +"limit v%s options:\n" +"--limit avg max average match rate: default "IPT_LIMIT_AVG"\n" +" [Packets per second unless followed by \n" +" /sec /minute /hour /day postfixes]\n" +"--limit-burst number number to match in a burst, default %u\n" +"\n", NETFILTER_VERSION, IPT_LIMIT_BURST); +} + +static struct option opts[] = { + { "limit", 1, 0, '%' }, + { "limit-burst", 1, 0, '$' }, + { 0 } +}; + +static +int parse_rate(const char *rate, u_int32_t *val) +{ + const char *delim; + u_int32_t r; + u_int32_t mult = 1; /* Seconds by default. */ + + delim = strchr(rate, '/'); + if (delim) { + if (strlen(delim+1) == 0) + return 0; + + if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) + mult = 1; + else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) + mult = 60; + else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) + mult = 60*60; + else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) + mult = 24*60*60; + else + return 0; + } + r = atoi(rate); + if (!r) + return 0; + + /* This would get mapped to infinite (1/day is minimum they + can specify, so we're ok at that end). */ + if (r / mult > IPT_LIMIT_SCALE) + exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate); + + *val = IPT_LIMIT_SCALE * mult / r; + return 1; +} + +/* Initialize the match. */ +static void +init(struct ipt_entry_match *m, unsigned int *nfcache) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)m->data; + + parse_rate(IPT_LIMIT_AVG, &r->avg); + r->burst = IPT_LIMIT_BURST; + + /* Can't cache this */ + *nfcache |= NFC_UNKNOWN; +} + +/* FIXME: handle overflow: + if (r->avg*r->burst/r->burst != r->avg) + exit_error(PARAMETER_PROBLEM, + "Sorry: burst too large for that avg rate.\n"); +*/ + +/* Function which parses command options; returns true if it + ate an option */ +static int +parse(int c, char **argv, int invert, unsigned int *flags, + const struct ipt_entry *entry, + unsigned int *nfcache, + struct ipt_entry_match **match) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)(*match)->data; + int num; + + switch(c) { + case '%': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --limit"); + if (!parse_rate(optarg, &r->avg)) + exit_error(PARAMETER_PROBLEM, + "bad rate `%s'", optarg); + break; + + case '$': + if (check_inverse(optarg, &invert)) + exit_error(PARAMETER_PROBLEM, + "Unexpected `!' after --limit-burst"); + + num = string_to_number(optarg, 0, 10000); + if (num <= 0) + exit_error(PARAMETER_PROBLEM, + "bad --limit-burst `%s'", optarg); + r->burst = num; + break; + + default: + return 0; + } + + return 1; +} + +/* Final check; nothing. */ +static void final_check(unsigned int flags) +{ +} + +static struct rates +{ + const char *name; + u_int32_t mult; +} rates[] = { { "day", IPT_LIMIT_SCALE*24*60*60 }, + { "hour", IPT_LIMIT_SCALE*60*60 }, + { "min", IPT_LIMIT_SCALE*60 }, + { "sec", IPT_LIMIT_SCALE } }; + +static void print_rate(u_int32_t period) +{ + unsigned int i; + + for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) { + if (period > rates[i].mult + || rates[i].mult % period != 0) + break; + } + + printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); +} + +/* Prints out the matchinfo. */ +static void +print(const struct ipt_ip *ip, + const struct ipt_entry_match *match, + int numeric) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data; + printf("limit: avg "); print_rate(r->avg); + printf("burst %u ", r->burst); +} + +/* FIXME: Make minimalist: only print rate if not default --RR */ +static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match) +{ + struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data; + + printf("--limit "); print_rate(r->avg); + if (r->burst != IPT_LIMIT_BURST) + printf("--limit-burst %u ", r->burst); +} + +struct iptables_match limit += { NULL, + "limit", + NETFILTER_VERSION, + sizeof(struct ipt_rateinfo), + &help, + &init, + &parse, + &final_check, + &print, + &save, + opts +}; + +void _init(void) +{ + register_match(&limit); +} |