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