libxt_CT.c revision 73866357e4a7a0fdc1b293bf8863fee2bd56da9e
1#include <stdbool.h>
2#include <stdio.h>
3#include <string.h>
4#include <stdlib.h>
5#include <stddef.h>
6#include <getopt.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
23enum ct_options {
24	CT_OPT_NOTRACK		= 0x1,
25	CT_OPT_HELPER		= 0x2,
26	CT_OPT_CTEVENTS		= 0x4,
27	CT_OPT_EXPEVENTS	= 0x8,
28	CT_OPT_ZONE		= 0x10,
29};
30
31static const struct option ct_opts[] = {
32	{.name = "notrack",	.has_arg = false, .val = CT_OPT_NOTRACK},
33	{.name = "helper",	.has_arg = true,  .val = CT_OPT_HELPER},
34	{.name = "ctevents",	.has_arg = true,  .val = CT_OPT_CTEVENTS},
35	{.name = "expevents",	.has_arg = true,  .val = CT_OPT_EXPEVENTS},
36	{.name = "zone",	.has_arg = true,  .val = CT_OPT_ZONE},
37	XT_GETOPT_TABLEEND,
38};
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 int ct_parse(int c, char **argv, int invert, unsigned int *flags,
100		    const void *entry, struct xt_entry_target **target)
101{
102	struct xt_ct_target_info *info = (struct xt_ct_target_info *)(*target)->data;
103	unsigned int zone;
104
105	switch (c) {
106	case CT_OPT_NOTRACK:
107		xtables_param_act(XTF_ONLY_ONCE, "CT", "--notrack", *flags & CT_OPT_NOTRACK);
108		info->flags |= XT_CT_NOTRACK;
109		break;
110	case CT_OPT_HELPER:
111		xtables_param_act(XTF_ONLY_ONCE, "CT", "--helper", *flags & CT_OPT_HELPER);
112		strncpy(info->helper, optarg, sizeof(info->helper));
113		info->helper[sizeof(info->helper) - 1] = '\0';
114		break;
115	case CT_OPT_CTEVENTS:
116		xtables_param_act(XTF_ONLY_ONCE, "CT", "--ctevents", *flags & CT_OPT_CTEVENTS);
117		info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), optarg);
118		break;
119	case CT_OPT_EXPEVENTS:
120		xtables_param_act(XTF_ONLY_ONCE, "CT", "--expevents", *flags & CT_OPT_EXPEVENTS);
121		info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), optarg);
122		break;
123	case CT_OPT_ZONE:
124		xtables_param_act(XTF_ONLY_ONCE, "CT", "--zone", *flags & CT_OPT_ZONE);
125		if (!xtables_strtoui(optarg, NULL, &zone, 0, UINT16_MAX))
126			xtables_error(PARAMETER_PROBLEM, "Bad zone value \"%s\"", optarg);
127		info->zone = zone;
128		break;
129	}
130
131	*flags |= c;
132	return 1;
133}
134
135static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
136{
137	const struct xt_ct_target_info *info =
138		(const struct xt_ct_target_info *)target->data;
139
140	printf(" CT");
141	if (info->flags & XT_CT_NOTRACK)
142		printf(" notrack");
143	if (info->helper[0])
144		printf(" helper %s", info->helper);
145	if (info->ct_events)
146		ct_print_events("ctevents", ct_event_tbl,
147				ARRAY_SIZE(ct_event_tbl), info->ct_events);
148	if (info->exp_events)
149		ct_print_events("expevents", exp_event_tbl,
150				ARRAY_SIZE(exp_event_tbl), info->exp_events);
151	if (info->zone)
152		printf("zone %u ", info->zone);
153}
154
155static void ct_save(const void *ip, const struct xt_entry_target *target)
156{
157	const struct xt_ct_target_info *info =
158		(const struct xt_ct_target_info *)target->data;
159
160	if (info->flags & XT_CT_NOTRACK)
161		printf(" --notrack");
162	if (info->helper[0])
163		printf(" --helper %s", info->helper);
164	if (info->ct_events)
165		ct_print_events("--ctevents", ct_event_tbl,
166				ARRAY_SIZE(ct_event_tbl), info->ct_events);
167	if (info->exp_events)
168		ct_print_events("--expevents", exp_event_tbl,
169				ARRAY_SIZE(exp_event_tbl), info->exp_events);
170	if (info->zone)
171		printf(" --zone %u", info->zone);
172}
173
174static struct xtables_target ct_target = {
175	.family		= NFPROTO_UNSPEC,
176	.name		= "CT",
177	.version	= XTABLES_VERSION,
178	.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
179	.userspacesize	= offsetof(struct xt_ct_target_info, ct),
180	.help		= ct_help,
181	.parse		= ct_parse,
182	.print		= ct_print,
183	.save		= ct_save,
184	.extra_opts	= ct_opts,
185};
186
187void _init(void)
188{
189	xtables_register_target(&ct_target);
190}
191