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