libxt_CT.c revision d09b6d591ca7d7d7575cb6aa20384c9830f777ab
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	}
131
132	*flags |= c;
133	return 1;
134}
135
136static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
137{
138	const struct xt_ct_target_info *info =
139		(const struct xt_ct_target_info *)target->data;
140
141	printf("CT ");
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 void ct_save(const void *ip, const struct xt_entry_target *target)
157{
158	const struct xt_ct_target_info *info =
159		(const struct xt_ct_target_info *)target->data;
160
161	if (info->flags & XT_CT_NOTRACK)
162		printf("--notrack ");
163	if (info->helper[0])
164		printf("--helper %s ", info->helper);
165	if (info->ct_events)
166		ct_print_events("--ctevents", ct_event_tbl,
167				ARRAY_SIZE(ct_event_tbl), info->ct_events);
168	if (info->exp_events)
169		ct_print_events("--expevents", exp_event_tbl,
170				ARRAY_SIZE(exp_event_tbl), info->exp_events);
171	if (info->zone)
172		printf("--zone %u ", info->zone);
173}
174
175static struct xtables_target ct_target = {
176	.family		= NFPROTO_UNSPEC,
177	.name		= "CT",
178	.version	= XTABLES_VERSION,
179	.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
180	.userspacesize	= offsetof(struct xt_ct_target_info, ct),
181	.help		= ct_help,
182	.parse		= ct_parse,
183	.print		= ct_print,
184	.save		= ct_save,
185	.extra_opts	= ct_opts,
186};
187
188void _init(void)
189{
190	xtables_register_target(&ct_target);
191}
192