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 <xtables.h>
22 #include <linux/netfilter/x_tables.h>
23 #include <linux/netfilter/xt_hashlimit.h>
24
25 #define XT_HASHLIMIT_BURST 5
26 #define XT_HASHLIMIT_BURST_MAX 10000
27
28 #define XT_HASHLIMIT_BYTE_EXPIRE 15
29 #define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60
30
31 /* miliseconds */
32 #define XT_HASHLIMIT_GCINTERVAL 1000
33
34 struct hashlimit_mt_udata {
35 uint32_t mult;
36 };
37
hashlimit_help(void)38 static void hashlimit_help(void)
39 {
40 printf(
41 "hashlimit match options:\n"
42 "--hashlimit <avg> max average match rate\n"
43 " [Packets per second unless followed by \n"
44 " /sec /minute /hour /day postfixes]\n"
45 "--hashlimit-mode <mode> mode is a comma-separated list of\n"
46 " dstip,srcip,dstport,srcport\n"
47 "--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n"
48 "[--hashlimit-burst <num>] number to match in a burst, default %u\n"
49 "[--hashlimit-htable-size <num>] number of hashtable buckets\n"
50 "[--hashlimit-htable-max <num>] number of hashtable entries\n"
51 "[--hashlimit-htable-gcinterval] interval between garbage collection runs\n"
52 "[--hashlimit-htable-expire] after which time are idle entries expired?\n",
53 XT_HASHLIMIT_BURST);
54 }
55
56 enum {
57 O_UPTO = 0,
58 O_ABOVE,
59 O_LIMIT,
60 O_MODE,
61 O_SRCMASK,
62 O_DSTMASK,
63 O_NAME,
64 O_BURST,
65 O_HTABLE_SIZE,
66 O_HTABLE_MAX,
67 O_HTABLE_GCINT,
68 O_HTABLE_EXPIRE,
69 F_BURST = 1 << O_BURST,
70 F_UPTO = 1 << O_UPTO,
71 F_ABOVE = 1 << O_ABOVE,
72 F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
73 };
74
hashlimit_mt_help(void)75 static void hashlimit_mt_help(void)
76 {
77 printf(
78 "hashlimit match options:\n"
79 " --hashlimit-upto <avg> max average match rate\n"
80 " [Packets per second unless followed by \n"
81 " /sec /minute /hour /day postfixes]\n"
82 " --hashlimit-above <avg> min average match rate\n"
83 " --hashlimit-mode <mode> mode is a comma-separated list of\n"
84 " dstip,srcip,dstport,srcport (or none)\n"
85 " --hashlimit-srcmask <length> source address grouping prefix length\n"
86 " --hashlimit-dstmask <length> destination address grouping prefix length\n"
87 " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
88 " --hashlimit-burst <num> number to match in a burst, default %u\n"
89 " --hashlimit-htable-size <num> number of hashtable buckets\n"
90 " --hashlimit-htable-max <num> number of hashtable entries\n"
91 " --hashlimit-htable-gcinterval interval between garbage collection runs\n"
92 " --hashlimit-htable-expire after which time are idle entries expired?\n"
93 "\n", XT_HASHLIMIT_BURST);
94 }
95
96 #define s struct xt_hashlimit_info
97 static const struct xt_option_entry hashlimit_opts[] = {
98 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
99 .type = XTTYPE_STRING},
100 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
101 .min = 1, .max = XT_HASHLIMIT_BURST_MAX, .flags = XTOPT_PUT,
102 XTOPT_POINTER(s, cfg.burst)},
103 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
104 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
105 XTOPT_POINTER(s, cfg.size)},
106 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
107 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
108 XTOPT_POINTER(s, cfg.max)},
109 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
110 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
111 XTOPT_POINTER(s, cfg.gc_interval)},
112 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
113 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
114 XTOPT_POINTER(s, cfg.expire)},
115 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
116 .flags = XTOPT_MAND},
117 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
118 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
119 XTOPT_TABLEEND,
120 };
121 #undef s
122
123 #define s struct xt_hashlimit_mtinfo1
124 static const struct xt_option_entry hashlimit_mt_opts[] = {
125 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
126 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
127 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
128 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
129 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
130 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
131 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
132 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
133 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
134 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
135 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
136 XTOPT_POINTER(s, cfg.size)},
137 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
138 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
139 XTOPT_POINTER(s, cfg.max)},
140 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
141 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
142 XTOPT_POINTER(s, cfg.gc_interval)},
143 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
144 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
145 XTOPT_POINTER(s, cfg.expire)},
146 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
147 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
148 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
149 XTOPT_TABLEEND,
150 };
151 #undef s
152
cost_to_bytes(uint32_t cost)153 static uint32_t cost_to_bytes(uint32_t cost)
154 {
155 uint32_t r;
156
157 r = cost ? UINT32_MAX / cost : UINT32_MAX;
158 r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
159 return r;
160 }
161
bytes_to_cost(uint32_t bytes)162 static uint64_t bytes_to_cost(uint32_t bytes)
163 {
164 uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
165 return UINT32_MAX / (r+1);
166 }
167
get_factor(int chr)168 static uint32_t get_factor(int chr)
169 {
170 switch (chr) {
171 case 'm': return 1024 * 1024;
172 case 'k': return 1024;
173 }
174 return 1;
175 }
176
burst_error(void)177 static void burst_error(void)
178 {
179 xtables_error(PARAMETER_PROBLEM, "bad value for option "
180 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
181 }
182
parse_burst(const char * burst,struct xt_hashlimit_mtinfo1 * info)183 static uint32_t parse_burst(const char *burst, struct xt_hashlimit_mtinfo1 *info)
184 {
185 uintmax_t v;
186 char *end;
187
188 if (!xtables_strtoul(burst, &end, &v, 1, UINT32_MAX) ||
189 (*end == 0 && v > XT_HASHLIMIT_BURST_MAX))
190 burst_error();
191
192 v *= get_factor(*end);
193 if (v > UINT32_MAX)
194 xtables_error(PARAMETER_PROBLEM, "bad value for option "
195 "\"--hashlimit-burst\", value \"%s\" too large "
196 "(max %umb).", burst, UINT32_MAX/1024/1024);
197 return v;
198 }
199
parse_bytes(const char * rate,uint32_t * val,struct hashlimit_mt_udata * ud)200 static bool parse_bytes(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
201 {
202 unsigned int factor = 1;
203 uint64_t tmp;
204 int r;
205 const char *mode = strstr(rate, "b/s");
206 if (!mode || mode == rate)
207 return false;
208
209 mode--;
210 r = atoi(rate);
211 if (r == 0)
212 return false;
213
214 factor = get_factor(*mode);
215 tmp = (uint64_t) r * factor;
216 if (tmp > UINT32_MAX)
217 xtables_error(PARAMETER_PROBLEM,
218 "Rate value too large \"%llu\" (max %u)\n",
219 (unsigned long long)tmp, UINT32_MAX);
220
221 *val = bytes_to_cost(tmp);
222 if (*val == 0)
223 xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
224
225 ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
226 return true;
227 }
228
229 static
parse_rate(const char * rate,uint32_t * val,struct hashlimit_mt_udata * ud)230 int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
231 {
232 const char *delim;
233 uint32_t r;
234
235 ud->mult = 1; /* Seconds by default. */
236 delim = strchr(rate, '/');
237 if (delim) {
238 if (strlen(delim+1) == 0)
239 return 0;
240
241 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
242 ud->mult = 1;
243 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
244 ud->mult = 60;
245 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
246 ud->mult = 60*60;
247 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
248 ud->mult = 24*60*60;
249 else
250 return 0;
251 }
252 r = atoi(rate);
253 if (!r)
254 return 0;
255
256 *val = XT_HASHLIMIT_SCALE * ud->mult / r;
257 if (*val == 0)
258 /*
259 * The rate maps to infinity. (1/day is the minimum they can
260 * specify, so we are ok at that end).
261 */
262 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
263 return 1;
264 }
265
hashlimit_init(struct xt_entry_match * m)266 static void hashlimit_init(struct xt_entry_match *m)
267 {
268 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
269
270 r->cfg.burst = XT_HASHLIMIT_BURST;
271 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
272
273 }
274
hashlimit_mt4_init(struct xt_entry_match * match)275 static void hashlimit_mt4_init(struct xt_entry_match *match)
276 {
277 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
278
279 info->cfg.mode = 0;
280 info->cfg.burst = XT_HASHLIMIT_BURST;
281 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
282 info->cfg.srcmask = 32;
283 info->cfg.dstmask = 32;
284 }
285
hashlimit_mt6_init(struct xt_entry_match * match)286 static void hashlimit_mt6_init(struct xt_entry_match *match)
287 {
288 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
289
290 info->cfg.mode = 0;
291 info->cfg.burst = XT_HASHLIMIT_BURST;
292 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
293 info->cfg.srcmask = 128;
294 info->cfg.dstmask = 128;
295 }
296
297 /* Parse a 'mode' parameter into the required bitmask */
parse_mode(uint32_t * mode,const char * option_arg)298 static int parse_mode(uint32_t *mode, const char *option_arg)
299 {
300 char *tok;
301 char *arg = strdup(option_arg);
302
303 if (!arg)
304 return -1;
305
306 for (tok = strtok(arg, ",|");
307 tok;
308 tok = strtok(NULL, ",|")) {
309 if (!strcmp(tok, "dstip"))
310 *mode |= XT_HASHLIMIT_HASH_DIP;
311 else if (!strcmp(tok, "srcip"))
312 *mode |= XT_HASHLIMIT_HASH_SIP;
313 else if (!strcmp(tok, "srcport"))
314 *mode |= XT_HASHLIMIT_HASH_SPT;
315 else if (!strcmp(tok, "dstport"))
316 *mode |= XT_HASHLIMIT_HASH_DPT;
317 else {
318 free(arg);
319 return -1;
320 }
321 }
322 free(arg);
323 return 0;
324 }
325
hashlimit_parse(struct xt_option_call * cb)326 static void hashlimit_parse(struct xt_option_call *cb)
327 {
328 struct xt_hashlimit_info *info = cb->data;
329
330 xtables_option_parse(cb);
331 switch (cb->entry->id) {
332 case O_UPTO:
333 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
334 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
335 "--hashlimit-upto", cb->arg);
336 break;
337 case O_MODE:
338 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
339 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
340 "--hashlimit-mode", cb->arg);
341 break;
342 }
343 }
344
hashlimit_mt_parse(struct xt_option_call * cb)345 static void hashlimit_mt_parse(struct xt_option_call *cb)
346 {
347 struct xt_hashlimit_mtinfo1 *info = cb->data;
348
349 xtables_option_parse(cb);
350 switch (cb->entry->id) {
351 case O_BURST:
352 info->cfg.burst = parse_burst(cb->arg, info);
353 break;
354 case O_UPTO:
355 if (cb->invert)
356 info->cfg.mode |= XT_HASHLIMIT_INVERT;
357 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
358 info->cfg.mode |= XT_HASHLIMIT_BYTES;
359 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
360 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
361 "--hashlimit-upto", cb->arg);
362 break;
363 case O_ABOVE:
364 if (!cb->invert)
365 info->cfg.mode |= XT_HASHLIMIT_INVERT;
366 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata))
367 info->cfg.mode |= XT_HASHLIMIT_BYTES;
368 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
369 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
370 "--hashlimit-above", cb->arg);
371 break;
372 case O_MODE:
373 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
374 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
375 "--hashlimit-mode", cb->arg);
376 break;
377 case O_SRCMASK:
378 info->cfg.srcmask = cb->val.hlen;
379 break;
380 case O_DSTMASK:
381 info->cfg.dstmask = cb->val.hlen;
382 break;
383 }
384 }
385
hashlimit_check(struct xt_fcheck_call * cb)386 static void hashlimit_check(struct xt_fcheck_call *cb)
387 {
388 const struct hashlimit_mt_udata *udata = cb->udata;
389 struct xt_hashlimit_info *info = cb->data;
390
391 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
392 xtables_error(PARAMETER_PROBLEM,
393 "You have to specify --hashlimit");
394 if (!(cb->xflags & F_HTABLE_EXPIRE))
395 info->cfg.expire = udata->mult * 1000; /* from s to msec */
396 }
397
hashlimit_mt_check(struct xt_fcheck_call * cb)398 static void hashlimit_mt_check(struct xt_fcheck_call *cb)
399 {
400 const struct hashlimit_mt_udata *udata = cb->udata;
401 struct xt_hashlimit_mtinfo1 *info = cb->data;
402
403 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
404 xtables_error(PARAMETER_PROBLEM,
405 "You have to specify --hashlimit");
406 if (!(cb->xflags & F_HTABLE_EXPIRE))
407 info->cfg.expire = udata->mult * 1000; /* from s to msec */
408
409 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
410 uint32_t burst = 0;
411 if (cb->xflags & F_BURST) {
412 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
413 xtables_error(PARAMETER_PROBLEM,
414 "burst cannot be smaller than %ub", cost_to_bytes(info->cfg.avg));
415
416 burst = info->cfg.burst;
417 burst /= cost_to_bytes(info->cfg.avg);
418 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
419 burst++;
420 if (!(cb->xflags & F_HTABLE_EXPIRE))
421 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
422 }
423 info->cfg.burst = burst;
424 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
425 burst_error();
426 }
427
428 static const struct rates
429 {
430 const char *name;
431 uint32_t mult;
432 } rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
433 { "hour", XT_HASHLIMIT_SCALE*60*60 },
434 { "min", XT_HASHLIMIT_SCALE*60 },
435 { "sec", XT_HASHLIMIT_SCALE } };
436
print_rate(uint32_t period)437 static uint32_t print_rate(uint32_t period)
438 {
439 unsigned int i;
440
441 if (period == 0) {
442 printf(" %f", INFINITY);
443 return 0;
444 }
445
446 for (i = 1; i < ARRAY_SIZE(rates); ++i)
447 if (period > rates[i].mult
448 || rates[i].mult/period < rates[i].mult%period)
449 break;
450
451 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
452 /* return in msec */
453 return rates[i-1].mult / XT_HASHLIMIT_SCALE * 1000;
454 }
455
456 static const struct {
457 const char *name;
458 uint32_t thresh;
459 } units[] = {
460 { "m", 1024 * 1024 },
461 { "k", 1024 },
462 { "", 1 },
463 };
464
print_bytes(uint32_t avg,uint32_t burst,const char * prefix)465 static uint32_t print_bytes(uint32_t avg, uint32_t burst, const char *prefix)
466 {
467 unsigned int i;
468 unsigned long long r;
469
470 r = cost_to_bytes(avg);
471
472 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
473 if (r >= units[i].thresh &&
474 bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
475 break;
476 printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
477
478 if (burst == 0)
479 return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
480
481 r *= burst;
482 printf(" %s", prefix);
483 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
484 if (r >= units[i].thresh)
485 break;
486
487 printf("burst %llu%sb", r / units[i].thresh, units[i].name);
488 return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
489 }
490
print_mode(unsigned int mode,char separator)491 static void print_mode(unsigned int mode, char separator)
492 {
493 bool prevmode = false;
494
495 putchar(' ');
496 if (mode & XT_HASHLIMIT_HASH_SIP) {
497 fputs("srcip", stdout);
498 prevmode = 1;
499 }
500 if (mode & XT_HASHLIMIT_HASH_SPT) {
501 if (prevmode)
502 putchar(separator);
503 fputs("srcport", stdout);
504 prevmode = 1;
505 }
506 if (mode & XT_HASHLIMIT_HASH_DIP) {
507 if (prevmode)
508 putchar(separator);
509 fputs("dstip", stdout);
510 prevmode = 1;
511 }
512 if (mode & XT_HASHLIMIT_HASH_DPT) {
513 if (prevmode)
514 putchar(separator);
515 fputs("dstport", stdout);
516 }
517 }
518
hashlimit_print(const void * ip,const struct xt_entry_match * match,int numeric)519 static void hashlimit_print(const void *ip,
520 const struct xt_entry_match *match, int numeric)
521 {
522 const struct xt_hashlimit_info *r = (const void *)match->data;
523 uint32_t quantum;
524
525 fputs(" limit: avg", stdout);
526 quantum = print_rate(r->cfg.avg);
527 printf(" burst %u", r->cfg.burst);
528 fputs(" mode", stdout);
529 print_mode(r->cfg.mode, '-');
530 if (r->cfg.size)
531 printf(" htable-size %u", r->cfg.size);
532 if (r->cfg.max)
533 printf(" htable-max %u", r->cfg.max);
534 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
535 printf(" htable-gcinterval %u", r->cfg.gc_interval);
536 if (r->cfg.expire != quantum)
537 printf(" htable-expire %u", r->cfg.expire);
538 }
539
540 static void
hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 * info,unsigned int dmask)541 hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
542 {
543 uint32_t quantum;
544
545 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
546 fputs(" limit: above", stdout);
547 else
548 fputs(" limit: up to", stdout);
549
550 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
551 quantum = print_bytes(info->cfg.avg, info->cfg.burst, "");
552 } else {
553 quantum = print_rate(info->cfg.avg);
554 printf(" burst %u", info->cfg.burst);
555 }
556 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
557 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
558 fputs(" mode", stdout);
559 print_mode(info->cfg.mode, '-');
560 }
561 if (info->cfg.size != 0)
562 printf(" htable-size %u", info->cfg.size);
563 if (info->cfg.max != 0)
564 printf(" htable-max %u", info->cfg.max);
565 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
566 printf(" htable-gcinterval %u", info->cfg.gc_interval);
567 if (info->cfg.expire != quantum)
568 printf(" htable-expire %u", info->cfg.expire);
569
570 if (info->cfg.srcmask != dmask)
571 printf(" srcmask %u", info->cfg.srcmask);
572 if (info->cfg.dstmask != dmask)
573 printf(" dstmask %u", info->cfg.dstmask);
574 }
575
576 static void
hashlimit_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)577 hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
578 int numeric)
579 {
580 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
581
582 hashlimit_mt_print(info, 32);
583 }
584
585 static void
hashlimit_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)586 hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
587 int numeric)
588 {
589 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
590
591 hashlimit_mt_print(info, 128);
592 }
593
hashlimit_save(const void * ip,const struct xt_entry_match * match)594 static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
595 {
596 const struct xt_hashlimit_info *r = (const void *)match->data;
597 uint32_t quantum;
598
599 fputs(" --hashlimit", stdout);
600 quantum = print_rate(r->cfg.avg);
601 printf(" --hashlimit-burst %u", r->cfg.burst);
602
603 fputs(" --hashlimit-mode", stdout);
604 print_mode(r->cfg.mode, ',');
605
606 printf(" --hashlimit-name %s", r->name);
607
608 if (r->cfg.size)
609 printf(" --hashlimit-htable-size %u", r->cfg.size);
610 if (r->cfg.max)
611 printf(" --hashlimit-htable-max %u", r->cfg.max);
612 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
613 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
614 if (r->cfg.expire != quantum)
615 printf(" --hashlimit-htable-expire %u", r->cfg.expire);
616 }
617
618 static void
hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 * info,unsigned int dmask)619 hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
620 {
621 uint32_t quantum;
622
623 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
624 fputs(" --hashlimit-above", stdout);
625 else
626 fputs(" --hashlimit-upto", stdout);
627
628 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
629 quantum = print_bytes(info->cfg.avg, info->cfg.burst, "--hashlimit-");
630 } else {
631 quantum = print_rate(info->cfg.avg);
632 printf(" --hashlimit-burst %u", info->cfg.burst);
633 }
634
635 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
636 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
637 fputs(" --hashlimit-mode", stdout);
638 print_mode(info->cfg.mode, ',');
639 }
640
641 printf(" --hashlimit-name %s", info->name);
642
643 if (info->cfg.size != 0)
644 printf(" --hashlimit-htable-size %u", info->cfg.size);
645 if (info->cfg.max != 0)
646 printf(" --hashlimit-htable-max %u", info->cfg.max);
647 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
648 printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
649 if (info->cfg.expire != quantum)
650 printf(" --hashlimit-htable-expire %u", info->cfg.expire);
651
652 if (info->cfg.srcmask != dmask)
653 printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
654 if (info->cfg.dstmask != dmask)
655 printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
656 }
657
658 static void
hashlimit_mt4_save(const void * ip,const struct xt_entry_match * match)659 hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
660 {
661 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
662
663 hashlimit_mt_save(info, 32);
664 }
665
666 static void
hashlimit_mt6_save(const void * ip,const struct xt_entry_match * match)667 hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
668 {
669 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
670
671 hashlimit_mt_save(info, 128);
672 }
673
674 static struct xtables_match hashlimit_mt_reg[] = {
675 {
676 .family = NFPROTO_UNSPEC,
677 .name = "hashlimit",
678 .version = XTABLES_VERSION,
679 .revision = 0,
680 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
681 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
682 .help = hashlimit_help,
683 .init = hashlimit_init,
684 .x6_parse = hashlimit_parse,
685 .x6_fcheck = hashlimit_check,
686 .print = hashlimit_print,
687 .save = hashlimit_save,
688 .x6_options = hashlimit_opts,
689 .udata_size = sizeof(struct hashlimit_mt_udata),
690 },
691 {
692 .version = XTABLES_VERSION,
693 .name = "hashlimit",
694 .revision = 1,
695 .family = NFPROTO_IPV4,
696 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
697 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
698 .help = hashlimit_mt_help,
699 .init = hashlimit_mt4_init,
700 .x6_parse = hashlimit_mt_parse,
701 .x6_fcheck = hashlimit_mt_check,
702 .print = hashlimit_mt4_print,
703 .save = hashlimit_mt4_save,
704 .x6_options = hashlimit_mt_opts,
705 .udata_size = sizeof(struct hashlimit_mt_udata),
706 },
707 {
708 .version = XTABLES_VERSION,
709 .name = "hashlimit",
710 .revision = 1,
711 .family = NFPROTO_IPV6,
712 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
713 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
714 .help = hashlimit_mt_help,
715 .init = hashlimit_mt6_init,
716 .x6_parse = hashlimit_mt_parse,
717 .x6_fcheck = hashlimit_mt_check,
718 .print = hashlimit_mt6_print,
719 .save = hashlimit_mt6_save,
720 .x6_options = hashlimit_mt_opts,
721 .udata_size = sizeof(struct hashlimit_mt_udata),
722 },
723 };
724
_init(void)725 void _init(void)
726 {
727 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
728 }
729