Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / iptables / extensions / libipt_dstlimit.c
blob3f3b6330d153181a266556420225326b3a9bc99a
1 /* iptables match extension for limiting packets per destination
3 * (C) 2003 by Harald Welte <laforge@netfilter.org>
5 * Development of this code was funded by Astaro AG, http://www.astaro.com/
7 * Based on ipt_limit.c by
8 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
9 * Hervé Eychenne <rv@wallfire.org>
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <getopt.h>
16 #include <iptables.h>
17 #include <stddef.h>
18 #include <linux/netfilter_ipv4/ip_tables.h>
19 #include <linux/netfilter_ipv4/ipt_dstlimit.h>
21 #define IPT_DSTLIMIT_BURST 5
23 /* miliseconds */
24 #define IPT_DSTLIMIT_GCINTERVAL 1000
25 #define IPT_DSTLIMIT_EXPIRE 10000
27 /* Function which prints out usage message. */
28 static void
29 help(void)
31 printf(
32 "dstlimit v%s options:\n"
33 "--dstlimit <avg> max average match rate\n"
34 " [Packets per second unless followed by \n"
35 " /sec /minute /hour /day postfixes]\n"
36 "--dstlimit-mode <mode> mode\n"
37 " dstip\n"
38 " dstip-dstport\n"
39 " srcip-dstip\n"
40 " srcip-dstip-dstport\n"
41 "--dstlimit-name <name> name for /proc/net/ipt_dstlimit/\n"
42 "[--dstlimit-burst <num>] number to match in a burst, default %u\n"
43 "[--dstlimit-htable-size <num>] number of hashtable buckets\n"
44 "[--dstlimit-htable-max <num>] number of hashtable entries\n"
45 "[--dstlimit-htable-gcinterval] interval between garbage collection runs\n"
46 "[--dstlimit-htable-expire] after which time are idle entries expired?\n"
47 "\n", IPTABLES_VERSION, IPT_DSTLIMIT_BURST);
50 static struct option opts[] = {
51 { "dstlimit", 1, 0, '%' },
52 { "dstlimit-burst", 1, 0, '$' },
53 { "dstlimit-htable-size", 1, 0, '&' },
54 { "dstlimit-htable-max", 1, 0, '*' },
55 { "dstlimit-htable-gcinterval", 1, 0, '(' },
56 { "dstlimit-htable-expire", 1, 0, ')' },
57 { "dstlimit-mode", 1, 0, '_' },
58 { "dstlimit-name", 1, 0, '"' },
59 { 0 }
62 static
63 int parse_rate(const char *rate, u_int32_t *val)
65 const char *delim;
66 u_int32_t r;
67 u_int32_t mult = 1; /* Seconds by default. */
69 delim = strchr(rate, '/');
70 if (delim) {
71 if (strlen(delim+1) == 0)
72 return 0;
74 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
75 mult = 1;
76 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
77 mult = 60;
78 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
79 mult = 60*60;
80 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
81 mult = 24*60*60;
82 else
83 return 0;
85 r = atoi(rate);
86 if (!r)
87 return 0;
89 /* This would get mapped to infinite (1/day is minimum they
90 can specify, so we're ok at that end). */
91 if (r / mult > IPT_DSTLIMIT_SCALE)
92 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
94 *val = IPT_DSTLIMIT_SCALE * mult / r;
95 return 1;
98 /* Initialize the match. */
99 static void
100 init(struct ipt_entry_match *m, unsigned int *nfcache)
102 struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *)m->data;
104 r->cfg.burst = IPT_DSTLIMIT_BURST;
105 r->cfg.gc_interval = IPT_DSTLIMIT_GCINTERVAL;
106 r->cfg.expire = IPT_DSTLIMIT_EXPIRE;
110 #define PARAM_LIMIT 0x00000001
111 #define PARAM_BURST 0x00000002
112 #define PARAM_MODE 0x00000004
113 #define PARAM_NAME 0x00000008
114 #define PARAM_SIZE 0x00000010
115 #define PARAM_MAX 0x00000020
116 #define PARAM_GCINTERVAL 0x00000040
117 #define PARAM_EXPIRE 0x00000080
119 /* Function which parses command options; returns true if it
120 ate an option */
121 static int
122 parse(int c, char **argv, int invert, unsigned int *flags,
123 const struct ipt_entry *entry,
124 unsigned int *nfcache,
125 struct ipt_entry_match **match)
127 struct ipt_dstlimit_info *r =
128 (struct ipt_dstlimit_info *)(*match)->data;
129 unsigned int num;
131 switch(c) {
132 case '%':
133 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
134 if (!parse_rate(optarg, &r->cfg.avg))
135 exit_error(PARAMETER_PROBLEM,
136 "bad rate `%s'", optarg);
137 *flags |= PARAM_LIMIT;
138 break;
140 case '$':
141 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
142 if (string_to_number(optarg, 0, 10000, &num) == -1)
143 exit_error(PARAMETER_PROBLEM,
144 "bad --dstlimit-burst `%s'", optarg);
145 r->cfg.burst = num;
146 *flags |= PARAM_BURST;
147 break;
148 case '&':
149 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
150 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
151 exit_error(PARAMETER_PROBLEM,
152 "bad --dstlimit-htable-size: `%s'", optarg);
153 r->cfg.size = num;
154 *flags |= PARAM_SIZE;
155 break;
156 case '*':
157 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
158 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
159 exit_error(PARAMETER_PROBLEM,
160 "bad --dstlimit-htable-max: `%s'", optarg);
161 r->cfg.max = num;
162 *flags |= PARAM_MAX;
163 break;
164 case '(':
165 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
166 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
167 exit_error(PARAMETER_PROBLEM,
168 "bad --dstlimit-htable-gcinterval: `%s'",
169 optarg);
170 /* FIXME: not HZ dependent!! */
171 r->cfg.gc_interval = num;
172 *flags |= PARAM_GCINTERVAL;
173 break;
174 case ')':
175 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
176 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
177 exit_error(PARAMETER_PROBLEM,
178 "bad --dstlimit-htable-expire: `%s'", optarg);
179 /* FIXME: not HZ dependent */
180 r->cfg.expire = num;
181 *flags |= PARAM_EXPIRE;
182 break;
183 case '_':
184 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
185 if (!strcmp(optarg, "dstip"))
186 r->cfg.mode = IPT_DSTLIMIT_HASH_DIP;
187 else if (!strcmp(optarg, "dstip-destport") ||
188 !strcmp(optarg, "dstip-dstport"))
189 r->cfg.mode = IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT;
190 else if (!strcmp(optarg, "srcip-dstip"))
191 r->cfg.mode = IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP;
192 else if (!strcmp(optarg, "srcip-dstip-destport") ||
193 !strcmp(optarg, "srcip-dstip-dstport"))
194 r->cfg.mode = IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT;
195 else
196 exit_error(PARAMETER_PROBLEM,
197 "bad --dstlimit-mode: `%s'\n", optarg);
198 *flags |= PARAM_MODE;
199 break;
200 case '"':
201 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
202 if (strlen(optarg) == 0)
203 exit_error(PARAMETER_PROBLEM, "Zero-length name?");
204 strncpy(r->name, optarg, sizeof(r->name));
205 *flags |= PARAM_NAME;
206 break;
207 default:
208 return 0;
211 if (invert)
212 exit_error(PARAMETER_PROBLEM,
213 "dstlimit does not support invert");
215 return 1;
218 /* Final check; nothing. */
219 static void final_check(unsigned int flags)
221 if (!(flags & PARAM_LIMIT))
222 exit_error(PARAMETER_PROBLEM,
223 "You have to specify --dstlimit");
224 if (!(flags & PARAM_MODE))
225 exit_error(PARAMETER_PROBLEM,
226 "You have to specify --dstlimit-mode");
227 if (!(flags & PARAM_NAME))
228 exit_error(PARAMETER_PROBLEM,
229 "You have to specify --dstlimit-name");
232 static struct rates
234 const char *name;
235 u_int32_t mult;
236 } rates[] = { { "day", IPT_DSTLIMIT_SCALE*24*60*60 },
237 { "hour", IPT_DSTLIMIT_SCALE*60*60 },
238 { "min", IPT_DSTLIMIT_SCALE*60 },
239 { "sec", IPT_DSTLIMIT_SCALE } };
241 static void print_rate(u_int32_t period)
243 unsigned int i;
245 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
246 if (period > rates[i].mult
247 || rates[i].mult/period < rates[i].mult%period)
248 break;
251 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
254 /* Prints out the matchinfo. */
255 static void
256 print(const struct ipt_ip *ip,
257 const struct ipt_entry_match *match,
258 int numeric)
260 struct ipt_dstlimit_info *r =
261 (struct ipt_dstlimit_info *)match->data;
262 printf("limit: avg "); print_rate(r->cfg.avg);
263 printf("burst %u ", r->cfg.burst);
264 switch (r->cfg.mode) {
265 case (IPT_DSTLIMIT_HASH_DIP):
266 printf("mode dstip ");
267 break;
268 case (IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
269 printf("mode dstip-dstport ");
270 break;
271 case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP):
272 printf("mode srcip-dstip ");
273 break;
274 case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
275 printf("mode srcip-dstip-dstport ");
276 break;
278 if (r->cfg.size)
279 printf("htable-size %u ", r->cfg.size);
280 if (r->cfg.max)
281 printf("htable-max %u ", r->cfg.max);
282 if (r->cfg.gc_interval != IPT_DSTLIMIT_GCINTERVAL)
283 printf("htable-gcinterval %u ", r->cfg.gc_interval);
284 if (r->cfg.expire != IPT_DSTLIMIT_EXPIRE)
285 printf("htable-expire %u ", r->cfg.expire);
288 /* FIXME: Make minimalist: only print rate if not default --RR */
289 static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
291 struct ipt_dstlimit_info *r =
292 (struct ipt_dstlimit_info *)match->data;
294 printf("--dstlimit "); print_rate(r->cfg.avg);
295 if (r->cfg.burst != IPT_DSTLIMIT_BURST)
296 printf("--dstlimit-burst %u ", r->cfg.burst);
297 switch (r->cfg.mode) {
298 case (IPT_DSTLIMIT_HASH_DIP):
299 printf("--mode dstip ");
300 break;
301 case (IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
302 printf("--mode dstip-dstport ");
303 break;
304 case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP):
305 printf("--mode srcip-dstip ");
306 break;
307 case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
308 printf("--mode srcip-dstip-dstport ");
309 break;
311 if (r->cfg.size)
312 printf("--dstlimit-htable-size %u ", r->cfg.size);
313 if (r->cfg.max)
314 printf("--dstlimit-htable-max %u ", r->cfg.max);
315 if (r->cfg.gc_interval != IPT_DSTLIMIT_GCINTERVAL)
316 printf("--dstlimit-htable-gcinterval %u", r->cfg.gc_interval);
317 if (r->cfg.expire != IPT_DSTLIMIT_EXPIRE)
318 printf("--dstlimit-htable-expire %u ", r->cfg.expire);
321 static struct iptables_match dstlimit = {
322 .next = NULL,
323 .name = "dstlimit",
324 .version = IPTABLES_VERSION,
325 .size = IPT_ALIGN(sizeof(struct ipt_dstlimit_info)),
326 .userspacesize = IPT_ALIGN(sizeof(struct ipt_dstlimit_info)),
327 //offsetof(struct ipt_dstlimit_info, prev),
328 .help = &help,
329 .init = &init,
330 .parse = &parse,
331 .final_check = &final_check,
332 .print = &print,
333 .save = &save,
334 .extra_opts = opts
337 void _init(void)
339 register_match(&dstlimit);