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 _DEFAULT_SOURCE 1
15 #define _ISOC99_SOURCE 1
16 #include <inttypes.h>
17 #include <math.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <xtables.h>
24 #include <linux/netfilter/x_tables.h>
25 #include <linux/netfilter/xt_hashlimit.h>
26
27 #define XT_HASHLIMIT_BURST 5
28 #define XT_HASHLIMIT_BURST_MAX_v1 10000
29 #define XT_HASHLIMIT_BURST_MAX 1000000
30
31 #define XT_HASHLIMIT_BYTE_EXPIRE 15
32 #define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60
33
34 /* miliseconds */
35 #define XT_HASHLIMIT_GCINTERVAL 1000
36
37 struct hashlimit_mt_udata {
38 uint32_t mult;
39 };
40
hashlimit_help(void)41 static void hashlimit_help(void)
42 {
43 printf(
44 "hashlimit match options:\n"
45 "--hashlimit <avg> max average match rate\n"
46 " [Packets per second unless followed by \n"
47 " /sec /minute /hour /day postfixes]\n"
48 "--hashlimit-mode <mode> mode is a comma-separated list of\n"
49 " dstip,srcip,dstport,srcport\n"
50 "--hashlimit-name <name> name for /proc/net/ipt_hashlimit/\n"
51 "[--hashlimit-burst <num>] number to match in a burst, default %u\n"
52 "[--hashlimit-htable-size <num>] number of hashtable buckets\n"
53 "[--hashlimit-htable-max <num>] number of hashtable entries\n"
54 "[--hashlimit-htable-gcinterval] interval between garbage collection runs\n"
55 "[--hashlimit-htable-expire] after which time are idle entries expired?\n",
56 XT_HASHLIMIT_BURST);
57 }
58
59 enum {
60 O_UPTO = 0,
61 O_ABOVE,
62 O_LIMIT,
63 O_MODE,
64 O_SRCMASK,
65 O_DSTMASK,
66 O_NAME,
67 O_BURST,
68 O_HTABLE_SIZE,
69 O_HTABLE_MAX,
70 O_HTABLE_GCINT,
71 O_HTABLE_EXPIRE,
72 O_RATEMATCH,
73 O_INTERVAL,
74 F_BURST = 1 << O_BURST,
75 F_UPTO = 1 << O_UPTO,
76 F_ABOVE = 1 << O_ABOVE,
77 F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE,
78 F_RATEMATCH = 1 << O_RATEMATCH,
79 };
80
hashlimit_mt_help(void)81 static void hashlimit_mt_help(void)
82 {
83 printf(
84 "hashlimit match options:\n"
85 " --hashlimit-upto <avg> max average match rate\n"
86 " [Packets per second unless followed by \n"
87 " /sec /minute /hour /day postfixes]\n"
88 " --hashlimit-above <avg> min average match rate\n"
89 " --hashlimit-mode <mode> mode is a comma-separated list of\n"
90 " dstip,srcip,dstport,srcport (or none)\n"
91 " --hashlimit-srcmask <length> source address grouping prefix length\n"
92 " --hashlimit-dstmask <length> destination address grouping prefix length\n"
93 " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
94 " --hashlimit-burst <num> number to match in a burst, default %u\n"
95 " --hashlimit-htable-size <num> number of hashtable buckets\n"
96 " --hashlimit-htable-max <num> number of hashtable entries\n"
97 " --hashlimit-htable-gcinterval interval between garbage collection runs\n"
98 " --hashlimit-htable-expire after which time are idle entries expired?\n"
99 "\n", XT_HASHLIMIT_BURST);
100 }
101
hashlimit_mt_help_v3(void)102 static void hashlimit_mt_help_v3(void)
103 {
104 printf(
105 "hashlimit match options:\n"
106 " --hashlimit-upto <avg> max average match rate\n"
107 " [Packets per second unless followed by \n"
108 " /sec /minute /hour /day postfixes]\n"
109 " --hashlimit-above <avg> min average match rate\n"
110 " --hashlimit-mode <mode> mode is a comma-separated list of\n"
111 " dstip,srcip,dstport,srcport (or none)\n"
112 " --hashlimit-srcmask <length> source address grouping prefix length\n"
113 " --hashlimit-dstmask <length> destination address grouping prefix length\n"
114 " --hashlimit-name <name> name for /proc/net/ipt_hashlimit\n"
115 " --hashlimit-burst <num> number to match in a burst, default %u\n"
116 " --hashlimit-htable-size <num> number of hashtable buckets\n"
117 " --hashlimit-htable-max <num> number of hashtable entries\n"
118 " --hashlimit-htable-gcinterval interval between garbage collection runs\n"
119 " --hashlimit-htable-expire after which time are idle entries expired?\n"
120 " --hashlimit-rate-match rate match the flow without rate-limiting it\n"
121 " --hashlimit-rate-interval interval in seconds for hashlimit-rate-match\n"
122 "\n", XT_HASHLIMIT_BURST);
123 }
124
125 #define s struct xt_hashlimit_info
126 static const struct xt_option_entry hashlimit_opts[] = {
127 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
128 .type = XTTYPE_STRING},
129 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
130 .min = 1, .max = XT_HASHLIMIT_BURST_MAX_v1, .flags = XTOPT_PUT,
131 XTOPT_POINTER(s, cfg.burst)},
132 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
133 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
134 XTOPT_POINTER(s, cfg.size)},
135 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
136 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
137 XTOPT_POINTER(s, cfg.max)},
138 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
139 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
140 XTOPT_POINTER(s, cfg.gc_interval)},
141 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
142 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
143 XTOPT_POINTER(s, cfg.expire)},
144 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING,
145 .flags = XTOPT_MAND},
146 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
147 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
148 XTOPT_TABLEEND,
149 };
150 #undef s
151
152 #define s struct xt_hashlimit_mtinfo1
153 static const struct xt_option_entry hashlimit_mt_opts_v1[] = {
154 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
155 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
156 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
157 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
158 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
159 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
160 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
161 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
162 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
163 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
164 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
165 XTOPT_POINTER(s, cfg.size)},
166 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
167 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
168 XTOPT_POINTER(s, cfg.max)},
169 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
170 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
171 XTOPT_POINTER(s, cfg.gc_interval)},
172 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
173 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
174 XTOPT_POINTER(s, cfg.expire)},
175 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
176 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
177 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
178 XTOPT_TABLEEND,
179 };
180 #undef s
181
182 #define s struct xt_hashlimit_mtinfo2
183 static const struct xt_option_entry hashlimit_mt_opts_v2[] = {
184 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
185 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
186 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
187 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
188 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
189 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
190 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
191 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
192 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
193 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
194 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
195 XTOPT_POINTER(s, cfg.size)},
196 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
197 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
198 XTOPT_POINTER(s, cfg.max)},
199 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
200 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
201 XTOPT_POINTER(s, cfg.gc_interval)},
202 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
203 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
204 XTOPT_POINTER(s, cfg.expire)},
205 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
206 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
207 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
208 XTOPT_TABLEEND,
209 };
210 #undef s
211
212 #define s struct xt_hashlimit_mtinfo3
213 static const struct xt_option_entry hashlimit_mt_opts[] = {
214 {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE,
215 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
216 {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO,
217 .type = XTTYPE_STRING, .flags = XTOPT_INVERT},
218 {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE,
219 .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */
220 {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN},
221 {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN},
222 {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING},
223 {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE,
224 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
225 XTOPT_POINTER(s, cfg.size)},
226 {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX,
227 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
228 XTOPT_POINTER(s, cfg.max)},
229 {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT,
230 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
231 XTOPT_POINTER(s, cfg.gc_interval)},
232 {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE,
233 .type = XTTYPE_UINT32, .flags = XTOPT_PUT,
234 XTOPT_POINTER(s, cfg.expire)},
235 {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING},
236 {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING,
237 .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1},
238 {.name = "hashlimit-rate-match", .id = O_RATEMATCH, .type = XTTYPE_NONE},
239 {.name = "hashlimit-rate-interval", .id = O_INTERVAL, .type = XTTYPE_STRING},
240 XTOPT_TABLEEND,
241 };
242 #undef s
243
244 static int
cfg_copy(struct hashlimit_cfg3 * to,const void * from,int revision)245 cfg_copy(struct hashlimit_cfg3 *to, const void *from, int revision)
246 {
247 if (revision == 1) {
248 struct hashlimit_cfg1 *cfg = (struct hashlimit_cfg1 *)from;
249
250 to->mode = cfg->mode;
251 to->avg = cfg->avg;
252 to->burst = cfg->burst;
253 to->size = cfg->size;
254 to->max = cfg->max;
255 to->gc_interval = cfg->gc_interval;
256 to->expire = cfg->expire;
257 to->srcmask = cfg->srcmask;
258 to->dstmask = cfg->dstmask;
259 } else if (revision == 2) {
260 struct hashlimit_cfg2 *cfg = (struct hashlimit_cfg2 *)from;
261
262 to->mode = cfg->mode;
263 to->avg = cfg->avg;
264 to->burst = cfg->burst;
265 to->size = cfg->size;
266 to->max = cfg->max;
267 to->gc_interval = cfg->gc_interval;
268 to->expire = cfg->expire;
269 to->srcmask = cfg->srcmask;
270 to->dstmask = cfg->dstmask;
271 } else if (revision == 3) {
272 memcpy(to, from, sizeof(struct hashlimit_cfg3));
273 } else {
274 return -EINVAL;
275 }
276
277 return 0;
278 }
279
cost_to_bytes(uint64_t cost)280 static uint64_t cost_to_bytes(uint64_t cost)
281 {
282 uint64_t r;
283
284 r = cost ? UINT32_MAX / cost : UINT32_MAX;
285 r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT;
286 return r;
287 }
288
bytes_to_cost(uint64_t bytes)289 static uint64_t bytes_to_cost(uint64_t bytes)
290 {
291 uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT;
292 return UINT32_MAX / (r+1);
293 }
294
get_factor(int chr)295 static uint32_t get_factor(int chr)
296 {
297 switch (chr) {
298 case 'm': return 1024 * 1024;
299 case 'k': return 1024;
300 }
301 return 1;
302 }
303
burst_error_v1(void)304 static void burst_error_v1(void)
305 {
306 xtables_error(PARAMETER_PROBLEM, "bad value for option "
307 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX_v1);
308 }
309
burst_error(void)310 static void burst_error(void)
311 {
312 xtables_error(PARAMETER_PROBLEM, "bad value for option "
313 "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX);
314 }
315
parse_burst(const char * burst,int revision)316 static uint64_t parse_burst(const char *burst, int revision)
317 {
318 uintmax_t v;
319 char *end;
320 uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
321 uint64_t burst_max = (revision == 1) ?
322 XT_HASHLIMIT_BURST_MAX_v1 : XT_HASHLIMIT_BURST_MAX;
323
324 if (!xtables_strtoul(burst, &end, &v, 1, max) ||
325 (*end == 0 && v > burst_max)) {
326 if (revision == 1)
327 burst_error_v1();
328 else
329 burst_error();
330 }
331
332 v *= get_factor(*end);
333 if (v > max)
334 xtables_error(PARAMETER_PROBLEM, "bad value for option "
335 "\"--hashlimit-burst\", value \"%s\" too large "
336 "(max %"PRIu64"mb).", burst, max/1024/1024);
337 return v;
338 }
339
parse_bytes(const char * rate,void * val,struct hashlimit_mt_udata * ud,int revision)340 static bool parse_bytes(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
341 {
342 unsigned int factor = 1;
343 uint64_t tmp, r;
344 const char *mode = strstr(rate, "b/s");
345 uint64_t max = (revision == 1) ? UINT32_MAX : UINT64_MAX;
346
347 if (!mode || mode == rate)
348 return false;
349
350 mode--;
351 r = atoll(rate);
352 if (r == 0)
353 return false;
354
355 factor = get_factor(*mode);
356 tmp = (uint64_t) r * factor;
357 if (tmp > max)
358 xtables_error(PARAMETER_PROBLEM,
359 "Rate value too large \"%"PRIu64"\" (max %"PRIu64")\n",
360 tmp, max);
361
362 tmp = bytes_to_cost(tmp);
363 if (tmp == 0)
364 xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate);
365
366 ud->mult = XT_HASHLIMIT_BYTE_EXPIRE;
367
368 if(revision == 1)
369 *((uint32_t*)val) = tmp;
370 else
371 *((uint64_t*)val) = tmp;
372
373 return true;
374 }
375
376 static
parse_rate(const char * rate,void * val,struct hashlimit_mt_udata * ud,int revision)377 int parse_rate(const char *rate, void *val, struct hashlimit_mt_udata *ud, int revision)
378 {
379 const char *delim;
380 uint64_t tmp, r;
381 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
382
383 ud->mult = 1; /* Seconds by default. */
384 delim = strchr(rate, '/');
385 if (delim) {
386 if (strlen(delim+1) == 0)
387 return 0;
388
389 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
390 ud->mult = 1;
391 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
392 ud->mult = 60;
393 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
394 ud->mult = 60*60;
395 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
396 ud->mult = 24*60*60;
397 else
398 return 0;
399 }
400 r = atoll(rate);
401 if (!r)
402 return 0;
403
404 tmp = scale * ud->mult / r;
405 if (tmp == 0)
406 /*
407 * The rate maps to infinity. (1/day is the minimum they can
408 * specify, so we are ok at that end).
409 */
410 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
411
412 if(revision == 1)
413 *((uint32_t*)val) = tmp;
414 else
415 *((uint64_t*)val) = tmp;
416
417 return 1;
418 }
419
parse_interval(const char * rate,uint32_t * val)420 static int parse_interval(const char *rate, uint32_t *val)
421 {
422 int r = atoi(rate);
423 if (r <= 0)
424 return 0;
425
426 *val = r;
427 return 1;
428 }
429
hashlimit_init(struct xt_entry_match * m)430 static void hashlimit_init(struct xt_entry_match *m)
431 {
432 struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data;
433
434 r->cfg.burst = XT_HASHLIMIT_BURST;
435 r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
436
437 }
438
hashlimit_mt4_init_v1(struct xt_entry_match * match)439 static void hashlimit_mt4_init_v1(struct xt_entry_match *match)
440 {
441 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
442
443 info->cfg.mode = 0;
444 info->cfg.burst = XT_HASHLIMIT_BURST;
445 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
446 info->cfg.srcmask = 32;
447 info->cfg.dstmask = 32;
448 }
449
hashlimit_mt6_init_v1(struct xt_entry_match * match)450 static void hashlimit_mt6_init_v1(struct xt_entry_match *match)
451 {
452 struct xt_hashlimit_mtinfo1 *info = (void *)match->data;
453
454 info->cfg.mode = 0;
455 info->cfg.burst = XT_HASHLIMIT_BURST;
456 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
457 info->cfg.srcmask = 128;
458 info->cfg.dstmask = 128;
459 }
460
hashlimit_mt4_init_v2(struct xt_entry_match * match)461 static void hashlimit_mt4_init_v2(struct xt_entry_match *match)
462 {
463 struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
464
465 info->cfg.mode = 0;
466 info->cfg.burst = XT_HASHLIMIT_BURST;
467 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
468 info->cfg.srcmask = 32;
469 info->cfg.dstmask = 32;
470 }
471
hashlimit_mt6_init_v2(struct xt_entry_match * match)472 static void hashlimit_mt6_init_v2(struct xt_entry_match *match)
473 {
474 struct xt_hashlimit_mtinfo2 *info = (void *)match->data;
475
476 info->cfg.mode = 0;
477 info->cfg.burst = XT_HASHLIMIT_BURST;
478 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
479 info->cfg.srcmask = 128;
480 info->cfg.dstmask = 128;
481 }
482
hashlimit_mt4_init(struct xt_entry_match * match)483 static void hashlimit_mt4_init(struct xt_entry_match *match)
484 {
485 struct xt_hashlimit_mtinfo3 *info = (void *)match->data;
486
487 info->cfg.mode = 0;
488 info->cfg.burst = XT_HASHLIMIT_BURST;
489 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
490 info->cfg.srcmask = 32;
491 info->cfg.dstmask = 32;
492 info->cfg.interval = 0;
493 }
494
hashlimit_mt6_init(struct xt_entry_match * match)495 static void hashlimit_mt6_init(struct xt_entry_match *match)
496 {
497 struct xt_hashlimit_mtinfo3 *info = (void *)match->data;
498
499 info->cfg.mode = 0;
500 info->cfg.burst = XT_HASHLIMIT_BURST;
501 info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL;
502 info->cfg.srcmask = 128;
503 info->cfg.dstmask = 128;
504 info->cfg.interval = 0;
505 }
506
507 /* Parse a 'mode' parameter into the required bitmask */
parse_mode(uint32_t * mode,const char * option_arg)508 static int parse_mode(uint32_t *mode, const char *option_arg)
509 {
510 char *tok;
511 char *arg = strdup(option_arg);
512
513 if (!arg)
514 return -1;
515
516 for (tok = strtok(arg, ",|");
517 tok;
518 tok = strtok(NULL, ",|")) {
519 if (!strcmp(tok, "dstip"))
520 *mode |= XT_HASHLIMIT_HASH_DIP;
521 else if (!strcmp(tok, "srcip"))
522 *mode |= XT_HASHLIMIT_HASH_SIP;
523 else if (!strcmp(tok, "srcport"))
524 *mode |= XT_HASHLIMIT_HASH_SPT;
525 else if (!strcmp(tok, "dstport"))
526 *mode |= XT_HASHLIMIT_HASH_DPT;
527 else {
528 free(arg);
529 return -1;
530 }
531 }
532 free(arg);
533 return 0;
534 }
535
hashlimit_parse(struct xt_option_call * cb)536 static void hashlimit_parse(struct xt_option_call *cb)
537 {
538 struct xt_hashlimit_info *info = cb->data;
539
540 xtables_option_parse(cb);
541 switch (cb->entry->id) {
542 case O_UPTO:
543 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
544 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
545 "--hashlimit-upto", cb->arg);
546 break;
547 case O_MODE:
548 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
549 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
550 "--hashlimit-mode", cb->arg);
551 break;
552 }
553 }
554
hashlimit_mt_parse_v1(struct xt_option_call * cb)555 static void hashlimit_mt_parse_v1(struct xt_option_call *cb)
556 {
557 struct xt_hashlimit_mtinfo1 *info = cb->data;
558
559 xtables_option_parse(cb);
560 switch (cb->entry->id) {
561 case O_BURST:
562 info->cfg.burst = parse_burst(cb->arg, 1);
563 break;
564 case O_UPTO:
565 if (cb->invert)
566 info->cfg.mode |= XT_HASHLIMIT_INVERT;
567 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
568 info->cfg.mode |= XT_HASHLIMIT_BYTES;
569 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
570 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
571 "--hashlimit-upto", cb->arg);
572 break;
573 case O_ABOVE:
574 if (!cb->invert)
575 info->cfg.mode |= XT_HASHLIMIT_INVERT;
576 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
577 info->cfg.mode |= XT_HASHLIMIT_BYTES;
578 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
579 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
580 "--hashlimit-above", cb->arg);
581 break;
582 case O_MODE:
583 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
584 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
585 "--hashlimit-mode", cb->arg);
586 break;
587 case O_SRCMASK:
588 info->cfg.srcmask = cb->val.hlen;
589 break;
590 case O_DSTMASK:
591 info->cfg.dstmask = cb->val.hlen;
592 break;
593 }
594 }
595
hashlimit_mt_parse_v2(struct xt_option_call * cb)596 static void hashlimit_mt_parse_v2(struct xt_option_call *cb)
597 {
598 struct xt_hashlimit_mtinfo2 *info = cb->data;
599
600 xtables_option_parse(cb);
601 switch (cb->entry->id) {
602 case O_BURST:
603 info->cfg.burst = parse_burst(cb->arg, 2);
604 break;
605 case O_UPTO:
606 if (cb->invert)
607 info->cfg.mode |= XT_HASHLIMIT_INVERT;
608 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
609 info->cfg.mode |= XT_HASHLIMIT_BYTES;
610 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
611 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
612 "--hashlimit-upto", cb->arg);
613 break;
614 case O_ABOVE:
615 if (!cb->invert)
616 info->cfg.mode |= XT_HASHLIMIT_INVERT;
617 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
618 info->cfg.mode |= XT_HASHLIMIT_BYTES;
619 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
620 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
621 "--hashlimit-above", cb->arg);
622 break;
623 case O_MODE:
624 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
625 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
626 "--hashlimit-mode", cb->arg);
627 break;
628 case O_SRCMASK:
629 info->cfg.srcmask = cb->val.hlen;
630 break;
631 case O_DSTMASK:
632 info->cfg.dstmask = cb->val.hlen;
633 break;
634 }
635 }
636
hashlimit_mt_parse(struct xt_option_call * cb)637 static void hashlimit_mt_parse(struct xt_option_call *cb)
638 {
639 struct xt_hashlimit_mtinfo3 *info = cb->data;
640
641 xtables_option_parse(cb);
642 switch (cb->entry->id) {
643 case O_BURST:
644 info->cfg.burst = parse_burst(cb->arg, 2);
645 break;
646 case O_UPTO:
647 if (cb->invert)
648 info->cfg.mode |= XT_HASHLIMIT_INVERT;
649 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
650 info->cfg.mode |= XT_HASHLIMIT_BYTES;
651 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
652 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
653 "--hashlimit-upto", cb->arg);
654 break;
655 case O_ABOVE:
656 if (!cb->invert)
657 info->cfg.mode |= XT_HASHLIMIT_INVERT;
658 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
659 info->cfg.mode |= XT_HASHLIMIT_BYTES;
660 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
661 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
662 "--hashlimit-above", cb->arg);
663 break;
664 case O_MODE:
665 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
666 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
667 "--hashlimit-mode", cb->arg);
668 break;
669 case O_SRCMASK:
670 info->cfg.srcmask = cb->val.hlen;
671 break;
672 case O_DSTMASK:
673 info->cfg.dstmask = cb->val.hlen;
674 break;
675 case O_RATEMATCH:
676 info->cfg.mode |= XT_HASHLIMIT_RATE_MATCH;
677 break;
678 case O_INTERVAL:
679 if (!parse_interval(cb->arg, &info->cfg.interval))
680 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
681 "--hashlimit-rate-interval", cb->arg);
682 }
683 }
684
hashlimit_check(struct xt_fcheck_call * cb)685 static void hashlimit_check(struct xt_fcheck_call *cb)
686 {
687 const struct hashlimit_mt_udata *udata = cb->udata;
688 struct xt_hashlimit_info *info = cb->data;
689
690 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
691 xtables_error(PARAMETER_PROBLEM,
692 "You have to specify --hashlimit");
693 if (!(cb->xflags & F_HTABLE_EXPIRE))
694 info->cfg.expire = udata->mult * 1000; /* from s to msec */
695 }
696
hashlimit_mt_check_v1(struct xt_fcheck_call * cb)697 static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)
698 {
699 const struct hashlimit_mt_udata *udata = cb->udata;
700 struct xt_hashlimit_mtinfo1 *info = cb->data;
701
702 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
703 xtables_error(PARAMETER_PROBLEM,
704 "You have to specify --hashlimit");
705 if (!(cb->xflags & F_HTABLE_EXPIRE))
706 info->cfg.expire = udata->mult * 1000; /* from s to msec */
707
708 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
709 uint32_t burst = 0;
710 if (cb->xflags & F_BURST) {
711 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
712 xtables_error(PARAMETER_PROBLEM,
713 "burst cannot be smaller than %"PRIu64"b",
714 cost_to_bytes(info->cfg.avg));
715
716 burst = info->cfg.burst;
717 burst /= cost_to_bytes(info->cfg.avg);
718 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
719 burst++;
720 if (!(cb->xflags & F_HTABLE_EXPIRE))
721 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
722 }
723 info->cfg.burst = burst;
724 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX_v1)
725 burst_error_v1();
726 }
727
hashlimit_mt_check_v2(struct xt_fcheck_call * cb)728 static void hashlimit_mt_check_v2(struct xt_fcheck_call *cb)
729 {
730 const struct hashlimit_mt_udata *udata = cb->udata;
731 struct xt_hashlimit_mtinfo2 *info = cb->data;
732
733 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
734 xtables_error(PARAMETER_PROBLEM,
735 "You have to specify --hashlimit");
736 if (!(cb->xflags & F_HTABLE_EXPIRE))
737 info->cfg.expire = udata->mult * 1000; /* from s to msec */
738
739 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
740 uint32_t burst = 0;
741 if (cb->xflags & F_BURST) {
742 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
743 xtables_error(PARAMETER_PROBLEM,
744 "burst cannot be smaller than %"PRIu64"b",
745 cost_to_bytes(info->cfg.avg));
746
747 burst = info->cfg.burst;
748 burst /= cost_to_bytes(info->cfg.avg);
749 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
750 burst++;
751 if (!(cb->xflags & F_HTABLE_EXPIRE))
752 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
753 }
754 info->cfg.burst = burst;
755 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
756 burst_error();
757 }
758
hashlimit_mt_check(struct xt_fcheck_call * cb)759 static void hashlimit_mt_check(struct xt_fcheck_call *cb)
760 {
761 const struct hashlimit_mt_udata *udata = cb->udata;
762 struct xt_hashlimit_mtinfo3 *info = cb->data;
763
764 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
765 xtables_error(PARAMETER_PROBLEM,
766 "You have to specify --hashlimit");
767 if (!(cb->xflags & F_HTABLE_EXPIRE))
768 info->cfg.expire = udata->mult * 1000; /* from s to msec */
769
770 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
771 uint32_t burst = 0;
772 if (cb->xflags & F_BURST) {
773 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
774 xtables_error(PARAMETER_PROBLEM,
775 "burst cannot be smaller than %"PRIu64"b", cost_to_bytes(info->cfg.avg));
776
777 burst = info->cfg.burst;
778 burst /= cost_to_bytes(info->cfg.avg);
779 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
780 burst++;
781 if (!(cb->xflags & F_HTABLE_EXPIRE))
782 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
783 }
784 info->cfg.burst = burst;
785 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
786 burst_error();
787
788 if (cb->xflags & F_RATEMATCH) {
789 if (!(info->cfg.mode & XT_HASHLIMIT_BYTES))
790 info->cfg.avg /= udata->mult;
791
792 if (info->cfg.interval == 0) {
793 if (info->cfg.mode & XT_HASHLIMIT_BYTES)
794 info->cfg.interval = 1;
795 else
796 info->cfg.interval = udata->mult;
797 }
798 }
799 }
800
801 struct rates {
802 const char *name;
803 uint64_t mult;
804 } rates_v1[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
805 { "hour", XT_HASHLIMIT_SCALE*60*60 },
806 { "min", XT_HASHLIMIT_SCALE*60 },
807 { "sec", XT_HASHLIMIT_SCALE } };
808
809 static const struct rates rates[] = {
810 { "day", XT_HASHLIMIT_SCALE_v2*24*60*60 },
811 { "hour", XT_HASHLIMIT_SCALE_v2*60*60 },
812 { "min", XT_HASHLIMIT_SCALE_v2*60 },
813 { "sec", XT_HASHLIMIT_SCALE_v2 } };
814
print_rate(uint64_t period,int revision)815 static uint32_t print_rate(uint64_t period, int revision)
816 {
817 unsigned int i;
818 const struct rates *_rates = (revision == 1) ? rates_v1 : rates;
819 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
820
821 if (period == 0) {
822 printf(" %f", INFINITY);
823 return 0;
824 }
825
826 for (i = 1; i < ARRAY_SIZE(rates); ++i)
827 if (period > _rates[i].mult
828 || _rates[i].mult/period < _rates[i].mult%period)
829 break;
830
831 printf(" %"PRIu64"/%s", _rates[i-1].mult / period, _rates[i-1].name);
832 /* return in msec */
833 return _rates[i-1].mult / scale * 1000;
834 }
835
836 static const struct {
837 const char *name;
838 uint32_t thresh;
839 } units[] = {
840 { "m", 1024 * 1024 },
841 { "k", 1024 },
842 { "", 1 },
843 };
844
print_bytes(uint64_t avg,uint64_t burst,const char * prefix)845 static uint32_t print_bytes(uint64_t avg, uint64_t burst, const char *prefix)
846 {
847 unsigned int i;
848 unsigned long long r;
849
850 r = cost_to_bytes(avg);
851
852 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
853 if (r >= units[i].thresh &&
854 bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
855 break;
856 printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
857
858 if (burst == 0)
859 return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
860
861 r *= burst;
862 printf(" %s", prefix);
863 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
864 if (r >= units[i].thresh)
865 break;
866
867 printf("burst %llu%sb", r / units[i].thresh, units[i].name);
868 return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
869 }
870
print_mode(unsigned int mode,char separator)871 static void print_mode(unsigned int mode, char separator)
872 {
873 bool prevmode = false;
874
875 putchar(' ');
876 if (mode & XT_HASHLIMIT_HASH_SIP) {
877 fputs("srcip", stdout);
878 prevmode = 1;
879 }
880 if (mode & XT_HASHLIMIT_HASH_SPT) {
881 if (prevmode)
882 putchar(separator);
883 fputs("srcport", stdout);
884 prevmode = 1;
885 }
886 if (mode & XT_HASHLIMIT_HASH_DIP) {
887 if (prevmode)
888 putchar(separator);
889 fputs("dstip", stdout);
890 prevmode = 1;
891 }
892 if (mode & XT_HASHLIMIT_HASH_DPT) {
893 if (prevmode)
894 putchar(separator);
895 fputs("dstport", stdout);
896 }
897 }
898
hashlimit_print(const void * ip,const struct xt_entry_match * match,int numeric)899 static void hashlimit_print(const void *ip,
900 const struct xt_entry_match *match, int numeric)
901 {
902 const struct xt_hashlimit_info *r = (const void *)match->data;
903 uint32_t quantum;
904
905 fputs(" limit: avg", stdout);
906 quantum = print_rate(r->cfg.avg, 1);
907 printf(" burst %u", r->cfg.burst);
908 fputs(" mode", stdout);
909 print_mode(r->cfg.mode, '-');
910 if (r->cfg.size)
911 printf(" htable-size %u", r->cfg.size);
912 if (r->cfg.max)
913 printf(" htable-max %u", r->cfg.max);
914 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
915 printf(" htable-gcinterval %u", r->cfg.gc_interval);
916 if (r->cfg.expire != quantum)
917 printf(" htable-expire %u", r->cfg.expire);
918 }
919
920 static void
hashlimit_mt_print(const struct hashlimit_cfg3 * cfg,unsigned int dmask,int revision)921 hashlimit_mt_print(const struct hashlimit_cfg3 *cfg, unsigned int dmask, int revision)
922 {
923 uint64_t quantum;
924 uint64_t period;
925
926 if (cfg->mode & XT_HASHLIMIT_INVERT)
927 fputs(" limit: above", stdout);
928 else
929 fputs(" limit: up to", stdout);
930
931 if (cfg->mode & XT_HASHLIMIT_BYTES) {
932 quantum = print_bytes(cfg->avg, cfg->burst, "");
933 } else {
934 if (revision == 3) {
935 period = cfg->avg;
936 if (cfg->interval != 0)
937 period *= cfg->interval;
938
939 quantum = print_rate(period, revision);
940 } else {
941 quantum = print_rate(cfg->avg, revision);
942 }
943 printf(" burst %llu", cfg->burst);
944 }
945 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
946 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
947 fputs(" mode", stdout);
948 print_mode(cfg->mode, '-');
949 }
950 if (cfg->size != 0)
951 printf(" htable-size %u", cfg->size);
952 if (cfg->max != 0)
953 printf(" htable-max %u", cfg->max);
954 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
955 printf(" htable-gcinterval %u", cfg->gc_interval);
956 if (cfg->expire != quantum)
957 printf(" htable-expire %u", cfg->expire);
958
959 if (cfg->srcmask != dmask)
960 printf(" srcmask %u", cfg->srcmask);
961 if (cfg->dstmask != dmask)
962 printf(" dstmask %u", cfg->dstmask);
963
964 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
965 printf(" rate-match");
966
967 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
968 if (cfg->interval != 1)
969 printf(" rate-interval %u", cfg->interval);
970 }
971
972 static void
hashlimit_mt4_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)973 hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match,
974 int numeric)
975 {
976 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
977 struct hashlimit_cfg3 cfg;
978 int ret;
979
980 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
981
982 if (ret)
983 xtables_error(OTHER_PROBLEM, "unknown revision");
984
985 hashlimit_mt_print(&cfg, 32, 1);
986 }
987
988 static void
hashlimit_mt6_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)989 hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match,
990 int numeric)
991 {
992 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
993 struct hashlimit_cfg3 cfg;
994 int ret;
995
996 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
997
998 if (ret)
999 xtables_error(OTHER_PROBLEM, "unknown revision");
1000
1001 hashlimit_mt_print(&cfg, 128, 1);
1002 }
1003
1004 static void
hashlimit_mt4_print_v2(const void * ip,const struct xt_entry_match * match,int numeric)1005 hashlimit_mt4_print_v2(const void *ip, const struct xt_entry_match *match,
1006 int numeric)
1007 {
1008 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1009 struct hashlimit_cfg3 cfg;
1010 int ret;
1011
1012 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1013
1014 if (ret)
1015 xtables_error(OTHER_PROBLEM, "unknown revision");
1016
1017 hashlimit_mt_print(&cfg, 32, 2);
1018 }
1019
1020 static void
hashlimit_mt6_print_v2(const void * ip,const struct xt_entry_match * match,int numeric)1021 hashlimit_mt6_print_v2(const void *ip, const struct xt_entry_match *match,
1022 int numeric)
1023 {
1024 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1025 struct hashlimit_cfg3 cfg;
1026 int ret;
1027
1028 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1029
1030 if (ret)
1031 xtables_error(OTHER_PROBLEM, "unknown revision");
1032
1033 hashlimit_mt_print(&cfg, 128, 2);
1034 }
1035 static void
hashlimit_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)1036 hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
1037 int numeric)
1038 {
1039 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1040
1041 hashlimit_mt_print(&info->cfg, 32, 3);
1042 }
1043
1044 static void
hashlimit_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)1045 hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
1046 int numeric)
1047 {
1048 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1049
1050 hashlimit_mt_print(&info->cfg, 128, 3);
1051 }
1052
hashlimit_save(const void * ip,const struct xt_entry_match * match)1053 static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
1054 {
1055 const struct xt_hashlimit_info *r = (const void *)match->data;
1056 uint32_t quantum;
1057
1058 fputs(" --hashlimit", stdout);
1059 quantum = print_rate(r->cfg.avg, 1);
1060 printf(" --hashlimit-burst %u", r->cfg.burst);
1061
1062 fputs(" --hashlimit-mode", stdout);
1063 print_mode(r->cfg.mode, ',');
1064
1065 printf(" --hashlimit-name %s", r->name);
1066
1067 if (r->cfg.size)
1068 printf(" --hashlimit-htable-size %u", r->cfg.size);
1069 if (r->cfg.max)
1070 printf(" --hashlimit-htable-max %u", r->cfg.max);
1071 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
1072 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
1073 if (r->cfg.expire != quantum)
1074 printf(" --hashlimit-htable-expire %u", r->cfg.expire);
1075 }
1076
1077 static void
hashlimit_mt_save(const struct hashlimit_cfg3 * cfg,const char * name,unsigned int dmask,int revision)1078 hashlimit_mt_save(const struct hashlimit_cfg3 *cfg, const char* name, unsigned int dmask, int revision)
1079 {
1080 uint32_t quantum;
1081
1082 if (cfg->mode & XT_HASHLIMIT_INVERT)
1083 fputs(" --hashlimit-above", stdout);
1084 else
1085 fputs(" --hashlimit-upto", stdout);
1086
1087 if (cfg->mode & XT_HASHLIMIT_BYTES) {
1088 quantum = print_bytes(cfg->avg, cfg->burst, "--hashlimit-");
1089 } else {
1090 quantum = print_rate(cfg->avg, revision);
1091 printf(" --hashlimit-burst %llu", cfg->burst);
1092 }
1093
1094 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
1095 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
1096 fputs(" --hashlimit-mode", stdout);
1097 print_mode(cfg->mode, ',');
1098 }
1099
1100 printf(" --hashlimit-name %s", name);
1101
1102 if (cfg->size != 0)
1103 printf(" --hashlimit-htable-size %u", cfg->size);
1104 if (cfg->max != 0)
1105 printf(" --hashlimit-htable-max %u", cfg->max);
1106 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
1107 printf(" --hashlimit-htable-gcinterval %u", cfg->gc_interval);
1108 if (cfg->expire != quantum)
1109 printf(" --hashlimit-htable-expire %u", cfg->expire);
1110
1111 if (cfg->srcmask != dmask)
1112 printf(" --hashlimit-srcmask %u", cfg->srcmask);
1113 if (cfg->dstmask != dmask)
1114 printf(" --hashlimit-dstmask %u", cfg->dstmask);
1115
1116 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
1117 printf(" --hashlimit-rate-match");
1118
1119 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
1120 if (cfg->interval != 1)
1121 printf(" --hashlimit-rate-interval %u", cfg->interval);
1122 }
1123
1124 static void
hashlimit_mt4_save_v1(const void * ip,const struct xt_entry_match * match)1125 hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match)
1126 {
1127 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
1128 struct hashlimit_cfg3 cfg;
1129 int ret;
1130
1131 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
1132
1133 if (ret)
1134 xtables_error(OTHER_PROBLEM, "unknown revision");
1135
1136 hashlimit_mt_save(&cfg, info->name, 32, 1);
1137 }
1138
1139 static void
hashlimit_mt6_save_v1(const void * ip,const struct xt_entry_match * match)1140 hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match)
1141 {
1142 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
1143 struct hashlimit_cfg3 cfg;
1144 int ret;
1145
1146 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
1147
1148 if (ret)
1149 xtables_error(OTHER_PROBLEM, "unknown revision");
1150
1151 hashlimit_mt_save(&cfg, info->name, 128, 1);
1152 }
1153
1154 static void
hashlimit_mt4_save_v2(const void * ip,const struct xt_entry_match * match)1155 hashlimit_mt4_save_v2(const void *ip, const struct xt_entry_match *match)
1156 {
1157 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1158 struct hashlimit_cfg3 cfg;
1159 int ret;
1160
1161 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1162
1163 if (ret)
1164 xtables_error(OTHER_PROBLEM, "unknown revision");
1165
1166 hashlimit_mt_save(&cfg, info->name, 32, 2);
1167 }
1168
1169 static void
hashlimit_mt6_save_v2(const void * ip,const struct xt_entry_match * match)1170 hashlimit_mt6_save_v2(const void *ip, const struct xt_entry_match *match)
1171 {
1172 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1173 struct hashlimit_cfg3 cfg;
1174 int ret;
1175
1176 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1177
1178 if (ret)
1179 xtables_error(OTHER_PROBLEM, "unknown revision");
1180
1181 hashlimit_mt_save(&cfg, info->name, 128, 2);
1182 }
1183
1184 static void
hashlimit_mt4_save(const void * ip,const struct xt_entry_match * match)1185 hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
1186 {
1187 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1188
1189 hashlimit_mt_save(&info->cfg, info->name, 32, 3);
1190 }
1191
1192 static void
hashlimit_mt6_save(const void * ip,const struct xt_entry_match * match)1193 hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
1194 {
1195 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1196
1197 hashlimit_mt_save(&info->cfg, info->name, 128, 3);
1198 }
1199
1200 static const struct rates rates_v1_xlate[] = {
1201 { "day", XT_HASHLIMIT_SCALE * 24 * 60 * 60 },
1202 { "hour", XT_HASHLIMIT_SCALE * 60 * 60 },
1203 { "minute", XT_HASHLIMIT_SCALE * 60 },
1204 { "second", XT_HASHLIMIT_SCALE } };
1205
1206 static const struct rates rates_xlate[] = {
1207 { "day", XT_HASHLIMIT_SCALE_v2 * 24 * 60 * 60 },
1208 { "hour", XT_HASHLIMIT_SCALE_v2 * 60 * 60 },
1209 { "minute", XT_HASHLIMIT_SCALE_v2 * 60 },
1210 { "second", XT_HASHLIMIT_SCALE_v2 } };
1211
print_packets_rate_xlate(struct xt_xlate * xl,uint64_t avg,int revision)1212 static void print_packets_rate_xlate(struct xt_xlate *xl, uint64_t avg,
1213 int revision)
1214 {
1215 unsigned int i;
1216 const struct rates *_rates = (revision == 1) ?
1217 rates_v1_xlate : rates_xlate;
1218
1219 for (i = 1; i < ARRAY_SIZE(rates); ++i)
1220 if (avg > _rates[i].mult ||
1221 _rates[i].mult / avg < _rates[i].mult % avg)
1222 break;
1223
1224 xt_xlate_add(xl, " %" PRIu64 "/%s ",
1225 _rates[i-1].mult / avg, _rates[i-1].name);
1226 }
1227
print_bytes_rate_xlate(struct xt_xlate * xl,const struct hashlimit_cfg3 * cfg)1228 static void print_bytes_rate_xlate(struct xt_xlate *xl,
1229 const struct hashlimit_cfg3 *cfg)
1230 {
1231 unsigned int i;
1232 unsigned long long r;
1233
1234 r = cost_to_bytes(cfg->avg);
1235
1236 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
1237 if (r >= units[i].thresh &&
1238 bytes_to_cost(r & ~(units[i].thresh - 1)) == cfg->avg)
1239 break;
1240
1241 xt_xlate_add(xl, " %llu %sbytes/second", r / units[i].thresh,
1242 units[i].name);
1243
1244 r *= cfg->burst;
1245 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
1246 if (r >= units[i].thresh)
1247 break;
1248
1249 if (cfg->burst > 0)
1250 xt_xlate_add(xl, " burst %llu %sbytes", r / units[i].thresh,
1251 units[i].name);
1252 }
1253
hashlimit_print_subnet_xlate(struct xt_xlate * xl,uint32_t nsub,int family)1254 static void hashlimit_print_subnet_xlate(struct xt_xlate *xl,
1255 uint32_t nsub, int family)
1256 {
1257 char sep = (family == NFPROTO_IPV4) ? '.' : ':';
1258 char *fmt = (family == NFPROTO_IPV4) ? "%u" : "%04x";
1259 unsigned int nblocks = (family == NFPROTO_IPV4) ? 4 : 8;
1260 unsigned int nbits = (family == NFPROTO_IPV4) ? 8 : 16;
1261 unsigned int acm, i;
1262
1263 xt_xlate_add(xl, " and ");
1264 while (nblocks--) {
1265 acm = 0;
1266
1267 for (i = 0; i < nbits; i++) {
1268 acm <<= 1;
1269
1270 if (nsub > 0) {
1271 acm++;
1272 nsub--;
1273 }
1274 }
1275
1276 xt_xlate_add(xl, fmt, acm);
1277 if (nblocks > 0)
1278 xt_xlate_add(xl, "%c", sep);
1279 }
1280 }
1281
1282 static const char *const hashlimit_modes4_xlate[] = {
1283 [XT_HASHLIMIT_HASH_DIP] = "ip daddr",
1284 [XT_HASHLIMIT_HASH_DPT] = "tcp dport",
1285 [XT_HASHLIMIT_HASH_SIP] = "ip saddr",
1286 [XT_HASHLIMIT_HASH_SPT] = "tcp sport",
1287 };
1288
1289 static const char *const hashlimit_modes6_xlate[] = {
1290 [XT_HASHLIMIT_HASH_DIP] = "ip6 daddr",
1291 [XT_HASHLIMIT_HASH_DPT] = "tcp dport",
1292 [XT_HASHLIMIT_HASH_SIP] = "ip6 saddr",
1293 [XT_HASHLIMIT_HASH_SPT] = "tcp sport",
1294 };
1295
hashlimit_mode_xlate(struct xt_xlate * xl,uint32_t mode,int family,unsigned int nsrc,unsigned int ndst)1296 static int hashlimit_mode_xlate(struct xt_xlate *xl,
1297 uint32_t mode, int family,
1298 unsigned int nsrc, unsigned int ndst)
1299 {
1300 const char * const *_modes = (family == NFPROTO_IPV4) ?
1301 hashlimit_modes4_xlate : hashlimit_modes6_xlate;
1302 bool prevopt = false;
1303 unsigned int mask;
1304
1305 mode &= ~XT_HASHLIMIT_INVERT & ~XT_HASHLIMIT_BYTES;
1306
1307 for (mask = 1; mode > 0; mask <<= 1) {
1308 if (!(mode & mask))
1309 continue;
1310
1311 if (!prevopt) {
1312 xt_xlate_add(xl, " ");
1313 prevopt = true;
1314 }
1315 else {
1316 xt_xlate_add(xl, " . ");
1317 }
1318
1319 xt_xlate_add(xl, "%s", _modes[mask]);
1320
1321 if (mask == XT_HASHLIMIT_HASH_DIP &&
1322 ((family == NFPROTO_IPV4 && ndst != 32) ||
1323 (family == NFPROTO_IPV6 && ndst != 128)))
1324 hashlimit_print_subnet_xlate(xl, ndst, family);
1325 else if (mask == XT_HASHLIMIT_HASH_SIP &&
1326 ((family == NFPROTO_IPV4 && nsrc != 32) ||
1327 (family == NFPROTO_IPV6 && nsrc != 128)))
1328 hashlimit_print_subnet_xlate(xl, nsrc, family);
1329
1330 mode &= ~mask;
1331 }
1332
1333 return prevopt;
1334 }
1335
hashlimit_mt_xlate(struct xt_xlate * xl,const char * name,const struct hashlimit_cfg3 * cfg,int revision,int family)1336 static int hashlimit_mt_xlate(struct xt_xlate *xl, const char *name,
1337 const struct hashlimit_cfg3 *cfg,
1338 int revision, int family)
1339 {
1340 int ret = 1;
1341
1342 xt_xlate_add(xl, "meter %s {", name);
1343 ret = hashlimit_mode_xlate(xl, cfg->mode, family,
1344 cfg->srcmask, cfg->dstmask);
1345 if (cfg->expire != 1000)
1346 xt_xlate_add(xl, " timeout %us", cfg->expire / 1000);
1347 xt_xlate_add(xl, " limit rate");
1348
1349 if (cfg->mode & XT_HASHLIMIT_INVERT)
1350 xt_xlate_add(xl, " over");
1351
1352 if (cfg->mode & XT_HASHLIMIT_BYTES)
1353 print_bytes_rate_xlate(xl, cfg);
1354 else {
1355 print_packets_rate_xlate(xl, cfg->avg, revision);
1356 if (cfg->burst != XT_HASHLIMIT_BURST)
1357 xt_xlate_add(xl, "burst %" PRIu64 " packets", (uint64_t)cfg->burst);
1358
1359 }
1360 xt_xlate_add(xl, "}");
1361
1362 return ret;
1363 }
1364
hashlimit_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1365 static int hashlimit_xlate(struct xt_xlate *xl,
1366 const struct xt_xlate_mt_params *params)
1367 {
1368 const struct xt_hashlimit_info *info = (const void *)params->match->data;
1369 int ret = 1;
1370
1371 xt_xlate_add(xl, "meter %s {", info->name);
1372 ret = hashlimit_mode_xlate(xl, info->cfg.mode, NFPROTO_IPV4, 32, 32);
1373 xt_xlate_add(xl, " timeout %us limit rate", info->cfg.expire / 1000);
1374 print_packets_rate_xlate(xl, info->cfg.avg, 1);
1375 xt_xlate_add(xl, " burst %u packets", info->cfg.burst);
1376 xt_xlate_add(xl, "}");
1377
1378 return ret;
1379 }
1380
hashlimit_mt4_xlate_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1381 static int hashlimit_mt4_xlate_v1(struct xt_xlate *xl,
1382 const struct xt_xlate_mt_params *params)
1383 {
1384 const struct xt_hashlimit_mtinfo1 *info =
1385 (const void *)params->match->data;
1386 struct hashlimit_cfg3 cfg;
1387
1388 if (cfg_copy(&cfg, (const void *)&info->cfg, 1))
1389 xtables_error(OTHER_PROBLEM, "unknown revision");
1390
1391 return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV4);
1392 }
1393
hashlimit_mt6_xlate_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1394 static int hashlimit_mt6_xlate_v1(struct xt_xlate *xl,
1395 const struct xt_xlate_mt_params *params)
1396 {
1397 const struct xt_hashlimit_mtinfo1 *info =
1398 (const void *)params->match->data;
1399 struct hashlimit_cfg3 cfg;
1400
1401 if (cfg_copy(&cfg, (const void *)&info->cfg, 1))
1402 xtables_error(OTHER_PROBLEM, "unknown revision");
1403
1404 return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV6);
1405 }
1406
hashlimit_mt4_xlate_v2(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1407 static int hashlimit_mt4_xlate_v2(struct xt_xlate *xl,
1408 const struct xt_xlate_mt_params *params)
1409 {
1410 const struct xt_hashlimit_mtinfo2 *info =
1411 (const void *)params->match->data;
1412 struct hashlimit_cfg3 cfg;
1413
1414 if (cfg_copy(&cfg, (const void *)&info->cfg, 2))
1415 xtables_error(OTHER_PROBLEM, "unknown revision");
1416
1417 return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV4);
1418 }
1419
hashlimit_mt6_xlate_v2(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1420 static int hashlimit_mt6_xlate_v2(struct xt_xlate *xl,
1421 const struct xt_xlate_mt_params *params)
1422 {
1423 const struct xt_hashlimit_mtinfo2 *info =
1424 (const void *)params->match->data;
1425 struct hashlimit_cfg3 cfg;
1426
1427 if (cfg_copy(&cfg, (const void *)&info->cfg, 2))
1428 xtables_error(OTHER_PROBLEM, "unknown revision");
1429
1430 return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV6);
1431 }
1432
hashlimit_mt4_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1433 static int hashlimit_mt4_xlate(struct xt_xlate *xl,
1434 const struct xt_xlate_mt_params *params)
1435 {
1436 const struct xt_hashlimit_mtinfo3 *info =
1437 (const void *)params->match->data;
1438
1439 return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV4);
1440 }
1441
hashlimit_mt6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1442 static int hashlimit_mt6_xlate(struct xt_xlate *xl,
1443 const struct xt_xlate_mt_params *params)
1444 {
1445 const struct xt_hashlimit_mtinfo3 *info =
1446 (const void *)params->match->data;
1447
1448 return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV6);
1449 }
1450
1451 static struct xtables_match hashlimit_mt_reg[] = {
1452 {
1453 .family = NFPROTO_UNSPEC,
1454 .name = "hashlimit",
1455 .version = XTABLES_VERSION,
1456 .revision = 0,
1457 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
1458 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
1459 .help = hashlimit_help,
1460 .init = hashlimit_init,
1461 .x6_parse = hashlimit_parse,
1462 .x6_fcheck = hashlimit_check,
1463 .print = hashlimit_print,
1464 .save = hashlimit_save,
1465 .x6_options = hashlimit_opts,
1466 .udata_size = sizeof(struct hashlimit_mt_udata),
1467 .xlate = hashlimit_xlate,
1468 },
1469 {
1470 .version = XTABLES_VERSION,
1471 .name = "hashlimit",
1472 .revision = 1,
1473 .family = NFPROTO_IPV4,
1474 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
1475 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
1476 .help = hashlimit_mt_help,
1477 .init = hashlimit_mt4_init_v1,
1478 .x6_parse = hashlimit_mt_parse_v1,
1479 .x6_fcheck = hashlimit_mt_check_v1,
1480 .print = hashlimit_mt4_print_v1,
1481 .save = hashlimit_mt4_save_v1,
1482 .x6_options = hashlimit_mt_opts_v1,
1483 .udata_size = sizeof(struct hashlimit_mt_udata),
1484 .xlate = hashlimit_mt4_xlate_v1,
1485 },
1486 {
1487 .version = XTABLES_VERSION,
1488 .name = "hashlimit",
1489 .revision = 1,
1490 .family = NFPROTO_IPV6,
1491 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
1492 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
1493 .help = hashlimit_mt_help,
1494 .init = hashlimit_mt6_init_v1,
1495 .x6_parse = hashlimit_mt_parse_v1,
1496 .x6_fcheck = hashlimit_mt_check_v1,
1497 .print = hashlimit_mt6_print_v1,
1498 .save = hashlimit_mt6_save_v1,
1499 .x6_options = hashlimit_mt_opts_v1,
1500 .udata_size = sizeof(struct hashlimit_mt_udata),
1501 .xlate = hashlimit_mt6_xlate_v1,
1502 },
1503 {
1504 .version = XTABLES_VERSION,
1505 .name = "hashlimit",
1506 .revision = 2,
1507 .family = NFPROTO_IPV4,
1508 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
1509 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
1510 .help = hashlimit_mt_help,
1511 .init = hashlimit_mt4_init_v2,
1512 .x6_parse = hashlimit_mt_parse_v2,
1513 .x6_fcheck = hashlimit_mt_check_v2,
1514 .print = hashlimit_mt4_print_v2,
1515 .save = hashlimit_mt4_save_v2,
1516 .x6_options = hashlimit_mt_opts_v2,
1517 .udata_size = sizeof(struct hashlimit_mt_udata),
1518 .xlate = hashlimit_mt4_xlate_v2,
1519 },
1520 {
1521 .version = XTABLES_VERSION,
1522 .name = "hashlimit",
1523 .revision = 2,
1524 .family = NFPROTO_IPV6,
1525 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
1526 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
1527 .help = hashlimit_mt_help,
1528 .init = hashlimit_mt6_init_v2,
1529 .x6_parse = hashlimit_mt_parse_v2,
1530 .x6_fcheck = hashlimit_mt_check_v2,
1531 .print = hashlimit_mt6_print_v2,
1532 .save = hashlimit_mt6_save_v2,
1533 .x6_options = hashlimit_mt_opts_v2,
1534 .udata_size = sizeof(struct hashlimit_mt_udata),
1535 .xlate = hashlimit_mt6_xlate_v2,
1536 },
1537 {
1538 .version = XTABLES_VERSION,
1539 .name = "hashlimit",
1540 .revision = 3,
1541 .family = NFPROTO_IPV4,
1542 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)),
1543 .userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo),
1544 .help = hashlimit_mt_help_v3,
1545 .init = hashlimit_mt4_init,
1546 .x6_parse = hashlimit_mt_parse,
1547 .x6_fcheck = hashlimit_mt_check,
1548 .print = hashlimit_mt4_print,
1549 .save = hashlimit_mt4_save,
1550 .x6_options = hashlimit_mt_opts,
1551 .udata_size = sizeof(struct hashlimit_mt_udata),
1552 .xlate = hashlimit_mt4_xlate,
1553 },
1554 {
1555 .version = XTABLES_VERSION,
1556 .name = "hashlimit",
1557 .revision = 3,
1558 .family = NFPROTO_IPV6,
1559 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)),
1560 .userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo),
1561 .help = hashlimit_mt_help_v3,
1562 .init = hashlimit_mt6_init,
1563 .x6_parse = hashlimit_mt_parse,
1564 .x6_fcheck = hashlimit_mt_check,
1565 .print = hashlimit_mt6_print,
1566 .save = hashlimit_mt6_save,
1567 .x6_options = hashlimit_mt_opts,
1568 .udata_size = sizeof(struct hashlimit_mt_udata),
1569 .xlate = hashlimit_mt6_xlate,
1570 },
1571 };
1572
_init(void)1573 void _init(void)
1574 {
1575 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
1576 }
1577