libxt_hashlimit.c revision de1f06dca906bfcb82d7c7c2d555fbf3229d12b6
1/* ip6tables match extension for limiting packets per destination
2 *
3 * (C) 2003-2004 by Harald Welte <laforge@netfilter.org>
4 *
5 * Development of this code was funded by Astaro AG, http://www.astaro.com/
6 *
7 * Based on ipt_limit.c by
8 * Jérôme de Vivie   <devivie@info.enserb.u-bordeaux.fr>
9 * Hervé Eychenne    <rv@wallfire.org>
10 *
11 * Error corections by nmalykh@bilim.com (22.01.2005)
12 */
13#include <stdbool.h>
14#include <stdint.h>
15#include <stdio.h>
16#include <string.h>
17#include <stdlib.h>
18#include <xtables.h>
19#include <linux/netfilter/x_tables.h>
20#include <linux/netfilter/xt_hashlimit.h>
21
22#define XT_HASHLIMIT_BURST	5
23
24/* miliseconds */
25#define XT_HASHLIMIT_GCINTERVAL	1000
26#define XT_HASHLIMIT_EXPIRE	10000
27
28struct hashlimit_mt_udata {
29	uint32_t mult;
30};
31
32static void hashlimit_help(void)
33{
34	printf(
35"hashlimit match options:\n"
36"--hashlimit <avg>		max average match rate\n"
37"                                [Packets per second unless followed by \n"
38"                                /sec /minute /hour /day postfixes]\n"
39"--hashlimit-mode <mode>		mode is a comma-separated list of\n"
40"					dstip,srcip,dstport,srcport\n"
41"--hashlimit-name <name>		name for /proc/net/ipt_hashlimit/\n"
42"[--hashlimit-burst <num>]	number to match in a burst, default %u\n"
43"[--hashlimit-htable-size <num>]	number of hashtable buckets\n"
44"[--hashlimit-htable-max <num>]	number of hashtable entries\n"
45"[--hashlimit-htable-gcinterval]	interval between garbage collection runs\n"
46"[--hashlimit-htable-expire]	after which time are idle entries expired?\n",
47XT_HASHLIMIT_BURST);
48}
49
50enum {
51	O_UPTO = 0,
52	O_ABOVE,
53	O_LIMIT,
54	O_MODE,
55	O_SRCMASK,
56	O_DSTMASK,
57	O_NAME,
58	O_BURST,
59	O_HTABLE_SIZE,
60	O_HTABLE_MAX,
61	O_HTABLE_GCINT,
62	O_HTABLE_EXPIRE,
63	F_UPTO          = 1 << O_UPTO,
64	F_ABOVE         = 1 << O_ABOVE,
65	F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
66};
67
68static void hashlimit_mt_help(void)
69{
70	printf(
71"hashlimit match options:\n"
72"  --hashlimit-upto <avg>           max average match rate\n"
73"                                   [Packets per second unless followed by \n"
74"                                   /sec /minute /hour /day postfixes]\n"
75"  --hashlimit-above <avg>          min average match rate\n"
76"  --hashlimit-mode <mode>          mode is a comma-separated list of\n"
77"                                   dstip,srcip,dstport,srcport (or none)\n"
78"  --hashlimit-srcmask <length>     source address grouping prefix length\n"
79"  --hashlimit-dstmask <length>     destination address grouping prefix length\n"
80"  --hashlimit-name <name>          name for /proc/net/ipt_hashlimit\n"
81"  --hashlimit-burst <num>	    number to match in a burst, default %u\n"
82"  --hashlimit-htable-size <num>    number of hashtable buckets\n"
83"  --hashlimit-htable-max <num>     number of hashtable entries\n"
84"  --hashlimit-htable-gcinterval    interval between garbage collection runs\n"
85"  --hashlimit-htable-expire        after which time are idle entries expired?\n"
86"\n", XT_HASHLIMIT_BURST);
87}
88
89#define s struct xt_hashlimit_info
90static const struct xt_option_entry hashlimit_opts[] = {
91	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
92	 .type = XTTYPE_STRING},
93	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
94	 .min = 1, .max = 10000, .flags = XTOPT_PUT,
95	 XTOPT_POINTER(s, cfg.burst)},
96	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
97	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
98	 XTOPT_POINTER(s, cfg.size)},
99	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
100	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
101	 XTOPT_POINTER(s, cfg.max)},
102	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
103	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
104	 XTOPT_POINTER(s, cfg.gc_interval)},
105	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
106	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
107	 XTOPT_POINTER(s, cfg.expire)},
108	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
109	 .flags = XTOPT_MAND},
110	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
111	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
112	XTOPT_TABLEEND,
113};
114#undef s
115
116#define s struct xt_hashlimit_mtinfo1
117static const struct xt_option_entry hashlimit_mt_opts[] = {
118	{.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
119	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
120	{.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
121	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
122	{.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
123	 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
124	{.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
125	{.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
126	{.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
127	 .min = 1, .max = 10000, .flags = XTOPT_PUT,
128	 XTOPT_POINTER(s, cfg.burst)},
129	{.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
130	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
131	 XTOPT_POINTER(s, cfg.size)},
132	{.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
133	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
134	 XTOPT_POINTER(s, cfg.max)},
135	{.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
136	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
137	 XTOPT_POINTER(s, cfg.gc_interval)},
138	{.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
139	 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
140	 XTOPT_POINTER(s, cfg.expire)},
141	{.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
142	{.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
143	 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
144	XTOPT_TABLEEND,
145};
146#undef s
147
148static
149int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
150{
151	const char *delim;
152	uint32_t r;
153
154	ud->mult = 1;  /* Seconds by default. */
155	delim = strchr(rate, '/');
156	if (delim) {
157		if (strlen(delim+1) == 0)
158			return 0;
159
160		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
161			ud->mult = 1;
162		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
163			ud->mult = 60;
164		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
165			ud->mult = 60*60;
166		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
167			ud->mult = 24*60*60;
168		else
169			return 0;
170	}
171	r = atoi(rate);
172	if (!r)
173		return 0;
174
175	/* This would get mapped to infinite (1/day is minimum they
176           can specify, so we're ok at that end). */
177	if (r / ud->mult > XT_HASHLIMIT_SCALE)
178		xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
179
180	*val = XT_HASHLIMIT_SCALE * ud->mult / r;
181	return 1;
182}
183
184static void hashlimit_init(struct xt_entry_match *m)
185{
186	struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
187
188	r->cfg.burst = XT_HASHLIMIT_BURST;
189	r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
190	r->cfg.expire = XT_HASHLIMIT_EXPIRE;
191
192}
193
194static void hashlimit_mt4_init(struct xt_entry_match *match)
195{
196	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
197
198	info->cfg.mode        = 0;
199	info->cfg.burst       = XT_HASHLIMIT_BURST;
200	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
201	info->cfg.expire      = XT_HASHLIMIT_EXPIRE;
202	info->cfg.srcmask     = 32;
203	info->cfg.dstmask     = 32;
204}
205
206static void hashlimit_mt6_init(struct xt_entry_match *match)
207{
208	struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
209
210	info->cfg.mode        = 0;
211	info->cfg.burst       = XT_HASHLIMIT_BURST;
212	info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
213	info->cfg.expire      = XT_HASHLIMIT_EXPIRE;
214	info->cfg.srcmask     = 128;
215	info->cfg.dstmask     = 128;
216}
217
218/* Parse a 'mode' parameter into the required bitmask */
219static int parse_mode(uint32_t *mode, const char *option_arg)
220{
221	char *tok;
222	char *arg = strdup(option_arg);
223
224	if (!arg)
225		return -1;
226
227	for (tok = strtok(arg, ",|");
228	     tok;
229	     tok = strtok(NULL, ",|")) {
230		if (!strcmp(tok, "dstip"))
231			*mode |= XT_HASHLIMIT_HASH_DIP;
232		else if (!strcmp(tok, "srcip"))
233			*mode |= XT_HASHLIMIT_HASH_SIP;
234		else if (!strcmp(tok, "srcport"))
235			*mode |= XT_HASHLIMIT_HASH_SPT;
236		else if (!strcmp(tok, "dstport"))
237			*mode |= XT_HASHLIMIT_HASH_DPT;
238		else {
239			free(arg);
240			return -1;
241		}
242	}
243	free(arg);
244	return 0;
245}
246
247static void hashlimit_parse(struct xt_option_call *cb)
248{
249	struct xt_hashlimit_info *info = cb->data;
250
251	xtables_option_parse(cb);
252	switch (cb->entry->id) {
253	case O_UPTO:
254		if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
255			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
256			          "--hashlimit-upto", cb->arg);
257		break;
258	case O_MODE:
259		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
260			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
261			          "--hashlimit-mode", cb->arg);
262		break;
263	}
264}
265
266static void hashlimit_mt_parse(struct xt_option_call *cb)
267{
268	struct xt_hashlimit_mtinfo1 *info = cb->data;
269
270	xtables_option_parse(cb);
271	switch (cb->entry->id) {
272	case O_UPTO:
273		if (cb->invert)
274			info->cfg.mode |= XT_HASHLIMIT_INVERT;
275		if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
276			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
277			          "--hashlimit-upto", cb->arg);
278		break;
279	case O_ABOVE:
280		if (!cb->invert)
281			info->cfg.mode |= XT_HASHLIMIT_INVERT;
282		if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
283			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
284			          "--hashlimit-above", cb->arg);
285		break;
286	case O_MODE:
287		if (parse_mode(&info->cfg.mode, cb->arg) < 0)
288			xtables_param_act(XTF_BAD_VALUE, "hashlimit",
289			          "--hashlimit-mode", cb->arg);
290		break;
291	case O_SRCMASK:
292		info->cfg.srcmask = cb->val.hlen;
293		break;
294	case O_DSTMASK:
295		info->cfg.dstmask = cb->val.hlen;
296		break;
297	}
298}
299
300static void hashlimit_check(struct xt_fcheck_call *cb)
301{
302	const struct hashlimit_mt_udata *udata = cb->udata;
303	struct xt_hashlimit_info *info = cb->data;
304
305	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
306		xtables_error(PARAMETER_PROBLEM,
307				"You have to specify --hashlimit");
308	if (!(cb->xflags & F_HTABLE_EXPIRE))
309		info->cfg.expire = udata->mult * 1000; /* from s to msec */
310}
311
312static void hashlimit_mt_check(struct xt_fcheck_call *cb)
313{
314	const struct hashlimit_mt_udata *udata = cb->udata;
315	struct xt_hashlimit_mtinfo1 *info = cb->data;
316
317	if (!(cb->xflags & (F_UPTO | F_ABOVE)))
318		xtables_error(PARAMETER_PROBLEM,
319				"You have to specify --hashlimit");
320	if (!(cb->xflags & F_HTABLE_EXPIRE))
321		info->cfg.expire = udata->mult * 1000; /* from s to msec */
322}
323
324static const struct rates
325{
326	const char *name;
327	uint32_t mult;
328} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
329	      { "hour", XT_HASHLIMIT_SCALE*60*60 },
330	      { "min", XT_HASHLIMIT_SCALE*60 },
331	      { "sec", XT_HASHLIMIT_SCALE } };
332
333static void print_rate(uint32_t period)
334{
335	unsigned int i;
336
337	for (i = 1; i < ARRAY_SIZE(rates); ++i)
338		if (period > rates[i].mult
339            || rates[i].mult/period < rates[i].mult%period)
340			break;
341
342	printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
343}
344
345static void print_mode(unsigned int mode, char separator)
346{
347	bool prevmode = false;
348
349	putchar(' ');
350	if (mode & XT_HASHLIMIT_HASH_SIP) {
351		fputs("srcip", stdout);
352		prevmode = 1;
353	}
354	if (mode & XT_HASHLIMIT_HASH_SPT) {
355		if (prevmode)
356			putchar(separator);
357		fputs("srcport", stdout);
358		prevmode = 1;
359	}
360	if (mode & XT_HASHLIMIT_HASH_DIP) {
361		if (prevmode)
362			putchar(separator);
363		fputs("dstip", stdout);
364		prevmode = 1;
365	}
366	if (mode & XT_HASHLIMIT_HASH_DPT) {
367		if (prevmode)
368			putchar(separator);
369		fputs("dstport", stdout);
370	}
371}
372
373static void hashlimit_print(const void *ip,
374                            const struct xt_entry_match *match, int numeric)
375{
376	const struct xt_hashlimit_info *r = (const void *)match->data;
377	fputs(" limit: avg", stdout); print_rate(r->cfg.avg);
378	printf(" burst %u", r->cfg.burst);
379	fputs(" mode", stdout);
380	print_mode(r->cfg.mode, '-');
381	if (r->cfg.size)
382		printf(" htable-size %u", r->cfg.size);
383	if (r->cfg.max)
384		printf(" htable-max %u", r->cfg.max);
385	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
386		printf(" htable-gcinterval %u", r->cfg.gc_interval);
387	if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
388		printf(" htable-expire %u", r->cfg.expire);
389}
390
391static void
392hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
393{
394	if (info->cfg.mode & XT_HASHLIMIT_INVERT)
395		fputs(" limit: above", stdout);
396	else
397		fputs(" limit: up to", stdout);
398	print_rate(info->cfg.avg);
399	printf(" burst %u", info->cfg.burst);
400	if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
401	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
402		fputs(" mode", stdout);
403		print_mode(info->cfg.mode, '-');
404	}
405	if (info->cfg.size != 0)
406		printf(" htable-size %u", info->cfg.size);
407	if (info->cfg.max != 0)
408		printf(" htable-max %u", info->cfg.max);
409	if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
410		printf(" htable-gcinterval %u", info->cfg.gc_interval);
411	if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
412		printf(" htable-expire %u", info->cfg.expire);
413
414	if (info->cfg.srcmask != dmask)
415		printf(" srcmask %u", info->cfg.srcmask);
416	if (info->cfg.dstmask != dmask)
417		printf(" dstmask %u", info->cfg.dstmask);
418}
419
420static void
421hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
422                   int numeric)
423{
424	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
425
426	hashlimit_mt_print(info, 32);
427}
428
429static void
430hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
431                   int numeric)
432{
433	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
434
435	hashlimit_mt_print(info, 128);
436}
437
438static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
439{
440	const struct xt_hashlimit_info *r = (const void *)match->data;
441
442	fputs(" --hashlimit", stdout); print_rate(r->cfg.avg);
443	printf(" --hashlimit-burst %u", r->cfg.burst);
444
445	fputs(" --hashlimit-mode", stdout);
446	print_mode(r->cfg.mode, ',');
447
448	printf(" --hashlimit-name %s", r->name);
449
450	if (r->cfg.size)
451		printf(" --hashlimit-htable-size %u", r->cfg.size);
452	if (r->cfg.max)
453		printf(" --hashlimit-htable-max %u", r->cfg.max);
454	if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
455		printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
456	if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
457		printf(" --hashlimit-htable-expire %u", r->cfg.expire);
458}
459
460static void
461hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
462{
463	if (info->cfg.mode & XT_HASHLIMIT_INVERT)
464		fputs(" --hashlimit-above", stdout);
465	else
466		fputs(" --hashlimit-upto", stdout);
467	print_rate(info->cfg.avg);
468	printf(" --hashlimit-burst %u", info->cfg.burst);
469
470	if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
471	    XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
472		fputs(" --hashlimit-mode", stdout);
473		print_mode(info->cfg.mode, ',');
474	}
475
476	printf(" --hashlimit-name %s", info->name);
477
478	if (info->cfg.size != 0)
479		printf(" --hashlimit-htable-size %u", info->cfg.size);
480	if (info->cfg.max != 0)
481		printf(" --hashlimit-htable-max %u", info->cfg.max);
482	if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
483		printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
484	if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
485		printf(" --hashlimit-htable-expire %u", info->cfg.expire);
486
487	if (info->cfg.srcmask != dmask)
488		printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
489	if (info->cfg.dstmask != dmask)
490		printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
491}
492
493static void
494hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
495{
496	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
497
498	hashlimit_mt_save(info, 32);
499}
500
501static void
502hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
503{
504	const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
505
506	hashlimit_mt_save(info, 128);
507}
508
509static struct xtables_match hashlimit_mt_reg[] = {
510	{
511		.family        = NFPROTO_UNSPEC,
512		.name          = "hashlimit",
513		.version       = XTABLES_VERSION,
514		.revision      = 0,
515		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
516		.userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
517		.help          = hashlimit_help,
518		.init          = hashlimit_init,
519		.x6_parse      = hashlimit_parse,
520		.x6_fcheck     = hashlimit_check,
521		.print         = hashlimit_print,
522		.save          = hashlimit_save,
523		.x6_options    = hashlimit_opts,
524		.udata_size    = sizeof(struct hashlimit_mt_udata),
525	},
526	{
527		.version       = XTABLES_VERSION,
528		.name          = "hashlimit",
529		.revision      = 1,
530		.family        = NFPROTO_IPV4,
531		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
532		.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
533		.help          = hashlimit_mt_help,
534		.init          = hashlimit_mt4_init,
535		.x6_parse      = hashlimit_mt_parse,
536		.x6_fcheck     = hashlimit_mt_check,
537		.print         = hashlimit_mt4_print,
538		.save          = hashlimit_mt4_save,
539		.x6_options    = hashlimit_mt_opts,
540		.udata_size    = sizeof(struct hashlimit_mt_udata),
541	},
542	{
543		.version       = XTABLES_VERSION,
544		.name          = "hashlimit",
545		.revision      = 1,
546		.family        = NFPROTO_IPV6,
547		.size          = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
548		.userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
549		.help          = hashlimit_mt_help,
550		.init          = hashlimit_mt6_init,
551		.x6_parse      = hashlimit_mt_parse,
552		.x6_fcheck     = hashlimit_mt_check,
553		.print         = hashlimit_mt6_print,
554		.save          = hashlimit_mt6_save,
555		.x6_options    = hashlimit_mt_opts,
556		.udata_size    = sizeof(struct hashlimit_mt_udata),
557	},
558};
559
560void _init(void)
561{
562	xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
563}
564