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