blob: c4ba58bb05322dd731a0d2eb60fa5018d0f57120 [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 */
Jan Engelhardt32b8e612010-07-23 21:16:14 +02006#include <stdbool.h>
Marc Bouchere6869a82000-03-20 06:03:29 +00007#include <stdio.h>
8#include <string.h>
9#include <stdlib.h>
10#include <getopt.h>
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000011#include <xtables.h>
Rusty Russell849779c2000-04-23 15:51:51 +000012#include <stddef.h>
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000013#include <linux/netfilter/x_tables.h>
Martin Josefsson1da399c2004-05-26 15:50:57 +000014/* For 64bit kernel / 32bit userspace */
Jan Engelhardta2a7f2b2008-09-01 14:20:13 +020015#include <linux/netfilter/xt_limit.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000016
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000017#define XT_LIMIT_AVG "3/hour"
18#define XT_LIMIT_BURST 5
Marc Bouchere6869a82000-03-20 06:03:29 +000019
Jan Engelhardt181dead2007-10-04 16:27:07 +000020static void limit_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000021{
22 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020023"limit match options:\n"
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000024"--limit avg max average match rate: default "XT_LIMIT_AVG"\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000025" [Packets per second unless followed by \n"
26" /sec /minute /hour /day postfixes]\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020027"--limit-burst number number to match in a burst, default %u\n",
28XT_LIMIT_BURST);
Marc Bouchere6869a82000-03-20 06:03:29 +000029}
30
Jan Engelhardt181dead2007-10-04 16:27:07 +000031static const struct option limit_opts[] = {
Jan Engelhardt32b8e612010-07-23 21:16:14 +020032 {.name = "limit", .has_arg = true, .val = '%'},
33 {.name = "limit-burst", .has_arg = true, .val = '$'},
34 XT_GETOPT_TABLEEND,
Marc Bouchere6869a82000-03-20 06:03:29 +000035};
36
37static
Jan Engelhardt7ac40522011-01-07 12:34:04 +010038int parse_rate(const char *rate, uint32_t *val)
Marc Bouchere6869a82000-03-20 06:03:29 +000039{
40 const char *delim;
Jan Engelhardt7ac40522011-01-07 12:34:04 +010041 uint32_t r;
42 uint32_t mult = 1; /* Seconds by default. */
Marc Bouchere6869a82000-03-20 06:03:29 +000043
44 delim = strchr(rate, '/');
45 if (delim) {
46 if (strlen(delim+1) == 0)
47 return 0;
48
49 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
50 mult = 1;
51 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
52 mult = 60;
53 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
54 mult = 60*60;
55 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
56 mult = 24*60*60;
57 else
58 return 0;
59 }
60 r = atoi(rate);
61 if (!r)
62 return 0;
63
64 /* This would get mapped to infinite (1/day is minimum they
65 can specify, so we're ok at that end). */
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000066 if (r / mult > XT_LIMIT_SCALE)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010067 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Marc Bouchere6869a82000-03-20 06:03:29 +000068
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000069 *val = XT_LIMIT_SCALE * mult / r;
Marc Bouchere6869a82000-03-20 06:03:29 +000070 return 1;
71}
72
Jan Engelhardt181dead2007-10-04 16:27:07 +000073static void limit_init(struct xt_entry_match *m)
Marc Bouchere6869a82000-03-20 06:03:29 +000074{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000075 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000076
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000077 parse_rate(XT_LIMIT_AVG, &r->avg);
78 r->burst = XT_LIMIT_BURST;
Marc Bouchere6869a82000-03-20 06:03:29 +000079
Marc Bouchere6869a82000-03-20 06:03:29 +000080}
81
82/* FIXME: handle overflow:
83 if (r->avg*r->burst/r->burst != r->avg)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010084 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +000085 "Sorry: burst too large for that avg rate.\n");
86*/
87
Marc Bouchere6869a82000-03-20 06:03:29 +000088static int
Jan Engelhardt181dead2007-10-04 16:27:07 +000089limit_parse(int c, char **argv, int invert, unsigned int *flags,
90 const void *entry, struct xt_entry_match **match)
Marc Bouchere6869a82000-03-20 06:03:29 +000091{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000092 struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data;
Harald Welteb4719762001-07-23 02:14:22 +000093 unsigned int num;
Marc Bouchere6869a82000-03-20 06:03:29 +000094
95 switch(c) {
96 case '%':
Jan Engelhardtbbe83862009-10-24 00:45:33 +020097 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Marc Bouchere6869a82000-03-20 06:03:29 +000098 if (!parse_rate(optarg, &r->avg))
Jan Engelhardt1829ed42009-02-21 03:29:44 +010099 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +0000100 "bad rate `%s'", optarg);
Rusty Russell7e53bf92000-03-20 07:03:28 +0000101 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000102
103 case '$':
Jan Engelhardtbbe83862009-10-24 00:45:33 +0200104 if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break;
Jan Engelhardt5f2922c2009-01-27 18:43:01 +0100105 if (!xtables_strtoui(optarg, NULL, &num, 0, 10000))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100106 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +0000107 "bad --limit-burst `%s'", optarg);
108 r->burst = num;
109 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000110 }
111
Phil Oester35160ee2004-09-21 10:43:45 +0000112 if (invert)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100113 xtables_error(PARAMETER_PROBLEM,
Phil Oester35160ee2004-09-21 10:43:45 +0000114 "limit does not support invert");
115
Marc Bouchere6869a82000-03-20 06:03:29 +0000116 return 1;
117}
118
Jan Engelhardt0e2abed2007-10-04 16:25:58 +0000119static const struct rates
Marc Bouchere6869a82000-03-20 06:03:29 +0000120{
121 const char *name;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100122 uint32_t mult;
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000123} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
124 { "hour", XT_LIMIT_SCALE*60*60 },
125 { "min", XT_LIMIT_SCALE*60 },
126 { "sec", XT_LIMIT_SCALE } };
Marc Bouchere6869a82000-03-20 06:03:29 +0000127
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100128static void print_rate(uint32_t period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000129{
130 unsigned int i;
131
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200132 for (i = 1; i < ARRAY_SIZE(rates); ++i)
Marc Bouchere6869a82000-03-20 06:03:29 +0000133 if (period > rates[i].mult
Harald Welte1412e452001-10-16 08:26:37 +0000134 || rates[i].mult/period < rates[i].mult%period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000135 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000136
Jan Engelhardt73866352010-12-18 02:04:59 +0100137 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000138}
139
Marc Bouchere6869a82000-03-20 06:03:29 +0000140static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000141limit_print(const void *ip, const struct xt_entry_match *match, int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000142{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200143 const struct xt_rateinfo *r = (const void *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100144 printf(" limit: avg"); print_rate(r->avg);
145 printf(" burst %u", r->burst);
Marc Bouchere6869a82000-03-20 06:03:29 +0000146}
147
Jan Engelhardt181dead2007-10-04 16:27:07 +0000148static void limit_save(const void *ip, const struct xt_entry_match *match)
Marc Bouchere6869a82000-03-20 06:03:29 +0000149{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200150 const struct xt_rateinfo *r = (const void *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000151
Jan Engelhardt73866352010-12-18 02:04:59 +0100152 printf(" --limit"); print_rate(r->avg);
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000153 if (r->burst != XT_LIMIT_BURST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100154 printf(" --limit-burst %u", r->burst);
Marc Bouchere6869a82000-03-20 06:03:29 +0000155}
156
Jan Engelhardt181dead2007-10-04 16:27:07 +0000157static struct xtables_match limit_match = {
Jan Engelhardt42979362009-06-01 11:56:23 +0200158 .family = NFPROTO_UNSPEC,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000159 .name = "limit",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200160 .version = XTABLES_VERSION,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000161 .size = XT_ALIGN(sizeof(struct xt_rateinfo)),
162 .userspacesize = offsetof(struct xt_rateinfo, prev),
Jan Engelhardt181dead2007-10-04 16:27:07 +0000163 .help = limit_help,
164 .init = limit_init,
165 .parse = limit_parse,
166 .print = limit_print,
167 .save = limit_save,
168 .extra_opts = limit_opts,
Marc Bouchere6869a82000-03-20 06:03:29 +0000169};
170
171void _init(void)
172{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000173 xtables_register_match(&limit_match);
Marc Bouchere6869a82000-03-20 06:03:29 +0000174}