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
19enum {
20	O_NOTRACK = 0,
21	O_HELPER,
22	O_CTEVENTS,
23	O_EXPEVENTS,
24	O_ZONE,
25};
26
27#define s struct xt_ct_target_info
28static const struct xt_option_entry ct_opts[] = {
29	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
30	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
31	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
32	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
33	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
34	{.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
35	 .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
36	XTOPT_TABLEEND,
37};
38#undef s
39
40struct event_tbl {
41	const char	*name;
42	unsigned int	event;
43};
44
45static const struct event_tbl ct_event_tbl[] = {
46	{ "new",		IPCT_NEW },
47	{ "related",		IPCT_RELATED },
48	{ "destroy",		IPCT_DESTROY },
49	{ "reply",		IPCT_REPLY },
50	{ "assured",		IPCT_ASSURED },
51	{ "protoinfo",		IPCT_PROTOINFO },
52	{ "helper",		IPCT_HELPER },
53	{ "mark",		IPCT_MARK },
54	{ "natseqinfo",		IPCT_NATSEQADJ },
55	{ "secmark",		IPCT_SECMARK },
56};
57
58static const struct event_tbl exp_event_tbl[] = {
59	{ "new",		IPEXP_NEW },
60};
61
62static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
63				const char *events)
64{
65	char str[strlen(events) + 1], *e = str, *t;
66	unsigned int mask = 0, i;
67
68	strcpy(str, events);
69	while ((t = strsep(&e, ","))) {
70		for (i = 0; i < size; i++) {
71			if (strcmp(t, tbl[i].name))
72				continue;
73			mask |= 1 << tbl[i].event;
74			break;
75		}
76
77		if (i == size)
78			xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t);
79	}
80
81	return mask;
82}
83
84static void ct_print_events(const char *pfx, const struct event_tbl *tbl,
85			    unsigned int size, uint32_t mask)
86{
87	const char *sep = "";
88	unsigned int i;
89
90	printf(" %s ", pfx);
91	for (i = 0; i < size; i++) {
92		if (mask & (1 << tbl[i].event)) {
93			printf("%s%s", sep, tbl[i].name);
94			sep = ",";
95		}
96	}
97}
98
99static void ct_parse(struct xt_option_call *cb)
100{
101	struct xt_ct_target_info *info = cb->data;
102
103	xtables_option_parse(cb);
104	switch (cb->entry->id) {
105	case O_NOTRACK:
106		info->flags |= XT_CT_NOTRACK;
107		break;
108	case O_CTEVENTS:
109		info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg);
110		break;
111	case O_EXPEVENTS:
112		info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), cb->arg);
113		break;
114	}
115}
116
117static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
118{
119	const struct xt_ct_target_info *info =
120		(const struct xt_ct_target_info *)target->data;
121
122	printf(" CT");
123	if (info->flags & XT_CT_NOTRACK)
124		printf(" notrack");
125	if (info->helper[0])
126		printf(" helper %s", info->helper);
127	if (info->ct_events)
128		ct_print_events("ctevents", ct_event_tbl,
129				ARRAY_SIZE(ct_event_tbl), info->ct_events);
130	if (info->exp_events)
131		ct_print_events("expevents", exp_event_tbl,
132				ARRAY_SIZE(exp_event_tbl), info->exp_events);
133	if (info->zone)
134		printf("zone %u ", info->zone);
135}
136
137static void ct_save(const void *ip, const struct xt_entry_target *target)
138{
139	const struct xt_ct_target_info *info =
140		(const struct xt_ct_target_info *)target->data;
141
142	if (info->flags & XT_CT_NOTRACK)
143		printf(" --notrack");
144	if (info->helper[0])
145		printf(" --helper %s", info->helper);
146	if (info->ct_events)
147		ct_print_events("--ctevents", ct_event_tbl,
148				ARRAY_SIZE(ct_event_tbl), info->ct_events);
149	if (info->exp_events)
150		ct_print_events("--expevents", exp_event_tbl,
151				ARRAY_SIZE(exp_event_tbl), info->exp_events);
152	if (info->zone)
153		printf(" --zone %u", info->zone);
154}
155
156static struct xtables_target ct_target = {
157	.family		= NFPROTO_UNSPEC,
158	.name		= "CT",
159	.version	= XTABLES_VERSION,
160	.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
161	.userspacesize	= offsetof(struct xt_ct_target_info, ct),
162	.help		= ct_help,
163	.print		= ct_print,
164	.save		= ct_save,
165	.x6_parse	= ct_parse,
166	.x6_options	= ct_opts,
167};
168
169void _init(void)
170{
171	xtables_register_target(&ct_target);
172}
173