libxt_CT.c revision 50f19190a60ff7d69e88406a71a2f27e09008566
1#include <stdio.h>
2#include <string.h>
3#include <xtables.h>
4#include <linux/netfilter/nf_conntrack_common.h>
5#include <linux/netfilter/xt_CT.h>
6
7static void ct_help(void)
8{
9	printf(
10"CT target options:\n"
11" --notrack			Don't track connection\n"
12" --helper name			Use conntrack helper 'name' for connection\n"
13" --ctevents event[,event...]	Generate specified conntrack events for connection\n"
14" --expevents event[,event...]	Generate specified expectation events for connection\n"
15" --zone ID			Assign/Lookup connection in zone ID\n"
16	);
17}
18
19static void ct_help_v1(void)
20{
21	printf(
22"CT target options:\n"
23" --notrack			Don't track connection\n"
24" --helper name			Use conntrack helper 'name' for connection\n"
25" --timeout name 		Use timeout policy 'name' for connection\n"
26" --ctevents event[,event...]	Generate specified conntrack events for connection\n"
27" --expevents event[,event...]	Generate specified expectation events for connection\n"
28" --zone ID			Assign/Lookup connection in zone ID\n"
29	);
30}
31
32enum {
33	O_NOTRACK = 0,
34	O_HELPER,
35	O_TIMEOUT,
36	O_CTEVENTS,
37	O_EXPEVENTS,
38	O_ZONE,
39};
40
41#define s struct xt_ct_target_info
42static const struct xt_option_entry ct_opts[] = {
43	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
44	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
45	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
46	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
47	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
48	{.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
49	 .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
50	XTOPT_TABLEEND,
51};
52#undef s
53
54#define s struct xt_ct_target_info_v1
55static const struct xt_option_entry ct_opts_v1[] = {
56	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
57	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
58	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
59	{.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_STRING,
60	 .flags = XTOPT_PUT, XTOPT_POINTER(s, timeout)},
61	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
62	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
63	{.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
64	 .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
65	XTOPT_TABLEEND,
66};
67#undef s
68
69struct event_tbl {
70	const char	*name;
71	unsigned int	event;
72};
73
74static const struct event_tbl ct_event_tbl[] = {
75	{ "new",		IPCT_NEW },
76	{ "related",		IPCT_RELATED },
77	{ "destroy",		IPCT_DESTROY },
78	{ "reply",		IPCT_REPLY },
79	{ "assured",		IPCT_ASSURED },
80	{ "protoinfo",		IPCT_PROTOINFO },
81	{ "helper",		IPCT_HELPER },
82	{ "mark",		IPCT_MARK },
83	{ "natseqinfo",		IPCT_NATSEQADJ },
84	{ "secmark",		IPCT_SECMARK },
85};
86
87static const struct event_tbl exp_event_tbl[] = {
88	{ "new",		IPEXP_NEW },
89};
90
91static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
92				const char *events)
93{
94	char str[strlen(events) + 1], *e = str, *t;
95	unsigned int mask = 0, i;
96
97	strcpy(str, events);
98	while ((t = strsep(&e, ","))) {
99		for (i = 0; i < size; i++) {
100			if (strcmp(t, tbl[i].name))
101				continue;
102			mask |= 1 << tbl[i].event;
103			break;
104		}
105
106		if (i == size)
107			xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t);
108	}
109
110	return mask;
111}
112
113static void ct_print_events(const char *pfx, const struct event_tbl *tbl,
114			    unsigned int size, uint32_t mask)
115{
116	const char *sep = "";
117	unsigned int i;
118
119	printf(" %s ", pfx);
120	for (i = 0; i < size; i++) {
121		if (mask & (1 << tbl[i].event)) {
122			printf("%s%s", sep, tbl[i].name);
123			sep = ",";
124		}
125	}
126}
127
128static void ct_parse(struct xt_option_call *cb)
129{
130	struct xt_ct_target_info *info = cb->data;
131
132	xtables_option_parse(cb);
133	switch (cb->entry->id) {
134	case O_NOTRACK:
135		info->flags |= XT_CT_NOTRACK;
136		break;
137	case O_CTEVENTS:
138		info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg);
139		break;
140	case O_EXPEVENTS:
141		info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), cb->arg);
142		break;
143	}
144}
145
146static void ct_parse_v1(struct xt_option_call *cb)
147{
148	struct xt_ct_target_info_v1 *info = cb->data;
149
150	xtables_option_parse(cb);
151	switch (cb->entry->id) {
152	case O_NOTRACK:
153		info->flags |= XT_CT_NOTRACK;
154		break;
155	case O_CTEVENTS:
156		info->ct_events = ct_parse_events(ct_event_tbl,
157						  ARRAY_SIZE(ct_event_tbl),
158						  cb->arg);
159		break;
160	case O_EXPEVENTS:
161		info->exp_events = ct_parse_events(exp_event_tbl,
162						   ARRAY_SIZE(exp_event_tbl),
163						   cb->arg);
164		break;
165	}
166}
167
168static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
169{
170	const struct xt_ct_target_info *info =
171		(const struct xt_ct_target_info *)target->data;
172
173	printf(" CT");
174	if (info->flags & XT_CT_NOTRACK)
175		printf(" notrack");
176	if (info->helper[0])
177		printf(" helper %s", info->helper);
178	if (info->ct_events)
179		ct_print_events("ctevents", ct_event_tbl,
180				ARRAY_SIZE(ct_event_tbl), info->ct_events);
181	if (info->exp_events)
182		ct_print_events("expevents", exp_event_tbl,
183				ARRAY_SIZE(exp_event_tbl), info->exp_events);
184	if (info->zone)
185		printf("zone %u ", info->zone);
186}
187
188static void
189ct_print_v1(const void *ip, const struct xt_entry_target *target, int numeric)
190{
191	const struct xt_ct_target_info_v1 *info =
192		(const struct xt_ct_target_info_v1 *)target->data;
193
194	printf(" CT");
195	if (info->flags & XT_CT_NOTRACK)
196		printf(" notrack");
197	if (info->helper[0])
198		printf(" helper %s", info->helper);
199	if (info->timeout[0])
200		printf(" timeout %s", info->timeout);
201	if (info->ct_events)
202		ct_print_events("ctevents", ct_event_tbl,
203				ARRAY_SIZE(ct_event_tbl), info->ct_events);
204	if (info->exp_events)
205		ct_print_events("expevents", exp_event_tbl,
206				ARRAY_SIZE(exp_event_tbl), info->exp_events);
207	if (info->zone)
208		printf("zone %u ", info->zone);
209}
210
211static void ct_save(const void *ip, const struct xt_entry_target *target)
212{
213	const struct xt_ct_target_info *info =
214		(const struct xt_ct_target_info *)target->data;
215
216	if (info->flags & XT_CT_NOTRACK)
217		printf(" --notrack");
218	if (info->helper[0])
219		printf(" --helper %s", info->helper);
220	if (info->ct_events)
221		ct_print_events("--ctevents", ct_event_tbl,
222				ARRAY_SIZE(ct_event_tbl), info->ct_events);
223	if (info->exp_events)
224		ct_print_events("--expevents", exp_event_tbl,
225				ARRAY_SIZE(exp_event_tbl), info->exp_events);
226	if (info->zone)
227		printf(" --zone %u", info->zone);
228}
229
230static void ct_save_v1(const void *ip, const struct xt_entry_target *target)
231{
232	const struct xt_ct_target_info_v1 *info =
233		(const struct xt_ct_target_info_v1 *)target->data;
234
235	if (info->flags & XT_CT_NOTRACK)
236		printf(" --notrack");
237	if (info->helper[0])
238		printf(" --helper %s", info->helper);
239	if (info->timeout[0])
240		printf(" --timeout %s", info->timeout);
241	if (info->ct_events)
242		ct_print_events("--ctevents", ct_event_tbl,
243				ARRAY_SIZE(ct_event_tbl), info->ct_events);
244	if (info->exp_events)
245		ct_print_events("--expevents", exp_event_tbl,
246				ARRAY_SIZE(exp_event_tbl), info->exp_events);
247	if (info->zone)
248		printf(" --zone %u", info->zone);
249}
250
251static void notrack_ct0_tg_init(struct xt_entry_target *target)
252{
253	struct xt_ct_target_info *info = (void *)target->data;
254
255	info->flags = XT_CT_NOTRACK;
256}
257
258static void notrack_ct1_tg_init(struct xt_entry_target *target)
259{
260	struct xt_ct_target_info_v1 *info = (void *)target->data;
261
262	info->flags = XT_CT_NOTRACK;
263}
264
265static struct xtables_target ct_target_reg[] = {
266	{
267		.family		= NFPROTO_UNSPEC,
268		.name		= "CT",
269		.version	= XTABLES_VERSION,
270		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
271		.userspacesize	= offsetof(struct xt_ct_target_info, ct),
272		.help		= ct_help,
273		.print		= ct_print,
274		.save		= ct_save,
275		.x6_parse	= ct_parse,
276		.x6_options	= ct_opts,
277	},
278	{
279		.family		= NFPROTO_UNSPEC,
280		.name		= "CT",
281		.revision	= 1,
282		.version	= XTABLES_VERSION,
283		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
284		.userspacesize	= offsetof(struct xt_ct_target_info_v1, ct),
285		.help		= ct_help_v1,
286		.print		= ct_print_v1,
287		.save		= ct_save_v1,
288		.x6_parse	= ct_parse_v1,
289		.x6_options	= ct_opts_v1,
290	},
291	{
292		.family        = NFPROTO_UNSPEC,
293		.name          = "NOTRACK",
294		.real_name     = "CT",
295		.revision      = 0,
296		.version       = XTABLES_VERSION,
297		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info)),
298		.userspacesize = offsetof(struct xt_ct_target_info, ct),
299		.init          = notrack_ct0_tg_init,
300	},
301	{
302		.family        = NFPROTO_UNSPEC,
303		.name          = "NOTRACK",
304		.real_name     = "CT",
305		.revision      = 1,
306		.version       = XTABLES_VERSION,
307		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
308		.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
309		.init          = notrack_ct1_tg_init,
310	},
311	{
312		.family        = NFPROTO_UNSPEC,
313		.name          = "NOTRACK",
314		.revision      = 0,
315		.version       = XTABLES_VERSION,
316	},
317};
318
319void _init(void)
320{
321	xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg));
322}
323