libxt_statistic.c revision ea146a982e26c42f9954f140276f8deeb2edbe98
1#include <stdio.h>
2#include <netdb.h>
3#include <string.h>
4#include <stdlib.h>
5#include <stddef.h>
6#include <getopt.h>
7
8#include <xtables.h>
9#include <linux/netfilter/xt_statistic.h>
10
11static void
12help(void)
13{
14	printf(
15"statistic match v%s options:\n"
16" --mode mode                    Match mode (random, nth)\n"
17" random mode:\n"
18" --probability p		 Probability\n"
19" nth mode:\n"
20" --every n			 Match every nth packet\n"
21" --packet p			 Initial counter value (0 <= p <= n-1, default 0)\n"
22"\n",
23IPTABLES_VERSION);
24}
25
26static const struct option opts[] = {
27	{ "mode", 1, 0, '1' },
28	{ "probability", 1, 0, '2' },
29	{ "every", 1, 0, '3' },
30	{ "packet", 1, 0, '4' },
31	{ 0 }
32};
33
34static struct xt_statistic_info *info;
35
36static int
37parse(int c, char **argv, int invert, unsigned int *flags,
38      const void *entry,
39      struct xt_entry_match **match)
40{
41	double prob;
42
43	info = (void *)(*match)->data;
44
45	if (invert)
46		info->flags |= XT_STATISTIC_INVERT;
47
48	switch (c) {
49	case '1':
50		if (*flags & 0x1)
51			exit_error(PARAMETER_PROBLEM, "double --mode");
52		if (!strcmp(optarg, "random"))
53			info->mode = XT_STATISTIC_MODE_RANDOM;
54		else if (!strcmp(optarg, "nth"))
55			info->mode = XT_STATISTIC_MODE_NTH;
56		else
57			exit_error(PARAMETER_PROBLEM, "Bad mode `%s'", optarg);
58		*flags |= 0x1;
59		break;
60	case '2':
61		if (*flags & 0x2)
62			exit_error(PARAMETER_PROBLEM, "double --probability");
63		prob = atof(optarg);
64		if (prob < 0 || prob > 1)
65			exit_error(PARAMETER_PROBLEM,
66				   "--probability must be between 0 and 1");
67		info->u.random.probability = 0x80000000 * prob;
68		*flags |= 0x2;
69		break;
70	case '3':
71		if (*flags & 0x4)
72			exit_error(PARAMETER_PROBLEM, "double --every");
73		if (string_to_number(optarg, 0, 0xFFFFFFFF,
74				     &info->u.nth.every) == -1)
75			exit_error(PARAMETER_PROBLEM,
76				   "cannot parse --every `%s'", optarg);
77		if (info->u.nth.every == 0)
78			exit_error(PARAMETER_PROBLEM, "--every cannot be 0");
79		info->u.nth.every--;
80		*flags |= 0x4;
81		break;
82	case '4':
83		if (*flags & 0x8)
84			exit_error(PARAMETER_PROBLEM, "double --packet");
85		if (string_to_number(optarg, 0, 0xFFFFFFFF,
86				     &info->u.nth.packet) == -1)
87			exit_error(PARAMETER_PROBLEM,
88				   "cannot parse --packet `%s'", optarg);
89		*flags |= 0x8;
90		break;
91	default:
92		return 0;
93	}
94	return 1;
95}
96
97/* Final check; must have specified --mark. */
98static void
99final_check(unsigned int flags)
100{
101	if (!(flags & 0x1))
102		exit_error(PARAMETER_PROBLEM, "no mode specified");
103	if ((flags & 0x2) && (flags & (0x4 | 0x8)))
104		exit_error(PARAMETER_PROBLEM,
105			   "both nth and random parameters given");
106	if (flags & 0x2 && info->mode != XT_STATISTIC_MODE_RANDOM)
107		exit_error(PARAMETER_PROBLEM,
108			   "--probability can only be used in random mode");
109	if (flags & 0x4 && info->mode != XT_STATISTIC_MODE_NTH)
110		exit_error(PARAMETER_PROBLEM,
111			   "--every can only be used in nth mode");
112	if (flags & 0x8 && info->mode != XT_STATISTIC_MODE_NTH)
113		exit_error(PARAMETER_PROBLEM,
114			   "--packet can only be used in nth mode");
115	if ((flags & 0x8) && !(flags & 0x4))
116		exit_error(PARAMETER_PROBLEM,
117			   "--packet can only be used with --every");
118	/* at this point, info->u.nth.every have been decreased. */
119	if (!(info->u.nth.packet >= 0 && info->u.nth.packet <= info->u.nth.every))
120		exit_error(PARAMETER_PROBLEM,
121			  "the --packet p must be 0 <= p <= n-1");
122
123
124	info->u.nth.count = info->u.nth.every - info->u.nth.packet;
125}
126
127/* Prints out the matchinfo. */
128static void print_match(const struct xt_statistic_info *info, char *prefix)
129{
130	if (info->flags & XT_STATISTIC_INVERT)
131		printf("! ");
132
133	switch (info->mode) {
134	case XT_STATISTIC_MODE_RANDOM:
135		printf("%smode random %sprobability %f ", prefix, prefix,
136		       1.0 * info->u.random.probability / 0x80000000);
137		break;
138	case XT_STATISTIC_MODE_NTH:
139		printf("%smode nth %severy %u ", prefix, prefix,
140		       info->u.nth.every + 1);
141		if (info->u.nth.packet)
142			printf("%spacket %u ", prefix, info->u.nth.packet);
143		break;
144	}
145}
146
147static void
148print(const void *ip,
149      const struct xt_entry_match *match,
150      int numeric)
151{
152	struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
153
154	printf("statistic ");
155	print_match(info, "");
156}
157
158/* Saves the union ipt_matchinfo in parsable form to stdout. */
159static void
160save(const void *ip, const struct xt_entry_match *match)
161{
162	struct xt_statistic_info *info = (struct xt_statistic_info *)match->data;
163
164	print_match(info, "--");
165}
166
167static struct xtables_match statistic = {
168	.family		= AF_INET,
169	.name		= "statistic",
170	.version	= IPTABLES_VERSION,
171	.size		= XT_ALIGN(sizeof(struct xt_statistic_info)),
172	.userspacesize	= offsetof(struct xt_statistic_info, u.nth.count),
173	.help		= help,
174	.parse		= parse,
175	.final_check	= final_check,
176	.print		= print,
177	.save		= save,
178	.extra_opts	= opts
179};
180
181static struct xtables_match statistic6 = {
182	.family		= AF_INET6,
183	.name		= "statistic",
184	.version	= IPTABLES_VERSION,
185	.size		= XT_ALIGN(sizeof(struct xt_statistic_info)),
186	.userspacesize	= offsetof(struct xt_statistic_info, u.nth.count),
187	.help		= help,
188	.parse		= parse,
189	.final_check	= final_check,
190	.print		= print,
191	.save		= save,
192	.extra_opts	= opts
193};
194
195void _init(void)
196{
197	xtables_register_match(&statistic);
198	xtables_register_match(&statistic6);
199}
200