1 /* Shared library add-on to iptables to add limit support.
3 * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr>
4 * Hervé Eychenne <rv@wallfire.org>
13 #include <linux/netfilter_ipv4/ip_tables.h>
14 /* For 64bit kernel / 32bit userspace */
15 #include "../include/linux/netfilter_ipv4/ipt_limit.h"
17 #define IPT_LIMIT_AVG "3/hour"
18 #define IPT_LIMIT_BURST 5
20 /* Function which prints out usage message. */
25 "limit v%s options:\n"
26 "--limit avg max average match rate: default "IPT_LIMIT_AVG
"\n"
27 " [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"
30 "\n", IPTABLES_VERSION
, IPT_LIMIT_BURST
);
33 static struct option opts
[] = {
34 { "limit", 1, 0, '%' },
35 { "limit-burst", 1, 0, '$' },
40 int parse_rate(const char *rate
, u_int32_t
*val
)
44 u_int32_t mult
= 1; /* Seconds by default. */
46 delim
= strchr(rate
, '/');
48 if (strlen(delim
+1) == 0)
51 if (strncasecmp(delim
+1, "second", strlen(delim
+1)) == 0)
53 else if (strncasecmp(delim
+1, "minute", strlen(delim
+1)) == 0)
55 else if (strncasecmp(delim
+1, "hour", strlen(delim
+1)) == 0)
57 else if (strncasecmp(delim
+1, "day", strlen(delim
+1)) == 0)
66 /* This would get mapped to infinite (1/day is minimum they
67 can specify, so we're ok at that end). */
68 if (r
/ mult
> IPT_LIMIT_SCALE
)
69 exit_error(PARAMETER_PROBLEM
, "Rate too fast `%s'\n", rate
);
71 *val
= IPT_LIMIT_SCALE
* mult
/ r
;
75 /* Initialize the match. */
77 init(struct ipt_entry_match
*m
, unsigned int *nfcache
)
79 struct ipt_rateinfo
*r
= (struct ipt_rateinfo
*)m
->data
;
81 parse_rate(IPT_LIMIT_AVG
, &r
->avg
);
82 r
->burst
= IPT_LIMIT_BURST
;
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");
92 /* Function which parses command options; returns true if it
95 parse(int c
, char **argv
, int invert
, unsigned int *flags
,
96 const struct ipt_entry
*entry
,
97 unsigned int *nfcache
,
98 struct ipt_entry_match
**match
)
100 struct ipt_rateinfo
*r
= (struct ipt_rateinfo
*)(*match
)->data
;
105 if (check_inverse(argv
[optind
-1], &invert
, &optind
, 0)) break;
106 if (!parse_rate(optarg
, &r
->avg
))
107 exit_error(PARAMETER_PROBLEM
,
108 "bad rate `%s'", optarg
);
112 if (check_inverse(argv
[optind
-1], &invert
, &optind
, 0)) break;
113 if (string_to_number(optarg
, 0, 10000, &num
) == -1)
114 exit_error(PARAMETER_PROBLEM
,
115 "bad --limit-burst `%s'", optarg
);
124 exit_error(PARAMETER_PROBLEM
,
125 "limit does not support invert");
130 /* Final check; nothing. */
131 static void final_check(unsigned int flags
)
139 } rates
[] = { { "day", IPT_LIMIT_SCALE
*24*60*60 },
140 { "hour", IPT_LIMIT_SCALE
*60*60 },
141 { "min", IPT_LIMIT_SCALE
*60 },
142 { "sec", IPT_LIMIT_SCALE
} };
144 static void print_rate(u_int32_t period
)
148 for (i
= 1; i
< sizeof(rates
)/sizeof(struct rates
); i
++) {
149 if (period
> rates
[i
].mult
150 || rates
[i
].mult
/period
< rates
[i
].mult
%period
)
154 printf("%u/%s ", rates
[i
-1].mult
/ period
, rates
[i
-1].name
);
157 /* Prints out the matchinfo. */
159 print(const struct ipt_ip
*ip
,
160 const struct ipt_entry_match
*match
,
163 struct ipt_rateinfo
*r
= (struct ipt_rateinfo
*)match
->data
;
164 printf("limit: avg "); print_rate(r
->avg
);
165 printf("burst %u ", r
->burst
);
168 /* FIXME: Make minimalist: only print rate if not default --RR */
169 static void save(const struct ipt_ip
*ip
, const struct ipt_entry_match
*match
)
171 struct ipt_rateinfo
*r
= (struct ipt_rateinfo
*)match
->data
;
173 printf("--limit "); print_rate(r
->avg
);
174 if (r
->burst
!= IPT_LIMIT_BURST
)
175 printf("--limit-burst %u ", r
->burst
);
178 static struct iptables_match limit
= {
181 .version
= IPTABLES_VERSION
,
182 .size
= IPT_ALIGN(sizeof(struct ipt_rateinfo
)),
183 .userspacesize
= offsetof(struct ipt_rateinfo
, prev
),
187 .final_check
= &final_check
,
195 register_match(&limit
);