1 /* Shared library add-on to iptables to add limit support.
3 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
4 * Hervé Eychenne <rv@wallfire.org>
11 #include <ip6tables.h>
13 #include <linux/netfilter_ipv6/ip6_tables.h>
14 /* For 64bit kernel / 32bit userspace */
15 #include "../include/linux/netfilter_ipv6/ip6t_limit.h"
17 #define IP6T_LIMIT_AVG "3/hour"
18 #define IP6T_LIMIT_BURST 5
20 /* Function which prints out usage message. */
25 "limit v%s options:\n"
26 "--limit avg max average match rate: default "IP6T_LIMIT_AVG"\n"
27 " [Packets per second unless followed by \n"
28 " /sec /minute /hour /day postfixes]\n"
29 "--limit-burst number number to match in a burst, default %u\n"
30 "\n", IPTABLES_VERSION, IP6T_LIMIT_BURST);
33 static struct option opts[] = {
34 { "limit", 1, 0, '%' },
35 { "limit-burst", 1, 0, '$' },
40 int parse_rate(const char *rate, u_int32_t *val)
44 u_int32_t mult = 1; /* Seconds by default. */
46 delim = strchr(rate, '/');
48 if (strlen(delim+1) == 0)
51 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
53 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
55 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
57 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
66 /* This would get mapped to infinite (1/day is minimum they
67 can specify, so we're ok at that end). */
68 if (r / mult > IP6T_LIMIT_SCALE)
69 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
71 *val = IP6T_LIMIT_SCALE * mult / r;
75 /* Initialize the match. */
77 init(struct ip6t_entry_match *m, unsigned int *nfcache)
79 struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)m->data;
81 parse_rate(IP6T_LIMIT_AVG, &r->avg);
82 r->burst = IP6T_LIMIT_BURST;
86 /* FIXME: handle overflow:
87 if (r->avg*r->burst/r->burst != r->avg)
88 exit_error(PARAMETER_PROBLEM,
89 "Sorry: burst too large for that avg rate.\n");
92 /* Function which parses command options; returns true if it
95 parse(int c, char **argv, int invert, unsigned int *flags,
96 const struct ip6t_entry *entry,
97 unsigned int *nfcache,
98 struct ip6t_entry_match **match)
100 struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)(*match)->data;
105 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
106 if (!parse_rate(optarg, &r->avg))
107 exit_error(PARAMETER_PROBLEM,
108 "bad rate `%s'", optarg);
112 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
113 if (string_to_number(optarg, 0, 10000, &num) == -1)
114 exit_error(PARAMETER_PROBLEM,
115 "bad --limit-burst `%s'", optarg);
124 exit_error(PARAMETER_PROBLEM,
125 "limit does not support invert");
130 /* Final check; nothing. */
131 static void final_check(unsigned int flags)
139 } rates[] = { { "day", IP6T_LIMIT_SCALE*24*60*60 },
140 { "hour", IP6T_LIMIT_SCALE*60*60 },
141 { "min", IP6T_LIMIT_SCALE*60 },
142 { "sec", IP6T_LIMIT_SCALE } };
144 static void print_rate(u_int32_t period)
148 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
149 if (period > rates[i].mult
150 || rates[i].mult % period != 0)
154 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
157 /* Prints out the matchinfo. */
159 print(const struct ip6t_ip6 *ip,
160 const struct ip6t_entry_match *match,
163 struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)match->data;
164 printf("limit: avg "); print_rate(r->avg);
165 printf("burst %u ", r->burst);
168 /* FIXME: Make minimalist: only print rate if not default --RR */
169 static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
171 struct ip6t_rateinfo *r = (struct ip6t_rateinfo *)match->data;
173 printf("--limit "); print_rate(r->avg);
174 if (r->burst != IP6T_LIMIT_BURST)
175 printf("--limit-burst %u ", r->burst);
178 static struct ip6tables_match limit = {
180 .version = IPTABLES_VERSION,
181 .size = IP6T_ALIGN(sizeof(struct ip6t_rateinfo)),
182 .userspacesize = offsetof(struct ip6t_rateinfo, prev),
186 .final_check = &final_check,
194 register_match6(&limit);