| /* ebt_limit |
| * |
| * Authors: |
| * Tom Marshall <tommy@home.tig-grr.com> |
| * |
| * Mostly copied from iptables' limit match. |
| * |
| * September, 2003 |
| * |
| * Translated to use libxtables for ebtables-compat in 2015 by |
| * Arturo Borrero Gonzalez <arturo@debian.org> |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <getopt.h> |
| #include <errno.h> |
| #include <xtables.h> |
| #include <linux/netfilter_bridge/ebt_limit.h> |
| #include "iptables/nft.h" |
| #include "iptables/nft-bridge.h" |
| |
| #define EBT_LIMIT_AVG "3/hour" |
| #define EBT_LIMIT_BURST 5 |
| |
| #define FLAG_LIMIT 0x01 |
| #define FLAG_LIMIT_BURST 0x02 |
| #define ARG_LIMIT '1' |
| #define ARG_LIMIT_BURST '2' |
| |
| static const struct option brlimit_opts[] = |
| { |
| { .name = "limit", .has_arg = true, .val = ARG_LIMIT }, |
| { .name = "limit-burst",.has_arg = true, .val = ARG_LIMIT_BURST }, |
| XT_GETOPT_TABLEEND, |
| }; |
| |
| static void brlimit_print_help(void) |
| { |
| printf( |
| "limit options:\n" |
| "--limit avg : max average match rate: default "EBT_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, -1 < number < 10001,\n" |
| " default %u\n", EBT_LIMIT_BURST); |
| } |
| |
| static int parse_rate(const char *rate, uint32_t *val) |
| { |
| const char *delim; |
| uint32_t r; |
| uint32_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 > EBT_LIMIT_SCALE) |
| return 0; |
| |
| *val = EBT_LIMIT_SCALE * mult / r; |
| return 1; |
| } |
| |
| static void brlimit_init(struct xt_entry_match *match) |
| { |
| struct ebt_limit_info *r = (struct ebt_limit_info *)match->data; |
| |
| parse_rate(EBT_LIMIT_AVG, &r->avg); |
| r->burst = EBT_LIMIT_BURST; |
| } |
| |
| static int brlimit_parse(int c, char **argv, int invert, unsigned int *flags, |
| const void *entry, struct xt_entry_match **match) |
| { |
| struct ebt_limit_info *r = (struct ebt_limit_info *)(*match)->data; |
| uintmax_t num; |
| |
| switch (c) { |
| case ARG_LIMIT: |
| EBT_CHECK_OPTION(flags, FLAG_LIMIT); |
| if (invert) |
| xtables_error(PARAMETER_PROBLEM, |
| "Unexpected `!' after --limit"); |
| if (!parse_rate(optarg, &r->avg)) |
| xtables_error(PARAMETER_PROBLEM, |
| "bad rate `%s'", optarg); |
| break; |
| case ARG_LIMIT_BURST: |
| EBT_CHECK_OPTION(flags, FLAG_LIMIT_BURST); |
| if (invert) |
| xtables_error(PARAMETER_PROBLEM, |
| "Unexpected `!' after --limit-burst"); |
| if (!xtables_strtoul(optarg, NULL, &num, 0, 10000)) |
| xtables_error(PARAMETER_PROBLEM, |
| "bad --limit-burst `%s'", optarg); |
| r->burst = num; |
| break; |
| default: |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| struct rates |
| { |
| const char *name; |
| uint32_t mult; |
| }; |
| |
| static struct rates g_rates[] = |
| { |
| { "day", EBT_LIMIT_SCALE*24*60*60 }, |
| { "hour", EBT_LIMIT_SCALE*60*60 }, |
| { "minute", EBT_LIMIT_SCALE*60 }, |
| { "second", EBT_LIMIT_SCALE } |
| }; |
| |
| static void print_rate(uint32_t period) |
| { |
| unsigned int i; |
| |
| for (i = 1; i < sizeof(g_rates)/sizeof(struct rates); i++) |
| if (period > g_rates[i].mult || |
| g_rates[i].mult/period < g_rates[i].mult%period) |
| break; |
| |
| printf("%u/%s ", g_rates[i-1].mult / period, g_rates[i-1].name); |
| } |
| |
| static void brlimit_print(const void *ip, const struct xt_entry_match *match, |
| int numeric) |
| { |
| struct ebt_limit_info *r = (struct ebt_limit_info *)match->data; |
| |
| printf("--limit "); |
| print_rate(r->avg); |
| printf("--limit-burst %u ", r->burst); |
| } |
| |
| static void print_rate_xlate(struct xt_xlate *xl, uint32_t period) |
| { |
| unsigned int i; |
| |
| for (i = 1; i < sizeof(g_rates)/sizeof(struct rates); i++) |
| if (period > g_rates[i].mult || |
| g_rates[i].mult/period < g_rates[i].mult%period) |
| break; |
| |
| xt_xlate_add(xl, "%u/%s ", g_rates[i-1].mult / period, g_rates[i-1].name); |
| } |
| |
| static int brlimit_xlate(struct xt_xlate *xl, |
| const struct xt_xlate_mt_params *params) |
| { |
| const struct ebt_limit_info *r = (const void *)params->match->data; |
| |
| xt_xlate_add(xl, "limit rate "); |
| print_rate_xlate(xl, r->avg); |
| if (r->burst != 0) |
| xt_xlate_add(xl, "burst %u packets ", r->burst); |
| |
| return 1; |
| } |
| |
| static struct xtables_match brlimit_match = { |
| .name = "limit", |
| .revision = 0, |
| .version = XTABLES_VERSION, |
| .family = NFPROTO_BRIDGE, |
| .size = XT_ALIGN(sizeof(struct ebt_limit_info)), |
| .userspacesize = offsetof(struct ebt_limit_info, prev), |
| .init = brlimit_init, |
| .help = brlimit_print_help, |
| .parse = brlimit_parse, |
| .print = brlimit_print, |
| .xlate = brlimit_xlate, |
| .extra_opts = brlimit_opts, |
| }; |
| |
| void _init(void) |
| { |
| xtables_register_match(&brlimit_match); |
| } |