libxt_hashlimit.c revision abdef13f36b63758f8775eb86febd96bf062df6f
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 <xtables.h> 19#include <linux/netfilter/x_tables.h> 20#include <linux/netfilter/xt_hashlimit.h> 21 22#define XT_HASHLIMIT_BURST 5 23#define XT_HASHLIMIT_BURST_MAX 10000 24 25#define XT_HASHLIMIT_BYTE_EXPIRE 15 26#define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60 27 28/* miliseconds */ 29#define XT_HASHLIMIT_GCINTERVAL 1000 30 31struct hashlimit_mt_udata { 32 uint32_t mult; 33}; 34 35static void hashlimit_help(void) 36{ 37 printf( 38"hashlimit match options:\n" 39"--hashlimit <avg> max average match rate\n" 40" [Packets per second unless followed by \n" 41" /sec /minute /hour /day postfixes]\n" 42"--hashlimit-mode <mode> mode is a comma-separated list of\n" 43" dstip,srcip,dstport,srcport\n" 44"--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n" 45"[--hashlimit-burst <num>] number to match in a burst, default %u\n" 46"[--hashlimit-htable-size <num>] number of hashtable buckets\n" 47"[--hashlimit-htable-max <num>] number of hashtable entries\n" 48"[--hashlimit-htable-gcinterval] interval between garbage collection runs\n" 49"[--hashlimit-htable-expire] after which time are idle entries expired?\n", 50XT_HASHLIMIT_BURST); 51} 52 53enum { 54 O_UPTO = 0, 55 O_ABOVE, 56 O_LIMIT, 57 O_MODE, 58 O_SRCMASK, 59 O_DSTMASK, 60 O_NAME, 61 O_BURST, 62 O_HTABLE_SIZE, 63 O_HTABLE_MAX, 64 O_HTABLE_GCINT, 65 O_HTABLE_EXPIRE, 66 F_BURST = 1 << O_BURST, 67 F_UPTO = 1 << O_UPTO, 68 F_ABOVE = 1 << O_ABOVE, 69 F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE, 70}; 71 72static void hashlimit_mt_help(void) 73{ 74 printf( 75"hashlimit match options:\n" 76" --hashlimit-upto <avg> max average match rate\n" 77" [Packets per second unless followed by \n" 78" /sec /minute /hour /day postfixes]\n" 79" --hashlimit-above <avg> min average match rate\n" 80" --hashlimit-mode <mode> mode is a comma-separated list of\n" 81" dstip,srcip,dstport,srcport (or none)\n" 82" --hashlimit-srcmask <length> source address grouping prefix length\n" 83" --hashlimit-dstmask <length> destination address grouping prefix length\n" 84" --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n" 85" --hashlimit-burst <num> number to match in a burst, default %u\n" 86" --hashlimit-htable-size <num> number of hashtable buckets\n" 87" --hashlimit-htable-max <num> number of hashtable entries\n" 88" --hashlimit-htable-gcinterval interval between garbage collection runs\n" 89" --hashlimit-htable-expire after which time are idle entries expired?\n" 90"\n", XT_HASHLIMIT_BURST); 91} 92 93#define s struct xt_hashlimit_info 94static const struct xt_option_entry hashlimit_opts[] = { 95 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, 96 .type = XTTYPE_STRING}, 97 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32, 98 .min = 1, .max = XT_HASHLIMIT_BURST_MAX, .flags = XTOPT_PUT, 99 XTOPT_POINTER(s, cfg.burst)}, 100 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, 101 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 102 XTOPT_POINTER(s, cfg.size)}, 103 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, 104 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 105 XTOPT_POINTER(s, cfg.max)}, 106 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, 107 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 108 XTOPT_POINTER(s, cfg.gc_interval)}, 109 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, 110 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 111 XTOPT_POINTER(s, cfg.expire)}, 112 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING, 113 .flags = XTOPT_MAND}, 114 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, 115 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, 116 XTOPT_TABLEEND, 117}; 118#undef s 119 120#define s struct xt_hashlimit_mtinfo1 121static const struct xt_option_entry hashlimit_mt_opts[] = { 122 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE, 123 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, 124 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO, 125 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, 126 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, 127 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */ 128 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN}, 129 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN}, 130 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING}, 131 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, 132 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 133 XTOPT_POINTER(s, cfg.size)}, 134 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, 135 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 136 XTOPT_POINTER(s, cfg.max)}, 137 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, 138 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 139 XTOPT_POINTER(s, cfg.gc_interval)}, 140 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, 141 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 142 XTOPT_POINTER(s, cfg.expire)}, 143 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING}, 144 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, 145 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, 146 XTOPT_TABLEEND, 147}; 148#undef s 149 150static uint32_t cost_to_bytes(uint32_t cost) 151{ 152 uint32_t r; 153 154 r = cost ? UINT32_MAX / cost : UINT32_MAX; 155 r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT; 156 return r; 157} 158 159static uint64_t bytes_to_cost(uint32_t bytes) 160{ 161 uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT; 162 return UINT32_MAX / (r+1); 163} 164 165static uint32_t get_factor(int chr) 166{ 167 switch (chr) { 168 case 'm': return 1024 * 1024; 169 case 'k': return 1024; 170 } 171 return 1; 172} 173 174static void burst_error(void) 175{ 176 xtables_error(PARAMETER_PROBLEM, "bad value for option " 177 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX); 178} 179 180static uint32_t parse_burst(const char *burst, struct xt_hashlimit_mtinfo1 *info) 181{ 182 uintmax_t v; 183 char *end; 184 185 if (!xtables_strtoul(burst, &end, &v, 1, UINT32_MAX) || 186 (*end == 0 && v > XT_HASHLIMIT_BURST_MAX)) 187 burst_error(); 188 189 v *= get_factor(*end); 190 if (v > UINT32_MAX) 191 xtables_error(PARAMETER_PROBLEM, "bad value for option " 192 "\"--hashlimit-burst\", value \"%s\" too large " 193 "(max %umb).", burst, UINT32_MAX/1024/1024); 194 return v; 195} 196 197static bool parse_bytes(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud) 198{ 199 unsigned int factor = 1; 200 uint64_t tmp; 201 int r; 202 const char *mode = strstr(rate, "b/s"); 203 if (!mode || mode == rate) 204 return false; 205 206 mode--; 207 r = atoi(rate); 208 if (r == 0) 209 return false; 210 211 factor = get_factor(*mode); 212 tmp = (uint64_t) r * factor; 213 if (tmp > UINT32_MAX) 214 xtables_error(PARAMETER_PROBLEM, 215 "Rate value too large \"%llu\" (max %u)\n", 216 (unsigned long long)tmp, UINT32_MAX); 217 218 *val = bytes_to_cost(tmp); 219 if (*val == 0) 220 xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate); 221 222 ud->mult = XT_HASHLIMIT_BYTE_EXPIRE; 223 return true; 224} 225 226static 227int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud) 228{ 229 const char *delim; 230 uint32_t r; 231 232 ud->mult = 1; /* Seconds by default. */ 233 delim = strchr(rate, '/'); 234 if (delim) { 235 if (strlen(delim+1) == 0) 236 return 0; 237 238 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 239 ud->mult = 1; 240 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 241 ud->mult = 60; 242 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 243 ud->mult = 60*60; 244 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 245 ud->mult = 24*60*60; 246 else 247 return 0; 248 } 249 r = atoi(rate); 250 if (!r) 251 return 0; 252 253 /* This would get mapped to infinite (1/day is minimum they 254 can specify, so we're ok at that end). */ 255 if (r / ud->mult > XT_HASHLIMIT_SCALE) 256 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); 257 258 *val = XT_HASHLIMIT_SCALE * ud->mult / r; 259 return 1; 260} 261 262static void hashlimit_init(struct xt_entry_match *m) 263{ 264 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data; 265 266 r->cfg.burst = XT_HASHLIMIT_BURST; 267 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 268 269} 270 271static void hashlimit_mt4_init(struct xt_entry_match *match) 272{ 273 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 274 275 info->cfg.mode = 0; 276 info->cfg.burst = XT_HASHLIMIT_BURST; 277 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 278 info->cfg.srcmask = 32; 279 info->cfg.dstmask = 32; 280} 281 282static void hashlimit_mt6_init(struct xt_entry_match *match) 283{ 284 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 285 286 info->cfg.mode = 0; 287 info->cfg.burst = XT_HASHLIMIT_BURST; 288 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 289 info->cfg.srcmask = 128; 290 info->cfg.dstmask = 128; 291} 292 293/* Parse a 'mode' parameter into the required bitmask */ 294static int parse_mode(uint32_t *mode, const char *option_arg) 295{ 296 char *tok; 297 char *arg = strdup(option_arg); 298 299 if (!arg) 300 return -1; 301 302 for (tok = strtok(arg, ",|"); 303 tok; 304 tok = strtok(NULL, ",|")) { 305 if (!strcmp(tok, "dstip")) 306 *mode |= XT_HASHLIMIT_HASH_DIP; 307 else if (!strcmp(tok, "srcip")) 308 *mode |= XT_HASHLIMIT_HASH_SIP; 309 else if (!strcmp(tok, "srcport")) 310 *mode |= XT_HASHLIMIT_HASH_SPT; 311 else if (!strcmp(tok, "dstport")) 312 *mode |= XT_HASHLIMIT_HASH_DPT; 313 else { 314 free(arg); 315 return -1; 316 } 317 } 318 free(arg); 319 return 0; 320} 321 322static void hashlimit_parse(struct xt_option_call *cb) 323{ 324 struct xt_hashlimit_info *info = cb->data; 325 326 xtables_option_parse(cb); 327 switch (cb->entry->id) { 328 case O_UPTO: 329 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata)) 330 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 331 "--hashlimit-upto", cb->arg); 332 break; 333 case O_MODE: 334 if (parse_mode(&info->cfg.mode, cb->arg) < 0) 335 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 336 "--hashlimit-mode", cb->arg); 337 break; 338 } 339} 340 341static void hashlimit_mt_parse(struct xt_option_call *cb) 342{ 343 struct xt_hashlimit_mtinfo1 *info = cb->data; 344 345 xtables_option_parse(cb); 346 switch (cb->entry->id) { 347 case O_BURST: 348 info->cfg.burst = parse_burst(cb->arg, info); 349 break; 350 case O_UPTO: 351 if (cb->invert) 352 info->cfg.mode |= XT_HASHLIMIT_INVERT; 353 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata)) 354 info->cfg.mode |= XT_HASHLIMIT_BYTES; 355 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata)) 356 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 357 "--hashlimit-upto", cb->arg); 358 break; 359 case O_ABOVE: 360 if (!cb->invert) 361 info->cfg.mode |= XT_HASHLIMIT_INVERT; 362 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata)) 363 info->cfg.mode |= XT_HASHLIMIT_BYTES; 364 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata)) 365 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 366 "--hashlimit-above", cb->arg); 367 break; 368 case O_MODE: 369 if (parse_mode(&info->cfg.mode, cb->arg) < 0) 370 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 371 "--hashlimit-mode", cb->arg); 372 break; 373 case O_SRCMASK: 374 info->cfg.srcmask = cb->val.hlen; 375 break; 376 case O_DSTMASK: 377 info->cfg.dstmask = cb->val.hlen; 378 break; 379 } 380} 381 382static void hashlimit_check(struct xt_fcheck_call *cb) 383{ 384 const struct hashlimit_mt_udata *udata = cb->udata; 385 struct xt_hashlimit_info *info = cb->data; 386 387 if (!(cb->xflags & (F_UPTO | F_ABOVE))) 388 xtables_error(PARAMETER_PROBLEM, 389 "You have to specify --hashlimit"); 390 if (!(cb->xflags & F_HTABLE_EXPIRE)) 391 info->cfg.expire = udata->mult * 1000; /* from s to msec */ 392} 393 394static void hashlimit_mt_check(struct xt_fcheck_call *cb) 395{ 396 const struct hashlimit_mt_udata *udata = cb->udata; 397 struct xt_hashlimit_mtinfo1 *info = cb->data; 398 399 if (!(cb->xflags & (F_UPTO | F_ABOVE))) 400 xtables_error(PARAMETER_PROBLEM, 401 "You have to specify --hashlimit"); 402 if (!(cb->xflags & F_HTABLE_EXPIRE)) 403 info->cfg.expire = udata->mult * 1000; /* from s to msec */ 404 405 if (info->cfg.mode & XT_HASHLIMIT_BYTES) { 406 uint32_t burst = 0; 407 if (cb->xflags & F_BURST) { 408 if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) 409 xtables_error(PARAMETER_PROBLEM, 410 "burst cannot be smaller than %ub", cost_to_bytes(info->cfg.avg)); 411 412 burst = info->cfg.burst; 413 burst /= cost_to_bytes(info->cfg.avg); 414 if (info->cfg.burst % cost_to_bytes(info->cfg.avg)) 415 burst++; 416 if (!(cb->xflags & F_HTABLE_EXPIRE)) 417 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; 418 } 419 info->cfg.burst = burst; 420 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX) 421 burst_error(); 422} 423 424static const struct rates 425{ 426 const char *name; 427 uint32_t mult; 428} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 }, 429 { "hour", XT_HASHLIMIT_SCALE*60*60 }, 430 { "min", XT_HASHLIMIT_SCALE*60 }, 431 { "sec", XT_HASHLIMIT_SCALE } }; 432 433static uint32_t print_rate(uint32_t period) 434{ 435 unsigned int i; 436 437 for (i = 1; i < ARRAY_SIZE(rates); ++i) 438 if (period > rates[i].mult 439 || rates[i].mult/period < rates[i].mult%period) 440 break; 441 442 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name); 443 /* return in msec */ 444 return rates[i-1].mult / XT_HASHLIMIT_SCALE * 1000; 445} 446 447static const struct { 448 const char *name; 449 uint32_t thresh; 450} units[] = { 451 { "m", 1024 * 1024 }, 452 { "k", 1024 }, 453 { "", 1 }, 454}; 455 456static uint32_t print_bytes(uint32_t avg, uint32_t burst, const char *prefix) 457{ 458 unsigned int i; 459 unsigned long long r; 460 461 r = cost_to_bytes(avg); 462 463 for (i = 0; i < ARRAY_SIZE(units) -1; ++i) 464 if (r >= units[i].thresh && 465 bytes_to_cost(r & ~(units[i].thresh - 1)) == avg) 466 break; 467 printf(" %llu%sb/s", r/units[i].thresh, units[i].name); 468 469 if (burst == 0) 470 return XT_HASHLIMIT_BYTE_EXPIRE * 1000; 471 472 r *= burst; 473 printf(" %s", prefix); 474 for (i = 0; i < ARRAY_SIZE(units) -1; ++i) 475 if (r >= units[i].thresh) 476 break; 477 478 printf("burst %llu%sb", r / units[i].thresh, units[i].name); 479 return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; 480} 481 482static void print_mode(unsigned int mode, char separator) 483{ 484 bool prevmode = false; 485 486 putchar(' '); 487 if (mode & XT_HASHLIMIT_HASH_SIP) { 488 fputs("srcip", stdout); 489 prevmode = 1; 490 } 491 if (mode & XT_HASHLIMIT_HASH_SPT) { 492 if (prevmode) 493 putchar(separator); 494 fputs("srcport", stdout); 495 prevmode = 1; 496 } 497 if (mode & XT_HASHLIMIT_HASH_DIP) { 498 if (prevmode) 499 putchar(separator); 500 fputs("dstip", stdout); 501 prevmode = 1; 502 } 503 if (mode & XT_HASHLIMIT_HASH_DPT) { 504 if (prevmode) 505 putchar(separator); 506 fputs("dstport", stdout); 507 } 508} 509 510static void hashlimit_print(const void *ip, 511 const struct xt_entry_match *match, int numeric) 512{ 513 const struct xt_hashlimit_info *r = (const void *)match->data; 514 uint32_t quantum; 515 516 fputs(" limit: avg", stdout); 517 quantum = print_rate(r->cfg.avg); 518 printf(" burst %u", r->cfg.burst); 519 fputs(" mode", stdout); 520 print_mode(r->cfg.mode, '-'); 521 if (r->cfg.size) 522 printf(" htable-size %u", r->cfg.size); 523 if (r->cfg.max) 524 printf(" htable-max %u", r->cfg.max); 525 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 526 printf(" htable-gcinterval %u", r->cfg.gc_interval); 527 if (r->cfg.expire != quantum) 528 printf(" htable-expire %u", r->cfg.expire); 529} 530 531static void 532hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 533{ 534 uint32_t quantum; 535 536 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 537 fputs(" limit: above", stdout); 538 else 539 fputs(" limit: up to", stdout); 540 541 if (info->cfg.mode & XT_HASHLIMIT_BYTES) { 542 quantum = print_bytes(info->cfg.avg, info->cfg.burst, ""); 543 } else { 544 quantum = print_rate(info->cfg.avg); 545 printf(" burst %u", info->cfg.burst); 546 } 547 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 548 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 549 fputs(" mode", stdout); 550 print_mode(info->cfg.mode, '-'); 551 } 552 if (info->cfg.size != 0) 553 printf(" htable-size %u", info->cfg.size); 554 if (info->cfg.max != 0) 555 printf(" htable-max %u", info->cfg.max); 556 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 557 printf(" htable-gcinterval %u", info->cfg.gc_interval); 558 if (info->cfg.expire != quantum) 559 printf(" htable-expire %u", info->cfg.expire); 560 561 if (info->cfg.srcmask != dmask) 562 printf(" srcmask %u", info->cfg.srcmask); 563 if (info->cfg.dstmask != dmask) 564 printf(" dstmask %u", info->cfg.dstmask); 565} 566 567static void 568hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, 569 int numeric) 570{ 571 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 572 573 hashlimit_mt_print(info, 32); 574} 575 576static void 577hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, 578 int numeric) 579{ 580 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 581 582 hashlimit_mt_print(info, 128); 583} 584 585static void hashlimit_save(const void *ip, const struct xt_entry_match *match) 586{ 587 const struct xt_hashlimit_info *r = (const void *)match->data; 588 uint32_t quantum; 589 590 fputs(" --hashlimit", stdout); 591 quantum = print_rate(r->cfg.avg); 592 printf(" --hashlimit-burst %u", r->cfg.burst); 593 594 fputs(" --hashlimit-mode", stdout); 595 print_mode(r->cfg.mode, ','); 596 597 printf(" --hashlimit-name %s", r->name); 598 599 if (r->cfg.size) 600 printf(" --hashlimit-htable-size %u", r->cfg.size); 601 if (r->cfg.max) 602 printf(" --hashlimit-htable-max %u", r->cfg.max); 603 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 604 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval); 605 if (r->cfg.expire != quantum) 606 printf(" --hashlimit-htable-expire %u", r->cfg.expire); 607} 608 609static void 610hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) 611{ 612 uint32_t quantum; 613 614 if (info->cfg.mode & XT_HASHLIMIT_INVERT) 615 fputs(" --hashlimit-above", stdout); 616 else 617 fputs(" --hashlimit-upto", stdout); 618 619 if (info->cfg.mode & XT_HASHLIMIT_BYTES) { 620 quantum = print_bytes(info->cfg.avg, info->cfg.burst, "--hashlimit-"); 621 } else { 622 quantum = print_rate(info->cfg.avg); 623 printf(" --hashlimit-burst %u", info->cfg.burst); 624 } 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 != quantum) 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_mt_reg[] = { 666 { 667 .family = NFPROTO_UNSPEC, 668 .name = "hashlimit", 669 .version = XTABLES_VERSION, 670 .revision = 0, 671 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)), 672 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo), 673 .help = hashlimit_help, 674 .init = hashlimit_init, 675 .x6_parse = hashlimit_parse, 676 .x6_fcheck = hashlimit_check, 677 .print = hashlimit_print, 678 .save = hashlimit_save, 679 .x6_options = hashlimit_opts, 680 .udata_size = sizeof(struct hashlimit_mt_udata), 681 }, 682 { 683 .version = XTABLES_VERSION, 684 .name = "hashlimit", 685 .revision = 1, 686 .family = NFPROTO_IPV4, 687 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 688 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 689 .help = hashlimit_mt_help, 690 .init = hashlimit_mt4_init, 691 .x6_parse = hashlimit_mt_parse, 692 .x6_fcheck = hashlimit_mt_check, 693 .print = hashlimit_mt4_print, 694 .save = hashlimit_mt4_save, 695 .x6_options = hashlimit_mt_opts, 696 .udata_size = sizeof(struct hashlimit_mt_udata), 697 }, 698 { 699 .version = XTABLES_VERSION, 700 .name = "hashlimit", 701 .revision = 1, 702 .family = NFPROTO_IPV6, 703 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 704 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 705 .help = hashlimit_mt_help, 706 .init = hashlimit_mt6_init, 707 .x6_parse = hashlimit_mt_parse, 708 .x6_fcheck = hashlimit_mt_check, 709 .print = hashlimit_mt6_print, 710 .save = hashlimit_mt6_save, 711 .x6_options = hashlimit_mt_opts, 712 .udata_size = sizeof(struct hashlimit_mt_udata), 713 }, 714}; 715 716void _init(void) 717{ 718 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); 719} 720