blob: a838680cba12dc4e47068f68578c80357cd4e6e9 [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>
Yasuyuki KOZAKAId62a9db2007-08-04 08:08:20 +000018#include <xtables.h>
Yasuyuki KOZAKAId62a9db2007-08-04 08:08:20 +000019#include <linux/netfilter/x_tables.h>
Patrick McHardy00524b22006-11-13 20:31:42 +000020#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
Jan Engelhardt68146da2011-06-22 11:18:19 +020028struct hashlimit_mt_udata {
29 uint32_t mult;
30};
31
Jan Engelhardt181dead2007-10-04 16:27:07 +000032static void hashlimit_help(void)
Patrick McHardy00524b22006-11-13 20:31:42 +000033{
34 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020035"hashlimit match options:\n"
Patrick McHardy00524b22006-11-13 20:31:42 +000036"--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"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020046"[--hashlimit-htable-expire] after which time are idle entries expired?\n",
47XT_HASHLIMIT_BURST);
Patrick McHardy00524b22006-11-13 20:31:42 +000048}
49
Jan Engelhardtfe02f762011-05-04 23:18:57 +020050enum {
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,
Jan Engelhardt68146da2011-06-22 11:18:19 +020063 F_UPTO = 1 << O_UPTO,
64 F_ABOVE = 1 << O_ABOVE,
65 F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
Jan Engelhardtfe02f762011-05-04 23:18:57 +020066};
67
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +010068static 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
Jan Engelhardtfe02f762011-05-04 23:18:57 +020089#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, .flags = XTOPT_INVERT},
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,
Patrick McHardy00524b22006-11-13 20:31:42 +0000113};
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200114#undef s
Patrick McHardy00524b22006-11-13 20:31:42 +0000115
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200116#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,
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100145};
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200146#undef s
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100147
Patrick McHardy00524b22006-11-13 20:31:42 +0000148static
Jan Engelhardt68146da2011-06-22 11:18:19 +0200149int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud)
Patrick McHardy00524b22006-11-13 20:31:42 +0000150{
151 const char *delim;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100152 uint32_t r;
Patrick McHardy00524b22006-11-13 20:31:42 +0000153
Jan Engelhardt68146da2011-06-22 11:18:19 +0200154 ud->mult = 1; /* Seconds by default. */
Patrick McHardy00524b22006-11-13 20:31:42 +0000155 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)
Jan Engelhardt68146da2011-06-22 11:18:19 +0200161 ud->mult = 1;
Patrick McHardy00524b22006-11-13 20:31:42 +0000162 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
Jan Engelhardt68146da2011-06-22 11:18:19 +0200163 ud->mult = 60;
Patrick McHardy00524b22006-11-13 20:31:42 +0000164 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
Jan Engelhardt68146da2011-06-22 11:18:19 +0200165 ud->mult = 60*60;
Patrick McHardy00524b22006-11-13 20:31:42 +0000166 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
Jan Engelhardt68146da2011-06-22 11:18:19 +0200167 ud->mult = 24*60*60;
Patrick McHardy00524b22006-11-13 20:31:42 +0000168 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). */
Jan Engelhardt68146da2011-06-22 11:18:19 +0200177 if (r / ud->mult > XT_HASHLIMIT_SCALE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100178 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Patrick McHardy00524b22006-11-13 20:31:42 +0000179
Jan Engelhardt68146da2011-06-22 11:18:19 +0200180 *val = XT_HASHLIMIT_SCALE * ud->mult / r;
Patrick McHardy00524b22006-11-13 20:31:42 +0000181 return 1;
182}
183
Jan Engelhardt181dead2007-10-04 16:27:07 +0000184static void hashlimit_init(struct xt_entry_match *m)
Patrick McHardy00524b22006-11-13 20:31:42 +0000185{
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
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100194static 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}
Patrick McHardy00524b22006-11-13 20:31:42 +0000217
218/* Parse a 'mode' parameter into the required bitmask */
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200219static int parse_mode(uint32_t *mode, const char *option_arg)
Patrick McHardy00524b22006-11-13 20:31:42 +0000220{
221 char *tok;
Jan Engelhardtdbb77542008-02-11 00:33:30 +0100222 char *arg = strdup(option_arg);
Patrick McHardy00524b22006-11-13 20:31:42 +0000223
224 if (!arg)
225 return -1;
226
Patrick McHardy00524b22006-11-13 20:31:42 +0000227 for (tok = strtok(arg, ",|");
228 tok;
229 tok = strtok(NULL, ",|")) {
230 if (!strcmp(tok, "dstip"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100231 *mode |= XT_HASHLIMIT_HASH_DIP;
Patrick McHardy00524b22006-11-13 20:31:42 +0000232 else if (!strcmp(tok, "srcip"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100233 *mode |= XT_HASHLIMIT_HASH_SIP;
Patrick McHardy00524b22006-11-13 20:31:42 +0000234 else if (!strcmp(tok, "srcport"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100235 *mode |= XT_HASHLIMIT_HASH_SPT;
Patrick McHardy00524b22006-11-13 20:31:42 +0000236 else if (!strcmp(tok, "dstport"))
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100237 *mode |= XT_HASHLIMIT_HASH_DPT;
Patrick McHardy00524b22006-11-13 20:31:42 +0000238 else {
239 free(arg);
240 return -1;
241 }
242 }
243 free(arg);
244 return 0;
245}
246
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200247static void hashlimit_parse(struct xt_option_call *cb)
Patrick McHardy00524b22006-11-13 20:31:42 +0000248{
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200249 struct xt_hashlimit_info *info = cb->data;
Patrick McHardy00524b22006-11-13 20:31:42 +0000250
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200251 xtables_option_parse(cb);
252 switch (cb->entry->id) {
253 case O_UPTO:
254 if (cb->invert)
255 info->cfg.mode |= XT_HASHLIMIT_INVERT;
Jan Engelhardt68146da2011-06-22 11:18:19 +0200256 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200257 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
258 "--hashlimit-upto", cb->arg);
Patrick McHardy00524b22006-11-13 20:31:42 +0000259 break;
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200260 case O_ABOVE:
261 if (!cb->invert)
262 info->cfg.mode |= XT_HASHLIMIT_INVERT;
Jan Engelhardt68146da2011-06-22 11:18:19 +0200263 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200264 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
265 "--hashlimit-above", cb->arg);
Patrick McHardy00524b22006-11-13 20:31:42 +0000266 break;
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200267 case O_MODE:
268 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
269 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
270 "--hashlimit-mode", cb->arg);
Patrick McHardy00524b22006-11-13 20:31:42 +0000271 break;
Patrick McHardy00524b22006-11-13 20:31:42 +0000272 }
Patrick McHardy00524b22006-11-13 20:31:42 +0000273}
274
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200275static void hashlimit_mt_parse(struct xt_option_call *cb)
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100276{
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200277 struct xt_hashlimit_mtinfo1 *info = cb->data;
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100278
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200279 xtables_option_parse(cb);
280 switch (cb->entry->id) {
281 case O_UPTO:
282 if (cb->invert)
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100283 info->cfg.mode |= XT_HASHLIMIT_INVERT;
Jan Engelhardt68146da2011-06-22 11:18:19 +0200284 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100285 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200286 "--hashlimit-upto", cb->arg);
287 break;
288 case O_ABOVE:
289 if (!cb->invert)
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100290 info->cfg.mode |= XT_HASHLIMIT_INVERT;
Jan Engelhardt68146da2011-06-22 11:18:19 +0200291 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata))
Jan Engelhardta41545c2009-01-27 21:27:19 +0100292 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200293 "--hashlimit-above", cb->arg);
294 break;
295 case O_MODE:
296 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
Jan Engelhardta41545c2009-01-27 21:27:19 +0100297 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200298 "--hashlimit-mode", cb->arg);
299 break;
300 case O_SRCMASK:
301 info->cfg.srcmask = cb->val.hlen;
302 break;
303 case O_DSTMASK:
304 info->cfg.dstmask = cb->val.hlen;
305 break;
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100306 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100307}
308
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200309static void hashlimit_check(struct xt_fcheck_call *cb)
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100310{
Jan Engelhardt68146da2011-06-22 11:18:19 +0200311 const struct hashlimit_mt_udata *udata = cb->udata;
312 struct xt_hashlimit_info *info = cb->data;
313
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200314 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100315 xtables_error(PARAMETER_PROBLEM,
Patrick McHardy00524b22006-11-13 20:31:42 +0000316 "You have to specify --hashlimit");
Jan Engelhardt68146da2011-06-22 11:18:19 +0200317 if (!(cb->xflags & F_HTABLE_EXPIRE))
318 info->cfg.expire = udata->mult;
319}
320
321static void hashlimit_mt_check(struct xt_fcheck_call *cb)
322{
323 const struct hashlimit_mt_udata *udata = cb->udata;
324 struct xt_hashlimit_mtinfo1 *info = cb->data;
325
326 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
327 xtables_error(PARAMETER_PROBLEM,
328 "You have to specify --hashlimit");
329 if (!(cb->xflags & F_HTABLE_EXPIRE))
330 info->cfg.expire = udata->mult;
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100331}
332
Jan Engelhardt0e2abed2007-10-04 16:25:58 +0000333static const struct rates
Patrick McHardy00524b22006-11-13 20:31:42 +0000334{
335 const char *name;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100336 uint32_t mult;
Patrick McHardy00524b22006-11-13 20:31:42 +0000337} rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
338 { "hour", XT_HASHLIMIT_SCALE*60*60 },
339 { "min", XT_HASHLIMIT_SCALE*60 },
340 { "sec", XT_HASHLIMIT_SCALE } };
341
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100342static void print_rate(uint32_t period)
Patrick McHardy00524b22006-11-13 20:31:42 +0000343{
344 unsigned int i;
345
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200346 for (i = 1; i < ARRAY_SIZE(rates); ++i)
Patrick McHardy00524b22006-11-13 20:31:42 +0000347 if (period > rates[i].mult
348 || rates[i].mult/period < rates[i].mult%period)
349 break;
Patrick McHardy00524b22006-11-13 20:31:42 +0000350
Jan Engelhardt73866352010-12-18 02:04:59 +0100351 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
Patrick McHardy00524b22006-11-13 20:31:42 +0000352}
353
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100354static void print_mode(unsigned int mode, char separator)
Patrick McHardy00524b22006-11-13 20:31:42 +0000355{
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100356 bool prevmode = false;
Patrick McHardy00524b22006-11-13 20:31:42 +0000357
Jan Engelhardt73866352010-12-18 02:04:59 +0100358 putchar(' ');
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100359 if (mode & XT_HASHLIMIT_HASH_SIP) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000360 fputs("srcip", stdout);
361 prevmode = 1;
362 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100363 if (mode & XT_HASHLIMIT_HASH_SPT) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000364 if (prevmode)
365 putchar(separator);
366 fputs("srcport", stdout);
367 prevmode = 1;
368 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100369 if (mode & XT_HASHLIMIT_HASH_DIP) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000370 if (prevmode)
371 putchar(separator);
372 fputs("dstip", stdout);
373 prevmode = 1;
374 }
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100375 if (mode & XT_HASHLIMIT_HASH_DPT) {
Patrick McHardy00524b22006-11-13 20:31:42 +0000376 if (prevmode)
377 putchar(separator);
378 fputs("dstport", stdout);
379 }
Patrick McHardy00524b22006-11-13 20:31:42 +0000380}
381
Jan Engelhardt181dead2007-10-04 16:27:07 +0000382static void hashlimit_print(const void *ip,
383 const struct xt_entry_match *match, int numeric)
Patrick McHardy00524b22006-11-13 20:31:42 +0000384{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200385 const struct xt_hashlimit_info *r = (const void *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100386 fputs(" limit: avg", stdout); print_rate(r->cfg.avg);
387 printf(" burst %u", r->cfg.burst);
388 fputs(" mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100389 print_mode(r->cfg.mode, '-');
Patrick McHardy00524b22006-11-13 20:31:42 +0000390 if (r->cfg.size)
Jan Engelhardt73866352010-12-18 02:04:59 +0100391 printf(" htable-size %u", r->cfg.size);
Patrick McHardy00524b22006-11-13 20:31:42 +0000392 if (r->cfg.max)
Jan Engelhardt73866352010-12-18 02:04:59 +0100393 printf(" htable-max %u", r->cfg.max);
Patrick McHardy00524b22006-11-13 20:31:42 +0000394 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100395 printf(" htable-gcinterval %u", r->cfg.gc_interval);
Patrick McHardy00524b22006-11-13 20:31:42 +0000396 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100397 printf(" htable-expire %u", r->cfg.expire);
Patrick McHardy00524b22006-11-13 20:31:42 +0000398}
399
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100400static void
401hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
402{
403 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
Jan Engelhardt73866352010-12-18 02:04:59 +0100404 fputs(" limit: above", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100405 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100406 fputs(" limit: up to", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100407 print_rate(info->cfg.avg);
Jan Engelhardt73866352010-12-18 02:04:59 +0100408 printf(" burst %u", info->cfg.burst);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100409 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
410 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100411 fputs(" mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100412 print_mode(info->cfg.mode, '-');
413 }
414 if (info->cfg.size != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100415 printf(" htable-size %u", info->cfg.size);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100416 if (info->cfg.max != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100417 printf(" htable-max %u", info->cfg.max);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100418 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100419 printf(" htable-gcinterval %u", info->cfg.gc_interval);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100420 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100421 printf(" htable-expire %u", info->cfg.expire);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100422
423 if (info->cfg.srcmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100424 printf(" srcmask %u", info->cfg.srcmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100425 if (info->cfg.dstmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100426 printf(" dstmask %u", info->cfg.dstmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100427}
428
429static void
430hashlimit_mt4_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, 32);
436}
437
438static void
439hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
440 int numeric)
441{
442 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
443
444 hashlimit_mt_print(info, 128);
445}
446
Jan Engelhardt181dead2007-10-04 16:27:07 +0000447static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
Patrick McHardy00524b22006-11-13 20:31:42 +0000448{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200449 const struct xt_hashlimit_info *r = (const void *)match->data;
Patrick McHardy00524b22006-11-13 20:31:42 +0000450
Jan Engelhardt73866352010-12-18 02:04:59 +0100451 fputs(" --hashlimit", stdout); print_rate(r->cfg.avg);
452 printf(" --hashlimit-burst %u", r->cfg.burst);
Patrick McHardy00524b22006-11-13 20:31:42 +0000453
Jan Engelhardt73866352010-12-18 02:04:59 +0100454 fputs(" --hashlimit-mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100455 print_mode(r->cfg.mode, ',');
Patrick McHardy00524b22006-11-13 20:31:42 +0000456
Jan Engelhardt73866352010-12-18 02:04:59 +0100457 printf(" --hashlimit-name %s", r->name);
Patrick McHardy00524b22006-11-13 20:31:42 +0000458
459 if (r->cfg.size)
Jan Engelhardt73866352010-12-18 02:04:59 +0100460 printf(" --hashlimit-htable-size %u", r->cfg.size);
Patrick McHardy00524b22006-11-13 20:31:42 +0000461 if (r->cfg.max)
Jan Engelhardt73866352010-12-18 02:04:59 +0100462 printf(" --hashlimit-htable-max %u", r->cfg.max);
Patrick McHardy00524b22006-11-13 20:31:42 +0000463 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100464 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
Patrick McHardy00524b22006-11-13 20:31:42 +0000465 if (r->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100466 printf(" --hashlimit-htable-expire %u", r->cfg.expire);
Patrick McHardy00524b22006-11-13 20:31:42 +0000467}
468
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100469static void
470hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask)
471{
472 if (info->cfg.mode & XT_HASHLIMIT_INVERT)
Jan Engelhardt73866352010-12-18 02:04:59 +0100473 fputs(" --hashlimit-above", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100474 else
Jan Engelhardt73866352010-12-18 02:04:59 +0100475 fputs(" --hashlimit-upto", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100476 print_rate(info->cfg.avg);
Jan Engelhardt73866352010-12-18 02:04:59 +0100477 printf(" --hashlimit-burst %u", info->cfg.burst);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100478
479 if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
480 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
Jan Engelhardt73866352010-12-18 02:04:59 +0100481 fputs(" --hashlimit-mode", stdout);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100482 print_mode(info->cfg.mode, ',');
483 }
484
Jan Engelhardt73866352010-12-18 02:04:59 +0100485 printf(" --hashlimit-name %s", info->name);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100486
487 if (info->cfg.size != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100488 printf(" --hashlimit-htable-size %u", info->cfg.size);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100489 if (info->cfg.max != 0)
Jan Engelhardt73866352010-12-18 02:04:59 +0100490 printf(" --hashlimit-htable-max %u", info->cfg.max);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100491 if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
Jan Engelhardt73866352010-12-18 02:04:59 +0100492 printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100493 if (info->cfg.expire != XT_HASHLIMIT_EXPIRE)
Jan Engelhardt73866352010-12-18 02:04:59 +0100494 printf(" --hashlimit-htable-expire %u", info->cfg.expire);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100495
496 if (info->cfg.srcmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100497 printf(" --hashlimit-srcmask %u", info->cfg.srcmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100498 if (info->cfg.dstmask != dmask)
Jan Engelhardt73866352010-12-18 02:04:59 +0100499 printf(" --hashlimit-dstmask %u", info->cfg.dstmask);
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100500}
501
502static void
503hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
504{
505 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
506
507 hashlimit_mt_save(info, 32);
508}
509
510static void
511hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
512{
513 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
514
515 hashlimit_mt_save(info, 128);
516}
517
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200518static struct xtables_match hashlimit_mt_reg[] = {
519 {
520 .family = NFPROTO_UNSPEC,
521 .name = "hashlimit",
522 .version = XTABLES_VERSION,
523 .revision = 0,
524 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
525 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
526 .help = hashlimit_help,
527 .init = hashlimit_init,
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200528 .x6_parse = hashlimit_parse,
529 .x6_fcheck = hashlimit_check,
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200530 .print = hashlimit_print,
531 .save = hashlimit_save,
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200532 .x6_options = hashlimit_mt_opts,
Jan Engelhardt68146da2011-06-22 11:18:19 +0200533 .udata_size = sizeof(struct hashlimit_mt_udata),
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200534 },
535 {
536 .version = XTABLES_VERSION,
537 .name = "hashlimit",
538 .revision = 1,
539 .family = NFPROTO_IPV4,
540 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
541 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
542 .help = hashlimit_mt_help,
543 .init = hashlimit_mt4_init,
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200544 .x6_parse = hashlimit_mt_parse,
Jan Engelhardt68146da2011-06-22 11:18:19 +0200545 .x6_fcheck = hashlimit_mt_check,
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200546 .print = hashlimit_mt4_print,
547 .save = hashlimit_mt4_save,
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200548 .x6_options = hashlimit_mt_opts,
Jan Engelhardt68146da2011-06-22 11:18:19 +0200549 .udata_size = sizeof(struct hashlimit_mt_udata),
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200550 },
551 {
552 .version = XTABLES_VERSION,
553 .name = "hashlimit",
554 .revision = 1,
555 .family = NFPROTO_IPV6,
556 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
557 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
558 .help = hashlimit_mt_help,
559 .init = hashlimit_mt6_init,
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200560 .x6_parse = hashlimit_mt_parse,
Jan Engelhardt68146da2011-06-22 11:18:19 +0200561 .x6_fcheck = hashlimit_mt_check,
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200562 .print = hashlimit_mt6_print,
563 .save = hashlimit_mt6_save,
Jan Engelhardtfe02f762011-05-04 23:18:57 +0200564 .x6_options = hashlimit_mt_opts,
Jan Engelhardt68146da2011-06-22 11:18:19 +0200565 .udata_size = sizeof(struct hashlimit_mt_udata),
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200566 },
Jan Engelhardt9a8c77f2008-02-11 00:55:33 +0100567};
568
Patrick McHardy00524b22006-11-13 20:31:42 +0000569void _init(void)
570{
Jan Engelhardtf2a77522009-06-25 20:12:12 +0200571 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
Patrick McHardy00524b22006-11-13 20:31:42 +0000572}