libxt_hashlimit.c revision bbe83862a5e1baf15f7c923352d4afdf59bc70e2
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 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.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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 223 if (!parse_rate(optarg, &r->cfg.avg)) 224 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 233 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) 234 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 243 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 244 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 253 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 254 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 264 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 265 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 276 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) 277 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 287 if (parse_mode(&r->cfg.mode, optarg) < 0) 288 xtables_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 (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; 296 if (strlen(optarg) == 0) 297 xtables_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 xtables_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 xtables_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 xtables_error(PARAMETER_PROBLEM, 456 "You have to specify --hashlimit"); 457 if (!(flags & PARAM_MODE)) 458 xtables_error(PARAMETER_PROBLEM, 459 "You have to specify --hashlimit-mode"); 460 if (!(flags & PARAM_NAME)) 461 xtables_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 xtables_error(PARAMETER_PROBLEM, "You have to specify " 469 "--hashlimit-upto or --hashlimit-above"); 470 if (!(flags & PARAM_NAME)) 471 xtables_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 < ARRAY_SIZE(rates); ++i) 489 if (period > rates[i].mult 490 || rates[i].mult/period < rates[i].mult%period) 491 break; 492 493 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); 494} 495 496static void print_mode(unsigned int mode, char separator) 497{ 498 bool prevmode = false; 499 500 if (mode & XT_HASHLIMIT_HASH_SIP) { 501 fputs("srcip", stdout); 502 prevmode = 1; 503 } 504 if (mode & XT_HASHLIMIT_HASH_SPT) { 505 if (prevmode) 506 putchar(separator); 507 fputs("srcport", stdout); 508 prevmode = 1; 509 } 510 if (mode & XT_HASHLIMIT_HASH_DIP) { 511 if (prevmode) 512 putchar(separator); 513 fputs("dstip", stdout); 514 prevmode = 1; 515 } 516 if (mode & XT_HASHLIMIT_HASH_DPT) { 517 if (prevmode) 518 putchar(separator); 519 fputs("dstport", stdout); 520 } 521 putchar(' '); 522} 523 524static void hashlimit_print(const void *ip, 525 const struct xt_entry_match *match, int numeric) 526{ 527 const struct xt_hashlimit_info *r = (const void *)match->data; 528 fputs("limit: avg ", stdout); print_rate(r->cfg.avg); 529 printf("burst %u ", r->cfg.burst); 530 fputs("mode ", stdout); 531 print_mode(r->cfg.mode, '-'); 532 if (r->cfg.size) 533 printf("htable-size %u ", r->cfg.size); 534 if (r->cfg.max) 535 printf("htable-max %u ", r->cfg.max); 536 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 537 printf("htable-gcinterval %u ", r->cfg.gc_interval); 538 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE) 539 printf("htable-expire %u ", r->cfg.expire); 540} 541 542static void 543hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 544{ 545 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 546 fputs("limit: above ", stdout); 547 else 548 fputs("limit: up to ", stdout); 549 print_rate(info->cfg.avg); 550 printf("burst %u ", info->cfg.burst); 551 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 552 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 553 fputs("mode ", stdout); 554 print_mode(info->cfg.mode, '-'); 555 } 556 if (info->cfg.size != 0) 557 printf("htable-size %u ", info->cfg.size); 558 if (info->cfg.max != 0) 559 printf("htable-max %u ", info->cfg.max); 560 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 561 printf("htable-gcinterval %u ", info->cfg.gc_interval); 562 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE) 563 printf("htable-expire %u ", info->cfg.expire); 564 565 if (info->cfg.srcmask != dmask) 566 printf("srcmask %u ", info->cfg.srcmask); 567 if (info->cfg.dstmask != dmask) 568 printf("dstmask %u ", info->cfg.dstmask); 569} 570 571static void 572hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, 573 int numeric) 574{ 575 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 576 577 hashlimit_mt_print(info, 32); 578} 579 580static void 581hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, 582 int numeric) 583{ 584 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 585 586 hashlimit_mt_print(info, 128); 587} 588 589static void hashlimit_save(const void *ip, const struct xt_entry_match *match) 590{ 591 const struct xt_hashlimit_info *r = (const void *)match->data; 592 593 fputs("--hashlimit ", stdout); print_rate(r->cfg.avg); 594 if (r->cfg.burst != XT_HASHLIMIT_BURST) 595 printf("--hashlimit-burst %u ", r->cfg.burst); 596 597 fputs("--hashlimit-mode ", stdout); 598 print_mode(r->cfg.mode, ','); 599 600 printf("--hashlimit-name %s ", r->name); 601 602 if (r->cfg.size) 603 printf("--hashlimit-htable-size %u ", r->cfg.size); 604 if (r->cfg.max) 605 printf("--hashlimit-htable-max %u ", r->cfg.max); 606 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 607 printf("--hashlimit-htable-gcinterval %u ", r->cfg.gc_interval); 608 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE) 609 printf("--hashlimit-htable-expire %u ", r->cfg.expire); 610} 611 612static void 613hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 614{ 615 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 616 fputs("--hashlimit-above ", stdout); 617 else 618 fputs("--hashlimit-upto ", stdout); 619 print_rate(info->cfg.avg); 620 if (info->cfg.burst != XT_HASHLIMIT_BURST) 621 printf("--hashlimit-burst %u ", info->cfg.burst); 622 623 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 624 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 625 fputs("--hashlimit-mode ", stdout); 626 print_mode(info->cfg.mode, ','); 627 } 628 629 printf("--hashlimit-name %s ", info->name); 630 631 if (info->cfg.size != 0) 632 printf("--hashlimit-htable-size %u ", info->cfg.size); 633 if (info->cfg.max != 0) 634 printf("--hashlimit-htable-max %u ", info->cfg.max); 635 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 636 printf("--hashlimit-htable-gcinterval %u ", info->cfg.gc_interval); 637 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE) 638 printf("--hashlimit-htable-expire %u ", info->cfg.expire); 639 640 if (info->cfg.srcmask != dmask) 641 printf("--hashlimit-srcmask %u ", info->cfg.srcmask); 642 if (info->cfg.dstmask != dmask) 643 printf("--hashlimit-dstmask %u ", info->cfg.dstmask); 644} 645 646static void 647hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match) 648{ 649 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 650 651 hashlimit_mt_save(info, 32); 652} 653 654static void 655hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match) 656{ 657 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 658 659 hashlimit_mt_save(info, 128); 660} 661 662static struct xtables_match hashlimit_mt_reg[] = { 663 { 664 .family = NFPROTO_UNSPEC, 665 .name = "hashlimit", 666 .version = XTABLES_VERSION, 667 .revision = 0, 668 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)), 669 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo), 670 .help = hashlimit_help, 671 .init = hashlimit_init, 672 .parse = hashlimit_parse, 673 .final_check = hashlimit_check, 674 .print = hashlimit_print, 675 .save = hashlimit_save, 676 .extra_opts = hashlimit_opts, 677 }, 678 { 679 .version = XTABLES_VERSION, 680 .name = "hashlimit", 681 .revision = 1, 682 .family = NFPROTO_IPV4, 683 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 684 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 685 .help = hashlimit_mt_help, 686 .init = hashlimit_mt4_init, 687 .parse = hashlimit_mt4_parse, 688 .final_check = hashlimit_mt_check, 689 .print = hashlimit_mt4_print, 690 .save = hashlimit_mt4_save, 691 .extra_opts = hashlimit_mt_opts, 692 }, 693 { 694 .version = XTABLES_VERSION, 695 .name = "hashlimit", 696 .revision = 1, 697 .family = NFPROTO_IPV6, 698 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 699 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 700 .help = hashlimit_mt_help, 701 .init = hashlimit_mt6_init, 702 .parse = hashlimit_mt6_parse, 703 .final_check = hashlimit_mt_check, 704 .print = hashlimit_mt6_print, 705 .save = hashlimit_mt6_save, 706 .extra_opts = hashlimit_mt_opts, 707 }, 708}; 709 710void _init(void) 711{ 712 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); 713} 714