libxt_connbytes.c revision bf97128c7262f17a02fec41cdae75b472ba77f88
1/* Shared library add-on to iptables to add byte tracking support. */
2#include <stdio.h>
3#include <netdb.h>
4#include <string.h>
5#include <stdlib.h>
6#include <getopt.h>
7#include <xtables.h>
8#include <linux/netfilter/nf_conntrack_common.h>
9#include <linux/netfilter/xt_connbytes.h>
10
11static void connbytes_help(void)
12{
13	printf(
14"connbytes match options:\n"
15" [!] --connbytes from:[to]\n"
16"     --connbytes-dir [original, reply, both]\n"
17"     --connbytes-mode [packets, bytes, avgpkt]\n");
18}
19
20static const struct option connbytes_opts[] = {
21	{ "connbytes", 1, NULL, '1' },
22	{ "connbytes-dir", 1, NULL, '2' },
23	{ "connbytes-mode", 1, NULL, '3' },
24	{ .name = NULL }
25};
26
27static void
28parse_range(const char *arg, struct xt_connbytes_info *si)
29{
30	char *colon,*p;
31
32	si->count.from = strtoul(arg,&colon,10);
33	if (*colon != ':')
34		xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", arg);
35	si->count.to = strtoul(colon+1,&p,10);
36	if (p == colon+1) {
37		/* second number omited */
38		si->count.to = 0xffffffff;
39	}
40	if (si->count.from > si->count.to)
41		xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
42			   (unsigned long long)si->count.from,
43			   (unsigned long long)si->count.to);
44}
45
46static int
47connbytes_parse(int c, char **argv, int invert, unsigned int *flags,
48                const void *entry, struct xt_entry_match **match)
49{
50	struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)(*match)->data;
51	unsigned long i;
52
53	switch (c) {
54	case '1':
55		if (xtables_check_inverse(optarg, &invert, &optind, 0, argv))
56			optind++;
57
58		parse_range(argv[optind-1], sinfo);
59		if (invert) {
60			i = sinfo->count.from;
61			sinfo->count.from = sinfo->count.to;
62			sinfo->count.to = i;
63		}
64		*flags |= 1;
65		break;
66	case '2':
67		if (!strcmp(optarg, "original"))
68			sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL;
69		else if (!strcmp(optarg, "reply"))
70			sinfo->direction = XT_CONNBYTES_DIR_REPLY;
71		else if (!strcmp(optarg, "both"))
72			sinfo->direction = XT_CONNBYTES_DIR_BOTH;
73		else
74			xtables_error(PARAMETER_PROBLEM,
75				   "Unknown --connbytes-dir `%s'", optarg);
76
77		*flags |= 2;
78		break;
79	case '3':
80		if (!strcmp(optarg, "packets"))
81			sinfo->what = XT_CONNBYTES_PKTS;
82		else if (!strcmp(optarg, "bytes"))
83			sinfo->what = XT_CONNBYTES_BYTES;
84		else if (!strcmp(optarg, "avgpkt"))
85			sinfo->what = XT_CONNBYTES_AVGPKT;
86		else
87			xtables_error(PARAMETER_PROBLEM,
88				   "Unknown --connbytes-mode `%s'", optarg);
89		*flags |= 4;
90		break;
91	default:
92		return 0;
93	}
94
95	return 1;
96}
97
98static void connbytes_check(unsigned int flags)
99{
100	if (flags != 7)
101		xtables_error(PARAMETER_PROBLEM, "You must specify `--connbytes'"
102			   "`--connbytes-dir' and `--connbytes-mode'");
103}
104
105static void print_mode(const struct xt_connbytes_info *sinfo)
106{
107	switch (sinfo->what) {
108		case XT_CONNBYTES_PKTS:
109			fputs("packets ", stdout);
110			break;
111		case XT_CONNBYTES_BYTES:
112			fputs("bytes ", stdout);
113			break;
114		case XT_CONNBYTES_AVGPKT:
115			fputs("avgpkt ", stdout);
116			break;
117		default:
118			fputs("unknown ", stdout);
119			break;
120	}
121}
122
123static void print_direction(const struct xt_connbytes_info *sinfo)
124{
125	switch (sinfo->direction) {
126		case XT_CONNBYTES_DIR_ORIGINAL:
127			fputs("original ", stdout);
128			break;
129		case XT_CONNBYTES_DIR_REPLY:
130			fputs("reply ", stdout);
131			break;
132		case XT_CONNBYTES_DIR_BOTH:
133			fputs("both ", stdout);
134			break;
135		default:
136			fputs("unknown ", stdout);
137			break;
138	}
139}
140
141static void
142connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
143{
144	const struct xt_connbytes_info *sinfo = (const void *)match->data;
145
146	if (sinfo->count.from > sinfo->count.to)
147		printf("connbytes ! %llu:%llu ",
148			(unsigned long long)sinfo->count.to,
149			(unsigned long long)sinfo->count.from);
150	else
151		printf("connbytes %llu:%llu ",
152			(unsigned long long)sinfo->count.from,
153			(unsigned long long)sinfo->count.to);
154
155	fputs("connbytes mode ", stdout);
156	print_mode(sinfo);
157
158	fputs("connbytes direction ", stdout);
159	print_direction(sinfo);
160}
161
162static void connbytes_save(const void *ip, const struct xt_entry_match *match)
163{
164	const struct xt_connbytes_info *sinfo = (const void *)match->data;
165
166	if (sinfo->count.from > sinfo->count.to)
167		printf("! --connbytes %llu:%llu ",
168			(unsigned long long)sinfo->count.to,
169			(unsigned long long)sinfo->count.from);
170	else
171		printf("--connbytes %llu:%llu ",
172			(unsigned long long)sinfo->count.from,
173			(unsigned long long)sinfo->count.to);
174
175	fputs("--connbytes-mode ", stdout);
176	print_mode(sinfo);
177
178	fputs("--connbytes-dir ", stdout);
179	print_direction(sinfo);
180}
181
182static struct xtables_match connbytes_match = {
183	.family		= NFPROTO_UNSPEC,
184	.name 		= "connbytes",
185	.version 	= XTABLES_VERSION,
186	.size 		= XT_ALIGN(sizeof(struct xt_connbytes_info)),
187	.userspacesize	= XT_ALIGN(sizeof(struct xt_connbytes_info)),
188	.help		= connbytes_help,
189	.parse		= connbytes_parse,
190	.final_check	= connbytes_check,
191	.print		= connbytes_print,
192	.save 		= connbytes_save,
193	.extra_opts	= connbytes_opts,
194};
195
196void _init(void)
197{
198	xtables_register_match(&connbytes_match);
199}
200