blob: b15b02f20ebd62f68ea56e3d6443ec4eb8178ebb [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add limit support.
2 *
Jan Engelhardt81bd5882008-09-04 17:49:18 +02003 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
4 * Hervé Eychenne <rv@wallfire.org>
Marc Bouchere6869a82000-03-20 06:03:29 +00005 */
6#include <stdio.h>
7#include <string.h>
8#include <stdlib.h>
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +00009#include <xtables.h>
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000010#include <linux/netfilter/x_tables.h>
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020011#include <linux/netfilter/xt_limit.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000012
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000013#define XT_LIMIT_AVG "3/hour"
14#define XT_LIMIT_BURST 5
Marc Bouchere6869a82000-03-20 06:03:29 +000015
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020016enum {
17 O_LIMIT = 0,
18 O_BURST,
19};
20
Jan Engelhardt181dead2007-10-04 16:27:07 +000021static void limit_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000022{
23 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020024"limit match options:\n"
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000025"--limit avg max average match rate: default "XT_LIMIT_AVG"\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000026" [Packets per second unless followed by \n"
27" /sec /minute /hour /day postfixes]\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020028"--limit-burst number number to match in a burst, default %u\n",
29XT_LIMIT_BURST);
Marc Bouchere6869a82000-03-20 06:03:29 +000030}
31
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020032static const struct xt_option_entry limit_opts[] = {
33 {.name = "limit", .id = O_LIMIT, .type = XTTYPE_STRING},
34 {.name = "limit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
35 .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_rateinfo, burst),
36 .min = 0, .max = 10000},
37 XTOPT_TABLEEND,
Marc Bouchere6869a82000-03-20 06:03:29 +000038};
39
40static
Jan Engelhardt7ac40522011-01-07 12:34:04 +010041int parse_rate(const char *rate, uint32_t *val)
Marc Bouchere6869a82000-03-20 06:03:29 +000042{
43 const char *delim;
Jan Engelhardt7ac40522011-01-07 12:34:04 +010044 uint32_t r;
45 uint32_t mult = 1; /* Seconds by default. */
Marc Bouchere6869a82000-03-20 06:03:29 +000046
47 delim = strchr(rate, '/');
48 if (delim) {
49 if (strlen(delim+1) == 0)
50 return 0;
51
52 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
53 mult = 1;
54 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
55 mult = 60;
56 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
57 mult = 60*60;
58 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
59 mult = 24*60*60;
60 else
61 return 0;
62 }
63 r = atoi(rate);
64 if (!r)
65 return 0;
66
67 /* This would get mapped to infinite (1/day is minimum they
68 can specify, so we're ok at that end). */
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000069 if (r / mult > XT_LIMIT_SCALE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010070 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Marc Bouchere6869a82000-03-20 06:03:29 +000071
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000072 *val = XT_LIMIT_SCALE * mult / r;
Marc Bouchere6869a82000-03-20 06:03:29 +000073 return 1;
74}
75
Jan Engelhardt181dead2007-10-04 16:27:07 +000076static void limit_init(struct xt_entry_match *m)
Marc Bouchere6869a82000-03-20 06:03:29 +000077{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000078 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000079
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000080 parse_rate(XT_LIMIT_AVG, &r->avg);
81 r->burst = XT_LIMIT_BURST;
Marc Bouchere6869a82000-03-20 06:03:29 +000082
Marc Bouchere6869a82000-03-20 06:03:29 +000083}
84
85/* FIXME: handle overflow:
86 if (r->avg*r->burst/r->burst != r->avg)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010087 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +000088 "Sorry: burst too large for that avg rate.\n");
89*/
90
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020091static void limit_parse(struct xt_option_call *cb)
Marc Bouchere6869a82000-03-20 06:03:29 +000092{
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020093 struct xt_rateinfo *r = cb->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000094
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020095 xtables_option_parse(cb);
96 switch (cb->entry->id) {
97 case O_LIMIT:
98 if (!parse_rate(cb->arg, &r->avg))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010099 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200100 "bad rate \"%s\"'", cb->arg);
Marc Bouchere6869a82000-03-20 06:03:29 +0000101 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000102 }
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200103 if (cb->invert)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100104 xtables_error(PARAMETER_PROBLEM,
Phil Oester35160ee2004-09-21 10:43:45 +0000105 "limit does not support invert");
Marc Bouchere6869a82000-03-20 06:03:29 +0000106}
107
Jan Engelhardt0e2abed2007-10-04 16:25:58 +0000108static const struct rates
Marc Bouchere6869a82000-03-20 06:03:29 +0000109{
110 const char *name;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100111 uint32_t mult;
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000112} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
113 { "hour", XT_LIMIT_SCALE*60*60 },
114 { "min", XT_LIMIT_SCALE*60 },
115 { "sec", XT_LIMIT_SCALE } };
Marc Bouchere6869a82000-03-20 06:03:29 +0000116
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100117static void print_rate(uint32_t period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000118{
119 unsigned int i;
120
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200121 for (i = 1; i < ARRAY_SIZE(rates); ++i)
Marc Bouchere6869a82000-03-20 06:03:29 +0000122 if (period > rates[i].mult
Harald Welte1412e452001-10-16 08:26:37 +0000123 || rates[i].mult/period < rates[i].mult%period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000124 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000125
Jan Engelhardt73866352010-12-18 02:04:59 +0100126 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000127}
128
Marc Bouchere6869a82000-03-20 06:03:29 +0000129static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000130limit_print(const void *ip, const struct xt_entry_match *match, int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000131{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200132 const struct xt_rateinfo *r = (const void *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100133 printf(" limit: avg"); print_rate(r->avg);
134 printf(" burst %u", r->burst);
Marc Bouchere6869a82000-03-20 06:03:29 +0000135}
136
Jan Engelhardt181dead2007-10-04 16:27:07 +0000137static void limit_save(const void *ip, const struct xt_entry_match *match)
Marc Bouchere6869a82000-03-20 06:03:29 +0000138{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200139 const struct xt_rateinfo *r = (const void *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000140
Jan Engelhardt73866352010-12-18 02:04:59 +0100141 printf(" --limit"); print_rate(r->avg);
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000142 if (r->burst != XT_LIMIT_BURST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100143 printf(" --limit-burst %u", r->burst);
Marc Bouchere6869a82000-03-20 06:03:29 +0000144}
145
Jan Engelhardt181dead2007-10-04 16:27:07 +0000146static struct xtables_match limit_match = {
Jan Engelhardt42979362009-06-01 11:56:23 +0200147 .family = NFPROTO_UNSPEC,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000148 .name = "limit",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200149 .version = XTABLES_VERSION,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000150 .size = XT_ALIGN(sizeof(struct xt_rateinfo)),
151 .userspacesize = offsetof(struct xt_rateinfo, prev),
Jan Engelhardt181dead2007-10-04 16:27:07 +0000152 .help = limit_help,
153 .init = limit_init,
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200154 .x6_parse = limit_parse,
Jan Engelhardt181dead2007-10-04 16:27:07 +0000155 .print = limit_print,
156 .save = limit_save,
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200157 .x6_options = limit_opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000158};
159
160void _init(void)
161{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000162 xtables_register_match(&limit_match);
Marc Bouchere6869a82000-03-20 06:03:29 +0000163}