Home | History | Annotate | Download | only in extensions
      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