blob: aed63059297a050987f531c85c9ab158e090395e [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add limit support.
2 *
3 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
4 * Hervé Eychenne <eychenne@info.enserb.u-bordeaux.fr>
5 */
6#include <stdio.h>
7#include <string.h>
8#include <stdlib.h>
9#include <getopt.h>
10#include <iptables.h>
11#include <linux/netfilter_ipv4/ip_tables.h>
12#include <linux/netfilter_ipv4/ipt_limit.h>
13
14#define IPT_LIMIT_AVG "3/hour"
15#define IPT_LIMIT_BURST 5
16
17/* Function which prints out usage message. */
18static void
19help(void)
20{
21 printf(
22"limit v%s options:\n"
23"--limit avg max average match rate: default "IPT_LIMIT_AVG"\n"
24" [Packets per second unless followed by \n"
25" /sec /minute /hour /day postfixes]\n"
26"--limit-burst number number to match in a burst, default %u\n"
27"\n", NETFILTER_VERSION, IPT_LIMIT_BURST);
28}
29
30static struct option opts[] = {
31 { "limit", 1, 0, '%' },
32 { "limit-burst", 1, 0, '$' },
33 { 0 }
34};
35
36static
37int parse_rate(const char *rate, u_int32_t *val)
38{
39 const char *delim;
40 u_int32_t r;
41 u_int32_t mult = 1; /* Seconds by default. */
42
43 delim = strchr(rate, '/');
44 if (delim) {
45 if (strlen(delim+1) == 0)
46 return 0;
47
48 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
49 mult = 1;
50 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
51 mult = 60;
52 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
53 mult = 60*60;
54 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
55 mult = 24*60*60;
56 else
57 return 0;
58 }
59 r = atoi(rate);
60 if (!r)
61 return 0;
62
63 /* This would get mapped to infinite (1/day is minimum they
64 can specify, so we're ok at that end). */
65 if (r / mult > IPT_LIMIT_SCALE)
66 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
67
68 *val = IPT_LIMIT_SCALE * mult / r;
69 return 1;
70}
71
72/* Initialize the match. */
73static void
74init(struct ipt_entry_match *m, unsigned int *nfcache)
75{
76 struct ipt_rateinfo *r = (struct ipt_rateinfo *)m->data;
77
78 parse_rate(IPT_LIMIT_AVG, &r->avg);
79 r->burst = IPT_LIMIT_BURST;
80
81 /* Can't cache this */
82 *nfcache |= NFC_UNKNOWN;
83}
84
85/* FIXME: handle overflow:
86 if (r->avg*r->burst/r->burst != r->avg)
87 exit_error(PARAMETER_PROBLEM,
88 "Sorry: burst too large for that avg rate.\n");
89*/
90
91/* Function which parses command options; returns true if it
92 ate an option */
93static int
94parse(int c, char **argv, int invert, unsigned int *flags,
95 const struct ipt_entry *entry,
96 unsigned int *nfcache,
97 struct ipt_entry_match **match)
98{
99 struct ipt_rateinfo *r = (struct ipt_rateinfo *)(*match)->data;
100 int num;
101
102 switch(c) {
103 case '%':
104 if (check_inverse(optarg, &invert))
105 exit_error(PARAMETER_PROBLEM,
106 "Unexpected `!' after --limit");
107 if (!parse_rate(optarg, &r->avg))
108 exit_error(PARAMETER_PROBLEM,
109 "bad rate `%s'", optarg);
110 break;
111
112 case '$':
113 if (check_inverse(optarg, &invert))
114 exit_error(PARAMETER_PROBLEM,
115 "Unexpected `!' after --limit-burst");
116
117 num = string_to_number(optarg, 0, 10000);
118 if (num <= 0)
119 exit_error(PARAMETER_PROBLEM,
120 "bad --limit-burst `%s'", optarg);
121 r->burst = num;
122 break;
123
124 default:
125 return 0;
126 }
127
128 return 1;
129}
130
131/* Final check; nothing. */
132static void final_check(unsigned int flags)
133{
134}
135
136static struct rates
137{
138 const char *name;
139 u_int32_t mult;
140} rates[] = { { "day", IPT_LIMIT_SCALE*24*60*60 },
141 { "hour", IPT_LIMIT_SCALE*60*60 },
142 { "min", IPT_LIMIT_SCALE*60 },
143 { "sec", IPT_LIMIT_SCALE } };
144
145static void print_rate(u_int32_t period)
146{
147 unsigned int i;
148
149 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
150 if (period > rates[i].mult
151 || rates[i].mult % period != 0)
152 break;
153 }
154
155 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
156}
157
158/* Prints out the matchinfo. */
159static void
160print(const struct ipt_ip *ip,
161 const struct ipt_entry_match *match,
162 int numeric)
163{
164 struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data;
165 printf("limit: avg "); print_rate(r->avg);
166 printf("burst %u ", r->burst);
167}
168
169/* FIXME: Make minimalist: only print rate if not default --RR */
170static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
171{
172 struct ipt_rateinfo *r = (struct ipt_rateinfo *)match->data;
173
174 printf("--limit "); print_rate(r->avg);
175 if (r->burst != IPT_LIMIT_BURST)
176 printf("--limit-burst %u ", r->burst);
177}
178
179struct iptables_match limit
180= { NULL,
181 "limit",
182 NETFILTER_VERSION,
183 sizeof(struct ipt_rateinfo),
184 &help,
185 &init,
186 &parse,
187 &final_check,
188 &print,
189 &save,
190 opts
191};
192
193void _init(void)
194{
195 register_match(&limit);
196}