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