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