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 <errno.h> 22 #include <xtables.h> 23 #include <linux/netfilter/x_tables.h> 24 #include <linux/netfilter/xt_hashlimit.h> 25 26 #define XT_HASHLIMIT_BURST 5 27 #define XT_HASHLIMIT_BURST_MAX_v1 10000 28 #define XT_HASHLIMIT_BURST_MAX 1000000 29 30 #define XT_HASHLIMIT_BYTE_EXPIRE 15 31 #define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60 32 33 /* miliseconds */ 34 #define XT_HASHLIMIT_GCINTERVAL 1000 35 36 struct hashlimit_mt_udata { 37 uint32_t mult; 38 }; 39 40 static void hashlimit_help(void) 41 { 42 printf( 43 "hashlimit match options:\n" 44 "--hashlimit <avg> max average match rate\n" 45 " [Packets per second unless followed by \n" 46 " /sec /minute /hour /day postfixes]\n" 47 "--hashlimit-mode <mode> mode is a comma-separated list of\n" 48 " dstip,srcip,dstport,srcport\n" 49 "--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n" 50 "[--hashlimit-burst <num>] number to match in a burst, default %u\n" 51 "[--hashlimit-htable-size <num>] number of hashtable buckets\n" 52 "[--hashlimit-htable-max <num>] number of hashtable entries\n" 53 "[--hashlimit-htable-gcinterval] interval between garbage collection runs\n" 54 "[--hashlimit-htable-expire] after which time are idle entries expired?\n", 55 XT_HASHLIMIT_BURST); 56 } 57 58 enum { 59 O_UPTO = 0, 60 O_ABOVE, 61 O_LIMIT, 62 O_MODE, 63 O_SRCMASK, 64 O_DSTMASK, 65 O_NAME, 66 O_BURST, 67 O_HTABLE_SIZE, 68 O_HTABLE_MAX, 69 O_HTABLE_GCINT, 70 O_HTABLE_EXPIRE, 71 F_BURST = 1 << O_BURST, 72 F_UPTO = 1 << O_UPTO, 73 F_ABOVE = 1 << O_ABOVE, 74 F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE, 75 }; 76 77 static void hashlimit_mt_help(void) 78 { 79 printf( 80 "hashlimit match options:\n" 81 " --hashlimit-upto <avg> max average match rate\n" 82 " [Packets per second unless followed by \n" 83 " /sec /minute /hour /day postfixes]\n" 84 " --hashlimit-above <avg> min average match rate\n" 85 " --hashlimit-mode <mode> mode is a comma-separated list of\n" 86 " dstip,srcip,dstport,srcport (or none)\n" 87 " --hashlimit-srcmask <length> source address grouping prefix length\n" 88 " --hashlimit-dstmask <length> destination address grouping prefix length\n" 89 " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n" 90 " --hashlimit-burst <num> number to match in a burst, default %u\n" 91 " --hashlimit-htable-size <num> number of hashtable buckets\n" 92 " --hashlimit-htable-max <num> number of hashtable entries\n" 93 " --hashlimit-htable-gcinterval interval between garbage collection runs\n" 94 " --hashlimit-htable-expire after which time are idle entries expired?\n" 95 "\n", XT_HASHLIMIT_BURST); 96 } 97 98 #define s struct xt_hashlimit_info 99 static const struct xt_option_entry hashlimit_opts[] = { 100 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, 101 .type = XTTYPE_STRING}, 102 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32, 103 .min = 1, .max = XT_HASHLIMIT_BURST_MAX_v1, .flags = XTOPT_PUT, 104 XTOPT_POINTER(s, cfg.burst)}, 105 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, 106 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 107 XTOPT_POINTER(s, cfg.size)}, 108 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, 109 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 110 XTOPT_POINTER(s, cfg.max)}, 111 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, 112 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 113 XTOPT_POINTER(s, cfg.gc_interval)}, 114 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, 115 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 116 XTOPT_POINTER(s, cfg.expire)}, 117 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING, 118 .flags = XTOPT_MAND}, 119 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, 120 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, 121 XTOPT_TABLEEND, 122 }; 123 #undef s 124 125 #define s struct xt_hashlimit_mtinfo1 126 static const struct xt_option_entry hashlimit_mt_opts_v1[] = { 127 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE, 128 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, 129 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO, 130 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, 131 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, 132 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */ 133 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN}, 134 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN}, 135 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING}, 136 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, 137 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 138 XTOPT_POINTER(s, cfg.size)}, 139 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, 140 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 141 XTOPT_POINTER(s, cfg.max)}, 142 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, 143 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 144 XTOPT_POINTER(s, cfg.gc_interval)}, 145 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, 146 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 147 XTOPT_POINTER(s, cfg.expire)}, 148 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING}, 149 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, 150 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, 151 XTOPT_TABLEEND, 152 }; 153 #undef s 154 155 #define s struct xt_hashlimit_mtinfo2 156 static const struct xt_option_entry hashlimit_mt_opts[] = { 157 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE, 158 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, 159 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO, 160 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, 161 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, 162 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */ 163 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN}, 164 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN}, 165 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING}, 166 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, 167 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 168 XTOPT_POINTER(s, cfg.size)}, 169 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, 170 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 171 XTOPT_POINTER(s, cfg.max)}, 172 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, 173 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 174 XTOPT_POINTER(s, cfg.gc_interval)}, 175 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, 176 .type = XTTYPE_UINT32, .flags = XTOPT_PUT, 177 XTOPT_POINTER(s, cfg.expire)}, 178 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING}, 179 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, 180 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, 181 XTOPT_TABLEEND, 182 }; 183 #undef s 184 185 static int 186 cfg_copy(struct hashlimit_cfg2 *to, const void *from, int revision) 187 { 188 if (revision == 1) { 189 struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from; 190 191 to->mode = cfg->mode; 192 to->avg = cfg->avg; 193 to->burst = cfg->burst; 194 to->size = cfg->size; 195 to->max = cfg->max; 196 to->gc_interval = cfg->gc_interval; 197 to->expire = cfg->expire; 198 to->srcmask = cfg->srcmask; 199 to->dstmask = cfg->dstmask; 200 } else if (revision == 2) { 201 memcpy(to, from, sizeof(struct hashlimit_cfg2)); 202 } else { 203 return -EINVAL; 204 } 205 206 return 0; 207 } 208 209 static uint64_t cost_to_bytes(uint64_t cost) 210 { 211 uint64_t r; 212 213 r = cost ? UINT32_MAX / cost : UINT32_MAX; 214 r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT; 215 return r; 216 } 217 218 static uint64_t bytes_to_cost(uint64_t bytes) 219 { 220 uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT; 221 return UINT32_MAX / (r+1); 222 } 223 224 static uint32_t get_factor(int chr) 225 { 226 switch (chr) { 227 case 'm': return 1024 * 1024; 228 case 'k': return 1024; 229 } 230 return 1; 231 } 232 233 static void burst_error_v1(void) 234 { 235 xtables_error(PARAMETER_PROBLEM, "bad value for option " 236 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX_v1); 237 } 238 239 static void burst_error(void) 240 { 241 xtables_error(PARAMETER_PROBLEM, "bad value for option " 242 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX); 243 } 244 245 static uint64_t parse_burst(const char *burst, int revision) 246 { 247 uintmax_t v; 248 char *end; 249 uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX; 250 uint64_t burst_max = (revision == 1) ? 251 XT_HASHLIMIT_BURST_MAX_v1 : XT_HASHLIMIT_BURST_MAX; 252 253 if (!xtables_strtoul(burst, &end, &v, 1, max) || 254 (*end == 0 && v > burst_max)) { 255 if (revision == 1) 256 burst_error_v1(); 257 else 258 burst_error(); 259 } 260 261 v *= get_factor(*end); 262 if (v > max) 263 xtables_error(PARAMETER_PROBLEM, "bad value for option " 264 "\"--hashlimit-burst\", value \"%s\" too large " 265 "(max %lumb).", burst, max/1024/1024); 266 return v; 267 } 268 269 static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision) 270 { 271 unsigned int factor = 1; 272 uint64_t tmp, r; 273 const char *mode = strstr(rate, "b/s"); 274 uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX; 275 276 if (!mode || mode == rate) 277 return false; 278 279 mode--; 280 r = atoll(rate); 281 if (r == 0) 282 return false; 283 284 factor = get_factor(*mode); 285 tmp = (uint64_t) r * factor; 286 if (tmp > max) 287 xtables_error(PARAMETER_PROBLEM, 288 "Rate value too large \"%llu\" (max %lu)\n", 289 (unsigned long long)tmp, max); 290 291 tmp = bytes_to_cost(tmp); 292 if (tmp == 0) 293 xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate); 294 295 ud->mult = XT_HASHLIMIT_BYTE_EXPIRE; 296 297 if(revision == 1) 298 *((uint32_t*)val) = tmp; 299 else 300 *((uint64_t*)val) = tmp; 301 302 return true; 303 } 304 305 static 306 int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision) 307 { 308 const char *delim; 309 uint64_t tmp, r; 310 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2; 311 312 ud->mult = 1; /* Seconds by default. */ 313 delim = strchr(rate, '/'); 314 if (delim) { 315 if (strlen(delim+1) == 0) 316 return 0; 317 318 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) 319 ud->mult = 1; 320 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) 321 ud->mult = 60; 322 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) 323 ud->mult = 60*60; 324 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) 325 ud->mult = 24*60*60; 326 else 327 return 0; 328 } 329 r = atoll(rate); 330 if (!r) 331 return 0; 332 333 tmp = scale * ud->mult / r; 334 if (tmp == 0) 335 /* 336 * The rate maps to infinity. (1/day is the minimum they can 337 * specify, so we are ok at that end). 338 */ 339 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); 340 341 if(revision == 1) 342 *((uint32_t*)val) = tmp; 343 else 344 *((uint64_t*)val) = tmp; 345 346 return 1; 347 } 348 349 static void hashlimit_init(struct xt_entry_match *m) 350 { 351 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data; 352 353 r->cfg.burst = XT_HASHLIMIT_BURST; 354 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 355 356 } 357 358 static void hashlimit_mt4_init_v1(struct xt_entry_match *match) 359 { 360 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 361 362 info->cfg.mode = 0; 363 info->cfg.burst = XT_HASHLIMIT_BURST; 364 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 365 info->cfg.srcmask = 32; 366 info->cfg.dstmask = 32; 367 } 368 369 static void hashlimit_mt6_init_v1(struct xt_entry_match *match) 370 { 371 struct xt_hashlimit_mtinfo1 *info = (void *)match->data; 372 373 info->cfg.mode = 0; 374 info->cfg.burst = XT_HASHLIMIT_BURST; 375 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 376 info->cfg.srcmask = 128; 377 info->cfg.dstmask = 128; 378 } 379 380 static void hashlimit_mt4_init(struct xt_entry_match *match) 381 { 382 struct xt_hashlimit_mtinfo2 *info = (void *)match->data; 383 384 info->cfg.mode = 0; 385 info->cfg.burst = XT_HASHLIMIT_BURST; 386 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 387 info->cfg.srcmask = 32; 388 info->cfg.dstmask = 32; 389 } 390 391 static void hashlimit_mt6_init(struct xt_entry_match *match) 392 { 393 struct xt_hashlimit_mtinfo2 *info = (void *)match->data; 394 395 info->cfg.mode = 0; 396 info->cfg.burst = XT_HASHLIMIT_BURST; 397 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; 398 info->cfg.srcmask = 128; 399 info->cfg.dstmask = 128; 400 } 401 402 /* Parse a 'mode' parameter into the required bitmask */ 403 static int parse_mode(uint32_t *mode, const char *option_arg) 404 { 405 char *tok; 406 char *arg = strdup(option_arg); 407 408 if (!arg) 409 return -1; 410 411 for (tok = strtok(arg, ",|"); 412 tok; 413 tok = strtok(NULL, ",|")) { 414 if (!strcmp(tok, "dstip")) 415 *mode |= XT_HASHLIMIT_HASH_DIP; 416 else if (!strcmp(tok, "srcip")) 417 *mode |= XT_HASHLIMIT_HASH_SIP; 418 else if (!strcmp(tok, "srcport")) 419 *mode |= XT_HASHLIMIT_HASH_SPT; 420 else if (!strcmp(tok, "dstport")) 421 *mode |= XT_HASHLIMIT_HASH_DPT; 422 else { 423 free(arg); 424 return -1; 425 } 426 } 427 free(arg); 428 return 0; 429 } 430 431 static void hashlimit_parse(struct xt_option_call *cb) 432 { 433 struct xt_hashlimit_info *info = cb->data; 434 435 xtables_option_parse(cb); 436 switch (cb->entry->id) { 437 case O_UPTO: 438 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1)) 439 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 440 "--hashlimit-upto", cb->arg); 441 break; 442 case O_MODE: 443 if (parse_mode(&info->cfg.mode, cb->arg) < 0) 444 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 445 "--hashlimit-mode", cb->arg); 446 break; 447 } 448 } 449 450 static void hashlimit_mt_parse_v1(struct xt_option_call *cb) 451 { 452 struct xt_hashlimit_mtinfo1 *info = cb->data; 453 454 xtables_option_parse(cb); 455 switch (cb->entry->id) { 456 case O_BURST: 457 info->cfg.burst = parse_burst(cb->arg, 1); 458 break; 459 case O_UPTO: 460 if (cb->invert) 461 info->cfg.mode |= XT_HASHLIMIT_INVERT; 462 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1)) 463 info->cfg.mode |= XT_HASHLIMIT_BYTES; 464 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1)) 465 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 466 "--hashlimit-upto", cb->arg); 467 break; 468 case O_ABOVE: 469 if (!cb->invert) 470 info->cfg.mode |= XT_HASHLIMIT_INVERT; 471 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1)) 472 info->cfg.mode |= XT_HASHLIMIT_BYTES; 473 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1)) 474 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 475 "--hashlimit-above", cb->arg); 476 break; 477 case O_MODE: 478 if (parse_mode(&info->cfg.mode, cb->arg) < 0) 479 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 480 "--hashlimit-mode", cb->arg); 481 break; 482 case O_SRCMASK: 483 info->cfg.srcmask = cb->val.hlen; 484 break; 485 case O_DSTMASK: 486 info->cfg.dstmask = cb->val.hlen; 487 break; 488 } 489 } 490 491 static void hashlimit_mt_parse(struct xt_option_call *cb) 492 { 493 struct xt_hashlimit_mtinfo2 *info = cb->data; 494 495 xtables_option_parse(cb); 496 switch (cb->entry->id) { 497 case O_BURST: 498 info->cfg.burst = parse_burst(cb->arg, 2); 499 break; 500 case O_UPTO: 501 if (cb->invert) 502 info->cfg.mode |= XT_HASHLIMIT_INVERT; 503 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2)) 504 info->cfg.mode |= XT_HASHLIMIT_BYTES; 505 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2)) 506 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 507 "--hashlimit-upto", cb->arg); 508 break; 509 case O_ABOVE: 510 if (!cb->invert) 511 info->cfg.mode |= XT_HASHLIMIT_INVERT; 512 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2)) 513 info->cfg.mode |= XT_HASHLIMIT_BYTES; 514 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2)) 515 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 516 "--hashlimit-above", cb->arg); 517 break; 518 case O_MODE: 519 if (parse_mode(&info->cfg.mode, cb->arg) < 0) 520 xtables_param_act(XTF_BAD_VALUE, "hashlimit", 521 "--hashlimit-mode", cb->arg); 522 break; 523 case O_SRCMASK: 524 info->cfg.srcmask = cb->val.hlen; 525 break; 526 case O_DSTMASK: 527 info->cfg.dstmask = cb->val.hlen; 528 break; 529 } 530 } 531 532 static void hashlimit_check(struct xt_fcheck_call *cb) 533 { 534 const struct hashlimit_mt_udata *udata = cb->udata; 535 struct xt_hashlimit_info *info = cb->data; 536 537 if (!(cb->xflags & (F_UPTO | F_ABOVE))) 538 xtables_error(PARAMETER_PROBLEM, 539 "You have to specify --hashlimit"); 540 if (!(cb->xflags & F_HTABLE_EXPIRE)) 541 info->cfg.expire = udata->mult * 1000; /* from s to msec */ 542 } 543 544 static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb) 545 { 546 const struct hashlimit_mt_udata *udata = cb->udata; 547 struct xt_hashlimit_mtinfo1 *info = cb->data; 548 549 if (!(cb->xflags & (F_UPTO | F_ABOVE))) 550 xtables_error(PARAMETER_PROBLEM, 551 "You have to specify --hashlimit"); 552 if (!(cb->xflags & F_HTABLE_EXPIRE)) 553 info->cfg.expire = udata->mult * 1000; /* from s to msec */ 554 555 if (info->cfg.mode & XT_HASHLIMIT_BYTES) { 556 uint32_t burst = 0; 557 if (cb->xflags & F_BURST) { 558 if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) 559 xtables_error(PARAMETER_PROBLEM, 560 "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg)); 561 562 burst = info->cfg.burst; 563 burst /= cost_to_bytes(info->cfg.avg); 564 if (info->cfg.burst % cost_to_bytes(info->cfg.avg)) 565 burst++; 566 if (!(cb->xflags & F_HTABLE_EXPIRE)) 567 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; 568 } 569 info->cfg.burst = burst; 570 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX_v1) 571 burst_error_v1(); 572 } 573 574 static void hashlimit_mt_check(struct xt_fcheck_call *cb) 575 { 576 const struct hashlimit_mt_udata *udata = cb->udata; 577 struct xt_hashlimit_mtinfo2 *info = cb->data; 578 579 if (!(cb->xflags & (F_UPTO | F_ABOVE))) 580 xtables_error(PARAMETER_PROBLEM, 581 "You have to specify --hashlimit"); 582 if (!(cb->xflags & F_HTABLE_EXPIRE)) 583 info->cfg.expire = udata->mult * 1000; /* from s to msec */ 584 585 if (info->cfg.mode & XT_HASHLIMIT_BYTES) { 586 uint32_t burst = 0; 587 if (cb->xflags & F_BURST) { 588 if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) 589 xtables_error(PARAMETER_PROBLEM, 590 "burst cannot be smaller than %lub", cost_to_bytes(info->cfg.avg)); 591 592 burst = info->cfg.burst; 593 burst /= cost_to_bytes(info->cfg.avg); 594 if (info->cfg.burst % cost_to_bytes(info->cfg.avg)) 595 burst++; 596 if (!(cb->xflags & F_HTABLE_EXPIRE)) 597 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; 598 } 599 info->cfg.burst = burst; 600 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX) 601 burst_error(); 602 } 603 604 struct rates { 605 const char *name; 606 uint64_t mult; 607 } rates_v1[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 }, 608 { "hour", XT_HASHLIMIT_SCALE*60*60 }, 609 { "min", XT_HASHLIMIT_SCALE*60 }, 610 { "sec", XT_HASHLIMIT_SCALE } }; 611 612 static const struct rates rates[] = { 613 { "day", XT_HASHLIMIT_SCALE_v2*24*60*60 }, 614 { "hour", XT_HASHLIMIT_SCALE_v2*60*60 }, 615 { "min", XT_HASHLIMIT_SCALE_v2*60 }, 616 { "sec", XT_HASHLIMIT_SCALE_v2 } }; 617 618 static uint32_t print_rate(uint32_t period, int revision) 619 { 620 unsigned int i; 621 const struct rates *_rates = (revision == 1) ? rates_v1 : rates; 622 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2; 623 624 if (period == 0) { 625 printf(" %f", INFINITY); 626 return 0; 627 } 628 629 for (i = 1; i < ARRAY_SIZE(rates); ++i) 630 if (period > _rates[i].mult 631 || _rates[i].mult/period < _rates[i].mult%period) 632 break; 633 634 printf(" %lu/%s", _rates[i-1].mult / period, _rates[i-1].name); 635 /* return in msec */ 636 return _rates[i-1].mult / scale * 1000; 637 } 638 639 static const struct { 640 const char *name; 641 uint32_t thresh; 642 } units[] = { 643 { "m", 1024 * 1024 }, 644 { "k", 1024 }, 645 { "", 1 }, 646 }; 647 648 static uint32_t print_bytes(uint64_t avg, uint64_t burst, const char *prefix) 649 { 650 unsigned int i; 651 unsigned long long r; 652 653 r = cost_to_bytes(avg); 654 655 for (i = 0; i < ARRAY_SIZE(units) -1; ++i) 656 if (r >= units[i].thresh && 657 bytes_to_cost(r & ~(units[i].thresh - 1)) == avg) 658 break; 659 printf(" %llu%sb/s", r/units[i].thresh, units[i].name); 660 661 if (burst == 0) 662 return XT_HASHLIMIT_BYTE_EXPIRE * 1000; 663 664 r *= burst; 665 printf(" %s", prefix); 666 for (i = 0; i < ARRAY_SIZE(units) -1; ++i) 667 if (r >= units[i].thresh) 668 break; 669 670 printf("burst %llu%sb", r / units[i].thresh, units[i].name); 671 return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; 672 } 673 674 static void print_mode(unsigned int mode, char separator) 675 { 676 bool prevmode = false; 677 678 putchar(' '); 679 if (mode & XT_HASHLIMIT_HASH_SIP) { 680 fputs("srcip", stdout); 681 prevmode = 1; 682 } 683 if (mode & XT_HASHLIMIT_HASH_SPT) { 684 if (prevmode) 685 putchar(separator); 686 fputs("srcport", stdout); 687 prevmode = 1; 688 } 689 if (mode & XT_HASHLIMIT_HASH_DIP) { 690 if (prevmode) 691 putchar(separator); 692 fputs("dstip", stdout); 693 prevmode = 1; 694 } 695 if (mode & XT_HASHLIMIT_HASH_DPT) { 696 if (prevmode) 697 putchar(separator); 698 fputs("dstport", stdout); 699 } 700 } 701 702 static void hashlimit_print(const void *ip, 703 const struct xt_entry_match *match, int numeric) 704 { 705 const struct xt_hashlimit_info *r = (const void *)match->data; 706 uint32_t quantum; 707 708 fputs(" limit: avg", stdout); 709 quantum = print_rate(r->cfg.avg, 1); 710 printf(" burst %u", r->cfg.burst); 711 fputs(" mode", stdout); 712 print_mode(r->cfg.mode, '-'); 713 if (r->cfg.size) 714 printf(" htable-size %u", r->cfg.size); 715 if (r->cfg.max) 716 printf(" htable-max %u", r->cfg.max); 717 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 718 printf(" htable-gcinterval %u", r->cfg.gc_interval); 719 if (r->cfg.expire != quantum) 720 printf(" htable-expire %u", r->cfg.expire); 721 } 722 723 static void 724 hashlimit_mt_print(const struct hashlimit_cfg2 *cfg, unsigned int dmask, int revision) 725 { 726 uint32_t quantum; 727 728 if (cfg->mode & XT_HASHLIMIT_INVERT) 729 fputs(" limit: above", stdout); 730 else 731 fputs(" limit: up to", stdout); 732 733 if (cfg->mode & XT_HASHLIMIT_BYTES) { 734 quantum = print_bytes(cfg->avg, cfg->burst, ""); 735 } else { 736 quantum = print_rate(cfg->avg, revision); 737 printf(" burst %llu", cfg->burst); 738 } 739 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 740 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 741 fputs(" mode", stdout); 742 print_mode(cfg->mode, '-'); 743 } 744 if (cfg->size != 0) 745 printf(" htable-size %u", cfg->size); 746 if (cfg->max != 0) 747 printf(" htable-max %u", cfg->max); 748 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL) 749 printf(" htable-gcinterval %u", cfg->gc_interval); 750 if (cfg->expire != quantum) 751 printf(" htable-expire %u", cfg->expire); 752 753 if (cfg->srcmask != dmask) 754 printf(" srcmask %u", cfg->srcmask); 755 if (cfg->dstmask != dmask) 756 printf(" dstmask %u", cfg->dstmask); 757 } 758 759 static void 760 hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match, 761 int numeric) 762 { 763 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 764 struct hashlimit_cfg2 cfg; 765 int ret; 766 767 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); 768 769 if (ret) 770 xtables_error(OTHER_PROBLEM, "unknown revision"); 771 772 hashlimit_mt_print(&cfg, 32, 1); 773 } 774 775 static void 776 hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match, 777 int numeric) 778 { 779 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 780 struct hashlimit_cfg2 cfg; 781 int ret; 782 783 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); 784 785 if (ret) 786 xtables_error(OTHER_PROBLEM, "unknown revision"); 787 788 hashlimit_mt_print(&cfg, 128, 1); 789 } 790 791 static void 792 hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match, 793 int numeric) 794 { 795 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; 796 797 hashlimit_mt_print(&info->cfg, 32, 2); 798 } 799 800 static void 801 hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, 802 int numeric) 803 { 804 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; 805 806 hashlimit_mt_print(&info->cfg, 128, 2); 807 } 808 809 static void hashlimit_save(const void *ip, const struct xt_entry_match *match) 810 { 811 const struct xt_hashlimit_info *r = (const void *)match->data; 812 uint32_t quantum; 813 814 fputs(" --hashlimit", stdout); 815 quantum = print_rate(r->cfg.avg, 1); 816 printf(" --hashlimit-burst %u", r->cfg.burst); 817 818 fputs(" --hashlimit-mode", stdout); 819 print_mode(r->cfg.mode, ','); 820 821 printf(" --hashlimit-name %s", r->name); 822 823 if (r->cfg.size) 824 printf(" --hashlimit-htable-size %u", r->cfg.size); 825 if (r->cfg.max) 826 printf(" --hashlimit-htable-max %u", r->cfg.max); 827 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) 828 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval); 829 if (r->cfg.expire != quantum) 830 printf(" --hashlimit-htable-expire %u", r->cfg.expire); 831 } 832 833 static void 834 hashlimit_mt_save(const struct hashlimit_cfg2 *cfg, const char* name, unsigned int dmask, int revision) 835 { 836 uint32_t quantum; 837 838 if (cfg->mode & XT_HASHLIMIT_INVERT) 839 fputs(" --hashlimit-above", stdout); 840 else 841 fputs(" --hashlimit-upto", stdout); 842 843 if (cfg->mode & XT_HASHLIMIT_BYTES) { 844 quantum = print_bytes(cfg->avg, cfg->burst, "--hashlimit-"); 845 } else { 846 quantum = print_rate(cfg->avg, revision); 847 printf(" --hashlimit-burst %llu", cfg->burst); 848 } 849 850 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | 851 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { 852 fputs(" --hashlimit-mode", stdout); 853 print_mode(cfg->mode, ','); 854 } 855 856 printf(" --hashlimit-name %s", name); 857 858 if (cfg->size != 0) 859 printf(" --hashlimit-htable-size %u", cfg->size); 860 if (cfg->max != 0) 861 printf(" --hashlimit-htable-max %u", cfg->max); 862 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL) 863 printf(" --hashlimit-htable-gcinterval %u", cfg->gc_interval); 864 if (cfg->expire != quantum) 865 printf(" --hashlimit-htable-expire %u", cfg->expire); 866 867 if (cfg->srcmask != dmask) 868 printf(" --hashlimit-srcmask %u", cfg->srcmask); 869 if (cfg->dstmask != dmask) 870 printf(" --hashlimit-dstmask %u", cfg->dstmask); 871 } 872 873 static void 874 hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match) 875 { 876 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 877 struct hashlimit_cfg2 cfg; 878 int ret; 879 880 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); 881 882 if (ret) 883 xtables_error(OTHER_PROBLEM, "unknown revision"); 884 885 hashlimit_mt_save(&cfg, info->name, 32, 1); 886 } 887 888 static void 889 hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match) 890 { 891 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data; 892 struct hashlimit_cfg2 cfg; 893 int ret; 894 895 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1); 896 897 if (ret) 898 xtables_error(OTHER_PROBLEM, "unknown revision"); 899 900 hashlimit_mt_save(&cfg, info->name, 128, 1); 901 } 902 903 static void 904 hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match) 905 { 906 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; 907 908 hashlimit_mt_save(&info->cfg, info->name, 32, 2); 909 } 910 911 static void 912 hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match) 913 { 914 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data; 915 916 hashlimit_mt_save(&info->cfg, info->name, 128, 2); 917 } 918 919 static struct xtables_match hashlimit_mt_reg[] = { 920 { 921 .family = NFPROTO_UNSPEC, 922 .name = "hashlimit", 923 .version = XTABLES_VERSION, 924 .revision = 0, 925 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)), 926 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo), 927 .help = hashlimit_help, 928 .init = hashlimit_init, 929 .x6_parse = hashlimit_parse, 930 .x6_fcheck = hashlimit_check, 931 .print = hashlimit_print, 932 .save = hashlimit_save, 933 .x6_options = hashlimit_opts, 934 .udata_size = sizeof(struct hashlimit_mt_udata), 935 }, 936 { 937 .version = XTABLES_VERSION, 938 .name = "hashlimit", 939 .revision = 1, 940 .family = NFPROTO_IPV4, 941 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 942 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 943 .help = hashlimit_mt_help, 944 .init = hashlimit_mt4_init_v1, 945 .x6_parse = hashlimit_mt_parse_v1, 946 .x6_fcheck = hashlimit_mt_check_v1, 947 .print = hashlimit_mt4_print_v1, 948 .save = hashlimit_mt4_save_v1, 949 .x6_options = hashlimit_mt_opts_v1, 950 .udata_size = sizeof(struct hashlimit_mt_udata), 951 }, 952 { 953 .version = XTABLES_VERSION, 954 .name = "hashlimit", 955 .revision = 1, 956 .family = NFPROTO_IPV6, 957 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)), 958 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), 959 .help = hashlimit_mt_help, 960 .init = hashlimit_mt6_init_v1, 961 .x6_parse = hashlimit_mt_parse_v1, 962 .x6_fcheck = hashlimit_mt_check_v1, 963 .print = hashlimit_mt6_print_v1, 964 .save = hashlimit_mt6_save_v1, 965 .x6_options = hashlimit_mt_opts_v1, 966 .udata_size = sizeof(struct hashlimit_mt_udata), 967 }, 968 { 969 .version = XTABLES_VERSION, 970 .name = "hashlimit", 971 .revision = 2, 972 .family = NFPROTO_IPV4, 973 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), 974 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), 975 .help = hashlimit_mt_help, 976 .init = hashlimit_mt4_init, 977 .x6_parse = hashlimit_mt_parse, 978 .x6_fcheck = hashlimit_mt_check, 979 .print = hashlimit_mt4_print, 980 .save = hashlimit_mt4_save, 981 .x6_options = hashlimit_mt_opts, 982 .udata_size = sizeof(struct hashlimit_mt_udata), 983 }, 984 { 985 .version = XTABLES_VERSION, 986 .name = "hashlimit", 987 .revision = 2, 988 .family = NFPROTO_IPV6, 989 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)), 990 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo), 991 .help = hashlimit_mt_help, 992 .init = hashlimit_mt6_init, 993 .x6_parse = hashlimit_mt_parse, 994 .x6_fcheck = hashlimit_mt_check, 995 .print = hashlimit_mt6_print, 996 .save = hashlimit_mt6_save, 997 .x6_options = hashlimit_mt_opts, 998 .udata_size = sizeof(struct hashlimit_mt_udata), 999 }, 1000 }; 1001 1002 void _init(void) 1003 { 1004 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); 1005 } 1006