1#include <stdio.h>
2#include <string.h>
3#include <xtables.h>
4#include <linux/netfilter/xt_connbytes.h>
5
6enum {
7	O_CONNBYTES = 0,
8	O_CONNBYTES_DIR,
9	O_CONNBYTES_MODE,
10};
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 xt_option_entry connbytes_opts[] = {
22	{.name = "connbytes", .id = O_CONNBYTES, .type = XTTYPE_UINT64RC,
23	 .flags = XTOPT_MAND | XTOPT_INVERT},
24	{.name = "connbytes-dir", .id = O_CONNBYTES_DIR, .type = XTTYPE_STRING,
25	 .flags = XTOPT_MAND},
26	{.name = "connbytes-mode", .id = O_CONNBYTES_MODE,
27	 .type = XTTYPE_STRING, .flags = XTOPT_MAND},
28	XTOPT_TABLEEND,
29};
30
31static void connbytes_parse(struct xt_option_call *cb)
32{
33	struct xt_connbytes_info *sinfo = cb->data;
34	unsigned long long i;
35
36	xtables_option_parse(cb);
37	switch (cb->entry->id) {
38	case O_CONNBYTES:
39		sinfo->count.from = cb->val.u64_range[0];
40		sinfo->count.to   = UINT64_MAX;
41		if (cb->nvals == 2)
42			sinfo->count.to = cb->val.u64_range[1];
43
44		if (sinfo->count.to < sinfo->count.from)
45			xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
46					(unsigned long long)sinfo->count.from,
47					(unsigned long long)sinfo->count.to);
48		if (cb->invert) {
49			i = sinfo->count.from;
50			sinfo->count.from = sinfo->count.to;
51			sinfo->count.to = i;
52		}
53		break;
54	case O_CONNBYTES_DIR:
55		if (strcmp(cb->arg, "original") == 0)
56			sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL;
57		else if (strcmp(cb->arg, "reply") == 0)
58			sinfo->direction = XT_CONNBYTES_DIR_REPLY;
59		else if (strcmp(cb->arg, "both") == 0)
60			sinfo->direction = XT_CONNBYTES_DIR_BOTH;
61		else
62			xtables_error(PARAMETER_PROBLEM,
63				   "Unknown --connbytes-dir `%s'", cb->arg);
64		break;
65	case O_CONNBYTES_MODE:
66		if (strcmp(cb->arg, "packets") == 0)
67			sinfo->what = XT_CONNBYTES_PKTS;
68		else if (strcmp(cb->arg, "bytes") == 0)
69			sinfo->what = XT_CONNBYTES_BYTES;
70		else if (strcmp(cb->arg, "avgpkt") == 0)
71			sinfo->what = XT_CONNBYTES_AVGPKT;
72		else
73			xtables_error(PARAMETER_PROBLEM,
74				   "Unknown --connbytes-mode `%s'", cb->arg);
75		break;
76	}
77}
78
79static void print_mode(const struct xt_connbytes_info *sinfo)
80{
81	switch (sinfo->what) {
82		case XT_CONNBYTES_PKTS:
83			fputs(" packets", stdout);
84			break;
85		case XT_CONNBYTES_BYTES:
86			fputs(" bytes", stdout);
87			break;
88		case XT_CONNBYTES_AVGPKT:
89			fputs(" avgpkt", stdout);
90			break;
91		default:
92			fputs(" unknown", stdout);
93			break;
94	}
95}
96
97static void print_direction(const struct xt_connbytes_info *sinfo)
98{
99	switch (sinfo->direction) {
100		case XT_CONNBYTES_DIR_ORIGINAL:
101			fputs(" original", stdout);
102			break;
103		case XT_CONNBYTES_DIR_REPLY:
104			fputs(" reply", stdout);
105			break;
106		case XT_CONNBYTES_DIR_BOTH:
107			fputs(" both", stdout);
108			break;
109		default:
110			fputs(" unknown", stdout);
111			break;
112	}
113}
114
115static void print_from_to(const struct xt_connbytes_info *sinfo, const char *prefix)
116{
117	unsigned long long from, to;
118
119	if (sinfo->count.from > sinfo->count.to) {
120		fputs(" !", stdout);
121		from = sinfo->count.to;
122		to = sinfo->count.from;
123	} else {
124		to = sinfo->count.to;
125		from = sinfo->count.from;
126	}
127	printf(" %sconnbytes %llu", prefix, from);
128	if (to && to < UINT64_MAX)
129		printf(":%llu", to);
130}
131
132static void
133connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
134{
135	const struct xt_connbytes_info *sinfo = (const void *)match->data;
136
137	print_from_to(sinfo, "");
138
139	fputs(" connbytes mode", stdout);
140	print_mode(sinfo);
141
142	fputs(" connbytes direction", stdout);
143	print_direction(sinfo);
144}
145
146static void connbytes_save(const void *ip, const struct xt_entry_match *match)
147{
148	const struct xt_connbytes_info *sinfo = (const void *)match->data;
149
150	print_from_to(sinfo, "--");
151
152	fputs(" --connbytes-mode", stdout);
153	print_mode(sinfo);
154
155	fputs(" --connbytes-dir", stdout);
156	print_direction(sinfo);
157}
158
159static struct xtables_match connbytes_match = {
160	.family		= NFPROTO_UNSPEC,
161	.name 		= "connbytes",
162	.version 	= XTABLES_VERSION,
163	.size 		= XT_ALIGN(sizeof(struct xt_connbytes_info)),
164	.userspacesize	= XT_ALIGN(sizeof(struct xt_connbytes_info)),
165	.help		= connbytes_help,
166	.print		= connbytes_print,
167	.save 		= connbytes_save,
168	.x6_parse	= connbytes_parse,
169	.x6_options	= connbytes_opts,
170};
171
172void _init(void)
173{
174	xtables_register_match(&connbytes_match);
175}
176