• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #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 
hashlimit_help(void)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 
hashlimit_mt_help(void)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
cfg_copy(struct hashlimit_cfg2 * to,const void * from,int revision)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 
cost_to_bytes(uint64_t cost)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 
bytes_to_cost(uint64_t bytes)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 
get_factor(int chr)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 
burst_error_v1(void)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 
burst_error(void)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 
parse_burst(const char * burst,int revision)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 
parse_bytes(const char * rate,void * val,struct hashlimit_mt_udata * ud,int revision)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
parse_rate(const char * rate,void * val,struct hashlimit_mt_udata * ud,int revision)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 
hashlimit_init(struct xt_entry_match * m)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 
hashlimit_mt4_init_v1(struct xt_entry_match * match)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 
hashlimit_mt6_init_v1(struct xt_entry_match * match)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 
hashlimit_mt4_init(struct xt_entry_match * match)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 
hashlimit_mt6_init(struct xt_entry_match * match)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 */
parse_mode(uint32_t * mode,const char * option_arg)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 
hashlimit_parse(struct xt_option_call * cb)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 
hashlimit_mt_parse_v1(struct xt_option_call * cb)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 
hashlimit_mt_parse(struct xt_option_call * cb)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 
hashlimit_check(struct xt_fcheck_call * cb)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 
hashlimit_mt_check_v1(struct xt_fcheck_call * cb)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 
hashlimit_mt_check(struct xt_fcheck_call * cb)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 
print_rate(uint32_t period,int revision)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 
print_bytes(uint64_t avg,uint64_t burst,const char * prefix)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 
print_mode(unsigned int mode,char separator)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 
hashlimit_print(const void * ip,const struct xt_entry_match * match,int numeric)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
hashlimit_mt_print(const struct hashlimit_cfg2 * cfg,unsigned int dmask,int revision)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
hashlimit_mt4_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)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
hashlimit_mt6_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)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
hashlimit_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)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
hashlimit_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)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 
hashlimit_save(const void * ip,const struct xt_entry_match * match)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
hashlimit_mt_save(const struct hashlimit_cfg2 * cfg,const char * name,unsigned int dmask,int revision)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
hashlimit_mt4_save_v1(const void * ip,const struct xt_entry_match * match)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
hashlimit_mt6_save_v1(const void * ip,const struct xt_entry_match * match)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
hashlimit_mt4_save(const void * ip,const struct xt_entry_match * match)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
hashlimit_mt6_save(const void * ip,const struct xt_entry_match * match)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 
_init(void)1002 void _init(void)
1003 {
1004 	xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
1005 }
1006