1 /* ip6tables match extension for limiting packets per destination
3 * (C) 2003-2004 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>
11 * Error corections by nmalykh@bilim.com (22.01.2005)
20 #include <linux/netfilter/x_tables.h>
21 #include <linux/netfilter/xt_hashlimit.h>
23 #define XT_HASHLIMIT_BURST 5
26 #define XT_HASHLIMIT_GCINTERVAL 1000
27 #define XT_HASHLIMIT_EXPIRE 10000
29 /* Function which prints out usage message. */
30 static void hashlimit_help(void)
33 "hashlimit match options:\n"
34 "--hashlimit <avg> max average match rate\n"
35 " [Packets per second unless followed by \n"
36 " /sec /minute /hour /day postfixes]\n"
37 "--hashlimit-mode <mode> mode is a comma-separated list of\n"
38 " dstip,srcip,dstport,srcport\n"
39 "--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n"
40 "[--hashlimit-burst <num>] number to match in a burst, default %u\n"
41 "[--hashlimit-htable-size <num>] number of hashtable buckets\n"
42 "[--hashlimit-htable-max <num>] number of hashtable entries\n"
43 "[--hashlimit-htable-gcinterval] interval between garbage collection runs\n"
44 "[--hashlimit-htable-expire] after which time are idle entries expired?\n",
48 static void hashlimit_mt_help(void)
51 "hashlimit match options:\n"
52 " --hashlimit-upto <avg> max average match rate\n"
53 " [Packets per second unless followed by \n"
54 " /sec /minute /hour /day postfixes]\n"
55 " --hashlimit-above <avg> min average match rate\n"
56 " --hashlimit-mode <mode> mode is a comma-separated list of\n"
57 " dstip,srcip,dstport,srcport (or none)\n"
58 " --hashlimit-srcmask <length> source address grouping prefix length\n"
59 " --hashlimit-dstmask <length> destination address grouping prefix length\n"
60 " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
61 " --hashlimit-burst <num> number to match in a burst, default %u\n"
62 " --hashlimit-htable-size <num> number of hashtable buckets\n"
63 " --hashlimit-htable-max <num> number of hashtable entries\n"
64 " --hashlimit-htable-gcinterval interval between garbage collection runs\n"
65 " --hashlimit-htable-expire after which time are idle entries expired?\n"
66 "\n", XT_HASHLIMIT_BURST);
69 static const struct option hashlimit_opts[] = {
70 { "hashlimit", 1, NULL, '%' },
71 { "hashlimit-burst", 1, NULL, '$' },
72 { "hashlimit-htable-size", 1, NULL, '&' },
73 { "hashlimit-htable-max", 1, NULL, '*' },
74 { "hashlimit-htable-gcinterval", 1, NULL, '(' },
75 { "hashlimit-htable-expire", 1, NULL, ')' },
76 { "hashlimit-mode", 1, NULL, '_' },
77 { "hashlimit-name", 1, NULL, '"' },
81 static const struct option hashlimit_mt_opts[] = {
82 {.name = "hashlimit-upto", .has_arg = true, .val = '%'},
83 {.name = "hashlimit-above", .has_arg = true, .val = '^'},
84 {.name = "hashlimit", .has_arg = true, .val = '%'},
85 {.name = "hashlimit-srcmask", .has_arg = true, .val = '<'},
86 {.name = "hashlimit-dstmask", .has_arg = true, .val = '>'},
87 {.name = "hashlimit-burst", .has_arg = true, .val = '$'},
88 {.name = "hashlimit-htable-size", .has_arg = true, .val = '&'},
89 {.name = "hashlimit-htable-max", .has_arg = true, .val = '*'},
90 {.name = "hashlimit-htable-gcinterval", .has_arg = true, .val = '('},
91 {.name = "hashlimit-htable-expire", .has_arg = true, .val = ')'},
92 {.name = "hashlimit-mode", .has_arg = true, .val = '_'},
93 {.name = "hashlimit-name", .has_arg = true, .val = '"'},
98 int parse_rate(const char *rate, u_int32_t *val)
102 u_int32_t mult = 1; /* Seconds by default. */
104 delim = strchr(rate, '/');
106 if (strlen(delim+1) == 0)
109 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
111 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
113 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
115 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
124 /* This would get mapped to infinite (1/day is minimum they
125 can specify, so we're ok at that end). */
126 if (r / mult > XT_HASHLIMIT_SCALE)
127 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
129 *val = XT_HASHLIMIT_SCALE * mult / r;
133 /* Initialize the match. */
134 static void hashlimit_init(struct xt_entry_match *m)
136 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
139 r->cfg.burst = XT_HASHLIMIT_BURST;
140 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
141 r->cfg.expire = XT_HASHLIMIT_EXPIRE;
145 static void hashlimit_mt4_init(struct xt_entry_match *match)
147 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
150 info->cfg.burst = XT_HASHLIMIT_BURST;
151 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
152 info->cfg.expire = XT_HASHLIMIT_EXPIRE;
153 info->cfg.srcmask = 32;
154 info->cfg.dstmask = 32;
157 static void hashlimit_mt6_init(struct xt_entry_match *match)
159 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
162 info->cfg.burst = XT_HASHLIMIT_BURST;
163 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
164 info->cfg.expire = XT_HASHLIMIT_EXPIRE;
165 info->cfg.srcmask = 128;
166 info->cfg.dstmask = 128;
169 /* Parse a 'mode' parameter into the required bitmask */
170 static int parse_mode(uint32_t *mode, char *option_arg)
173 char *arg = strdup(option_arg);
178 for (tok = strtok(arg, ",|");
180 tok = strtok(NULL, ",|")) {
181 if (!strcmp(tok, "dstip"))
182 *mode |= XT_HASHLIMIT_HASH_DIP;
183 else if (!strcmp(tok, "srcip"))
184 *mode |= XT_HASHLIMIT_HASH_SIP;
185 else if (!strcmp(tok, "srcport"))
186 *mode |= XT_HASHLIMIT_HASH_SPT;
187 else if (!strcmp(tok, "dstport"))
188 *mode |= XT_HASHLIMIT_HASH_DPT;
199 PARAM_LIMIT = 1 << 0,
200 PARAM_BURST = 1 << 1,
205 PARAM_GCINTERVAL = 1 << 6,
206 PARAM_EXPIRE = 1 << 7,
207 PARAM_SRCMASK = 1 << 8,
208 PARAM_DSTMASK = 1 << 9,
211 /* Function which parses command options; returns true if it
214 hashlimit_parse(int c, char **argv, int invert, unsigned int *flags,
215 const void *entry, struct xt_entry_match **match)
217 struct xt_hashlimit_info *r =
218 (struct xt_hashlimit_info *)(*match)->data;
223 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit",
224 *flags & PARAM_LIMIT);
225 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
226 if (!parse_rate(optarg, &r->cfg.avg))
227 exit_error(PARAMETER_PROBLEM,
228 "bad rate `%s'", optarg);
229 *flags |= PARAM_LIMIT;
233 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-burst",
234 *flags & PARAM_BURST);
235 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
236 if (string_to_number(optarg, 0, 10000, &num) == -1)
237 exit_error(PARAMETER_PROBLEM,
238 "bad --hashlimit-burst `%s'", optarg);
240 *flags |= PARAM_BURST;
243 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size",
244 *flags & PARAM_SIZE);
245 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
246 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
247 exit_error(PARAMETER_PROBLEM,
248 "bad --hashlimit-htable-size: `%s'", optarg);
250 *flags |= PARAM_SIZE;
253 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max",
255 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
256 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
257 exit_error(PARAMETER_PROBLEM,
258 "bad --hashlimit-htable-max: `%s'", optarg);
263 param_act(P_ONLY_ONCE, "hashlimit",
264 "--hashlimit-htable-gcinterval",
265 *flags & PARAM_GCINTERVAL);
266 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
267 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
268 exit_error(PARAMETER_PROBLEM,
269 "bad --hashlimit-htable-gcinterval: `%s'",
271 /* FIXME: not HZ dependent!! */
272 r->cfg.gc_interval = num;
273 *flags |= PARAM_GCINTERVAL;
276 param_act(P_ONLY_ONCE, "hashlimit",
277 "--hashlimit-htable-expire", *flags & PARAM_EXPIRE);
278 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
279 if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
280 exit_error(PARAMETER_PROBLEM,
281 "bad --hashlimit-htable-expire: `%s'", optarg);
282 /* FIXME: not HZ dependent */
284 *flags |= PARAM_EXPIRE;
287 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-mode",
288 *flags & PARAM_MODE);
289 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
290 if (parse_mode(&r->cfg.mode, optarg) < 0)
291 exit_error(PARAMETER_PROBLEM,
292 "bad --hashlimit-mode: `%s'\n", optarg);
293 *flags |= PARAM_MODE;
296 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-name",
297 *flags & PARAM_NAME);
298 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
299 if (strlen(optarg) == 0)
300 exit_error(PARAMETER_PROBLEM, "Zero-length name?");
301 strncpy(r->name, optarg, sizeof(r->name));
302 *flags |= PARAM_NAME;
309 exit_error(PARAMETER_PROBLEM,
310 "hashlimit does not support invert");
316 hashlimit_mt_parse(struct xt_hashlimit_mtinfo1 *info, unsigned int *flags,
317 int c, int invert, unsigned int maxmask)
322 case '%': /* --hashlimit / --hashlimit-below */
323 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-upto",
324 *flags & PARAM_LIMIT);
326 info->cfg.mode |= XT_HASHLIMIT_INVERT;
327 if (!parse_rate(optarg, &info->cfg.avg))
328 param_act(P_BAD_VALUE, "hashlimit",
329 "--hashlimit-upto", optarg);
330 *flags |= PARAM_LIMIT;
333 case '^': /* --hashlimit-above == !--hashlimit-below */
334 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-above",
335 *flags & PARAM_LIMIT);
337 info->cfg.mode |= XT_HASHLIMIT_INVERT;
338 if (!parse_rate(optarg, &info->cfg.avg))
339 param_act(P_BAD_VALUE, "hashlimit",
340 "--hashlimit-above", optarg);
341 *flags |= PARAM_LIMIT;
344 case '$': /* --hashlimit-burst */
345 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-burst",
346 *flags & PARAM_BURST);
347 if (!strtonum(optarg, NULL, &num, 0, 10000))
348 param_act(P_BAD_VALUE, "hashlimit",
349 "--hashlimit-burst", optarg);
350 info->cfg.burst = num;
351 *flags |= PARAM_BURST;
354 case '&': /* --hashlimit-htable-size */
355 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size",
356 *flags & PARAM_SIZE);
357 if (!strtonum(optarg, NULL, &num, 0, 0xffffffff))
358 param_act(P_BAD_VALUE, "hashlimit",
359 "--hashlimit-htable-size", optarg);
360 info->cfg.size = num;
361 *flags |= PARAM_SIZE;
364 case '*': /* --hashlimit-htable-max */
365 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max",
367 if (!strtonum(optarg, NULL, &num, 0, 0xffffffff))
368 param_act(P_BAD_VALUE, "hashlimit",
369 "--hashlimit-htable-max", optarg);
374 case '(': /* --hashlimit-htable-gcinterval */
375 param_act(P_ONLY_ONCE, "hashlimit",
376 "--hashlimit-htable-gcinterval",
377 *flags & PARAM_GCINTERVAL);
378 if (!strtonum(optarg, NULL, &num, 0, 0xffffffff))
379 param_act(P_BAD_VALUE, "hashlimit",
380 "--hashlimit-htable-gcinterval", optarg);
381 /* FIXME: not HZ dependent!! */
382 info->cfg.gc_interval = num;
383 *flags |= PARAM_GCINTERVAL;
386 case ')': /* --hashlimit-htable-expire */
387 param_act(P_ONLY_ONCE, "hashlimit",
388 "--hashlimit-htable-expire", *flags & PARAM_EXPIRE);
389 if (!strtonum(optarg, NULL, &num, 0, 0xffffffff))
390 param_act(P_BAD_VALUE, "hashlimit",
391 "--hashlimit-htable-expire", optarg);
392 /* FIXME: not HZ dependent */
393 info->cfg.expire = num;
394 *flags |= PARAM_EXPIRE;
398 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-mode",
399 *flags & PARAM_MODE);
400 if (parse_mode(&info->cfg.mode, optarg) < 0)
401 param_act(P_BAD_VALUE, "hashlimit",
402 "--hashlimit-mode", optarg);
403 *flags |= PARAM_MODE;
406 case '"': /* --hashlimit-name */
407 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-name",
408 *flags & PARAM_NAME);
409 if (strlen(optarg) == 0)
410 exit_error(PARAMETER_PROBLEM, "Zero-length name?");
411 strncpy(info->name, optarg, sizeof(info->name));
412 info->name[sizeof(info->name)-1] = '\0';
413 *flags |= PARAM_NAME;
416 case '<': /* --hashlimit-srcmask */
417 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-srcmask",
418 *flags & PARAM_SRCMASK);
419 if (!strtonum(optarg, NULL, &num, 0, maxmask))
420 param_act(P_BAD_VALUE, "hashlimit",
421 "--hashlimit-srcmask", optarg);
422 info->cfg.srcmask = num;
423 *flags |= PARAM_SRCMASK;
426 case '>': /* --hashlimit-dstmask */
427 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-dstmask",
428 *flags & PARAM_DSTMASK);
429 if (!strtonum(optarg, NULL, &num, 0, maxmask))
430 param_act(P_BAD_VALUE, "hashlimit",
431 "--hashlimit-dstmask", optarg);
432 info->cfg.dstmask = num;
433 *flags |= PARAM_DSTMASK;
440 hashlimit_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
441 const void *entry, struct xt_entry_match **match)
443 return hashlimit_mt_parse((void *)(*match)->data,
444 flags, c, invert, 32);
448 hashlimit_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
449 const void *entry, struct xt_entry_match **match)
451 return hashlimit_mt_parse((void *)(*match)->data,
452 flags, c, invert, 128);
455 /* Final check; nothing. */
456 static void hashlimit_check(unsigned int flags)
458 if (!(flags & PARAM_LIMIT))
459 exit_error(PARAMETER_PROBLEM,
460 "You have to specify --hashlimit");
461 if (!(flags & PARAM_MODE))
462 exit_error(PARAMETER_PROBLEM,
463 "You have to specify --hashlimit-mode");
464 if (!(flags & PARAM_NAME))
465 exit_error(PARAMETER_PROBLEM,
466 "You have to specify --hashlimit-name");
469 static void hashlimit_mt_check(unsigned int flags)
471 if (!(flags & PARAM_LIMIT))
472 exit_error(PARAMETER_PROBLEM, "You have to specify "
473 "--hashlimit-upto or --hashlimit-above");
474 if (!(flags & PARAM_NAME))
475 exit_error(PARAMETER_PROBLEM,
476 "You have to specify --hashlimit-name");
479 static const struct rates
483 } rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
484 { "hour", XT_HASHLIMIT_SCALE*60*60 },
485 { "min", XT_HASHLIMIT_SCALE*60 },
486 { "sec", XT_HASHLIMIT_SCALE } };
488 static void print_rate(u_int32_t period)
492 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
493 if (period > rates[i].mult
494 || rates[i].mult/period < rates[i].mult%period)
498 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
501 static void print_mode(unsigned int mode, char separator)
503 bool prevmode = false;
505 if (mode & XT_HASHLIMIT_HASH_SIP) {
506 fputs("srcip", stdout);
509 if (mode & XT_HASHLIMIT_HASH_SPT) {
512 fputs("srcport", stdout);
515 if (mode & XT_HASHLIMIT_HASH_DIP) {
518 fputs("dstip", stdout);
521 if (mode & XT_HASHLIMIT_HASH_DPT) {
524 fputs("dstport", stdout);
529 /* Prints out the matchinfo. */
530 static void hashlimit_print(const void *ip,
531 const struct xt_entry_match *match, int numeric)
533 struct xt_hashlimit_info *r =
534 (struct xt_hashlimit_info *)match->data;
535 fputs("limit: avg ", stdout); print_rate(r->cfg.avg);
536 printf("burst %u ", r->cfg.burst);
537 fputs("mode ", stdout);
538 print_mode(r->cfg.mode, '-');
540 printf("htable-size %u ", r->cfg.size);
542 printf("htable-max %u ", r->cfg.max);
543 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
544 printf("htable-gcinterval %u ", r->cfg.gc_interval);
545 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
546 printf("htable-expire %u ", r->cfg.expire);
550 hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
552 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
553 fputs("limit: above ", stdout);
555 fputs("limit: up to ", stdout);
556 print_rate(info->cfg.avg);
557 printf("burst %u ", info->cfg.burst);
558 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
559 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
560 fputs("mode ", stdout);
561 print_mode(info->cfg.mode, '-');
563 if (info->cfg.size != 0)
564 printf("htable-size %u ", info->cfg.size);
565 if (info->cfg.max != 0)
566 printf("htable-max %u ", info->cfg.max);
567 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
568 printf("htable-gcinterval %u ", info->cfg.gc_interval);
569 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
570 printf("htable-expire %u ", info->cfg.expire);
572 if (info->cfg.srcmask != dmask)
573 printf("srcmask %u ", info->cfg.srcmask);
574 if (info->cfg.dstmask != dmask)
575 printf("dstmask %u ", info->cfg.dstmask);
579 hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
582 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
584 hashlimit_mt_print(info, 32);
588 hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
591 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
593 hashlimit_mt_print(info, 128);
596 /* FIXME: Make minimalist: only print rate if not default --RR */
597 static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
599 struct xt_hashlimit_info *r =
600 (struct xt_hashlimit_info *)match->data;
602 fputs("--hashlimit ", stdout); print_rate(r->cfg.avg);
603 if (r->cfg.burst != XT_HASHLIMIT_BURST)
604 printf("--hashlimit-burst %u ", r->cfg.burst);
606 fputs("--hashlimit-mode ", stdout);
607 print_mode(r->cfg.mode, ',');
609 printf("--hashlimit-name %s ", r->name);
612 printf("--hashlimit-htable-size %u ", r->cfg.size);
614 printf("--hashlimit-htable-max %u ", r->cfg.max);
615 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
616 printf("--hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
617 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
618 printf("--hashlimit-htable-expire %u ", r->cfg.expire);
622 hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
624 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
625 fputs("--hashlimit-above ", stdout);
627 fputs("--hashlimit-upto ", stdout);
628 print_rate(info->cfg.avg);
629 if (info->cfg.burst != XT_HASHLIMIT_BURST)
630 printf("--hashlimit-burst %u ", info->cfg.burst);
632 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
633 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
634 fputs("--hashlimit-mode ", stdout);
635 print_mode(info->cfg.mode, ',');
638 printf("--hashlimit-name %s ", info->name);
640 if (info->cfg.size != 0)
641 printf("--hashlimit-htable-size %u ", info->cfg.size);
642 if (info->cfg.max != 0)
643 printf("--hashlimit-htable-max %u ", info->cfg.max);
644 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
645 printf("--hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
646 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
647 printf("--hashlimit-htable-expire %u ", info->cfg.expire);
649 if (info->cfg.srcmask != dmask)
650 printf("--hashlimit-srcmask %u ", info->cfg.srcmask);
651 if (info->cfg.dstmask != dmask)
652 printf("--hashlimit-dstmask %u ", info->cfg.dstmask);
656 hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
658 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
660 hashlimit_mt_save(info, 32);
664 hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
666 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
668 hashlimit_mt_save(info, 128);
671 static struct xtables_match hashlimit_match = {
674 .version = XTABLES_VERSION,
676 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
677 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
678 .help = hashlimit_help,
679 .init = hashlimit_init,
680 .parse = hashlimit_parse,
681 .final_check = hashlimit_check,
682 .print = hashlimit_print,
683 .save = hashlimit_save,
684 .extra_opts = hashlimit_opts,
687 static struct xtables_match hashlimit_match6 = {
690 .version = XTABLES_VERSION,
692 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
693 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
694 .help = hashlimit_help,
695 .init = hashlimit_init,
696 .parse = hashlimit_parse,
697 .final_check = hashlimit_check,
698 .print = hashlimit_print,
699 .save = hashlimit_save,
700 .extra_opts = hashlimit_opts,
703 static struct xtables_match hashlimit_mt_reg = {
704 .version = XTABLES_VERSION,
708 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
709 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
710 .help = hashlimit_mt_help,
711 .init = hashlimit_mt4_init,
712 .parse = hashlimit_mt4_parse,
713 .final_check = hashlimit_mt_check,
714 .print = hashlimit_mt4_print,
715 .save = hashlimit_mt4_save,
716 .extra_opts = hashlimit_mt_opts,
719 static struct xtables_match hashlimit_mt6_reg = {
720 .version = XTABLES_VERSION,
724 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
725 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
726 .help = hashlimit_mt_help,
727 .init = hashlimit_mt6_init,
728 .parse = hashlimit_mt6_parse,
729 .final_check = hashlimit_mt_check,
730 .print = hashlimit_mt6_print,
731 .save = hashlimit_mt6_save,
732 .extra_opts = hashlimit_mt_opts,
737 xtables_register_match(&hashlimit_match);
738 xtables_register_match(&hashlimit_match6);
739 xtables_register_match(&hashlimit_mt_reg);
740 xtables_register_match(&hashlimit_mt6_reg);