blob: c8ddca8778400991868f6100382215e24e67a459 [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 Engelhardt9921f2b2012-10-10 00:35:14 +00006#define _BSD_SOURCE 1
Varsha Rao27de2812017-12-21 09:05:45 +05307#define _DEFAULT_SOURCE 1
Jan Engelhardt9921f2b2012-10-10 00:35:14 +00008#define _ISOC99_SOURCE 1
Jan Engelhardt9d69da42012-07-28 19:10:08 +02009#include <math.h>
Marc Bouchere6869a82000-03-20 06:03:29 +000010#include <stdio.h>
11#include <string.h>
12#include <stdlib.h>
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000013#include <xtables.h>
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000014#include <linux/netfilter/x_tables.h>
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 Engelhardt0f77e2e2011-05-07 03:26:08 +020020enum {
21 O_LIMIT = 0,
22 O_BURST,
23};
24
Jan Engelhardt181dead2007-10-04 16:27:07 +000025static void limit_help(void)
Marc Bouchere6869a82000-03-20 06:03:29 +000026{
27 printf(
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020028"limit match options:\n"
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000029"--limit avg max average match rate: default "XT_LIMIT_AVG"\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000030" [Packets per second unless followed by \n"
31" /sec /minute /hour /day postfixes]\n"
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +020032"--limit-burst number number to match in a burst, default %u\n",
33XT_LIMIT_BURST);
Marc Bouchere6869a82000-03-20 06:03:29 +000034}
35
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020036static const struct xt_option_entry limit_opts[] = {
37 {.name = "limit", .id = O_LIMIT, .type = XTTYPE_STRING},
38 {.name = "limit-burst", .id = O_BURST, .type = XTTYPE_UINT32,
39 .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_rateinfo, burst),
40 .min = 0, .max = 10000},
41 XTOPT_TABLEEND,
Marc Bouchere6869a82000-03-20 06:03:29 +000042};
43
44static
Jan Engelhardt7ac40522011-01-07 12:34:04 +010045int parse_rate(const char *rate, uint32_t *val)
Marc Bouchere6869a82000-03-20 06:03:29 +000046{
47 const char *delim;
Jan Engelhardt7ac40522011-01-07 12:34:04 +010048 uint32_t r;
49 uint32_t mult = 1; /* Seconds by default. */
Marc Bouchere6869a82000-03-20 06:03:29 +000050
51 delim = strchr(rate, '/');
52 if (delim) {
53 if (strlen(delim+1) == 0)
54 return 0;
55
56 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
57 mult = 1;
58 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
59 mult = 60;
60 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
61 mult = 60*60;
62 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
63 mult = 24*60*60;
64 else
65 return 0;
66 }
67 r = atoi(rate);
68 if (!r)
69 return 0;
70
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000071 *val = XT_LIMIT_SCALE * mult / r;
Jan Engelhardt9d69da42012-07-28 19:10:08 +020072 if (*val == 0)
73 /*
74 * The rate maps to infinity. (1/day is the minimum they can
75 * specify, so we are ok at that end).
76 */
77 xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate);
Marc Bouchere6869a82000-03-20 06:03:29 +000078 return 1;
79}
80
Jan Engelhardt181dead2007-10-04 16:27:07 +000081static void limit_init(struct xt_entry_match *m)
Marc Bouchere6869a82000-03-20 06:03:29 +000082{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000083 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000084
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000085 parse_rate(XT_LIMIT_AVG, &r->avg);
86 r->burst = XT_LIMIT_BURST;
Marc Bouchere6869a82000-03-20 06:03:29 +000087
Marc Bouchere6869a82000-03-20 06:03:29 +000088}
89
90/* FIXME: handle overflow:
91 if (r->avg*r->burst/r->burst != r->avg)
Jan Engelhardt1829ed42009-02-21 03:29:44 +010092 xtables_error(PARAMETER_PROBLEM,
Marc Bouchere6869a82000-03-20 06:03:29 +000093 "Sorry: burst too large for that avg rate.\n");
94*/
95
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020096static void limit_parse(struct xt_option_call *cb)
Marc Bouchere6869a82000-03-20 06:03:29 +000097{
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +020098 struct xt_rateinfo *r = cb->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000099
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200100 xtables_option_parse(cb);
101 switch (cb->entry->id) {
102 case O_LIMIT:
103 if (!parse_rate(cb->arg, &r->avg))
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100104 xtables_error(PARAMETER_PROBLEM,
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200105 "bad rate \"%s\"'", cb->arg);
Marc Bouchere6869a82000-03-20 06:03:29 +0000106 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000107 }
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200108 if (cb->invert)
Jan Engelhardt1829ed42009-02-21 03:29:44 +0100109 xtables_error(PARAMETER_PROBLEM,
Phil Oester35160ee2004-09-21 10:43:45 +0000110 "limit does not support invert");
Marc Bouchere6869a82000-03-20 06:03:29 +0000111}
112
Jan Engelhardt0e2abed2007-10-04 16:25:58 +0000113static const struct rates
Marc Bouchere6869a82000-03-20 06:03:29 +0000114{
115 const char *name;
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100116 uint32_t mult;
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000117} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
118 { "hour", XT_LIMIT_SCALE*60*60 },
119 { "min", XT_LIMIT_SCALE*60 },
120 { "sec", XT_LIMIT_SCALE } };
Marc Bouchere6869a82000-03-20 06:03:29 +0000121
Jan Engelhardt7ac40522011-01-07 12:34:04 +0100122static void print_rate(uint32_t period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000123{
124 unsigned int i;
125
Jan Engelhardt9d69da42012-07-28 19:10:08 +0200126 if (period == 0) {
127 printf(" %f", INFINITY);
128 return;
129 }
130
Jan Engelhardt2c69b552009-04-30 19:32:02 +0200131 for (i = 1; i < ARRAY_SIZE(rates); ++i)
Marc Bouchere6869a82000-03-20 06:03:29 +0000132 if (period > rates[i].mult
Harald Welte1412e452001-10-16 08:26:37 +0000133 || rates[i].mult/period < rates[i].mult%period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000134 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000135
Jan Engelhardt73866352010-12-18 02:04:59 +0100136 printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name);
Marc Bouchere6869a82000-03-20 06:03:29 +0000137}
138
Marc Bouchere6869a82000-03-20 06:03:29 +0000139static void
Jan Engelhardt181dead2007-10-04 16:27:07 +0000140limit_print(const void *ip, const struct xt_entry_match *match, int numeric)
Marc Bouchere6869a82000-03-20 06:03:29 +0000141{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200142 const struct xt_rateinfo *r = (const void *)match->data;
Jan Engelhardt73866352010-12-18 02:04:59 +0100143 printf(" limit: avg"); print_rate(r->avg);
144 printf(" burst %u", r->burst);
Marc Bouchere6869a82000-03-20 06:03:29 +0000145}
146
Jan Engelhardt181dead2007-10-04 16:27:07 +0000147static void limit_save(const void *ip, const struct xt_entry_match *match)
Marc Bouchere6869a82000-03-20 06:03:29 +0000148{
Jan Engelhardt69f564e2009-05-26 13:14:06 +0200149 const struct xt_rateinfo *r = (const void *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000150
Jan Engelhardt73866352010-12-18 02:04:59 +0100151 printf(" --limit"); print_rate(r->avg);
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000152 if (r->burst != XT_LIMIT_BURST)
Jan Engelhardt73866352010-12-18 02:04:59 +0100153 printf(" --limit-burst %u", r->burst);
Marc Bouchere6869a82000-03-20 06:03:29 +0000154}
155
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530156static const struct rates rates_xlate[] = {
157 { "day", XT_LIMIT_SCALE * 24 * 60 * 60 },
158 { "hour", XT_LIMIT_SCALE * 60 * 60 },
159 { "minute", XT_LIMIT_SCALE * 60 },
160 { "second", XT_LIMIT_SCALE }
161};
162
Pablo Neira Ayuso6b60dc52016-02-01 19:24:38 +0100163static void print_rate_xlate(uint32_t period, struct xt_xlate *xl)
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530164{
165 unsigned int i;
166
167 if (period == 0) {
Pablo M. Bermudo Garayf035be32016-07-09 12:27:51 +0200168 xt_xlate_add(xl, " %f", INFINITY);
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530169 return;
170 }
171
172 for (i = 1; i < ARRAY_SIZE(rates); ++i)
173 if (period > rates_xlate[i].mult ||
174 rates_xlate[i].mult / period < rates_xlate[i].mult % period)
175 break;
176
Pablo M. Bermudo Garayf035be32016-07-09 12:27:51 +0200177 xt_xlate_add(xl, " %u/%s", rates_xlate[i - 1].mult / period,
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530178 rates_xlate[i - 1].name);
179}
180
Pablo Neira Ayuso7a0992d2016-07-24 12:45:53 +0200181static int limit_xlate(struct xt_xlate *xl,
182 const struct xt_xlate_mt_params *params)
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530183{
Pablo Neira Ayuso7a0992d2016-07-24 12:45:53 +0200184 const struct xt_rateinfo *r = (const void *)params->match->data;
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530185
Pablo Neira Ayuso6b60dc52016-02-01 19:24:38 +0100186 xt_xlate_add(xl, "limit rate");
187 print_rate_xlate(r->avg, xl);
Liping Zhang99164702016-05-21 18:07:16 +0800188 if (r->burst != 0)
Pablo M. Bermudo Garayf035be32016-07-09 12:27:51 +0200189 xt_xlate_add(xl, " burst %u packets", r->burst);
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530190
191 return 1;
192}
193
Jan Engelhardt181dead2007-10-04 16:27:07 +0000194static struct xtables_match limit_match = {
Jan Engelhardt42979362009-06-01 11:56:23 +0200195 .family = NFPROTO_UNSPEC,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000196 .name = "limit",
Jan Engelhardt8b7c64d2008-04-15 11:48:25 +0200197 .version = XTABLES_VERSION,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000198 .size = XT_ALIGN(sizeof(struct xt_rateinfo)),
199 .userspacesize = offsetof(struct xt_rateinfo, prev),
Jan Engelhardt181dead2007-10-04 16:27:07 +0000200 .help = limit_help,
201 .init = limit_init,
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200202 .x6_parse = limit_parse,
Jan Engelhardt181dead2007-10-04 16:27:07 +0000203 .print = limit_print,
204 .save = limit_save,
Jan Engelhardt0f77e2e2011-05-07 03:26:08 +0200205 .x6_options = limit_opts,
Shivani Bhardwaja8dfbe32015-12-23 03:25:21 +0530206 .xlate = limit_xlate,
Marc Bouchere6869a82000-03-20 06:03:29 +0000207};
208
209void _init(void)
210{
Jan Engelhardt181dead2007-10-04 16:27:07 +0000211 xtables_register_match(&limit_match);
Marc Bouchere6869a82000-03-20 06:03:29 +0000212}