blob: d0fd7bcf0057a4214aff33d2f9b8b84021b3593b [file] [log] [blame]
Marc Bouchere6869a82000-03-20 06:03:29 +00001/* Shared library add-on to iptables to add limit support.
2 *
3 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
Harald Welteb77f1da2002-03-14 11:35:58 +00004 * Hervé Eychenne <rv@wallfire.org>
Marc Bouchere6869a82000-03-20 06:03:29 +00005 */
Harald Welteb77f1da2002-03-14 11:35:58 +00006
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 */
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000015#include "../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
20/* Function which prints out usage message. */
21static void
22help(void)
23{
24 printf(
25"limit v%s options:\n"
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000026"--limit avg max average match rate: default "XT_LIMIT_AVG"\n"
Marc Bouchere6869a82000-03-20 06:03:29 +000027" [Packets per second unless followed by \n"
28" /sec /minute /hour /day postfixes]\n"
29"--limit-burst number number to match in a burst, default %u\n"
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000030"\n", IPTABLES_VERSION, XT_LIMIT_BURST);
Marc Bouchere6869a82000-03-20 06:03:29 +000031}
32
Jan Engelhardt661f1122007-07-30 14:46:51 +000033static const struct option opts[] = {
Patrick McHardy500f4832007-09-08 15:59:04 +000034 { "limit", 1, NULL, '%' },
35 { "limit-burst", 1, NULL, '$' },
36 { }
Marc Bouchere6869a82000-03-20 06:03:29 +000037};
38
39static
40int parse_rate(const char *rate, u_int32_t *val)
41{
42 const char *delim;
43 u_int32_t r;
44 u_int32_t mult = 1; /* Seconds by default. */
45
46 delim = strchr(rate, '/');
47 if (delim) {
48 if (strlen(delim+1) == 0)
49 return 0;
50
51 if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
52 mult = 1;
53 else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
54 mult = 60;
55 else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
56 mult = 60*60;
57 else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
58 mult = 24*60*60;
59 else
60 return 0;
61 }
62 r = atoi(rate);
63 if (!r)
64 return 0;
65
66 /* This would get mapped to infinite (1/day is minimum they
67 can specify, so we're ok at that end). */
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000068 if (r / mult > XT_LIMIT_SCALE)
Marc Bouchere6869a82000-03-20 06:03:29 +000069 exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
70
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000071 *val = XT_LIMIT_SCALE * mult / r;
Marc Bouchere6869a82000-03-20 06:03:29 +000072 return 1;
73}
74
75/* Initialize the match. */
76static void
Peter Rileyea146a92007-09-02 13:09:07 +000077init(struct xt_entry_match *m)
Marc Bouchere6869a82000-03-20 06:03:29 +000078{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000079 struct xt_rateinfo *r = (struct xt_rateinfo *)m->data;
Marc Bouchere6869a82000-03-20 06:03:29 +000080
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000081 parse_rate(XT_LIMIT_AVG, &r->avg);
82 r->burst = XT_LIMIT_BURST;
Marc Bouchere6869a82000-03-20 06:03:29 +000083
Marc Bouchere6869a82000-03-20 06:03:29 +000084}
85
86/* FIXME: handle overflow:
87 if (r->avg*r->burst/r->burst != r->avg)
88 exit_error(PARAMETER_PROBLEM,
89 "Sorry: burst too large for that avg rate.\n");
90*/
91
92/* Function which parses command options; returns true if it
93 ate an option */
94static int
95parse(int c, char **argv, int invert, unsigned int *flags,
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +000096 const void *entry,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +000097 struct xt_entry_match **match)
Marc Bouchere6869a82000-03-20 06:03:29 +000098{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +000099 struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data;
Harald Welteb4719762001-07-23 02:14:22 +0000100 unsigned int num;
Marc Bouchere6869a82000-03-20 06:03:29 +0000101
102 switch(c) {
103 case '%':
Phil Oester35160ee2004-09-21 10:43:45 +0000104 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000105 if (!parse_rate(optarg, &r->avg))
106 exit_error(PARAMETER_PROBLEM,
107 "bad rate `%s'", optarg);
Rusty Russell7e53bf92000-03-20 07:03:28 +0000108 break;
Marc Bouchere6869a82000-03-20 06:03:29 +0000109
110 case '$':
Phil Oester35160ee2004-09-21 10:43:45 +0000111 if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
Marc Boucher06e63942001-07-23 15:34:46 +0000112 if (string_to_number(optarg, 0, 10000, &num) == -1)
Marc Bouchere6869a82000-03-20 06:03:29 +0000113 exit_error(PARAMETER_PROBLEM,
114 "bad --limit-burst `%s'", optarg);
115 r->burst = num;
116 break;
117
118 default:
119 return 0;
120 }
121
Phil Oester35160ee2004-09-21 10:43:45 +0000122 if (invert)
123 exit_error(PARAMETER_PROBLEM,
124 "limit does not support invert");
125
Marc Bouchere6869a82000-03-20 06:03:29 +0000126 return 1;
127}
128
Jan Engelhardt0e2abed2007-10-04 16:25:58 +0000129static const struct rates
Marc Bouchere6869a82000-03-20 06:03:29 +0000130{
131 const char *name;
132 u_int32_t mult;
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000133} rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 },
134 { "hour", XT_LIMIT_SCALE*60*60 },
135 { "min", XT_LIMIT_SCALE*60 },
136 { "sec", XT_LIMIT_SCALE } };
Marc Bouchere6869a82000-03-20 06:03:29 +0000137
138static void print_rate(u_int32_t period)
139{
140 unsigned int i;
141
142 for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
143 if (period > rates[i].mult
Harald Welte1412e452001-10-16 08:26:37 +0000144 || rates[i].mult/period < rates[i].mult%period)
Marc Bouchere6869a82000-03-20 06:03:29 +0000145 break;
146 }
147
148 printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
149}
150
151/* Prints out the matchinfo. */
152static void
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000153print(const void *ip,
Yasuyuki KOZAKAI193df8e2007-07-24 05:57:28 +0000154 const struct xt_entry_match *match,
Marc Bouchere6869a82000-03-20 06:03:29 +0000155 int numeric)
156{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000157 struct xt_rateinfo *r = (struct xt_rateinfo *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000158 printf("limit: avg "); print_rate(r->avg);
159 printf("burst %u ", r->burst);
160}
161
162/* FIXME: Make minimalist: only print rate if not default --RR */
Yasuyuki KOZAKAIc0a9ab92007-07-24 06:02:05 +0000163static void save(const void *ip, const struct xt_entry_match *match)
Marc Bouchere6869a82000-03-20 06:03:29 +0000164{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000165 struct xt_rateinfo *r = (struct xt_rateinfo *)match->data;
Marc Bouchere6869a82000-03-20 06:03:29 +0000166
167 printf("--limit "); print_rate(r->avg);
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000168 if (r->burst != XT_LIMIT_BURST)
Marc Bouchere6869a82000-03-20 06:03:29 +0000169 printf("--limit-burst %u ", r->burst);
170}
171
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000172static struct xtables_match limit = {
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000173 .family = AF_INET,
Pablo Neira8caee8b2004-12-28 13:11:59 +0000174 .name = "limit",
175 .version = IPTABLES_VERSION,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000176 .size = XT_ALIGN(sizeof(struct xt_rateinfo)),
177 .userspacesize = offsetof(struct xt_rateinfo, prev),
178 .help = &help,
179 .init = &init,
180 .parse = &parse,
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000181 .print = &print,
182 .save = &save,
183 .extra_opts = opts
184};
185
186static struct xtables_match limit6 = {
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000187 .family = AF_INET6,
188 .name = "limit",
189 .version = IPTABLES_VERSION,
190 .size = XT_ALIGN(sizeof(struct xt_rateinfo)),
191 .userspacesize = offsetof(struct xt_rateinfo, prev),
Pablo Neira8caee8b2004-12-28 13:11:59 +0000192 .help = &help,
193 .init = &init,
194 .parse = &parse,
Pablo Neira8caee8b2004-12-28 13:11:59 +0000195 .print = &print,
196 .save = &save,
197 .extra_opts = opts
Marc Bouchere6869a82000-03-20 06:03:29 +0000198};
199
200void _init(void)
201{
Yasuyuki KOZAKAI4489c0d2007-07-24 07:11:26 +0000202 xtables_register_match(&limit);
203 xtables_register_match(&limit6);
Marc Bouchere6869a82000-03-20 06:03:29 +0000204}