1 /* ip6tables match extension for limiting packets per destination
2 *
3 * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
4 *
5 * Development of this code was funded by Astaro AG, http://www.astaro.com/
6 *
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>
10 *
11 * Error corections by nmalykh@bilim.com (22.01.2005)
12 */
13 #define _BSD_SOURCE 1
14 #define _ISOC99_SOURCE 1
15 #include <math.h>
16 #include <stdbool.h>
17 #include <stdint.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <xtables.h>
23 #include <linux/netfilter/x_tables.h>
24 #include <linux/netfilter/xt_hashlimit.h>
25
26 #define XT_HASHLIMIT_BURST 5
27 #define XT_HASHLIMIT_BURST_MAX_v1 10000
28 #define XT_HASHLIMIT_BURST_MAX 1000000
29
30 #define XT_HASHLIMIT_BYTE_EXPIRE 15
31 #define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60
32
33 /* miliseconds */
34 #define XT_HASHLIMIT_GCINTERVAL 1000
35
36 struct hashlimit_mt_udata {
37 uint32_t mult;
38 };
39
hashlimit_help(void)40 static void hashlimit_help(void)
41 {
42 printf(
43 "hashlimit match options:\n"
44 "--hashlimit <avg> max average match rate\n"
45 " [Packets per second unless followed by \n"
46 " /sec /minute /hour /day postfixes]\n"
47 "--hashlimit-mode <mode> mode is a comma-separated list of\n"
48 " dstip,srcip,dstport,srcport\n"
49 "--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n"
50 "[--hashlimit-burst <num>] number to match in a burst, default %u\n"
51 "[--hashlimit-htable-size <num>] number of hashtable buckets\n"
52 "[--hashlimit-htable-max <num>] number of hashtable entries\n"
53 "[--hashlimit-htable-gcinterval] interval between garbage collection runs\n"
54 "[--hashlimit-htable-expire] after which time are idle entries expired?\n",
55 XT_HASHLIMIT_BURST);
56 }
57
58 enum {
59 O_UPTO = 0,
60 O_ABOVE,
61 O_LIMIT,
62 O_MODE,
63 O_SRCMASK,
64 O_DSTMASK,
65 O_NAME,
66 O_BURST,
67 O_HTABLE_SIZE,
68 O_HTABLE_MAX,
69 O_HTABLE_GCINT,
70 O_HTABLE_EXPIRE,
71 F_BURST = 1 << O_BURST,
72 F_UPTO = 1 << O_UPTO,
73 F_ABOVE = 1 << O_ABOVE,
74 F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
75 };
76
hashlimit_mt_help(void)77 static void hashlimit_mt_help(void)
78 {
79 printf(
80 "hashlimit match options:\n"
81 " --hashlimit-upto <avg> max average match rate\n"
82 " [Packets per second unless followed by \n"
83 " /sec /minute /hour /day postfixes]\n"
84 " --hashlimit-above <avg> min average match rate\n"
85 " --hashlimit-mode <mode> mode is a comma-separated list of\n"
86 " dstip,srcip,dstport,srcport (or none)\n"
87 " --hashlimit-srcmask <length> source address grouping prefix length\n"
88 " --hashlimit-dstmask <length> destination address grouping prefix length\n"
89 " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
90 " --hashlimit-burst <num> number to match in a burst, default %u\n"
91 " --hashlimit-htable-size <num> number of hashtable buckets\n"
92 " --hashlimit-htable-max <num> number of hashtable entries\n"
93 " --hashlimit-htable-gcinterval interval between garbage collection runs\n"
94 " --hashlimit-htable-expire after which time are idle entries expired?\n"
95 "\n", XT_HASHLIMIT_BURST);
96 }
97
98 #define s struct xt_hashlimit_info
99 static const struct xt_option_entry hashlimit_opts[] = {
100 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
101 .type = XTTYPE_STRING},
102 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
103 .min = 1, .max = XT_HASHLIMIT_BURST_MAX_v1, .flags = XTOPT_PUT,
104 XTOPT_POINTER(s, cfg.burst)},
105 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
106 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
107 XTOPT_POINTER(s, cfg.size)},
108 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
109 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
110 XTOPT_POINTER(s, cfg.max)},
111 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
112 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
113 XTOPT_POINTER(s, cfg.gc_interval)},
114 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
115 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
116 XTOPT_POINTER(s, cfg.expire)},
117 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
118 .flags = XTOPT_MAND},
119 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
120 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
121 XTOPT_TABLEEND,
122 };
123 #undef s
124
125 #define s struct xt_hashlimit_mtinfo1
126 static const struct xt_option_entry hashlimit_mt_opts_v1[] = {
127 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
128 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
129 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
130 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
131 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
132 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
133 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
134 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
135 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
136 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
137 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
138 XTOPT_POINTER(s, cfg.size)},
139 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
140 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
141 XTOPT_POINTER(s, cfg.max)},
142 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
143 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
144 XTOPT_POINTER(s, cfg.gc_interval)},
145 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
146 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
147 XTOPT_POINTER(s, cfg.expire)},
148 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
149 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
150 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
151 XTOPT_TABLEEND,
152 };
153 #undef s
154
155 #define s struct xt_hashlimit_mtinfo2
156 static const struct xt_option_entry hashlimit_mt_opts[] = {
157 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
158 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
159 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
160 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
161 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
162 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
163 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
164 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
165 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
166 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
167 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
168 XTOPT_POINTER(s, cfg.size)},
169 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
170 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
171 XTOPT_POINTER(s, cfg.max)},
172 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
173 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
174 XTOPT_POINTER(s, cfg.gc_interval)},
175 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
176 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
177 XTOPT_POINTER(s, cfg.expire)},
178 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
179 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
180 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
181 XTOPT_TABLEEND,
182 };
183 #undef s
184
185 static int
cfg_copy(struct hashlimit_cfg2 * to,const void * from,int revision)186 cfg_copy(struct hashlimit_cfg2 *to, const void *from, int revision)
187 {
188 if (revision == 1) {
189 struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from;
190
191 to->mode = cfg->mode;
192 to->avg = cfg->avg;
193 to->burst = cfg->burst;
194 to->size = cfg->size;
195 to->max = cfg->max;
196 to->gc_interval = cfg->gc_interval;
197 to->expire = cfg->expire;
198 to->srcmask = cfg->srcmask;
199 to->dstmask = cfg->dstmask;
200 } else if (revision == 2) {
201 memcpy(to, from, sizeof(struct hashlimit_cfg2));
202 } else {
203 return -EINVAL;
204 }
205
206 return 0;
207 }
208
cost_to_bytes(uint64_t cost)209 static uint64_t cost_to_bytes(uint64_t cost)
210 {
211 uint64_t r;
212
213 r = cost ? UINT32_MAX / cost : UINT32_MAX;
214 r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
215 return r;
216 }
217
bytes_to_cost(uint64_t bytes)218 static uint64_t bytes_to_cost(uint64_t bytes)
219 {
220 uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
221 return UINT32_MAX / (r+1);
222 }
223
get_factor(int chr)224 static uint32_t get_factor(int chr)
225 {
226 switch (chr) {
227 case 'm': return 1024 * 1024;
228 case 'k': return 1024;
229 }
230 return 1;
231 }
232
burst_error_v1(void)233 static void burst_error_v1(void)
234 {
235 xtables_error(PARAMETER_PROBLEM, "bad value for option "
236 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX_v1);
237 }
238
burst_error(void)239 static void burst_error(void)
240 {
241 xtables_error(PARAMETER_PROBLEM, "bad value for option "
242 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
243 }
244
parse_burst(const char * burst,int revision)245 static uint64_t parse_burst(const char *burst, int revision)
246 {
247 uintmax_t v;
248 char *end;
249 uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
250 uint64_t burst_max = (revision == 1) ?
251 XT_HASHLIMIT_BURST_MAX_v1 : XT_HASHLIMIT_BURST_MAX;
252
253 if (!xtables_strtoul(burst, &end, &v, 1, max) ||
254 (*end == 0 && v > burst_max)) {
255 if (revision == 1)
256 burst_error_v1();
257 else
258 burst_error();
259 }
260
261 v *= get_factor(*end);
262 if (v > max)
263 xtables_error(PARAMETER_PROBLEM, "bad value for option "
264 "\"--hashlimit-burst\", value \"%s\" too large "
265 "(max %lumb).", burst, max/1024/1024);
266 return v;
267 }
268
parse_bytes(const char * rate,void * val,struct hashlimit_mt_udata * ud,int revision)269 static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
270 {
271 unsigned int factor = 1;
272 uint64_t tmp, r;
273 const char *mode = strstr(rate, "b/s");
274 uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
275
276 if (!mode || mode == rate)
277 return false;
278
279 mode--;
280 r = atoll(rate);
281 if (r == 0)
282 return false;
283
284 factor = get_factor(*mode);
285 tmp = (uint64_t) r * factor;
286 if (tmp > max)
287 xtables_error(PARAMETER_PROBLEM,
288 "Rate value too large \"%llu\" (max %lu)\n",
289 (unsigned long long)tmp, max);
290
291 tmp = bytes_to_cost(tmp);
292 if (tmp == 0)
293 xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
294
295 ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
296
297 if(revision == 1)
298 *((uint32_t*)val) = tmp;
299 else
300 *((uint64_t*)val) = tmp;
301
302 return true;
303 }
304
305 static
parse_rate(const char * rate,void * val,struct hashlimit_mt_udata * ud,int revision)306 int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
307 {
308 const char *delim;
309 uint64_t tmp, r;
310 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
311
312 ud->mult = 1; /* Seconds by default. */
313 delim = strchr(rate, '/');
314 if (delim) {
315 if (strlen(delim+1) == 0)
316 return 0;
317
318 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
319 ud->mult = 1;
320 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
321 ud->mult = 60;
322 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
323 ud->mult = 60*60;
324 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
325 ud->mult = 24*60*60;
326 else
327 return 0;
328 }
329 r = atoll(rate);
330 if (!r)
331 return 0;
332
333 tmp = scale * ud->mult / r;
334 if (tmp == 0)
335 /*
336 * The rate maps to infinity. (1/day is the minimum they can
337 * specify, so we are ok at that end).
338 */
339 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
340
341 if(revision == 1)
342 *((uint32_t*)val) = tmp;
343 else
344 *((uint64_t*)val) = tmp;
345
346 return 1;
347 }
348
hashlimit_init(struct xt_entry_match * m)349 static void hashlimit_init(struct xt_entry_match *m)
350 {
351 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
352
353 r->cfg.burst = XT_HASHLIMIT_BURST;
354 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
355
356 }
357
hashlimit_mt4_init_v1(struct xt_entry_match * match)358 static void hashlimit_mt4_init_v1(struct xt_entry_match *match)
359 {
360 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
361
362 info->cfg.mode = 0;
363 info->cfg.burst = XT_HASHLIMIT_BURST;
364 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
365 info->cfg.srcmask = 32;
366 info->cfg.dstmask = 32;
367 }
368
hashlimit_mt6_init_v1(struct xt_entry_match * match)369 static void hashlimit_mt6_init_v1(struct xt_entry_match *match)
370 {
371 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
372
373 info->cfg.mode = 0;
374 info->cfg.burst = XT_HASHLIMIT_BURST;
375 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
376 info->cfg.srcmask = 128;
377 info->cfg.dstmask = 128;
378 }
379
hashlimit_mt4_init(struct xt_entry_match * match)380 static void hashlimit_mt4_init(struct xt_entry_match *match)
381 {
382 struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
383
384 info->cfg.mode = 0;
385 info->cfg.burst = XT_HASHLIMIT_BURST;
386 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
387 info->cfg.srcmask = 32;
388 info->cfg.dstmask = 32;
389 }
390
hashlimit_mt6_init(struct xt_entry_match * match)391 static void hashlimit_mt6_init(struct xt_entry_match *match)
392 {
393 struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
394
395 info->cfg.mode = 0;
396 info->cfg.burst = XT_HASHLIMIT_BURST;
397 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
398 info->cfg.srcmask = 128;
399 info->cfg.dstmask = 128;
400 }
401
402 /* Parse a 'mode' parameter into the required bitmask */
parse_mode(uint32_t * mode,const char * option_arg)403 static int parse_mode(uint32_t *mode, const char *option_arg)
404 {
405 char *tok;
406 char *arg = strdup(option_arg);
407
408 if (!arg)
409 return -1;
410
411 for (tok = strtok(arg, ",|");
412 tok;
413 tok = strtok(NULL, ",|")) {
414 if (!strcmp(tok, "dstip"))
415 *mode |= XT_HASHLIMIT_HASH_DIP;
416 else if (!strcmp(tok, "srcip"))
417 *mode |= XT_HASHLIMIT_HASH_SIP;
418 else if (!strcmp(tok, "srcport"))
419 *mode |= XT_HASHLIMIT_HASH_SPT;
420 else if (!strcmp(tok, "dstport"))
421 *mode |= XT_HASHLIMIT_HASH_DPT;
422 else {
423 free(arg);
424 return -1;
425 }
426 }
427 free(arg);
428 return 0;
429 }
430
hashlimit_parse(struct xt_option_call * cb)431 static void hashlimit_parse(struct xt_option_call *cb)
432 {
433 struct xt_hashlimit_info *info = cb->data;
434
435 xtables_option_parse(cb);
436 switch (cb->entry->id) {
437 case O_UPTO:
438 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
439 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
440 "--hashlimit-upto", cb->arg);
441 break;
442 case O_MODE:
443 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
444 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
445 "--hashlimit-mode", cb->arg);
446 break;
447 }
448 }
449
hashlimit_mt_parse_v1(struct xt_option_call * cb)450 static void hashlimit_mt_parse_v1(struct xt_option_call *cb)
451 {
452 struct xt_hashlimit_mtinfo1 *info = cb->data;
453
454 xtables_option_parse(cb);
455 switch (cb->entry->id) {
456 case O_BURST:
457 info->cfg.burst = parse_burst(cb->arg, 1);
458 break;
459 case O_UPTO:
460 if (cb->invert)
461 info->cfg.mode |= XT_HASHLIMIT_INVERT;
462 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
463 info->cfg.mode |= XT_HASHLIMIT_BYTES;
464 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
465 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
466 "--hashlimit-upto", cb->arg);
467 break;
468 case O_ABOVE:
469 if (!cb->invert)
470 info->cfg.mode |= XT_HASHLIMIT_INVERT;
471 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
472 info->cfg.mode |= XT_HASHLIMIT_BYTES;
473 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
474 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
475 "--hashlimit-above", cb->arg);
476 break;
477 case O_MODE:
478 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
479 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
480 "--hashlimit-mode", cb->arg);
481 break;
482 case O_SRCMASK:
483 info->cfg.srcmask = cb->val.hlen;
484 break;
485 case O_DSTMASK:
486 info->cfg.dstmask = cb->val.hlen;
487 break;
488 }
489 }
490
hashlimit_mt_parse(struct xt_option_call * cb)491 static void hashlimit_mt_parse(struct xt_option_call *cb)
492 {
493 struct xt_hashlimit_mtinfo2 *info = cb->data;
494
495 xtables_option_parse(cb);
496 switch (cb->entry->id) {
497 case O_BURST:
498 info->cfg.burst = parse_burst(cb->arg, 2);
499 break;
500 case O_UPTO:
501 if (cb->invert)
502 info->cfg.mode |= XT_HASHLIMIT_INVERT;
503 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
504 info->cfg.mode |= XT_HASHLIMIT_BYTES;
505 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
506 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
507 "--hashlimit-upto", cb->arg);
508 break;
509 case O_ABOVE:
510 if (!cb->invert)
511 info->cfg.mode |= XT_HASHLIMIT_INVERT;
512 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
513 info->cfg.mode |= XT_HASHLIMIT_BYTES;
514 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
515 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
516 "--hashlimit-above", cb->arg);
517 break;
518 case O_MODE:
519 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
520 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
521 "--hashlimit-mode", cb->arg);
522 break;
523 case O_SRCMASK:
524 info->cfg.srcmask = cb->val.hlen;
525 break;
526 case O_DSTMASK:
527 info->cfg.dstmask = cb->val.hlen;
528 break;
529 }
530 }
531
hashlimit_check(struct xt_fcheck_call * cb)532 static void hashlimit_check(struct xt_fcheck_call *cb)
533 {
534 const struct hashlimit_mt_udata *udata = cb->udata;
535 struct xt_hashlimit_info *info = cb->data;
536
537 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
538 xtables_error(PARAMETER_PROBLEM,
539 "You have to specify --hashlimit");
540 if (!(cb->xflags & F_HTABLE_EXPIRE))
541 info->cfg.expire = udata->mult * 1000; /* from s to msec */
542 }
543
hashlimit_mt_check_v1(struct xt_fcheck_call * cb)544 static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)
545 {
546 const struct hashlimit_mt_udata *udata = cb->udata;
547 struct xt_hashlimit_mtinfo1 *info = cb->data;
548
549 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
550 xtables_error(PARAMETER_PROBLEM,
551 "You have to specify --hashlimit");
552 if (!(cb->xflags & F_HTABLE_EXPIRE))
553 info->cfg.expire = udata->mult * 1000; /* from s to msec */
554
555 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
556 uint32_t burst = 0;
557 if (cb->xflags & F_BURST) {
558 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
559 xtables_error(PARAMETER_PROBLEM,
560 "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg));
561
562 burst = info->cfg.burst;
563 burst /= cost_to_bytes(info->cfg.avg);
564 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
565 burst++;
566 if (!(cb->xflags & F_HTABLE_EXPIRE))
567 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
568 }
569 info->cfg.burst = burst;
570 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX_v1)
571 burst_error_v1();
572 }
573
hashlimit_mt_check(struct xt_fcheck_call * cb)574 static void hashlimit_mt_check(struct xt_fcheck_call *cb)
575 {
576 const struct hashlimit_mt_udata *udata = cb->udata;
577 struct xt_hashlimit_mtinfo2 *info = cb->data;
578
579 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
580 xtables_error(PARAMETER_PROBLEM,
581 "You have to specify --hashlimit");
582 if (!(cb->xflags & F_HTABLE_EXPIRE))
583 info->cfg.expire = udata->mult * 1000; /* from s to msec */
584
585 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
586 uint32_t burst = 0;
587 if (cb->xflags & F_BURST) {
588 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
589 xtables_error(PARAMETER_PROBLEM,
590 "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg));
591
592 burst = info->cfg.burst;
593 burst /= cost_to_bytes(info->cfg.avg);
594 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
595 burst++;
596 if (!(cb->xflags & F_HTABLE_EXPIRE))
597 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
598 }
599 info->cfg.burst = burst;
600 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
601 burst_error();
602 }
603
604 struct rates {
605 const char *name;
606 uint64_t mult;
607 } rates_v1[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
608 { "hour", XT_HASHLIMIT_SCALE*60*60 },
609 { "min", XT_HASHLIMIT_SCALE*60 },
610 { "sec", XT_HASHLIMIT_SCALE } };
611
612 static const struct rates rates[] = {
613 { "day", XT_HASHLIMIT_SCALE_v2*24*60*60 },
614 { "hour", XT_HASHLIMIT_SCALE_v2*60*60 },
615 { "min", XT_HASHLIMIT_SCALE_v2*60 },
616 { "sec", XT_HASHLIMIT_SCALE_v2 } };
617
print_rate(uint32_t period,int revision)618 static uint32_t print_rate(uint32_t period, int revision)
619 {
620 unsigned int i;
621 const struct rates *_rates = (revision == 1) ? rates_v1 : rates;
622 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
623
624 if (period == 0) {
625 printf(" %f", INFINITY);
626 return 0;
627 }
628
629 for (i = 1; i < ARRAY_SIZE(rates); ++i)
630 if (period > _rates[i].mult
631 || _rates[i].mult/period < _rates[i].mult%period)
632 break;
633
634 printf(" %lu/%s", _rates[i-1].mult / period, _rates[i-1].name);
635 /* return in msec */
636 return _rates[i-1].mult / scale * 1000;
637 }
638
639 static const struct {
640 const char *name;
641 uint32_t thresh;
642 } units[] = {
643 { "m", 1024 * 1024 },
644 { "k", 1024 },
645 { "", 1 },
646 };
647
print_bytes(uint64_t avg,uint64_t burst,const char * prefix)648 static uint32_t print_bytes(uint64_t avg, uint64_t burst, const char *prefix)
649 {
650 unsigned int i;
651 unsigned long long r;
652
653 r = cost_to_bytes(avg);
654
655 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
656 if (r >= units[i].thresh &&
657 bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
658 break;
659 printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
660
661 if (burst == 0)
662 return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
663
664 r *= burst;
665 printf(" %s", prefix);
666 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
667 if (r >= units[i].thresh)
668 break;
669
670 printf("burst %llu%sb", r / units[i].thresh, units[i].name);
671 return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
672 }
673
print_mode(unsigned int mode,char separator)674 static void print_mode(unsigned int mode, char separator)
675 {
676 bool prevmode = false;
677
678 putchar(' ');
679 if (mode & XT_HASHLIMIT_HASH_SIP) {
680 fputs("srcip", stdout);
681 prevmode = 1;
682 }
683 if (mode & XT_HASHLIMIT_HASH_SPT) {
684 if (prevmode)
685 putchar(separator);
686 fputs("srcport", stdout);
687 prevmode = 1;
688 }
689 if (mode & XT_HASHLIMIT_HASH_DIP) {
690 if (prevmode)
691 putchar(separator);
692 fputs("dstip", stdout);
693 prevmode = 1;
694 }
695 if (mode & XT_HASHLIMIT_HASH_DPT) {
696 if (prevmode)
697 putchar(separator);
698 fputs("dstport", stdout);
699 }
700 }
701
hashlimit_print(const void * ip,const struct xt_entry_match * match,int numeric)702 static void hashlimit_print(const void *ip,
703 const struct xt_entry_match *match, int numeric)
704 {
705 const struct xt_hashlimit_info *r = (const void *)match->data;
706 uint32_t quantum;
707
708 fputs(" limit: avg", stdout);
709 quantum = print_rate(r->cfg.avg, 1);
710 printf(" burst %u", r->cfg.burst);
711 fputs(" mode", stdout);
712 print_mode(r->cfg.mode, '-');
713 if (r->cfg.size)
714 printf(" htable-size %u", r->cfg.size);
715 if (r->cfg.max)
716 printf(" htable-max %u", r->cfg.max);
717 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
718 printf(" htable-gcinterval %u", r->cfg.gc_interval);
719 if (r->cfg.expire != quantum)
720 printf(" htable-expire %u", r->cfg.expire);
721 }
722
723 static void
hashlimit_mt_print(const struct hashlimit_cfg2 * cfg,unsigned int dmask,int revision)724 hashlimit_mt_print(const struct hashlimit_cfg2 *cfg, unsigned int dmask, int revision)
725 {
726 uint32_t quantum;
727
728 if (cfg->mode & XT_HASHLIMIT_INVERT)
729 fputs(" limit: above", stdout);
730 else
731 fputs(" limit: up to", stdout);
732
733 if (cfg->mode & XT_HASHLIMIT_BYTES) {
734 quantum = print_bytes(cfg->avg, cfg->burst, "");
735 } else {
736 quantum = print_rate(cfg->avg, revision);
737 printf(" burst %llu", cfg->burst);
738 }
739 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
740 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
741 fputs(" mode", stdout);
742 print_mode(cfg->mode, '-');
743 }
744 if (cfg->size != 0)
745 printf(" htable-size %u", cfg->size);
746 if (cfg->max != 0)
747 printf(" htable-max %u", cfg->max);
748 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
749 printf(" htable-gcinterval %u", cfg->gc_interval);
750 if (cfg->expire != quantum)
751 printf(" htable-expire %u", cfg->expire);
752
753 if (cfg->srcmask != dmask)
754 printf(" srcmask %u", cfg->srcmask);
755 if (cfg->dstmask != dmask)
756 printf(" dstmask %u", cfg->dstmask);
757 }
758
759 static void
hashlimit_mt4_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)760 hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match,
761 int numeric)
762 {
763 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
764 struct hashlimit_cfg2 cfg;
765 int ret;
766
767 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
768
769 if (ret)
770 xtables_error(OTHER_PROBLEM, "unknown revision");
771
772 hashlimit_mt_print(&cfg, 32, 1);
773 }
774
775 static void
hashlimit_mt6_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)776 hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match,
777 int numeric)
778 {
779 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
780 struct hashlimit_cfg2 cfg;
781 int ret;
782
783 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
784
785 if (ret)
786 xtables_error(OTHER_PROBLEM, "unknown revision");
787
788 hashlimit_mt_print(&cfg, 128, 1);
789 }
790
791 static void
hashlimit_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)792 hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
793 int numeric)
794 {
795 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
796
797 hashlimit_mt_print(&info->cfg, 32, 2);
798 }
799
800 static void
hashlimit_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)801 hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
802 int numeric)
803 {
804 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
805
806 hashlimit_mt_print(&info->cfg, 128, 2);
807 }
808
hashlimit_save(const void * ip,const struct xt_entry_match * match)809 static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
810 {
811 const struct xt_hashlimit_info *r = (const void *)match->data;
812 uint32_t quantum;
813
814 fputs(" --hashlimit", stdout);
815 quantum = print_rate(r->cfg.avg, 1);
816 printf(" --hashlimit-burst %u", r->cfg.burst);
817
818 fputs(" --hashlimit-mode", stdout);
819 print_mode(r->cfg.mode, ',');
820
821 printf(" --hashlimit-name %s", r->name);
822
823 if (r->cfg.size)
824 printf(" --hashlimit-htable-size %u", r->cfg.size);
825 if (r->cfg.max)
826 printf(" --hashlimit-htable-max %u", r->cfg.max);
827 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
828 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
829 if (r->cfg.expire != quantum)
830 printf(" --hashlimit-htable-expire %u", r->cfg.expire);
831 }
832
833 static void
hashlimit_mt_save(const struct hashlimit_cfg2 * cfg,const char * name,unsigned int dmask,int revision)834 hashlimit_mt_save(const struct hashlimit_cfg2 *cfg, const char* name, unsigned int dmask, int revision)
835 {
836 uint32_t quantum;
837
838 if (cfg->mode & XT_HASHLIMIT_INVERT)
839 fputs(" --hashlimit-above", stdout);
840 else
841 fputs(" --hashlimit-upto", stdout);
842
843 if (cfg->mode & XT_HASHLIMIT_BYTES) {
844 quantum = print_bytes(cfg->avg, cfg->burst, "--hashlimit-");
845 } else {
846 quantum = print_rate(cfg->avg, revision);
847 printf(" --hashlimit-burst %llu", cfg->burst);
848 }
849
850 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
851 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
852 fputs(" --hashlimit-mode", stdout);
853 print_mode(cfg->mode, ',');
854 }
855
856 printf(" --hashlimit-name %s", name);
857
858 if (cfg->size != 0)
859 printf(" --hashlimit-htable-size %u", cfg->size);
860 if (cfg->max != 0)
861 printf(" --hashlimit-htable-max %u", cfg->max);
862 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
863 printf(" --hashlimit-htable-gcinterval %u", cfg->gc_interval);
864 if (cfg->expire != quantum)
865 printf(" --hashlimit-htable-expire %u", cfg->expire);
866
867 if (cfg->srcmask != dmask)
868 printf(" --hashlimit-srcmask %u", cfg->srcmask);
869 if (cfg->dstmask != dmask)
870 printf(" --hashlimit-dstmask %u", cfg->dstmask);
871 }
872
873 static void
hashlimit_mt4_save_v1(const void * ip,const struct xt_entry_match * match)874 hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match)
875 {
876 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
877 struct hashlimit_cfg2 cfg;
878 int ret;
879
880 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
881
882 if (ret)
883 xtables_error(OTHER_PROBLEM, "unknown revision");
884
885 hashlimit_mt_save(&cfg, info->name, 32, 1);
886 }
887
888 static void
hashlimit_mt6_save_v1(const void * ip,const struct xt_entry_match * match)889 hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match)
890 {
891 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
892 struct hashlimit_cfg2 cfg;
893 int ret;
894
895 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
896
897 if (ret)
898 xtables_error(OTHER_PROBLEM, "unknown revision");
899
900 hashlimit_mt_save(&cfg, info->name, 128, 1);
901 }
902
903 static void
hashlimit_mt4_save(const void * ip,const struct xt_entry_match * match)904 hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
905 {
906 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
907
908 hashlimit_mt_save(&info->cfg, info->name, 32, 2);
909 }
910
911 static void
hashlimit_mt6_save(const void * ip,const struct xt_entry_match * match)912 hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
913 {
914 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
915
916 hashlimit_mt_save(&info->cfg, info->name, 128, 2);
917 }
918
919 static struct xtables_match hashlimit_mt_reg[] = {
920 {
921 .family = NFPROTO_UNSPEC,
922 .name = "hashlimit",
923 .version = XTABLES_VERSION,
924 .revision = 0,
925 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
926 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
927 .help = hashlimit_help,
928 .init = hashlimit_init,
929 .x6_parse = hashlimit_parse,
930 .x6_fcheck = hashlimit_check,
931 .print = hashlimit_print,
932 .save = hashlimit_save,
933 .x6_options = hashlimit_opts,
934 .udata_size = sizeof(struct hashlimit_mt_udata),
935 },
936 {
937 .version = XTABLES_VERSION,
938 .name = "hashlimit",
939 .revision = 1,
940 .family = NFPROTO_IPV4,
941 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
942 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
943 .help = hashlimit_mt_help,
944 .init = hashlimit_mt4_init_v1,
945 .x6_parse = hashlimit_mt_parse_v1,
946 .x6_fcheck = hashlimit_mt_check_v1,
947 .print = hashlimit_mt4_print_v1,
948 .save = hashlimit_mt4_save_v1,
949 .x6_options = hashlimit_mt_opts_v1,
950 .udata_size = sizeof(struct hashlimit_mt_udata),
951 },
952 {
953 .version = XTABLES_VERSION,
954 .name = "hashlimit",
955 .revision = 1,
956 .family = NFPROTO_IPV6,
957 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
958 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
959 .help = hashlimit_mt_help,
960 .init = hashlimit_mt6_init_v1,
961 .x6_parse = hashlimit_mt_parse_v1,
962 .x6_fcheck = hashlimit_mt_check_v1,
963 .print = hashlimit_mt6_print_v1,
964 .save = hashlimit_mt6_save_v1,
965 .x6_options = hashlimit_mt_opts_v1,
966 .udata_size = sizeof(struct hashlimit_mt_udata),
967 },
968 {
969 .version = XTABLES_VERSION,
970 .name = "hashlimit",
971 .revision = 2,
972 .family = NFPROTO_IPV4,
973 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
974 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
975 .help = hashlimit_mt_help,
976 .init = hashlimit_mt4_init,
977 .x6_parse = hashlimit_mt_parse,
978 .x6_fcheck = hashlimit_mt_check,
979 .print = hashlimit_mt4_print,
980 .save = hashlimit_mt4_save,
981 .x6_options = hashlimit_mt_opts,
982 .udata_size = sizeof(struct hashlimit_mt_udata),
983 },
984 {
985 .version = XTABLES_VERSION,
986 .name = "hashlimit",
987 .revision = 2,
988 .family = NFPROTO_IPV6,
989 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
990 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
991 .help = hashlimit_mt_help,
992 .init = hashlimit_mt6_init,
993 .x6_parse = hashlimit_mt_parse,
994 .x6_fcheck = hashlimit_mt_check,
995 .print = hashlimit_mt6_print,
996 .save = hashlimit_mt6_save,
997 .x6_options = hashlimit_mt_opts,
998 .udata_size = sizeof(struct hashlimit_mt_udata),
999 },
1000 };
1001
_init(void)1002 void _init(void)
1003 {
1004 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
1005 }
1006