1 /* ip6tables match extension for limiting packets per destination
2 *
3 * (C) 2003-2004 by Harald Welte <[email protected]>
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 <[email protected]>
9 * Hervé Eychenne <[email protected]>
10 *
11 * Error corections by [email protected] (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")",
360 tmp, max);
361
362 tmp = bytes_to_cost(tmp);
363 if (tmp == 0)
364 xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"", 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\"", 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 = xtables_strdup(option_arg);
512
513 for (tok = strtok(arg, ",|");
514 tok;
515 tok = strtok(NULL, ",|")) {
516 if (!strcmp(tok, "dstip"))
517 *mode |= XT_HASHLIMIT_HASH_DIP;
518 else if (!strcmp(tok, "srcip"))
519 *mode |= XT_HASHLIMIT_HASH_SIP;
520 else if (!strcmp(tok, "srcport"))
521 *mode |= XT_HASHLIMIT_HASH_SPT;
522 else if (!strcmp(tok, "dstport"))
523 *mode |= XT_HASHLIMIT_HASH_DPT;
524 else {
525 free(arg);
526 return -1;
527 }
528 }
529 free(arg);
530 return 0;
531 }
532
hashlimit_parse(struct xt_option_call * cb)533 static void hashlimit_parse(struct xt_option_call *cb)
534 {
535 struct xt_hashlimit_info *info = cb->data;
536
537 xtables_option_parse(cb);
538 switch (cb->entry->id) {
539 case O_UPTO:
540 if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
541 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
542 "--hashlimit-upto", cb->arg);
543 break;
544 case O_MODE:
545 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
546 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
547 "--hashlimit-mode", cb->arg);
548 break;
549 }
550 }
551
hashlimit_mt_parse_v1(struct xt_option_call * cb)552 static void hashlimit_mt_parse_v1(struct xt_option_call *cb)
553 {
554 struct xt_hashlimit_mtinfo1 *info = cb->data;
555
556 xtables_option_parse(cb);
557 switch (cb->entry->id) {
558 case O_BURST:
559 info->cfg.burst = parse_burst(cb->arg, 1);
560 break;
561 case O_UPTO:
562 if (cb->invert)
563 info->cfg.mode |= XT_HASHLIMIT_INVERT;
564 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
565 info->cfg.mode |= XT_HASHLIMIT_BYTES;
566 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
567 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
568 "--hashlimit-upto", cb->arg);
569 break;
570 case O_ABOVE:
571 if (!cb->invert)
572 info->cfg.mode |= XT_HASHLIMIT_INVERT;
573 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 1))
574 info->cfg.mode |= XT_HASHLIMIT_BYTES;
575 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 1))
576 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
577 "--hashlimit-above", cb->arg);
578 break;
579 case O_MODE:
580 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
581 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
582 "--hashlimit-mode", cb->arg);
583 break;
584 case O_SRCMASK:
585 info->cfg.srcmask = cb->val.hlen;
586 break;
587 case O_DSTMASK:
588 info->cfg.dstmask = cb->val.hlen;
589 break;
590 }
591 }
592
hashlimit_mt_parse_v2(struct xt_option_call * cb)593 static void hashlimit_mt_parse_v2(struct xt_option_call *cb)
594 {
595 struct xt_hashlimit_mtinfo2 *info = cb->data;
596
597 xtables_option_parse(cb);
598 switch (cb->entry->id) {
599 case O_BURST:
600 info->cfg.burst = parse_burst(cb->arg, 2);
601 break;
602 case O_UPTO:
603 if (cb->invert)
604 info->cfg.mode |= XT_HASHLIMIT_INVERT;
605 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
606 info->cfg.mode |= XT_HASHLIMIT_BYTES;
607 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
608 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
609 "--hashlimit-upto", cb->arg);
610 break;
611 case O_ABOVE:
612 if (!cb->invert)
613 info->cfg.mode |= XT_HASHLIMIT_INVERT;
614 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
615 info->cfg.mode |= XT_HASHLIMIT_BYTES;
616 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
617 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
618 "--hashlimit-above", cb->arg);
619 break;
620 case O_MODE:
621 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
622 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
623 "--hashlimit-mode", cb->arg);
624 break;
625 case O_SRCMASK:
626 info->cfg.srcmask = cb->val.hlen;
627 break;
628 case O_DSTMASK:
629 info->cfg.dstmask = cb->val.hlen;
630 break;
631 }
632 }
633
hashlimit_mt_parse(struct xt_option_call * cb)634 static void hashlimit_mt_parse(struct xt_option_call *cb)
635 {
636 struct xt_hashlimit_mtinfo3 *info = cb->data;
637
638 xtables_option_parse(cb);
639 switch (cb->entry->id) {
640 case O_BURST:
641 info->cfg.burst = parse_burst(cb->arg, 2);
642 break;
643 case O_UPTO:
644 if (cb->invert)
645 info->cfg.mode |= XT_HASHLIMIT_INVERT;
646 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
647 info->cfg.mode |= XT_HASHLIMIT_BYTES;
648 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
649 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
650 "--hashlimit-upto", cb->arg);
651 break;
652 case O_ABOVE:
653 if (!cb->invert)
654 info->cfg.mode |= XT_HASHLIMIT_INVERT;
655 if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata, 2))
656 info->cfg.mode |= XT_HASHLIMIT_BYTES;
657 else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata, 2))
658 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
659 "--hashlimit-above", cb->arg);
660 break;
661 case O_MODE:
662 if (parse_mode(&info->cfg.mode, cb->arg) < 0)
663 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
664 "--hashlimit-mode", cb->arg);
665 break;
666 case O_SRCMASK:
667 info->cfg.srcmask = cb->val.hlen;
668 break;
669 case O_DSTMASK:
670 info->cfg.dstmask = cb->val.hlen;
671 break;
672 case O_RATEMATCH:
673 info->cfg.mode |= XT_HASHLIMIT_RATE_MATCH;
674 break;
675 case O_INTERVAL:
676 if (!parse_interval(cb->arg, &info->cfg.interval))
677 xtables_param_act(XTF_BAD_VALUE, "hashlimit",
678 "--hashlimit-rate-interval", cb->arg);
679 }
680 }
681
hashlimit_check(struct xt_fcheck_call * cb)682 static void hashlimit_check(struct xt_fcheck_call *cb)
683 {
684 const struct hashlimit_mt_udata *udata = cb->udata;
685 struct xt_hashlimit_info *info = cb->data;
686
687 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
688 xtables_error(PARAMETER_PROBLEM,
689 "You have to specify --hashlimit");
690 if (!(cb->xflags & F_HTABLE_EXPIRE))
691 info->cfg.expire = udata->mult * 1000; /* from s to msec */
692 }
693
hashlimit_mt_check_v1(struct xt_fcheck_call * cb)694 static void hashlimit_mt_check_v1(struct xt_fcheck_call *cb)
695 {
696 const struct hashlimit_mt_udata *udata = cb->udata;
697 struct xt_hashlimit_mtinfo1 *info = cb->data;
698
699 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
700 xtables_error(PARAMETER_PROBLEM,
701 "You have to specify --hashlimit");
702 if (!(cb->xflags & F_HTABLE_EXPIRE))
703 info->cfg.expire = udata->mult * 1000; /* from s to msec */
704
705 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
706 uint32_t burst = 0;
707 if (cb->xflags & F_BURST) {
708 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
709 xtables_error(PARAMETER_PROBLEM,
710 "burst cannot be smaller than %"PRIu64"b",
711 cost_to_bytes(info->cfg.avg));
712
713 burst = info->cfg.burst;
714 burst /= cost_to_bytes(info->cfg.avg);
715 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
716 burst++;
717 if (!(cb->xflags & F_HTABLE_EXPIRE))
718 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
719 }
720 info->cfg.burst = burst;
721 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX_v1)
722 burst_error_v1();
723 }
724
hashlimit_mt_check_v2(struct xt_fcheck_call * cb)725 static void hashlimit_mt_check_v2(struct xt_fcheck_call *cb)
726 {
727 const struct hashlimit_mt_udata *udata = cb->udata;
728 struct xt_hashlimit_mtinfo2 *info = cb->data;
729
730 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
731 xtables_error(PARAMETER_PROBLEM,
732 "You have to specify --hashlimit");
733 if (!(cb->xflags & F_HTABLE_EXPIRE))
734 info->cfg.expire = udata->mult * 1000; /* from s to msec */
735
736 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
737 uint32_t burst = 0;
738 if (cb->xflags & F_BURST) {
739 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
740 xtables_error(PARAMETER_PROBLEM,
741 "burst cannot be smaller than %"PRIu64"b",
742 cost_to_bytes(info->cfg.avg));
743
744 burst = info->cfg.burst;
745 burst /= cost_to_bytes(info->cfg.avg);
746 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
747 burst++;
748 if (!(cb->xflags & F_HTABLE_EXPIRE))
749 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
750 }
751 info->cfg.burst = burst;
752 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
753 burst_error();
754 }
755
hashlimit_mt_check(struct xt_fcheck_call * cb)756 static void hashlimit_mt_check(struct xt_fcheck_call *cb)
757 {
758 const struct hashlimit_mt_udata *udata = cb->udata;
759 struct xt_hashlimit_mtinfo3 *info = cb->data;
760
761 if (!(cb->xflags & (F_UPTO | F_ABOVE)))
762 xtables_error(PARAMETER_PROBLEM,
763 "You have to specify --hashlimit");
764 if (!(cb->xflags & F_HTABLE_EXPIRE))
765 info->cfg.expire = udata->mult * 1000; /* from s to msec */
766
767 if (info->cfg.mode & XT_HASHLIMIT_BYTES) {
768 uint32_t burst = 0;
769 if (cb->xflags & F_BURST) {
770 if (info->cfg.burst < cost_to_bytes(info->cfg.avg))
771 xtables_error(PARAMETER_PROBLEM,
772 "burst cannot be smaller than %"PRIu64"b", cost_to_bytes(info->cfg.avg));
773
774 burst = info->cfg.burst;
775 burst /= cost_to_bytes(info->cfg.avg);
776 if (info->cfg.burst % cost_to_bytes(info->cfg.avg))
777 burst++;
778 if (!(cb->xflags & F_HTABLE_EXPIRE))
779 info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
780 }
781 info->cfg.burst = burst;
782 } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX)
783 burst_error();
784
785 if (cb->xflags & F_RATEMATCH) {
786 if (!(info->cfg.mode & XT_HASHLIMIT_BYTES))
787 info->cfg.avg /= udata->mult;
788
789 if (info->cfg.interval == 0) {
790 if (info->cfg.mode & XT_HASHLIMIT_BYTES)
791 info->cfg.interval = 1;
792 else
793 info->cfg.interval = udata->mult;
794 }
795 }
796 }
797
798 struct rates {
799 const char *name;
800 uint64_t mult;
801 } rates_v1[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 },
802 { "hour", XT_HASHLIMIT_SCALE*60*60 },
803 { "min", XT_HASHLIMIT_SCALE*60 },
804 { "sec", XT_HASHLIMIT_SCALE } };
805
806 static const struct rates rates[] = {
807 { "day", XT_HASHLIMIT_SCALE_v2*24*60*60 },
808 { "hour", XT_HASHLIMIT_SCALE_v2*60*60 },
809 { "min", XT_HASHLIMIT_SCALE_v2*60 },
810 { "sec", XT_HASHLIMIT_SCALE_v2 } };
811
print_rate(uint64_t period,int revision)812 static uint32_t print_rate(uint64_t period, int revision)
813 {
814 unsigned int i;
815 const struct rates *_rates = (revision == 1) ? rates_v1 : rates;
816 uint64_t scale = (revision == 1) ? XT_HASHLIMIT_SCALE : XT_HASHLIMIT_SCALE_v2;
817
818 if (period == 0) {
819 printf(" %f", INFINITY);
820 return 0;
821 }
822
823 for (i = 1; i < ARRAY_SIZE(rates); ++i)
824 if (period > _rates[i].mult
825 || _rates[i].mult/period < _rates[i].mult%period)
826 break;
827
828 printf(" %"PRIu64"/%s", _rates[i-1].mult / period, _rates[i-1].name);
829 /* return in msec */
830 return _rates[i-1].mult / scale * 1000;
831 }
832
833 static const struct {
834 const char *name;
835 uint32_t thresh;
836 } units[] = {
837 { "m", 1024 * 1024 },
838 { "k", 1024 },
839 { "", 1 },
840 };
841
print_bytes(uint64_t avg,uint64_t burst,const char * prefix)842 static uint32_t print_bytes(uint64_t avg, uint64_t burst, const char *prefix)
843 {
844 unsigned int i;
845 unsigned long long r;
846
847 r = cost_to_bytes(avg);
848
849 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
850 if (r >= units[i].thresh &&
851 bytes_to_cost(r & ~(units[i].thresh - 1)) == avg)
852 break;
853 printf(" %llu%sb/s", r/units[i].thresh, units[i].name);
854
855 if (burst == 0)
856 return XT_HASHLIMIT_BYTE_EXPIRE * 1000;
857
858 r *= burst;
859 printf(" %s", prefix);
860 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
861 if (r >= units[i].thresh)
862 break;
863
864 printf("burst %llu%sb", r / units[i].thresh, units[i].name);
865 return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000;
866 }
867
print_mode(unsigned int mode,char separator)868 static void print_mode(unsigned int mode, char separator)
869 {
870 bool prevmode = false;
871
872 putchar(' ');
873 if (mode & XT_HASHLIMIT_HASH_SIP) {
874 fputs("srcip", stdout);
875 prevmode = 1;
876 }
877 if (mode & XT_HASHLIMIT_HASH_SPT) {
878 if (prevmode)
879 putchar(separator);
880 fputs("srcport", stdout);
881 prevmode = 1;
882 }
883 if (mode & XT_HASHLIMIT_HASH_DIP) {
884 if (prevmode)
885 putchar(separator);
886 fputs("dstip", stdout);
887 prevmode = 1;
888 }
889 if (mode & XT_HASHLIMIT_HASH_DPT) {
890 if (prevmode)
891 putchar(separator);
892 fputs("dstport", stdout);
893 }
894 }
895
hashlimit_print(const void * ip,const struct xt_entry_match * match,int numeric)896 static void hashlimit_print(const void *ip,
897 const struct xt_entry_match *match, int numeric)
898 {
899 const struct xt_hashlimit_info *r = (const void *)match->data;
900 uint32_t quantum;
901
902 fputs(" limit: avg", stdout);
903 quantum = print_rate(r->cfg.avg, 1);
904 printf(" burst %u", r->cfg.burst);
905 fputs(" mode", stdout);
906 print_mode(r->cfg.mode, '-');
907 if (r->cfg.size)
908 printf(" htable-size %u", r->cfg.size);
909 if (r->cfg.max)
910 printf(" htable-max %u", r->cfg.max);
911 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
912 printf(" htable-gcinterval %u", r->cfg.gc_interval);
913 if (r->cfg.expire != quantum)
914 printf(" htable-expire %u", r->cfg.expire);
915 }
916
917 static void
hashlimit_mt_print(const struct hashlimit_cfg3 * cfg,unsigned int dmask,int revision)918 hashlimit_mt_print(const struct hashlimit_cfg3 *cfg, unsigned int dmask, int revision)
919 {
920 uint64_t quantum;
921 uint64_t period;
922
923 if (cfg->mode & XT_HASHLIMIT_INVERT)
924 fputs(" limit: above", stdout);
925 else
926 fputs(" limit: up to", stdout);
927
928 if (cfg->mode & XT_HASHLIMIT_BYTES) {
929 quantum = print_bytes(cfg->avg, cfg->burst, "");
930 } else {
931 if (revision == 3) {
932 period = cfg->avg;
933 if (cfg->interval != 0)
934 period *= cfg->interval;
935
936 quantum = print_rate(period, revision);
937 } else {
938 quantum = print_rate(cfg->avg, revision);
939 }
940 printf(" burst %llu", cfg->burst);
941 }
942 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
943 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
944 fputs(" mode", stdout);
945 print_mode(cfg->mode, '-');
946 }
947 if (cfg->size != 0)
948 printf(" htable-size %u", cfg->size);
949 if (cfg->max != 0)
950 printf(" htable-max %u", cfg->max);
951 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
952 printf(" htable-gcinterval %u", cfg->gc_interval);
953 if (cfg->expire != quantum)
954 printf(" htable-expire %u", cfg->expire);
955
956 if (cfg->srcmask != dmask)
957 printf(" srcmask %u", cfg->srcmask);
958 if (cfg->dstmask != dmask)
959 printf(" dstmask %u", cfg->dstmask);
960
961 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
962 printf(" rate-match");
963
964 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
965 if (cfg->interval != 1)
966 printf(" rate-interval %u", cfg->interval);
967 }
968
969 static void
hashlimit_mt4_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)970 hashlimit_mt4_print_v1(const void *ip, const struct xt_entry_match *match,
971 int numeric)
972 {
973 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
974 struct hashlimit_cfg3 cfg;
975 int ret;
976
977 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
978
979 if (ret)
980 xtables_error(OTHER_PROBLEM, "unknown revision");
981
982 hashlimit_mt_print(&cfg, 32, 1);
983 }
984
985 static void
hashlimit_mt6_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)986 hashlimit_mt6_print_v1(const void *ip, const struct xt_entry_match *match,
987 int numeric)
988 {
989 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
990 struct hashlimit_cfg3 cfg;
991 int ret;
992
993 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
994
995 if (ret)
996 xtables_error(OTHER_PROBLEM, "unknown revision");
997
998 hashlimit_mt_print(&cfg, 128, 1);
999 }
1000
1001 static void
hashlimit_mt4_print_v2(const void * ip,const struct xt_entry_match * match,int numeric)1002 hashlimit_mt4_print_v2(const void *ip, const struct xt_entry_match *match,
1003 int numeric)
1004 {
1005 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1006 struct hashlimit_cfg3 cfg;
1007 int ret;
1008
1009 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1010
1011 if (ret)
1012 xtables_error(OTHER_PROBLEM, "unknown revision");
1013
1014 hashlimit_mt_print(&cfg, 32, 2);
1015 }
1016
1017 static void
hashlimit_mt6_print_v2(const void * ip,const struct xt_entry_match * match,int numeric)1018 hashlimit_mt6_print_v2(const void *ip, const struct xt_entry_match *match,
1019 int numeric)
1020 {
1021 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1022 struct hashlimit_cfg3 cfg;
1023 int ret;
1024
1025 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1026
1027 if (ret)
1028 xtables_error(OTHER_PROBLEM, "unknown revision");
1029
1030 hashlimit_mt_print(&cfg, 128, 2);
1031 }
1032 static void
hashlimit_mt4_print(const void * ip,const struct xt_entry_match * match,int numeric)1033 hashlimit_mt4_print(const void *ip, const struct xt_entry_match *match,
1034 int numeric)
1035 {
1036 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1037
1038 hashlimit_mt_print(&info->cfg, 32, 3);
1039 }
1040
1041 static void
hashlimit_mt6_print(const void * ip,const struct xt_entry_match * match,int numeric)1042 hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match,
1043 int numeric)
1044 {
1045 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1046
1047 hashlimit_mt_print(&info->cfg, 128, 3);
1048 }
1049
hashlimit_save(const void * ip,const struct xt_entry_match * match)1050 static void hashlimit_save(const void *ip, const struct xt_entry_match *match)
1051 {
1052 const struct xt_hashlimit_info *r = (const void *)match->data;
1053 uint32_t quantum;
1054
1055 fputs(" --hashlimit", stdout);
1056 quantum = print_rate(r->cfg.avg, 1);
1057 printf(" --hashlimit-burst %u", r->cfg.burst);
1058
1059 fputs(" --hashlimit-mode", stdout);
1060 print_mode(r->cfg.mode, ',');
1061
1062 printf(" --hashlimit-name %s", r->name);
1063
1064 if (r->cfg.size)
1065 printf(" --hashlimit-htable-size %u", r->cfg.size);
1066 if (r->cfg.max)
1067 printf(" --hashlimit-htable-max %u", r->cfg.max);
1068 if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL)
1069 printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval);
1070 if (r->cfg.expire != quantum)
1071 printf(" --hashlimit-htable-expire %u", r->cfg.expire);
1072 }
1073
1074 static void
hashlimit_mt_save(const struct hashlimit_cfg3 * cfg,const char * name,unsigned int dmask,int revision)1075 hashlimit_mt_save(const struct hashlimit_cfg3 *cfg, const char* name, unsigned int dmask, int revision)
1076 {
1077 uint32_t quantum;
1078
1079 if (cfg->mode & XT_HASHLIMIT_INVERT)
1080 fputs(" --hashlimit-above", stdout);
1081 else
1082 fputs(" --hashlimit-upto", stdout);
1083
1084 if (cfg->mode & XT_HASHLIMIT_BYTES) {
1085 quantum = print_bytes(cfg->avg, cfg->burst, "--hashlimit-");
1086 } else {
1087 quantum = print_rate(cfg->avg, revision);
1088 printf(" --hashlimit-burst %llu", cfg->burst);
1089 }
1090
1091 if (cfg->mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT |
1092 XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) {
1093 fputs(" --hashlimit-mode", stdout);
1094 print_mode(cfg->mode, ',');
1095 }
1096
1097 printf(" --hashlimit-name %s", name);
1098
1099 if (cfg->size != 0)
1100 printf(" --hashlimit-htable-size %u", cfg->size);
1101 if (cfg->max != 0)
1102 printf(" --hashlimit-htable-max %u", cfg->max);
1103 if (cfg->gc_interval != XT_HASHLIMIT_GCINTERVAL)
1104 printf(" --hashlimit-htable-gcinterval %u", cfg->gc_interval);
1105 if (cfg->expire != quantum)
1106 printf(" --hashlimit-htable-expire %u", cfg->expire);
1107
1108 if (cfg->srcmask != dmask)
1109 printf(" --hashlimit-srcmask %u", cfg->srcmask);
1110 if (cfg->dstmask != dmask)
1111 printf(" --hashlimit-dstmask %u", cfg->dstmask);
1112
1113 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
1114 printf(" --hashlimit-rate-match");
1115
1116 if ((revision == 3) && (cfg->mode & XT_HASHLIMIT_RATE_MATCH))
1117 if (cfg->interval != 1)
1118 printf(" --hashlimit-rate-interval %u", cfg->interval);
1119 }
1120
1121 static void
hashlimit_mt4_save_v1(const void * ip,const struct xt_entry_match * match)1122 hashlimit_mt4_save_v1(const void *ip, const struct xt_entry_match *match)
1123 {
1124 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
1125 struct hashlimit_cfg3 cfg;
1126 int ret;
1127
1128 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
1129
1130 if (ret)
1131 xtables_error(OTHER_PROBLEM, "unknown revision");
1132
1133 hashlimit_mt_save(&cfg, info->name, 32, 1);
1134 }
1135
1136 static void
hashlimit_mt6_save_v1(const void * ip,const struct xt_entry_match * match)1137 hashlimit_mt6_save_v1(const void *ip, const struct xt_entry_match *match)
1138 {
1139 const struct xt_hashlimit_mtinfo1 *info = (const void *)match->data;
1140 struct hashlimit_cfg3 cfg;
1141 int ret;
1142
1143 ret = cfg_copy(&cfg, (const void *)&info->cfg, 1);
1144
1145 if (ret)
1146 xtables_error(OTHER_PROBLEM, "unknown revision");
1147
1148 hashlimit_mt_save(&cfg, info->name, 128, 1);
1149 }
1150
1151 static void
hashlimit_mt4_save_v2(const void * ip,const struct xt_entry_match * match)1152 hashlimit_mt4_save_v2(const void *ip, const struct xt_entry_match *match)
1153 {
1154 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1155 struct hashlimit_cfg3 cfg;
1156 int ret;
1157
1158 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1159
1160 if (ret)
1161 xtables_error(OTHER_PROBLEM, "unknown revision");
1162
1163 hashlimit_mt_save(&cfg, info->name, 32, 2);
1164 }
1165
1166 static void
hashlimit_mt6_save_v2(const void * ip,const struct xt_entry_match * match)1167 hashlimit_mt6_save_v2(const void *ip, const struct xt_entry_match *match)
1168 {
1169 const struct xt_hashlimit_mtinfo2 *info = (const void *)match->data;
1170 struct hashlimit_cfg3 cfg;
1171 int ret;
1172
1173 ret = cfg_copy(&cfg, (const void *)&info->cfg, 2);
1174
1175 if (ret)
1176 xtables_error(OTHER_PROBLEM, "unknown revision");
1177
1178 hashlimit_mt_save(&cfg, info->name, 128, 2);
1179 }
1180
1181 static void
hashlimit_mt4_save(const void * ip,const struct xt_entry_match * match)1182 hashlimit_mt4_save(const void *ip, const struct xt_entry_match *match)
1183 {
1184 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1185
1186 hashlimit_mt_save(&info->cfg, info->name, 32, 3);
1187 }
1188
1189 static void
hashlimit_mt6_save(const void * ip,const struct xt_entry_match * match)1190 hashlimit_mt6_save(const void *ip, const struct xt_entry_match *match)
1191 {
1192 const struct xt_hashlimit_mtinfo3 *info = (const void *)match->data;
1193
1194 hashlimit_mt_save(&info->cfg, info->name, 128, 3);
1195 }
1196
1197 static const struct rates rates_v1_xlate[] = {
1198 { "day", XT_HASHLIMIT_SCALE * 24 * 60 * 60 },
1199 { "hour", XT_HASHLIMIT_SCALE * 60 * 60 },
1200 { "minute", XT_HASHLIMIT_SCALE * 60 },
1201 { "second", XT_HASHLIMIT_SCALE } };
1202
1203 static const struct rates rates_xlate[] = {
1204 { "day", XT_HASHLIMIT_SCALE_v2 * 24 * 60 * 60 },
1205 { "hour", XT_HASHLIMIT_SCALE_v2 * 60 * 60 },
1206 { "minute", XT_HASHLIMIT_SCALE_v2 * 60 },
1207 { "second", XT_HASHLIMIT_SCALE_v2 } };
1208
print_packets_rate_xlate(struct xt_xlate * xl,uint64_t avg,int revision)1209 static void print_packets_rate_xlate(struct xt_xlate *xl, uint64_t avg,
1210 int revision)
1211 {
1212 unsigned int i;
1213 const struct rates *_rates = (revision == 1) ?
1214 rates_v1_xlate : rates_xlate;
1215
1216 for (i = 1; i < ARRAY_SIZE(rates); ++i)
1217 if (avg > _rates[i].mult ||
1218 _rates[i].mult / avg < _rates[i].mult % avg)
1219 break;
1220
1221 xt_xlate_add(xl, " %" PRIu64 "/%s ",
1222 _rates[i-1].mult / avg, _rates[i-1].name);
1223 }
1224
print_bytes_rate_xlate(struct xt_xlate * xl,const struct hashlimit_cfg3 * cfg)1225 static void print_bytes_rate_xlate(struct xt_xlate *xl,
1226 const struct hashlimit_cfg3 *cfg)
1227 {
1228 unsigned int i;
1229 unsigned long long r;
1230
1231 r = cost_to_bytes(cfg->avg);
1232
1233 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
1234 if (r >= units[i].thresh &&
1235 bytes_to_cost(r & ~(units[i].thresh - 1)) == cfg->avg)
1236 break;
1237
1238 xt_xlate_add(xl, " %llu %sbytes/second", r / units[i].thresh,
1239 units[i].name);
1240
1241 r *= cfg->burst;
1242 for (i = 0; i < ARRAY_SIZE(units) -1; ++i)
1243 if (r >= units[i].thresh)
1244 break;
1245
1246 if (cfg->burst > 0)
1247 xt_xlate_add(xl, " burst %llu %sbytes", r / units[i].thresh,
1248 units[i].name);
1249 }
1250
hashlimit_print_subnet_xlate(struct xt_xlate * xl,uint32_t nsub,int family)1251 static void hashlimit_print_subnet_xlate(struct xt_xlate *xl,
1252 uint32_t nsub, int family)
1253 {
1254 char sep = (family == NFPROTO_IPV4) ? '.' : ':';
1255 char *fmt = (family == NFPROTO_IPV4) ? "%u" : "%04x";
1256 unsigned int nblocks = (family == NFPROTO_IPV4) ? 4 : 8;
1257 unsigned int nbits = (family == NFPROTO_IPV4) ? 8 : 16;
1258 unsigned int acm, i;
1259
1260 xt_xlate_add(xl, " and ");
1261 while (nblocks--) {
1262 acm = 0;
1263
1264 for (i = 0; i < nbits; i++) {
1265 acm <<= 1;
1266
1267 if (nsub > 0) {
1268 acm++;
1269 nsub--;
1270 }
1271 }
1272
1273 xt_xlate_add_nospc(xl, fmt, acm);
1274 if (nblocks > 0)
1275 xt_xlate_add(xl, "%c", sep);
1276 }
1277 }
1278
1279 static const char *const hashlimit_modes4_xlate[] = {
1280 [XT_HASHLIMIT_HASH_DIP] = "ip daddr",
1281 [XT_HASHLIMIT_HASH_DPT] = "tcp dport",
1282 [XT_HASHLIMIT_HASH_SIP] = "ip saddr",
1283 [XT_HASHLIMIT_HASH_SPT] = "tcp sport",
1284 };
1285
1286 static const char *const hashlimit_modes6_xlate[] = {
1287 [XT_HASHLIMIT_HASH_DIP] = "ip6 daddr",
1288 [XT_HASHLIMIT_HASH_DPT] = "tcp dport",
1289 [XT_HASHLIMIT_HASH_SIP] = "ip6 saddr",
1290 [XT_HASHLIMIT_HASH_SPT] = "tcp sport",
1291 };
1292
hashlimit_mode_xlate(struct xt_xlate * xl,uint32_t mode,int family,unsigned int nsrc,unsigned int ndst)1293 static int hashlimit_mode_xlate(struct xt_xlate *xl,
1294 uint32_t mode, int family,
1295 unsigned int nsrc, unsigned int ndst)
1296 {
1297 const char * const *_modes = (family == NFPROTO_IPV4) ?
1298 hashlimit_modes4_xlate : hashlimit_modes6_xlate;
1299 bool prevopt = false;
1300 unsigned int mask;
1301
1302 mode &= ~XT_HASHLIMIT_INVERT & ~XT_HASHLIMIT_BYTES;
1303
1304 for (mask = 1; mode > 0; mask <<= 1) {
1305 if (!(mode & mask))
1306 continue;
1307
1308 if (!prevopt) {
1309 xt_xlate_add(xl, " ");
1310 prevopt = true;
1311 }
1312 else {
1313 xt_xlate_add(xl, " . ");
1314 }
1315
1316 xt_xlate_add(xl, "%s", _modes[mask]);
1317
1318 if (mask == XT_HASHLIMIT_HASH_DIP &&
1319 ((family == NFPROTO_IPV4 && ndst != 32) ||
1320 (family == NFPROTO_IPV6 && ndst != 128)))
1321 hashlimit_print_subnet_xlate(xl, ndst, family);
1322 else if (mask == XT_HASHLIMIT_HASH_SIP &&
1323 ((family == NFPROTO_IPV4 && nsrc != 32) ||
1324 (family == NFPROTO_IPV6 && nsrc != 128)))
1325 hashlimit_print_subnet_xlate(xl, nsrc, family);
1326
1327 mode &= ~mask;
1328 }
1329
1330 return prevopt;
1331 }
1332
hashlimit_mt_xlate(struct xt_xlate * xl,const char * name,const struct hashlimit_cfg3 * cfg,int revision,int family)1333 static int hashlimit_mt_xlate(struct xt_xlate *xl, const char *name,
1334 const struct hashlimit_cfg3 *cfg,
1335 int revision, int family)
1336 {
1337 int ret = 1;
1338
1339 xt_xlate_add(xl, "meter %s {", name);
1340 ret = hashlimit_mode_xlate(xl, cfg->mode, family,
1341 cfg->srcmask, cfg->dstmask);
1342 if (cfg->expire != 1000)
1343 xt_xlate_add(xl, " timeout %us", cfg->expire / 1000);
1344 xt_xlate_add(xl, " limit rate");
1345
1346 if (cfg->mode & XT_HASHLIMIT_INVERT)
1347 xt_xlate_add(xl, " over");
1348
1349 if (cfg->mode & XT_HASHLIMIT_BYTES)
1350 print_bytes_rate_xlate(xl, cfg);
1351 else {
1352 print_packets_rate_xlate(xl, cfg->avg, revision);
1353 if (cfg->burst != XT_HASHLIMIT_BURST)
1354 xt_xlate_add(xl, "burst %" PRIu64 " packets", (uint64_t)cfg->burst);
1355
1356 }
1357 xt_xlate_add(xl, "}");
1358
1359 return ret;
1360 }
1361
hashlimit_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1362 static int hashlimit_xlate(struct xt_xlate *xl,
1363 const struct xt_xlate_mt_params *params)
1364 {
1365 const struct xt_hashlimit_info *info = (const void *)params->match->data;
1366 int ret = 1;
1367
1368 xt_xlate_add(xl, "meter %s {", info->name);
1369 ret = hashlimit_mode_xlate(xl, info->cfg.mode, NFPROTO_IPV4, 32, 32);
1370 xt_xlate_add(xl, " timeout %us limit rate", info->cfg.expire / 1000);
1371 print_packets_rate_xlate(xl, info->cfg.avg, 1);
1372 xt_xlate_add(xl, " burst %u packets", info->cfg.burst);
1373 xt_xlate_add(xl, "}");
1374
1375 return ret;
1376 }
1377
hashlimit_mt4_xlate_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1378 static int hashlimit_mt4_xlate_v1(struct xt_xlate *xl,
1379 const struct xt_xlate_mt_params *params)
1380 {
1381 const struct xt_hashlimit_mtinfo1 *info =
1382 (const void *)params->match->data;
1383 struct hashlimit_cfg3 cfg;
1384
1385 if (cfg_copy(&cfg, (const void *)&info->cfg, 1))
1386 xtables_error(OTHER_PROBLEM, "unknown revision");
1387
1388 return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV4);
1389 }
1390
hashlimit_mt6_xlate_v1(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1391 static int hashlimit_mt6_xlate_v1(struct xt_xlate *xl,
1392 const struct xt_xlate_mt_params *params)
1393 {
1394 const struct xt_hashlimit_mtinfo1 *info =
1395 (const void *)params->match->data;
1396 struct hashlimit_cfg3 cfg;
1397
1398 if (cfg_copy(&cfg, (const void *)&info->cfg, 1))
1399 xtables_error(OTHER_PROBLEM, "unknown revision");
1400
1401 return hashlimit_mt_xlate(xl, info->name, &cfg, 1, NFPROTO_IPV6);
1402 }
1403
hashlimit_mt4_xlate_v2(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1404 static int hashlimit_mt4_xlate_v2(struct xt_xlate *xl,
1405 const struct xt_xlate_mt_params *params)
1406 {
1407 const struct xt_hashlimit_mtinfo2 *info =
1408 (const void *)params->match->data;
1409 struct hashlimit_cfg3 cfg;
1410
1411 if (cfg_copy(&cfg, (const void *)&info->cfg, 2))
1412 xtables_error(OTHER_PROBLEM, "unknown revision");
1413
1414 return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV4);
1415 }
1416
hashlimit_mt6_xlate_v2(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1417 static int hashlimit_mt6_xlate_v2(struct xt_xlate *xl,
1418 const struct xt_xlate_mt_params *params)
1419 {
1420 const struct xt_hashlimit_mtinfo2 *info =
1421 (const void *)params->match->data;
1422 struct hashlimit_cfg3 cfg;
1423
1424 if (cfg_copy(&cfg, (const void *)&info->cfg, 2))
1425 xtables_error(OTHER_PROBLEM, "unknown revision");
1426
1427 return hashlimit_mt_xlate(xl, info->name, &cfg, 2, NFPROTO_IPV6);
1428 }
1429
hashlimit_mt4_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1430 static int hashlimit_mt4_xlate(struct xt_xlate *xl,
1431 const struct xt_xlate_mt_params *params)
1432 {
1433 const struct xt_hashlimit_mtinfo3 *info =
1434 (const void *)params->match->data;
1435
1436 return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV4);
1437 }
1438
hashlimit_mt6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)1439 static int hashlimit_mt6_xlate(struct xt_xlate *xl,
1440 const struct xt_xlate_mt_params *params)
1441 {
1442 const struct xt_hashlimit_mtinfo3 *info =
1443 (const void *)params->match->data;
1444
1445 return hashlimit_mt_xlate(xl, info->name, &info->cfg, 3, NFPROTO_IPV6);
1446 }
1447
1448 static struct xtables_match hashlimit_mt_reg[] = {
1449 {
1450 .family = NFPROTO_UNSPEC,
1451 .name = "hashlimit",
1452 .version = XTABLES_VERSION,
1453 .revision = 0,
1454 .size = XT_ALIGN(sizeof(struct xt_hashlimit_info)),
1455 .userspacesize = offsetof(struct xt_hashlimit_info, hinfo),
1456 .help = hashlimit_help,
1457 .init = hashlimit_init,
1458 .x6_parse = hashlimit_parse,
1459 .x6_fcheck = hashlimit_check,
1460 .print = hashlimit_print,
1461 .save = hashlimit_save,
1462 .x6_options = hashlimit_opts,
1463 .udata_size = sizeof(struct hashlimit_mt_udata),
1464 .xlate = hashlimit_xlate,
1465 },
1466 {
1467 .version = XTABLES_VERSION,
1468 .name = "hashlimit",
1469 .revision = 1,
1470 .family = NFPROTO_IPV4,
1471 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
1472 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
1473 .help = hashlimit_mt_help,
1474 .init = hashlimit_mt4_init_v1,
1475 .x6_parse = hashlimit_mt_parse_v1,
1476 .x6_fcheck = hashlimit_mt_check_v1,
1477 .print = hashlimit_mt4_print_v1,
1478 .save = hashlimit_mt4_save_v1,
1479 .x6_options = hashlimit_mt_opts_v1,
1480 .udata_size = sizeof(struct hashlimit_mt_udata),
1481 .xlate = hashlimit_mt4_xlate_v1,
1482 },
1483 {
1484 .version = XTABLES_VERSION,
1485 .name = "hashlimit",
1486 .revision = 1,
1487 .family = NFPROTO_IPV6,
1488 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo1)),
1489 .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo),
1490 .help = hashlimit_mt_help,
1491 .init = hashlimit_mt6_init_v1,
1492 .x6_parse = hashlimit_mt_parse_v1,
1493 .x6_fcheck = hashlimit_mt_check_v1,
1494 .print = hashlimit_mt6_print_v1,
1495 .save = hashlimit_mt6_save_v1,
1496 .x6_options = hashlimit_mt_opts_v1,
1497 .udata_size = sizeof(struct hashlimit_mt_udata),
1498 .xlate = hashlimit_mt6_xlate_v1,
1499 },
1500 {
1501 .version = XTABLES_VERSION,
1502 .name = "hashlimit",
1503 .revision = 2,
1504 .family = NFPROTO_IPV4,
1505 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
1506 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
1507 .help = hashlimit_mt_help,
1508 .init = hashlimit_mt4_init_v2,
1509 .x6_parse = hashlimit_mt_parse_v2,
1510 .x6_fcheck = hashlimit_mt_check_v2,
1511 .print = hashlimit_mt4_print_v2,
1512 .save = hashlimit_mt4_save_v2,
1513 .x6_options = hashlimit_mt_opts_v2,
1514 .udata_size = sizeof(struct hashlimit_mt_udata),
1515 .xlate = hashlimit_mt4_xlate_v2,
1516 },
1517 {
1518 .version = XTABLES_VERSION,
1519 .name = "hashlimit",
1520 .revision = 2,
1521 .family = NFPROTO_IPV6,
1522 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo2)),
1523 .userspacesize = offsetof(struct xt_hashlimit_mtinfo2, hinfo),
1524 .help = hashlimit_mt_help,
1525 .init = hashlimit_mt6_init_v2,
1526 .x6_parse = hashlimit_mt_parse_v2,
1527 .x6_fcheck = hashlimit_mt_check_v2,
1528 .print = hashlimit_mt6_print_v2,
1529 .save = hashlimit_mt6_save_v2,
1530 .x6_options = hashlimit_mt_opts_v2,
1531 .udata_size = sizeof(struct hashlimit_mt_udata),
1532 .xlate = hashlimit_mt6_xlate_v2,
1533 },
1534 {
1535 .version = XTABLES_VERSION,
1536 .name = "hashlimit",
1537 .revision = 3,
1538 .family = NFPROTO_IPV4,
1539 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)),
1540 .userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo),
1541 .help = hashlimit_mt_help_v3,
1542 .init = hashlimit_mt4_init,
1543 .x6_parse = hashlimit_mt_parse,
1544 .x6_fcheck = hashlimit_mt_check,
1545 .print = hashlimit_mt4_print,
1546 .save = hashlimit_mt4_save,
1547 .x6_options = hashlimit_mt_opts,
1548 .udata_size = sizeof(struct hashlimit_mt_udata),
1549 .xlate = hashlimit_mt4_xlate,
1550 },
1551 {
1552 .version = XTABLES_VERSION,
1553 .name = "hashlimit",
1554 .revision = 3,
1555 .family = NFPROTO_IPV6,
1556 .size = XT_ALIGN(sizeof(struct xt_hashlimit_mtinfo3)),
1557 .userspacesize = offsetof(struct xt_hashlimit_mtinfo3, hinfo),
1558 .help = hashlimit_mt_help_v3,
1559 .init = hashlimit_mt6_init,
1560 .x6_parse = hashlimit_mt_parse,
1561 .x6_fcheck = hashlimit_mt_check,
1562 .print = hashlimit_mt6_print,
1563 .save = hashlimit_mt6_save,
1564 .x6_options = hashlimit_mt_opts,
1565 .udata_size = sizeof(struct hashlimit_mt_udata),
1566 .xlate = hashlimit_mt6_xlate,
1567 },
1568 };
1569
_init(void)1570 void _init(void)
1571 {
1572 xtables_register_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg));
1573 }
1574