libxt_hashlimit.c revision e88a7c2c7175742b58b6aa03f2b5aba2d80330a1
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#include <stdbool.h> 14#include <stdint.h> 15#include <stdio.h> 16#include <string.h> 17#include <stdlib.h> 18#include <getopt.h> 19#include <xtables.h> 20#include <stddef.h> 21#include <linux/netfilter/x_tables.h> 22#include <linux/netfilter/xt_hashlimit.h> 23 24#define XT_HASHLIMIT_BURST 5 25 26/* miliseconds */ 27#define XT_HASHLIMIT_GCINTERVAL 1000 28#define XT_HASHLIMIT_EXPIRE 10000 29 30static void hashlimit_help(void) 31{ 32 printf( 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", 45XT_HASHLIMIT_BURST); 46} 47 48static void hashlimit_mt_help(void) 49{ 50 printf( 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); 67} 68 69static const struct option hashlimit_opts[] = { 70 {.name = "hashlimit", .has_arg = true, .val = '%'}, 71 {.name = "hashlimit-burst", .has_arg = true, .val = '$'}, 72 {.name = "hashlimit-htable-size", .has_arg = true, .val = '&'}, 73 {.name = "hashlimit-htable-max", .has_arg = true, .val = '*'}, 74 {.name = "hashlimit-htable-gcinterval", .has_arg = true, .val = '('}, 75 {.name = "hashlimit-htable-expire", .has_arg = true, .val = ')'}, 76 {.name = "hashlimit-mode", .has_arg = true, .val = '_'}, 77 {.name = "hashlimit-name", .has_arg = true, .val = '"'}, 78 XT_GETOPT_TABLEEND, 79}; 80 81static 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 = '"'}, 94 XT_GETOPT_TABLEEND, 95}; 96 97static 98int parse_rate(const char *rate, uint32_t *val) 99{ 100 const char *delim; 101 uint32_t r; 102 uint32_t mult = 1; /* Seconds by default. */ 103 104 delim = strchr(rate, '/'); 105 if (delim) { 106 if (strlen(delim+1) == 0) 107 return 0; 108 109 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 110 mult = 1; 111 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 112 mult = 60; 113 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 114 mult = 60*60; 115 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 116 mult = 24*60*60; 117 else 118 return 0; 119 } 120 r = atoi(rate); 121 if (!r) 122 return 0; 123 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 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); 128 129 *val = XT_HASHLIMIT_SCALE * mult / r; 130 return 1; 131} 132 133static void hashlimit_init(struct xt_entry_match *m) 134{ 135 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data; 136 137 r->cfg.burst = XT_HASHLIMIT_BURST; 138 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 139 r->cfg.expire = XT_HASHLIMIT_EXPIRE; 140 141} 142 143static void hashlimit_mt4_init(struct xt_entry_match *match) 144{ 145 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 146 147 info->cfg.mode = 0; 148 info->cfg.burst = XT_HASHLIMIT_BURST; 149 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 150 info->cfg.expire = XT_HASHLIMIT_EXPIRE; 151 info->cfg.srcmask = 32; 152 info->cfg.dstmask = 32; 153} 154 155static void hashlimit_mt6_init(struct xt_entry_match *match) 156{ 157 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 158 159 info->cfg.mode = 0; 160 info->cfg.burst = XT_HASHLIMIT_BURST; 161 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 162 info->cfg.expire = XT_HASHLIMIT_EXPIRE; 163 info->cfg.srcmask = 128; 164 info->cfg.dstmask = 128; 165} 166 167/* Parse a 'mode' parameter into the required bitmask */ 168static int parse_mode(uint32_t *mode, char *option_arg) 169{ 170 char *tok; 171 char *arg = strdup(option_arg); 172 173 if (!arg) 174 return -1; 175 176 for (tok = strtok(arg, ",|"); 177 tok; 178 tok = strtok(NULL, ",|")) { 179 if (!strcmp(tok, "dstip")) 180 *mode |= XT_HASHLIMIT_HASH_DIP; 181 else if (!strcmp(tok, "srcip")) 182 *mode |= XT_HASHLIMIT_HASH_SIP; 183 else if (!strcmp(tok, "srcport")) 184 *mode |= XT_HASHLIMIT_HASH_SPT; 185 else if (!strcmp(tok, "dstport")) 186 *mode |= XT_HASHLIMIT_HASH_DPT; 187 else { 188 free(arg); 189 return -1; 190 } 191 } 192 free(arg); 193 return 0; 194} 195 196enum { 197 PARAM_LIMIT = 1 << 0, 198 PARAM_BURST = 1 << 1, 199 PARAM_MODE = 1 << 2, 200 PARAM_NAME = 1 << 3, 201 PARAM_SIZE = 1 << 4, 202 PARAM_MAX = 1 << 5, 203 PARAM_GCINTERVAL = 1 << 6, 204 PARAM_EXPIRE = 1 << 7, 205 PARAM_SRCMASK = 1 << 8, 206 PARAM_DSTMASK = 1 << 9, 207}; 208 209static int 210hashlimit_parse(int c, char **argv, int invert, unsigned int *flags, 211 const void *entry, struct xt_entry_match **match) 212{ 213 struct xt_hashlimit_info *r = 214 (struct xt_hashlimit_info *)(*match)->data; 215 unsigned int num; 216 217 switch(c) { 218 case '%': 219 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit", 220 *flags & PARAM_LIMIT); 221 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 222 if (!parse_rate(optarg, &r->cfg.avg)) 223 xtables_error(PARAMETER_PROBLEM, 224 "bad rate `%s'", optarg); 225 *flags |= PARAM_LIMIT; 226 break; 227 228 case '$': 229 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst", 230 *flags & PARAM_BURST); 231 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 232 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) 233 xtables_error(PARAMETER_PROBLEM, 234 "bad --hashlimit-burst `%s'", optarg); 235 r->cfg.burst = num; 236 *flags |= PARAM_BURST; 237 break; 238 case '&': 239 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size", 240 *flags & PARAM_SIZE); 241 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 242 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 243 xtables_error(PARAMETER_PROBLEM, 244 "bad --hashlimit-htable-size: `%s'", optarg); 245 r->cfg.size = num; 246 *flags |= PARAM_SIZE; 247 break; 248 case '*': 249 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max", 250 *flags & PARAM_MAX); 251 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 252 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 253 xtables_error(PARAMETER_PROBLEM, 254 "bad --hashlimit-htable-max: `%s'", optarg); 255 r->cfg.max = num; 256 *flags |= PARAM_MAX; 257 break; 258 case '(': 259 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", 260 "--hashlimit-htable-gcinterval", 261 *flags & PARAM_GCINTERVAL); 262 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 263 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 264 xtables_error(PARAMETER_PROBLEM, 265 "bad --hashlimit-htable-gcinterval: `%s'", 266 optarg); 267 /* FIXME: not HZ dependent!! */ 268 r->cfg.gc_interval = num; 269 *flags |= PARAM_GCINTERVAL; 270 break; 271 case ')': 272 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", 273 "--hashlimit-htable-expire", *flags & PARAM_EXPIRE); 274 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 275 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 276 xtables_error(PARAMETER_PROBLEM, 277 "bad --hashlimit-htable-expire: `%s'", optarg); 278 /* FIXME: not HZ dependent */ 279 r->cfg.expire = num; 280 *flags |= PARAM_EXPIRE; 281 break; 282 case '_': 283 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode", 284 *flags & PARAM_MODE); 285 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 286 if (parse_mode(&r->cfg.mode, optarg) < 0) 287 xtables_error(PARAMETER_PROBLEM, 288 "bad --hashlimit-mode: `%s'\n", optarg); 289 *flags |= PARAM_MODE; 290 break; 291 case '"': 292 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name", 293 *flags & PARAM_NAME); 294 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 295 if (strlen(optarg) == 0) 296 xtables_error(PARAMETER_PROBLEM, "Zero-length name?"); 297 strncpy(r->name, optarg, sizeof(r->name)); 298 *flags |= PARAM_NAME; 299 break; 300 } 301 302 if (invert) 303 xtables_error(PARAMETER_PROBLEM, 304 "hashlimit does not support invert"); 305 306 return 1; 307} 308 309static int 310hashlimit_mt_parse(struct xt_hashlimit_mtinfo1 *info, unsigned int *flags, 311 int c, int invert, unsigned int maxmask) 312{ 313 unsigned int num; 314 315 switch(c) { 316 case '%': /* --hashlimit / --hashlimit-below */ 317 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-upto", 318 *flags & PARAM_LIMIT); 319 if (invert) 320 info->cfg.mode |= XT_HASHLIMIT_INVERT; 321 if (!parse_rate(optarg, &info->cfg.avg)) 322 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 323 "--hashlimit-upto", optarg); 324 *flags |= PARAM_LIMIT; 325 return true; 326 327 case '^': /* --hashlimit-above == !--hashlimit-below */ 328 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-above", 329 *flags & PARAM_LIMIT); 330 if (!invert) 331 info->cfg.mode |= XT_HASHLIMIT_INVERT; 332 if (!parse_rate(optarg, &info->cfg.avg)) 333 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 334 "--hashlimit-above", optarg); 335 *flags |= PARAM_LIMIT; 336 return true; 337 338 case '$': /* --hashlimit-burst */ 339 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst", 340 *flags & PARAM_BURST); 341 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) 342 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 343 "--hashlimit-burst", optarg); 344 info->cfg.burst = num; 345 *flags |= PARAM_BURST; 346 return true; 347 348 case '&': /* --hashlimit-htable-size */ 349 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size", 350 *flags & PARAM_SIZE); 351 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 352 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 353 "--hashlimit-htable-size", optarg); 354 info->cfg.size = num; 355 *flags |= PARAM_SIZE; 356 return true; 357 358 case '*': /* --hashlimit-htable-max */ 359 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max", 360 *flags & PARAM_MAX); 361 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 362 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 363 "--hashlimit-htable-max", optarg); 364 info->cfg.max = num; 365 *flags |= PARAM_MAX; 366 return true; 367 368 case '(': /* --hashlimit-htable-gcinterval */ 369 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", 370 "--hashlimit-htable-gcinterval", 371 *flags & PARAM_GCINTERVAL); 372 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 373 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 374 "--hashlimit-htable-gcinterval", optarg); 375 /* FIXME: not HZ dependent!! */ 376 info->cfg.gc_interval = num; 377 *flags |= PARAM_GCINTERVAL; 378 return true; 379 380 case ')': /* --hashlimit-htable-expire */ 381 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", 382 "--hashlimit-htable-expire", *flags & PARAM_EXPIRE); 383 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 384 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 385 "--hashlimit-htable-expire", optarg); 386 /* FIXME: not HZ dependent */ 387 info->cfg.expire = num; 388 *flags |= PARAM_EXPIRE; 389 return true; 390 391 case '_': 392 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode", 393 *flags & PARAM_MODE); 394 if (parse_mode(&info->cfg.mode, optarg) < 0) 395 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 396 "--hashlimit-mode", optarg); 397 *flags |= PARAM_MODE; 398 return true; 399 400 case '"': /* --hashlimit-name */ 401 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name", 402 *flags & PARAM_NAME); 403 if (strlen(optarg) == 0) 404 xtables_error(PARAMETER_PROBLEM, "Zero-length name?"); 405 strncpy(info->name, optarg, sizeof(info->name)); 406 info->name[sizeof(info->name)-1] = '\0'; 407 *flags |= PARAM_NAME; 408 return true; 409 410 case '<': /* --hashlimit-srcmask */ 411 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-srcmask", 412 *flags & PARAM_SRCMASK); 413 if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask)) 414 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 415 "--hashlimit-srcmask", optarg); 416 info->cfg.srcmask = num; 417 *flags |= PARAM_SRCMASK; 418 return true; 419 420 case '>': /* --hashlimit-dstmask */ 421 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-dstmask", 422 *flags & PARAM_DSTMASK); 423 if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask)) 424 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 425 "--hashlimit-dstmask", optarg); 426 info->cfg.dstmask = num; 427 *flags |= PARAM_DSTMASK; 428 return true; 429 } 430 return false; 431} 432 433static int 434hashlimit_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 435 const void *entry, struct xt_entry_match **match) 436{ 437 return hashlimit_mt_parse((void *)(*match)->data, 438 flags, c, invert, 32); 439} 440 441static int 442hashlimit_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 443 const void *entry, struct xt_entry_match **match) 444{ 445 return hashlimit_mt_parse((void *)(*match)->data, 446 flags, c, invert, 128); 447} 448 449static void hashlimit_check(unsigned int flags) 450{ 451 if (!(flags & PARAM_LIMIT)) 452 xtables_error(PARAMETER_PROBLEM, 453 "You have to specify --hashlimit"); 454 if (!(flags & PARAM_MODE)) 455 xtables_error(PARAMETER_PROBLEM, 456 "You have to specify --hashlimit-mode"); 457 if (!(flags & PARAM_NAME)) 458 xtables_error(PARAMETER_PROBLEM, 459 "You have to specify --hashlimit-name"); 460} 461 462static void hashlimit_mt_check(unsigned int flags) 463{ 464 if (!(flags & PARAM_LIMIT)) 465 xtables_error(PARAMETER_PROBLEM, "You have to specify " 466 "--hashlimit-upto or --hashlimit-above"); 467 if (!(flags & PARAM_NAME)) 468 xtables_error(PARAMETER_PROBLEM, 469 "You have to specify --hashlimit-name"); 470} 471 472static const struct rates 473{ 474 const char *name; 475 uint32_t mult; 476} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 }, 477 { "hour", XT_HASHLIMIT_SCALE*60*60 }, 478 { "min", XT_HASHLIMIT_SCALE*60 }, 479 { "sec", XT_HASHLIMIT_SCALE } }; 480 481static void print_rate(uint32_t period) 482{ 483 unsigned int i; 484 485 for (i = 1; i < ARRAY_SIZE(rates); ++i) 486 if (period > rates[i].mult 487 || rates[i].mult/period < rates[i].mult%period) 488 break; 489 490 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name); 491} 492 493static void print_mode(unsigned int mode, char separator) 494{ 495 bool prevmode = false; 496 497 putchar(' '); 498 if (mode & XT_HASHLIMIT_HASH_SIP) { 499 fputs("srcip", stdout); 500 prevmode = 1; 501 } 502 if (mode & XT_HASHLIMIT_HASH_SPT) { 503 if (prevmode) 504 putchar(separator); 505 fputs("srcport", stdout); 506 prevmode = 1; 507 } 508 if (mode & XT_HASHLIMIT_HASH_DIP) { 509 if (prevmode) 510 putchar(separator); 511 fputs("dstip", stdout); 512 prevmode = 1; 513 } 514 if (mode & XT_HASHLIMIT_HASH_DPT) { 515 if (prevmode) 516 putchar(separator); 517 fputs("dstport", stdout); 518 } 519} 520 521static void hashlimit_print(const void *ip, 522 const struct xt_entry_match *match, int numeric) 523{ 524 const struct xt_hashlimit_info *r = (const void *)match->data; 525 fputs(" limit: avg", stdout); print_rate(r->cfg.avg); 526 printf(" burst %u", r->cfg.burst); 527 fputs(" mode", stdout); 528 print_mode(r->cfg.mode, '-'); 529 if (r->cfg.size) 530 printf(" htable-size %u", r->cfg.size); 531 if (r->cfg.max) 532 printf(" htable-max %u", r->cfg.max); 533 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 534 printf(" htable-gcinterval %u", r->cfg.gc_interval); 535 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE) 536 printf(" htable-expire %u", r->cfg.expire); 537} 538 539static void 540hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 541{ 542 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 543 fputs(" limit: above", stdout); 544 else 545 fputs(" limit: up to", stdout); 546 print_rate(info->cfg.avg); 547 printf(" burst %u", info->cfg.burst); 548 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 549 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 550 fputs(" mode", stdout); 551 print_mode(info->cfg.mode, '-'); 552 } 553 if (info->cfg.size != 0) 554 printf(" htable-size %u", info->cfg.size); 555 if (info->cfg.max != 0) 556 printf(" htable-max %u", info->cfg.max); 557 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 558 printf(" htable-gcinterval %u", info->cfg.gc_interval); 559 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE) 560 printf(" htable-expire %u", info->cfg.expire); 561 562 if (info->cfg.srcmask != dmask) 563 printf(" srcmask %u", info->cfg.srcmask); 564 if (info->cfg.dstmask != dmask) 565 printf(" dstmask %u", info->cfg.dstmask); 566} 567 568static void 569hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, 570 int numeric) 571{ 572 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 573 574 hashlimit_mt_print(info, 32); 575} 576 577static void 578hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, 579 int numeric) 580{ 581 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 582 583 hashlimit_mt_print(info, 128); 584} 585 586static void hashlimit_save(const void *ip, const struct xt_entry_match *match) 587{ 588 const struct xt_hashlimit_info *r = (const void *)match->data; 589 590 fputs(" --hashlimit", stdout); print_rate(r->cfg.avg); 591 printf(" --hashlimit-burst %u", r->cfg.burst); 592 593 fputs(" --hashlimit-mode", stdout); 594 print_mode(r->cfg.mode, ','); 595 596 printf(" --hashlimit-name %s", r->name); 597 598 if (r->cfg.size) 599 printf(" --hashlimit-htable-size %u", r->cfg.size); 600 if (r->cfg.max) 601 printf(" --hashlimit-htable-max %u", r->cfg.max); 602 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 603 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval); 604 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE) 605 printf(" --hashlimit-htable-expire %u", r->cfg.expire); 606} 607 608static void 609hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 610{ 611 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 612 fputs(" --hashlimit-above", stdout); 613 else 614 fputs(" --hashlimit-upto", stdout); 615 print_rate(info->cfg.avg); 616 printf(" --hashlimit-burst %u", info->cfg.burst); 617 618 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 619 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 620 fputs(" --hashlimit-mode", stdout); 621 print_mode(info->cfg.mode, ','); 622 } 623 624 printf(" --hashlimit-name %s", info->name); 625 626 if (info->cfg.size != 0) 627 printf(" --hashlimit-htable-size %u", info->cfg.size); 628 if (info->cfg.max != 0) 629 printf(" --hashlimit-htable-max %u", info->cfg.max); 630 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 631 printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval); 632 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE) 633 printf(" --hashlimit-htable-expire %u", info->cfg.expire); 634 635 if (info->cfg.srcmask != dmask) 636 printf(" --hashlimit-srcmask %u", info->cfg.srcmask); 637 if (info->cfg.dstmask != dmask) 638 printf(" --hashlimit-dstmask %u", info->cfg.dstmask); 639} 640 641static void 642hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match) 643{ 644 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 645 646 hashlimit_mt_save(info, 32); 647} 648 649static void 650hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match) 651{ 652 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 653 654 hashlimit_mt_save(info, 128); 655} 656 657static struct xtables_match hashlimit_mt_reg[] = { 658 { 659 .family = NFPROTO_UNSPEC, 660 .name = "hashlimit", 661 .version = XTABLES_VERSION, 662 .revision = 0, 663 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)), 664 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo), 665 .help = hashlimit_help, 666 .init = hashlimit_init, 667 .parse = hashlimit_parse, 668 .final_check = hashlimit_check, 669 .print = hashlimit_print, 670 .save = hashlimit_save, 671 .extra_opts = hashlimit_opts, 672 }, 673 { 674 .version = XTABLES_VERSION, 675 .name = "hashlimit", 676 .revision = 1, 677 .family = NFPROTO_IPV4, 678 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 679 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 680 .help = hashlimit_mt_help, 681 .init = hashlimit_mt4_init, 682 .parse = hashlimit_mt4_parse, 683 .final_check = hashlimit_mt_check, 684 .print = hashlimit_mt4_print, 685 .save = hashlimit_mt4_save, 686 .extra_opts = hashlimit_mt_opts, 687 }, 688 { 689 .version = XTABLES_VERSION, 690 .name = "hashlimit", 691 .revision = 1, 692 .family = NFPROTO_IPV6, 693 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 694 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 695 .help = hashlimit_mt_help, 696 .init = hashlimit_mt6_init, 697 .parse = hashlimit_mt6_parse, 698 .final_check = hashlimit_mt_check, 699 .print = hashlimit_mt6_print, 700 .save = hashlimit_mt6_save, 701 .extra_opts = hashlimit_mt_opts, 702 }, 703}; 704 705void _init(void) 706{ 707 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); 708} 709