blob: cd057c5ff3600a17c75aa6dc847584c88fa10d52 [file] [log] [blame]
Patrick McHardy00524b22006-11-13 20:31:42 +00001/* 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
Jan Engelhardt81bd5882008-09-04 17:49:18 +02008 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
9 * Hervé Eychenne <rv@wallfire.org>
Patrick McHardy00524b22006-11-13 20:31:42 +000010 *
11 * Error corections by nmalykh@bilim.com (22.01.2005)
12 */
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +010013#include <stdbool.h>
Jan Engelhardtef18e812008-08-04 12:47:48 +020014#include <stdint.h>
Patrick McHardy00524b22006-11-13 20:31:42 +000015#include <stdio.h>
16#include <string.h>
17#include <stdlib.h>
18#include <getopt.h>
Yasuyuki KOZAKAId62a9db2007-08-04 08:08:20 +000019#include <xtables.h>
Patrick McHardy00524b22006-11-13 20:31:42 +000020#include <stddef.h>
Yasuyuki KOZAKAId62a9db2007-08-04 08:08:20 +000021#include <linux/netfilter/x_tables.h>
Patrick McHardy00524b22006-11-13 20:31:42 +000022#include <linux/netfilter/xt_hashlimit.h>
23
24#define XT_HASHLIMIT_BURST 5
25
26/* miliseconds */
27#define XT_HASHLIMIT_GCINTERVAL 1000
28#define XT_HASHLIMIT_EXPIRE 10000
29
Jan Engelhardt181dead2007-10-04 16:27:07 +000030static void hashlimit_help(void)
Patrick McHardy00524b22006-11-13 20:31:42 +000031{
32 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020033"hashlimit match options:\n"
Patrick McHardy00524b22006-11-13 20:31:42 +000034"--hashlimit <avg> max average match rate\n"
35" [Packets per second unless followed by \n"
36" /sec /minute /hour /day postfixes]\n"
37"--hashlimit-mode <mode> mode is a comma-separated list of\n"
38" dstip,srcip,dstport,srcport\n"
39"--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n"
40"[--hashlimit-burst <num>] number to match in a burst, default %u\n"
41"[--hashlimit-htable-size <num>] number of hashtable buckets\n"
42"[--hashlimit-htable-max <num>] number of hashtable entries\n"
43"[--hashlimit-htable-gcinterval] interval between garbage collection runs\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020044"[--hashlimit-htable-expire] after which time are idle entries expired?\n",
45XT_HASHLIMIT_BURST);
Patrick McHardy00524b22006-11-13 20:31:42 +000046}
47
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +010048static void hashlimit_mt_help(void)
49{
50 printf(
51"hashlimit match options:\n"
52" --hashlimit-upto <avg> max average match rate\n"
53" [Packets per second unless followed by \n"
54" /sec /minute /hour /day postfixes]\n"
55" --hashlimit-above <avg> min average match rate\n"
56" --hashlimit-mode <mode> mode is a comma-separated list of\n"
57" dstip,srcip,dstport,srcport (or none)\n"
58" --hashlimit-srcmask <length> source address grouping prefix length\n"
59" --hashlimit-dstmask <length> destination address grouping prefix length\n"
60" --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
61" --hashlimit-burst <num> number to match in a burst, default %u\n"
62" --hashlimit-htable-size <num> number of hashtable buckets\n"
63" --hashlimit-htable-max <num> number of hashtable entries\n"
64" --hashlimit-htable-gcinterval interval between garbage collection runs\n"
65" --hashlimit-htable-expire after which time are idle entries expired?\n"
66"\n", XT_HASHLIMIT_BURST);
67}
68
Jan Engelhardt181dead2007-10-04 16:27:07 +000069static const struct option hashlimit_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020070 {.name = "hashlimit", .has_arg = true, .val = '%'},
71 {.name = "hashlimit-burst", .has_arg = true, .val = '$'},
72 {.name = "hashlimit-htable-size", .has_arg = true, .val = '&'},
73 {.name = "hashlimit-htable-max", .has_arg = true, .val = '*'},
74 {.name = "hashlimit-htable-gcinterval", .has_arg = true, .val = '('},
75 {.name = "hashlimit-htable-expire", .has_arg = true, .val = ')'},
76 {.name = "hashlimit-mode", .has_arg = true, .val = '_'},
77 {.name = "hashlimit-name", .has_arg = true, .val = '"'},
78 XT_GETOPT_TABLEEND,
Patrick McHardy00524b22006-11-13 20:31:42 +000079};
80
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +010081static const struct option hashlimit_mt_opts[] = {
82 {.name = "hashlimit-upto", .has_arg = true, .val = '%'},
83 {.name = "hashlimit-above", .has_arg = true, .val = '^'},
84 {.name = "hashlimit", .has_arg = true, .val = '%'},
85 {.name = "hashlimit-srcmask", .has_arg = true, .val = '<'},
86 {.name = "hashlimit-dstmask", .has_arg = true, .val = '>'},
87 {.name = "hashlimit-burst", .has_arg = true, .val = '$'},
88 {.name = "hashlimit-htable-size", .has_arg = true, .val = '&'},
89 {.name = "hashlimit-htable-max", .has_arg = true, .val = '*'},
90 {.name = "hashlimit-htable-gcinterval", .has_arg = true, .val = '('},
91 {.name = "hashlimit-htable-expire", .has_arg = true, .val = ')'},
92 {.name = "hashlimit-mode", .has_arg = true, .val = '_'},
93 {.name = "hashlimit-name", .has_arg = true, .val = '"'},
Jan Engelhardt32b8e612010-07-23 21:16:14 +020094 XT_GETOPT_TABLEEND,
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +010095};
96
Patrick McHardy00524b22006-11-13 20:31:42 +000097static
Jan Engelhardt7ac40522011-01-07 12:34:04 +010098int parse_rate(const char *rate, uint32_t *val)
Patrick McHardy00524b22006-11-13 20:31:42 +000099{
100 const char *delim;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100101 uint32_t r;
102 uint32_t mult = 1; /* Seconds by default. */
Patrick McHardy00524b22006-11-13 20:31:42 +0000103
104 delim = strchr(rate, '/');
105 if (delim) {
106 if (strlen(delim+1) == 0)
107 return 0;
108
109 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
110 mult = 1;
111 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
112 mult = 60;
113 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
114 mult = 60*60;
115 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
116 mult = 24*60*60;
117 else
118 return 0;
119 }
120 r = atoi(rate);
121 if (!r)
122 return 0;
123
124 /* This would get mapped to infinite (1/day is minimum they
125 can specify, so we're ok at that end). */
126 if (r / mult > XT_HASHLIMIT_SCALE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100127 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Patrick McHardy00524b22006-11-13 20:31:42 +0000128
129 *val = XT_HASHLIMIT_SCALE * mult / r;
130 return 1;
131}
132
Jan Engelhardt181dead2007-10-04 16:27:07 +0000133static void hashlimit_init(struct xt_entry_match *m)
Patrick McHardy00524b22006-11-13 20:31:42 +0000134{
135 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
136
137 r->cfg.burst = XT_HASHLIMIT_BURST;
138 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
139 r->cfg.expire = XT_HASHLIMIT_EXPIRE;
140
141}
142
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100143static void hashlimit_mt4_init(struct xt_entry_match *match)
144{
145 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
146
147 info->cfg.mode = 0;
148 info->cfg.burst = XT_HASHLIMIT_BURST;
149 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
150 info->cfg.expire = XT_HASHLIMIT_EXPIRE;
151 info->cfg.srcmask = 32;
152 info->cfg.dstmask = 32;
153}
154
155static void hashlimit_mt6_init(struct xt_entry_match *match)
156{
157 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
158
159 info->cfg.mode = 0;
160 info->cfg.burst = XT_HASHLIMIT_BURST;
161 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
162 info->cfg.expire = XT_HASHLIMIT_EXPIRE;
163 info->cfg.srcmask = 128;
164 info->cfg.dstmask = 128;
165}
Patrick McHardy00524b22006-11-13 20:31:42 +0000166
167/* Parse a 'mode' parameter into the required bitmask */
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100168static int parse_mode(uint32_t *mode, char *option_arg)
Patrick McHardy00524b22006-11-13 20:31:42 +0000169{
170 char *tok;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100171 char *arg = strdup(option_arg);
Patrick McHardy00524b22006-11-13 20:31:42 +0000172
173 if (!arg)
174 return -1;
175
Patrick McHardy00524b22006-11-13 20:31:42 +0000176 for (tok = strtok(arg, ",|");
177 tok;
178 tok = strtok(NULL, ",|")) {
179 if (!strcmp(tok, "dstip"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100180 *mode |= XT_HASHLIMIT_HASH_DIP;
Patrick McHardy00524b22006-11-13 20:31:42 +0000181 else if (!strcmp(tok, "srcip"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100182 *mode |= XT_HASHLIMIT_HASH_SIP;
Patrick McHardy00524b22006-11-13 20:31:42 +0000183 else if (!strcmp(tok, "srcport"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100184 *mode |= XT_HASHLIMIT_HASH_SPT;
Patrick McHardy00524b22006-11-13 20:31:42 +0000185 else if (!strcmp(tok, "dstport"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100186 *mode |= XT_HASHLIMIT_HASH_DPT;
Patrick McHardy00524b22006-11-13 20:31:42 +0000187 else {
188 free(arg);
189 return -1;
190 }
191 }
192 free(arg);
193 return 0;
194}
195
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100196enum {
197 PARAM_LIMIT = 1 << 0,
198 PARAM_BURST = 1 << 1,
199 PARAM_MODE = 1 << 2,
200 PARAM_NAME = 1 << 3,
201 PARAM_SIZE = 1 << 4,
202 PARAM_MAX = 1 << 5,
203 PARAM_GCINTERVAL = 1 << 6,
204 PARAM_EXPIRE = 1 << 7,
205 PARAM_SRCMASK = 1 << 8,
206 PARAM_DSTMASK = 1 << 9,
207};
Patrick McHardy00524b22006-11-13 20:31:42 +0000208
Patrick McHardy00524b22006-11-13 20:31:42 +0000209static int
Jan Engelhardt181dead2007-10-04 16:27:07 +0000210hashlimit_parse(int c, char **argv, int invert, unsigned int *flags,
211 const void *entry, struct xt_entry_match **match)
Patrick McHardy00524b22006-11-13 20:31:42 +0000212{
213 struct xt_hashlimit_info *r =
214 (struct xt_hashlimit_info *)(*match)->data;
215 unsigned int num;
216
217 switch(c) {
218 case '%':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100219 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000220 *flags & PARAM_LIMIT);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200221 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Patrick McHardy00524b22006-11-13 20:31:42 +0000222 if (!parse_rate(optarg, &r->cfg.avg))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100223 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000224 "bad rate `%s'", optarg);
225 *flags |= PARAM_LIMIT;
226 break;
227
228 case '$':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100229 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000230 *flags & PARAM_BURST);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200231 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100232 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100233 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000234 "bad --hashlimit-burst `%s'", optarg);
235 r->cfg.burst = num;
236 *flags |= PARAM_BURST;
237 break;
238 case '&':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100239 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000240 *flags & PARAM_SIZE);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200241 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100242 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100243 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000244 "bad --hashlimit-htable-size: `%s'", optarg);
245 r->cfg.size = num;
246 *flags |= PARAM_SIZE;
247 break;
248 case '*':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100249 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000250 *flags & PARAM_MAX);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200251 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100252 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100253 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000254 "bad --hashlimit-htable-max: `%s'", optarg);
255 r->cfg.max = num;
256 *flags |= PARAM_MAX;
257 break;
258 case '(':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100259 xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000260 "--hashlimit-htable-gcinterval",
261 *flags & PARAM_GCINTERVAL);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200262 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100263 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100264 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000265 "bad --hashlimit-htable-gcinterval: `%s'",
266 optarg);
267 /* FIXME: not HZ dependent!! */
268 r->cfg.gc_interval = num;
269 *flags |= PARAM_GCINTERVAL;
270 break;
271 case ')':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100272 xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000273 "--hashlimit-htable-expire", *flags & PARAM_EXPIRE);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200274 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100275 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100276 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000277 "bad --hashlimit-htable-expire: `%s'", optarg);
278 /* FIXME: not HZ dependent */
279 r->cfg.expire = num;
280 *flags |= PARAM_EXPIRE;
281 break;
282 case '_':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100283 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000284 *flags & PARAM_MODE);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200285 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100286 if (parse_mode(&r->cfg.mode, optarg) < 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100287 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000288 "bad --hashlimit-mode: `%s'\n", optarg);
289 *flags |= PARAM_MODE;
290 break;
291 case '"':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100292 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name",
Jan Engelhardtda75a5a2008-01-20 13:39:11 +0000293 *flags & PARAM_NAME);
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200294 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Patrick McHardy00524b22006-11-13 20:31:42 +0000295 if (strlen(optarg) == 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100296 xtables_error(PARAMETER_PROBLEM, "Zero-length name?");
Patrick McHardy00524b22006-11-13 20:31:42 +0000297 strncpy(r->name, optarg, sizeof(r->name));
298 *flags |= PARAM_NAME;
299 break;
Patrick McHardy00524b22006-11-13 20:31:42 +0000300 }
301
302 if (invert)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100303 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000304 "hashlimit does not support invert");
305
306 return 1;
307}
308
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100309static int
310hashlimit_mt_parse(struct xt_hashlimit_mtinfo1 *info, unsigned int *flags,
311 int c, int invert, unsigned int maxmask)
312{
313 unsigned int num;
314
315 switch(c) {
316 case '%': /* --hashlimit / --hashlimit-below */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100317 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-upto",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100318 *flags & PARAM_LIMIT);
319 if (invert)
320 info->cfg.mode |= XT_HASHLIMIT_INVERT;
321 if (!parse_rate(optarg, &info->cfg.avg))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100322 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100323 "--hashlimit-upto", optarg);
324 *flags |= PARAM_LIMIT;
325 return true;
326
327 case '^': /* --hashlimit-above == !--hashlimit-below */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100328 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-above",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100329 *flags & PARAM_LIMIT);
330 if (!invert)
331 info->cfg.mode |= XT_HASHLIMIT_INVERT;
332 if (!parse_rate(optarg, &info->cfg.avg))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100333 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100334 "--hashlimit-above", optarg);
335 *flags |= PARAM_LIMIT;
336 return true;
337
338 case '$': /* --hashlimit-burst */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100339 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100340 *flags & PARAM_BURST);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100341 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100342 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100343 "--hashlimit-burst", optarg);
344 info->cfg.burst = num;
345 *flags |= PARAM_BURST;
346 return true;
347
348 case '&': /* --hashlimit-htable-size */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100349 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100350 *flags & PARAM_SIZE);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100351 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100352 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100353 "--hashlimit-htable-size", optarg);
354 info->cfg.size = num;
355 *flags |= PARAM_SIZE;
356 return true;
357
358 case '*': /* --hashlimit-htable-max */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100359 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100360 *flags & PARAM_MAX);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100361 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100362 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100363 "--hashlimit-htable-max", optarg);
364 info->cfg.max = num;
365 *flags |= PARAM_MAX;
366 return true;
367
368 case '(': /* --hashlimit-htable-gcinterval */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100369 xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100370 "--hashlimit-htable-gcinterval",
371 *flags & PARAM_GCINTERVAL);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100372 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100373 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100374 "--hashlimit-htable-gcinterval", optarg);
375 /* FIXME: not HZ dependent!! */
376 info->cfg.gc_interval = num;
377 *flags |= PARAM_GCINTERVAL;
378 return true;
379
380 case ')': /* --hashlimit-htable-expire */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100381 xtables_param_act(XTF_ONLY_ONCE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100382 "--hashlimit-htable-expire", *flags & PARAM_EXPIRE);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100383 if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100384 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100385 "--hashlimit-htable-expire", optarg);
386 /* FIXME: not HZ dependent */
387 info->cfg.expire = num;
388 *flags |= PARAM_EXPIRE;
389 return true;
390
391 case '_':
Jan Engelhardta41545c2009-01-27 21:27:19 +0100392 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100393 *flags & PARAM_MODE);
394 if (parse_mode(&info->cfg.mode, optarg) < 0)
Jan Engelhardta41545c2009-01-27 21:27:19 +0100395 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100396 "--hashlimit-mode", optarg);
397 *flags |= PARAM_MODE;
398 return true;
399
400 case '"': /* --hashlimit-name */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100401 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100402 *flags & PARAM_NAME);
403 if (strlen(optarg) == 0)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100404 xtables_error(PARAMETER_PROBLEM, "Zero-length name?");
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100405 strncpy(info->name, optarg, sizeof(info->name));
406 info->name[sizeof(info->name)-1] = '\0';
407 *flags |= PARAM_NAME;
408 return true;
409
410 case '<': /* --hashlimit-srcmask */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100411 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-srcmask",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100412 *flags & PARAM_SRCMASK);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100413 if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100414 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100415 "--hashlimit-srcmask", optarg);
416 info->cfg.srcmask = num;
417 *flags |= PARAM_SRCMASK;
418 return true;
419
420 case '>': /* --hashlimit-dstmask */
Jan Engelhardta41545c2009-01-27 21:27:19 +0100421 xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-dstmask",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100422 *flags & PARAM_DSTMASK);
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100423 if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100424 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100425 "--hashlimit-dstmask", optarg);
426 info->cfg.dstmask = num;
427 *flags |= PARAM_DSTMASK;
428 return true;
429 }
430 return false;
431}
432
433static int
434hashlimit_mt4_parse(int c, char **argv, int invert, unsigned int *flags,
435 const void *entry, struct xt_entry_match **match)
436{
437 return hashlimit_mt_parse((void *)(*match)->data,
438 flags, c, invert, 32);
439}
440
441static int
442hashlimit_mt6_parse(int c, char **argv, int invert, unsigned int *flags,
443 const void *entry, struct xt_entry_match **match)
444{
445 return hashlimit_mt_parse((void *)(*match)->data,
446 flags, c, invert, 128);
447}
448
Jan Engelhardt181dead2007-10-04 16:27:07 +0000449static void hashlimit_check(unsigned int flags)
Patrick McHardy00524b22006-11-13 20:31:42 +0000450{
451 if (!(flags & PARAM_LIMIT))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100452 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000453 "You have to specify --hashlimit");
454 if (!(flags & PARAM_MODE))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100455 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000456 "You have to specify --hashlimit-mode");
457 if (!(flags & PARAM_NAME))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100458 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000459 "You have to specify --hashlimit-name");
460}
461
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100462static void hashlimit_mt_check(unsigned int flags)
463{
464 if (!(flags & PARAM_LIMIT))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100465 xtables_error(PARAMETER_PROBLEM, "You have to specify "
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100466 "--hashlimit-upto or --hashlimit-above");
467 if (!(flags & PARAM_NAME))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100468 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100469 "You have to specify --hashlimit-name");
470}
471
Jan Engelhardt0e2abed2007-10-04 16:25:58 +0000472static const struct rates
Patrick McHardy00524b22006-11-13 20:31:42 +0000473{
474 const char *name;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100475 uint32_t mult;
Patrick McHardy00524b22006-11-13 20:31:42 +0000476} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
477 { "hour", XT_HASHLIMIT_SCALE*60*60 },
478 { "min", XT_HASHLIMIT_SCALE*60 },
479 { "sec", XT_HASHLIMIT_SCALE } };
480
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100481static void print_rate(uint32_t period)
Patrick McHardy00524b22006-11-13 20:31:42 +0000482{
483 unsigned int i;
484
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200485 for (i = 1; i < ARRAY_SIZE(rates); ++i)
Patrick McHardy00524b22006-11-13 20:31:42 +0000486 if (period > rates[i].mult
487 || rates[i].mult/period < rates[i].mult%period)
488 break;
Patrick McHardy00524b22006-11-13 20:31:42 +0000489
Jan Engelhardt73866352010-12-18 02:04:59 +0100490 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
Patrick McHardy00524b22006-11-13 20:31:42 +0000491}
492
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100493static void print_mode(unsigned int mode, char separator)
Patrick McHardy00524b22006-11-13 20:31:42 +0000494{
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100495 bool prevmode = false;
Patrick McHardy00524b22006-11-13 20:31:42 +0000496
Jan Engelhardt73866352010-12-18 02:04:59 +0100497 putchar(' ');
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100498 if (mode & XT_HASHLIMIT_HASH_SIP) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000499 fputs("srcip", stdout);
500 prevmode = 1;
501 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100502 if (mode & XT_HASHLIMIT_HASH_SPT) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000503 if (prevmode)
504 putchar(separator);
505 fputs("srcport", stdout);
506 prevmode = 1;
507 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100508 if (mode & XT_HASHLIMIT_HASH_DIP) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000509 if (prevmode)
510 putchar(separator);
511 fputs("dstip", stdout);
512 prevmode = 1;
513 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100514 if (mode & XT_HASHLIMIT_HASH_DPT) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000515 if (prevmode)
516 putchar(separator);
517 fputs("dstport", stdout);
518 }
Patrick McHardy00524b22006-11-13 20:31:42 +0000519}
520
Jan Engelhardt181dead2007-10-04 16:27:07 +0000521static void hashlimit_print(const void *ip,
522 const struct xt_entry_match *match, int numeric)
Patrick McHardy00524b22006-11-13 20:31:42 +0000523{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200524 const struct xt_hashlimit_info *r = (const void *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100525 fputs(" limit: avg", stdout); print_rate(r->cfg.avg);
526 printf(" burst %u", r->cfg.burst);
527 fputs(" mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100528 print_mode(r->cfg.mode, '-');
Patrick McHardy00524b22006-11-13 20:31:42 +0000529 if (r->cfg.size)
Jan Engelhardt73866352010-12-18 02:04:59 +0100530 printf(" htable-size %u", r->cfg.size);
Patrick McHardy00524b22006-11-13 20:31:42 +0000531 if (r->cfg.max)
Jan Engelhardt73866352010-12-18 02:04:59 +0100532 printf(" htable-max %u", r->cfg.max);
Patrick McHardy00524b22006-11-13 20:31:42 +0000533 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100534 printf(" htable-gcinterval %u", r->cfg.gc_interval);
Patrick McHardy00524b22006-11-13 20:31:42 +0000535 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100536 printf(" htable-expire %u", r->cfg.expire);
Patrick McHardy00524b22006-11-13 20:31:42 +0000537}
538
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100539static void
540hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
541{
542 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
Jan Engelhardt73866352010-12-18 02:04:59 +0100543 fputs(" limit: above", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100544 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100545 fputs(" limit: up to", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100546 print_rate(info->cfg.avg);
Jan Engelhardt73866352010-12-18 02:04:59 +0100547 printf(" burst %u", info->cfg.burst);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100548 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
549 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100550 fputs(" mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100551 print_mode(info->cfg.mode, '-');
552 }
553 if (info->cfg.size != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100554 printf(" htable-size %u", info->cfg.size);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100555 if (info->cfg.max != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100556 printf(" htable-max %u", info->cfg.max);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100557 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100558 printf(" htable-gcinterval %u", info->cfg.gc_interval);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100559 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100560 printf(" htable-expire %u", info->cfg.expire);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100561
562 if (info->cfg.srcmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100563 printf(" srcmask %u", info->cfg.srcmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100564 if (info->cfg.dstmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100565 printf(" dstmask %u", info->cfg.dstmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100566}
567
568static void
569hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
570 int numeric)
571{
572 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
573
574 hashlimit_mt_print(info, 32);
575}
576
577static void
578hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
579 int numeric)
580{
581 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
582
583 hashlimit_mt_print(info, 128);
584}
585
Jan Engelhardt181dead2007-10-04 16:27:07 +0000586static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
Patrick McHardy00524b22006-11-13 20:31:42 +0000587{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200588 const struct xt_hashlimit_info *r = (const void *)match->data;
Patrick McHardy00524b22006-11-13 20:31:42 +0000589
Jan Engelhardt73866352010-12-18 02:04:59 +0100590 fputs(" --hashlimit", stdout); print_rate(r->cfg.avg);
591 printf(" --hashlimit-burst %u", r->cfg.burst);
Patrick McHardy00524b22006-11-13 20:31:42 +0000592
Jan Engelhardt73866352010-12-18 02:04:59 +0100593 fputs(" --hashlimit-mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100594 print_mode(r->cfg.mode, ',');
Patrick McHardy00524b22006-11-13 20:31:42 +0000595
Jan Engelhardt73866352010-12-18 02:04:59 +0100596 printf(" --hashlimit-name %s", r->name);
Patrick McHardy00524b22006-11-13 20:31:42 +0000597
598 if (r->cfg.size)
Jan Engelhardt73866352010-12-18 02:04:59 +0100599 printf(" --hashlimit-htable-size %u", r->cfg.size);
Patrick McHardy00524b22006-11-13 20:31:42 +0000600 if (r->cfg.max)
Jan Engelhardt73866352010-12-18 02:04:59 +0100601 printf(" --hashlimit-htable-max %u", r->cfg.max);
Patrick McHardy00524b22006-11-13 20:31:42 +0000602 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100603 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
Patrick McHardy00524b22006-11-13 20:31:42 +0000604 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100605 printf(" --hashlimit-htable-expire %u", r->cfg.expire);
Patrick McHardy00524b22006-11-13 20:31:42 +0000606}
607
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100608static void
609hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
610{
611 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
Jan Engelhardt73866352010-12-18 02:04:59 +0100612 fputs(" --hashlimit-above", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100613 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100614 fputs(" --hashlimit-upto", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100615 print_rate(info->cfg.avg);
Jan Engelhardt73866352010-12-18 02:04:59 +0100616 printf(" --hashlimit-burst %u", info->cfg.burst);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100617
618 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
619 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100620 fputs(" --hashlimit-mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100621 print_mode(info->cfg.mode, ',');
622 }
623
Jan Engelhardt73866352010-12-18 02:04:59 +0100624 printf(" --hashlimit-name %s", info->name);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100625
626 if (info->cfg.size != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100627 printf(" --hashlimit-htable-size %u", info->cfg.size);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100628 if (info->cfg.max != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100629 printf(" --hashlimit-htable-max %u", info->cfg.max);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100630 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100631 printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100632 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100633 printf(" --hashlimit-htable-expire %u", info->cfg.expire);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100634
635 if (info->cfg.srcmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100636 printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100637 if (info->cfg.dstmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100638 printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100639}
640
641static void
642hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
643{
644 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
645
646 hashlimit_mt_save(info, 32);
647}
648
649static void
650hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
651{
652 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
653
654 hashlimit_mt_save(info, 128);
655}
656
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200657static struct xtables_match hashlimit_mt_reg[] = {
658 {
659 .family = NFPROTO_UNSPEC,
660 .name = "hashlimit",
661 .version = XTABLES_VERSION,
662 .revision = 0,
663 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
664 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
665 .help = hashlimit_help,
666 .init = hashlimit_init,
667 .parse = hashlimit_parse,
668 .final_check = hashlimit_check,
669 .print = hashlimit_print,
670 .save = hashlimit_save,
671 .extra_opts = hashlimit_opts,
672 },
673 {
674 .version = XTABLES_VERSION,
675 .name = "hashlimit",
676 .revision = 1,
677 .family = NFPROTO_IPV4,
678 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
679 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
680 .help = hashlimit_mt_help,
681 .init = hashlimit_mt4_init,
682 .parse = hashlimit_mt4_parse,
683 .final_check = hashlimit_mt_check,
684 .print = hashlimit_mt4_print,
685 .save = hashlimit_mt4_save,
686 .extra_opts = hashlimit_mt_opts,
687 },
688 {
689 .version = XTABLES_VERSION,
690 .name = "hashlimit",
691 .revision = 1,
692 .family = NFPROTO_IPV6,
693 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
694 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
695 .help = hashlimit_mt_help,
696 .init = hashlimit_mt6_init,
697 .parse = hashlimit_mt6_parse,
698 .final_check = hashlimit_mt_check,
699 .print = hashlimit_mt6_print,
700 .save = hashlimit_mt6_save,
701 .extra_opts = hashlimit_mt_opts,
702 },
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100703};
704
Patrick McHardy00524b22006-11-13 20:31:42 +0000705void _init(void)
706{
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200707 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
Patrick McHardy00524b22006-11-13 20:31:42 +0000708}