libxt_hashlimit.c revision 9a8c77fc8df3155747c34dcea79b7834a2a9a40a
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 <stdio.h> 15#include <string.h> 16#include <stdlib.h> 17#include <getopt.h> 18#include <xtables.h> 19#include <stddef.h> 20#include <linux/netfilter/x_tables.h> 21#include <linux/netfilter/xt_hashlimit.h> 22 23#define XT_HASHLIMIT_BURST 5 24 25/* miliseconds */ 26#define XT_HASHLIMIT_GCINTERVAL 1000 27#define XT_HASHLIMIT_EXPIRE 10000 28 29/* Function which prints out usage message. */ 30static void hashlimit_help(void) 31{ 32 printf( 33"hashlimit v%s 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" 45"\n", IPTABLES_VERSION, XT_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 133/* Initialize the match. */ 134static void hashlimit_init(struct xt_entry_match *m) 135{ 136 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data; 137 138 r->cfg.mode = 0; 139 r->cfg.burst = XT_HASHLIMIT_BURST; 140 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 141 r->cfg.expire = XT_HASHLIMIT_EXPIRE; 142 143} 144 145static void hashlimit_mt4_init(struct xt_entry_match *match) 146{ 147 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 148 149 info->cfg.mode = 0; 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; 155} 156 157static void hashlimit_mt6_init(struct xt_entry_match *match) 158{ 159 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 160 161 info->cfg.mode = 0; 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; 167} 168 169/* Parse a 'mode' parameter into the required bitmask */ 170static int parse_mode(uint32_t *mode, char *option_arg) 171{ 172 char *tok; 173 char *arg = strdup(option_arg); 174 175 if (!arg) 176 return -1; 177 178 for (tok = strtok(arg, ",|"); 179 tok; 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; 189 else { 190 free(arg); 191 return -1; 192 } 193 } 194 free(arg); 195 return 0; 196} 197 198enum { 199 PARAM_LIMIT = 1 << 0, 200 PARAM_BURST = 1 << 1, 201 PARAM_MODE = 1 << 2, 202 PARAM_NAME = 1 << 3, 203 PARAM_SIZE = 1 << 4, 204 PARAM_MAX = 1 << 5, 205 PARAM_GCINTERVAL = 1 << 6, 206 PARAM_EXPIRE = 1 << 7, 207 PARAM_SRCMASK = 1 << 8, 208 PARAM_DSTMASK = 1 << 9, 209}; 210 211/* Function which parses command options; returns true if it 212 ate an option */ 213static int 214hashlimit_parse(int c, char **argv, int invert, unsigned int *flags, 215 const void *entry, struct xt_entry_match **match) 216{ 217 struct xt_hashlimit_info *r = 218 (struct xt_hashlimit_info *)(*match)->data; 219 unsigned int num; 220 221 switch(c) { 222 case '%': 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; 230 break; 231 232 case '$': 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); 239 r->cfg.burst = num; 240 *flags |= PARAM_BURST; 241 break; 242 case '&': 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); 249 r->cfg.size = num; 250 *flags |= PARAM_SIZE; 251 break; 252 case '*': 253 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max", 254 *flags & PARAM_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); 259 r->cfg.max = num; 260 *flags |= PARAM_MAX; 261 break; 262 case '(': 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'", 270 optarg); 271 /* FIXME: not HZ dependent!! */ 272 r->cfg.gc_interval = num; 273 *flags |= PARAM_GCINTERVAL; 274 break; 275 case ')': 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 */ 283 r->cfg.expire = num; 284 *flags |= PARAM_EXPIRE; 285 break; 286 case '_': 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; 294 break; 295 case '"': 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; 303 break; 304 default: 305 return 0; 306 } 307 308 if (invert) 309 exit_error(PARAMETER_PROBLEM, 310 "hashlimit does not support invert"); 311 312 return 1; 313} 314 315static int 316hashlimit_mt_parse(struct xt_hashlimit_mtinfo1 *info, unsigned int *flags, 317 int c, int invert, unsigned int maxmask) 318{ 319 unsigned int num; 320 321 switch(c) { 322 case '%': /* --hashlimit / --hashlimit-below */ 323 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-upto", 324 *flags & PARAM_LIMIT); 325 if (invert) 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; 331 return true; 332 333 case '^': /* --hashlimit-above == !--hashlimit-below */ 334 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-above", 335 *flags & PARAM_LIMIT); 336 if (!invert) 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; 342 return true; 343 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; 352 return true; 353 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; 362 return true; 363 364 case '*': /* --hashlimit-htable-max */ 365 param_act(P_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max", 366 *flags & PARAM_MAX); 367 if (!strtonum(optarg, NULL, &num, 0, 0xffffffff)) 368 param_act(P_BAD_VALUE, "hashlimit", 369 "--hashlimit-htable-max", optarg); 370 info->cfg.max = num; 371 *flags |= PARAM_MAX; 372 return true; 373 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; 384 return true; 385 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; 395 return true; 396 397 case '_': 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; 404 return true; 405 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; 414 return true; 415 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; 424 return true; 425 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; 434 return true; 435 } 436 return false; 437} 438 439static int 440hashlimit_mt4_parse(int c, char **argv, int invert, unsigned int *flags, 441 const void *entry, struct xt_entry_match **match) 442{ 443 return hashlimit_mt_parse((void *)(*match)->data, 444 flags, c, invert, 32); 445} 446 447static int 448hashlimit_mt6_parse(int c, char **argv, int invert, unsigned int *flags, 449 const void *entry, struct xt_entry_match **match) 450{ 451 return hashlimit_mt_parse((void *)(*match)->data, 452 flags, c, invert, 128); 453} 454 455/* Final check; nothing. */ 456static void hashlimit_check(unsigned int flags) 457{ 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"); 467} 468 469static void hashlimit_mt_check(unsigned int flags) 470{ 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"); 477} 478 479static const struct rates 480{ 481 const char *name; 482 u_int32_t mult; 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 } }; 487 488static void print_rate(u_int32_t period) 489{ 490 unsigned int i; 491 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) 495 break; 496 } 497 498 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); 499} 500 501static void print_mode(unsigned int mode, char separator) 502{ 503 bool prevmode = false; 504 505 if (mode & XT_HASHLIMIT_HASH_SIP) { 506 fputs("srcip", stdout); 507 prevmode = 1; 508 } 509 if (mode & XT_HASHLIMIT_HASH_SPT) { 510 if (prevmode) 511 putchar(separator); 512 fputs("srcport", stdout); 513 prevmode = 1; 514 } 515 if (mode & XT_HASHLIMIT_HASH_DIP) { 516 if (prevmode) 517 putchar(separator); 518 fputs("dstip", stdout); 519 prevmode = 1; 520 } 521 if (mode & XT_HASHLIMIT_HASH_DPT) { 522 if (prevmode) 523 putchar(separator); 524 fputs("dstport", stdout); 525 } 526 putchar(' '); 527} 528 529/* Prints out the matchinfo. */ 530static void hashlimit_print(const void *ip, 531 const struct xt_entry_match *match, int numeric) 532{ 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, '-'); 539 if (r->cfg.size) 540 printf("htable-size %u ", r->cfg.size); 541 if (r->cfg.max) 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); 547} 548 549static void 550hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 551{ 552 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 553 fputs("limit: above ", stdout); 554 else 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, '-'); 562 } 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); 571 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); 576} 577 578static void 579hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, 580 int numeric) 581{ 582 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 583 584 hashlimit_mt_print(info, 32); 585} 586 587static void 588hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, 589 int numeric) 590{ 591 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 592 593 hashlimit_mt_print(info, 128); 594} 595 596/* FIXME: Make minimalist: only print rate if not default --RR */ 597static void hashlimit_save(const void *ip, const struct xt_entry_match *match) 598{ 599 struct xt_hashlimit_info *r = 600 (struct xt_hashlimit_info *)match->data; 601 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); 605 606 fputs("--hashlimit-mode ", stdout); 607 print_mode(r->cfg.mode, ','); 608 609 printf("--hashlimit-name %s ", r->name); 610 611 if (r->cfg.size) 612 printf("--hashlimit-htable-size %u ", r->cfg.size); 613 if (r->cfg.max) 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); 619} 620 621static void 622hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 623{ 624 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 625 fputs("--hashlimit-above ", stdout); 626 else 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); 631 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, ','); 636 } 637 638 printf("--hashlimit-name %s ", info->name); 639 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); 648 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); 653} 654 655static void 656hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match) 657{ 658 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 659 660 hashlimit_mt_save(info, 32); 661} 662 663static void 664hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match) 665{ 666 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 667 668 hashlimit_mt_save(info, 128); 669} 670 671static struct xtables_match hashlimit_match = { 672 .family = AF_INET, 673 .name = "hashlimit", 674 .version = IPTABLES_VERSION, 675 .revision = 0, 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, 685}; 686 687static struct xtables_match hashlimit_match6 = { 688 .family = AF_INET6, 689 .name = "hashlimit", 690 .version = IPTABLES_VERSION, 691 .revision = 0, 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, 701}; 702 703static struct xtables_match hashlimit_mt_reg = { 704 .version = IPTABLES_VERSION, 705 .name = "hashlimit", 706 .revision = 1, 707 .family = AF_INET, 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, 717}; 718 719static struct xtables_match hashlimit_mt6_reg = { 720 .version = IPTABLES_VERSION, 721 .name = "hashlimit", 722 .revision = 1, 723 .family = AF_INET6, 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, 733}; 734 735void _init(void) 736{ 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); 741} 742