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