• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/iptables/extensions/
1/* iptables match extension for limiting packets per destination
2 *
3 * (C) 2003 by Harald Welte <laforge@netfilter.org>
4 *
5 * Development of this code was funded by Astaro AG, http://www.astaro.com/
6 *
7 * Based on ipt_limit.c by
8 * J�r�me de Vivie   <devivie@info.enserb.u-bordeaux.fr>
9 * Herv� Eychenne    <rv@wallfire.org>
10 */
11
12#include <stdio.h>
13#include <string.h>
14#include <stdlib.h>
15#include <getopt.h>
16#include <iptables.h>
17#include <stddef.h>
18#include <linux/netfilter_ipv4/ip_tables.h>
19#include <linux/netfilter_ipv4/ipt_dstlimit.h>
20
21#define IPT_DSTLIMIT_BURST	5
22
23/* miliseconds */
24#define IPT_DSTLIMIT_GCINTERVAL	1000
25#define IPT_DSTLIMIT_EXPIRE	10000
26
27/* Function which prints out usage message. */
28static void
29help(void)
30{
31	printf(
32"dstlimit v%s options:\n"
33"--dstlimit <avg>		max average match rate\n"
34"                                [Packets per second unless followed by \n"
35"                                /sec /minute /hour /day postfixes]\n"
36"--dstlimit-mode <mode>		mode\n"
37"					dstip\n"
38"					dstip-dstport\n"
39"					srcip-dstip\n"
40"					srcip-dstip-dstport\n"
41"--dstlimit-name <name>		name for /proc/net/ipt_dstlimit/\n"
42"[--dstlimit-burst <num>]	number to match in a burst, default %u\n"
43"[--dstlimit-htable-size <num>]	number of hashtable buckets\n"
44"[--dstlimit-htable-max <num>]	number of hashtable entries\n"
45"[--dstlimit-htable-gcinterval]	interval between garbage collection runs\n"
46"[--dstlimit-htable-expire]	after which time are idle entries expired?\n"
47"\n", IPTABLES_VERSION, IPT_DSTLIMIT_BURST);
48}
49
50static struct option opts[] = {
51	{ "dstlimit", 1, 0, '%' },
52	{ "dstlimit-burst", 1, 0, '$' },
53	{ "dstlimit-htable-size", 1, 0, '&' },
54	{ "dstlimit-htable-max", 1, 0, '*' },
55	{ "dstlimit-htable-gcinterval", 1, 0, '(' },
56	{ "dstlimit-htable-expire", 1, 0, ')' },
57	{ "dstlimit-mode", 1, 0, '_' },
58	{ "dstlimit-name", 1, 0, '"' },
59	{ 0 }
60};
61
62static
63int parse_rate(const char *rate, u_int32_t *val)
64{
65	const char *delim;
66	u_int32_t r;
67	u_int32_t mult = 1;  /* Seconds by default. */
68
69	delim = strchr(rate, '/');
70	if (delim) {
71		if (strlen(delim+1) == 0)
72			return 0;
73
74		if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0)
75			mult = 1;
76		else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0)
77			mult = 60;
78		else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0)
79			mult = 60*60;
80		else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0)
81			mult = 24*60*60;
82		else
83			return 0;
84	}
85	r = atoi(rate);
86	if (!r)
87		return 0;
88
89	/* This would get mapped to infinite (1/day is minimum they
90           can specify, so we're ok at that end). */
91	if (r / mult > IPT_DSTLIMIT_SCALE)
92		exit_error(PARAMETER_PROBLEM, "Rate too fast `%s'\n", rate);
93
94	*val = IPT_DSTLIMIT_SCALE * mult / r;
95	return 1;
96}
97
98/* Initialize the match. */
99static void
100init(struct ipt_entry_match *m, unsigned int *nfcache)
101{
102	struct ipt_dstlimit_info *r = (struct ipt_dstlimit_info *)m->data;
103
104	r->cfg.burst = IPT_DSTLIMIT_BURST;
105	r->cfg.gc_interval = IPT_DSTLIMIT_GCINTERVAL;
106	r->cfg.expire = IPT_DSTLIMIT_EXPIRE;
107
108}
109
110#define PARAM_LIMIT		0x00000001
111#define PARAM_BURST		0x00000002
112#define PARAM_MODE		0x00000004
113#define PARAM_NAME		0x00000008
114#define PARAM_SIZE		0x00000010
115#define PARAM_MAX		0x00000020
116#define PARAM_GCINTERVAL	0x00000040
117#define PARAM_EXPIRE		0x00000080
118
119/* Function which parses command options; returns true if it
120   ate an option */
121static int
122parse(int c, char **argv, int invert, unsigned int *flags,
123      const struct ipt_entry *entry,
124      unsigned int *nfcache,
125      struct ipt_entry_match **match)
126{
127	struct ipt_dstlimit_info *r =
128			(struct ipt_dstlimit_info *)(*match)->data;
129	unsigned int num;
130
131	switch(c) {
132	case '%':
133		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
134		if (!parse_rate(optarg, &r->cfg.avg))
135			exit_error(PARAMETER_PROBLEM,
136				   "bad rate `%s'", optarg);
137		*flags |= PARAM_LIMIT;
138		break;
139
140	case '$':
141		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
142		if (string_to_number(optarg, 0, 10000, &num) == -1)
143			exit_error(PARAMETER_PROBLEM,
144				   "bad --dstlimit-burst `%s'", optarg);
145		r->cfg.burst = num;
146		*flags |= PARAM_BURST;
147		break;
148	case '&':
149		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
150		if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
151			exit_error(PARAMETER_PROBLEM,
152				"bad --dstlimit-htable-size: `%s'", optarg);
153		r->cfg.size = num;
154		*flags |= PARAM_SIZE;
155		break;
156	case '*':
157		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
158		if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
159			exit_error(PARAMETER_PROBLEM,
160				"bad --dstlimit-htable-max: `%s'", optarg);
161		r->cfg.max = num;
162		*flags |= PARAM_MAX;
163		break;
164	case '(':
165		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
166		if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
167			exit_error(PARAMETER_PROBLEM,
168				"bad --dstlimit-htable-gcinterval: `%s'",
169				optarg);
170		/* FIXME: not HZ dependent!! */
171		r->cfg.gc_interval = num;
172		*flags |= PARAM_GCINTERVAL;
173		break;
174	case ')':
175		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
176		if (string_to_number(optarg, 0, 0xffffffff, &num) == -1)
177			exit_error(PARAMETER_PROBLEM,
178				"bad --dstlimit-htable-expire: `%s'", optarg);
179		/* FIXME: not HZ dependent */
180		r->cfg.expire = num;
181		*flags |= PARAM_EXPIRE;
182		break;
183	case '_':
184		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
185		if (!strcmp(optarg, "dstip"))
186			r->cfg.mode = IPT_DSTLIMIT_HASH_DIP;
187		else if (!strcmp(optarg, "dstip-destport") ||
188			 !strcmp(optarg, "dstip-dstport"))
189			r->cfg.mode = IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT;
190		else if (!strcmp(optarg, "srcip-dstip"))
191			r->cfg.mode = IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP;
192		else if (!strcmp(optarg, "srcip-dstip-destport") ||
193			 !strcmp(optarg, "srcip-dstip-dstport"))
194			r->cfg.mode = IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT;
195		else
196			exit_error(PARAMETER_PROBLEM,
197				"bad --dstlimit-mode: `%s'\n", optarg);
198		*flags |= PARAM_MODE;
199		break;
200	case '"':
201		if (check_inverse(argv[optind-1], &invert, &optind, 0)) break;
202		if (strlen(optarg) == 0)
203			exit_error(PARAMETER_PROBLEM, "Zero-length name?");
204		strncpy(r->name, optarg, sizeof(r->name));
205		*flags |= PARAM_NAME;
206		break;
207	default:
208		return 0;
209	}
210
211	if (invert)
212		exit_error(PARAMETER_PROBLEM,
213			   "dstlimit does not support invert");
214
215	return 1;
216}
217
218/* Final check; nothing. */
219static void final_check(unsigned int flags)
220{
221	if (!(flags & PARAM_LIMIT))
222		exit_error(PARAMETER_PROBLEM,
223				"You have to specify --dstlimit");
224	if (!(flags & PARAM_MODE))
225		exit_error(PARAMETER_PROBLEM,
226				"You have to specify --dstlimit-mode");
227	if (!(flags & PARAM_NAME))
228		exit_error(PARAMETER_PROBLEM,
229				"You have to specify --dstlimit-name");
230}
231
232static struct rates
233{
234	const char *name;
235	u_int32_t mult;
236} rates[] = { { "day", IPT_DSTLIMIT_SCALE*24*60*60 },
237	      { "hour", IPT_DSTLIMIT_SCALE*60*60 },
238	      { "min", IPT_DSTLIMIT_SCALE*60 },
239	      { "sec", IPT_DSTLIMIT_SCALE } };
240
241static void print_rate(u_int32_t period)
242{
243	unsigned int i;
244
245	for (i = 1; i < sizeof(rates)/sizeof(struct rates); i++) {
246		if (period > rates[i].mult
247            || rates[i].mult/period < rates[i].mult%period)
248			break;
249	}
250
251	printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name);
252}
253
254/* Prints out the matchinfo. */
255static void
256print(const struct ipt_ip *ip,
257      const struct ipt_entry_match *match,
258      int numeric)
259{
260	struct ipt_dstlimit_info *r =
261		(struct ipt_dstlimit_info *)match->data;
262	printf("limit: avg "); print_rate(r->cfg.avg);
263	printf("burst %u ", r->cfg.burst);
264	switch (r->cfg.mode) {
265		case (IPT_DSTLIMIT_HASH_DIP):
266			printf("mode dstip ");
267			break;
268		case (IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
269			printf("mode dstip-dstport ");
270			break;
271		case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP):
272			printf("mode srcip-dstip ");
273			break;
274		case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
275			printf("mode srcip-dstip-dstport ");
276			break;
277	}
278	if (r->cfg.size)
279		printf("htable-size %u ", r->cfg.size);
280	if (r->cfg.max)
281		printf("htable-max %u ", r->cfg.max);
282	if (r->cfg.gc_interval != IPT_DSTLIMIT_GCINTERVAL)
283		printf("htable-gcinterval %u ", r->cfg.gc_interval);
284	if (r->cfg.expire != IPT_DSTLIMIT_EXPIRE)
285		printf("htable-expire %u ", r->cfg.expire);
286}
287
288/* FIXME: Make minimalist: only print rate if not default --RR */
289static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
290{
291	struct ipt_dstlimit_info *r =
292		(struct ipt_dstlimit_info *)match->data;
293
294	printf("--dstlimit "); print_rate(r->cfg.avg);
295	if (r->cfg.burst != IPT_DSTLIMIT_BURST)
296		printf("--dstlimit-burst %u ", r->cfg.burst);
297	switch (r->cfg.mode) {
298		case (IPT_DSTLIMIT_HASH_DIP):
299			printf("--mode dstip ");
300			break;
301		case (IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
302			printf("--mode dstip-dstport ");
303			break;
304		case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP):
305			printf("--mode srcip-dstip ");
306			break;
307		case (IPT_DSTLIMIT_HASH_SIP|IPT_DSTLIMIT_HASH_DIP|IPT_DSTLIMIT_HASH_DPT):
308			printf("--mode srcip-dstip-dstport ");
309			break;
310	}
311	if (r->cfg.size)
312		printf("--dstlimit-htable-size %u ", r->cfg.size);
313	if (r->cfg.max)
314		printf("--dstlimit-htable-max %u ", r->cfg.max);
315	if (r->cfg.gc_interval != IPT_DSTLIMIT_GCINTERVAL)
316		printf("--dstlimit-htable-gcinterval %u", r->cfg.gc_interval);
317	if (r->cfg.expire != IPT_DSTLIMIT_EXPIRE)
318		printf("--dstlimit-htable-expire %u ", r->cfg.expire);
319}
320
321static struct iptables_match dstlimit = {
322	.next		= NULL,
323	.name 		= "dstlimit",
324	.version	= IPTABLES_VERSION,
325	.size		= IPT_ALIGN(sizeof(struct ipt_dstlimit_info)),
326	.userspacesize	= IPT_ALIGN(sizeof(struct ipt_dstlimit_info)),
327	//offsetof(struct ipt_dstlimit_info, prev),
328	.help		= &help,
329	.init		= &init,
330	.parse		= &parse,
331	.final_check	= &final_check,
332	.print 		= &print,
333	.save		= &save,
334	.extra_opts	= opts
335};
336
337void _init(void)
338{
339	register_match(&dstlimit);
340}
341