libxt_CT.c revision 9f27e6b6f8638bde93e9901e999287ad5118f17c
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <stddef.h>
5#include <getopt.h>
6#include <xtables.h>
7#include <linux/netfilter/nf_conntrack_common.h>
8#include <linux/netfilter/xt_CT.h>
9
10static void ct_help(void)
11{
12	printf(
13"CT target options:\n"
14" --notrack			Don't track connection\n"
15" --helper name			Use conntrack helper 'name' for connection\n"
16" --ctevents event[,event...]	Generate specified conntrack events for connection\n"
17" --expevents event[,event...]	Generate specified expectation events for connection\n"
18" --zone ID			Assign/Lookup connection in zone ID\n"
19	);
20}
21
22enum ct_options {
23	CT_OPT_NOTRACK		= 0x1,
24	CT_OPT_HELPER		= 0x2,
25	CT_OPT_CTEVENTS		= 0x4,
26	CT_OPT_EXPEVENTS	= 0x8,
27	CT_OPT_ZONE		= 0x10,
28};
29
30static const struct option ct_opts[] = {
31	{ "notrack",	0, NULL, CT_OPT_NOTRACK },
32	{ "helper",	1, NULL, CT_OPT_HELPER },
33	{ "ctevents",	1, NULL, CT_OPT_CTEVENTS },
34	{ "expevents",	1, NULL, CT_OPT_EXPEVENTS },
35	{ "zone",	1, NULL, CT_OPT_ZONE },
36	{ .name	= NULL },
37};
38
39struct event_tbl {
40	const char	*name;
41	unsigned int	event;
42};
43
44static const struct event_tbl ct_event_tbl[] = {
45	{ "new",		IPCT_NEW },
46	{ "related",		IPCT_RELATED },
47	{ "destroy",		IPCT_DESTROY },
48	{ "reply",		IPCT_REPLY },
49	{ "assured",		IPCT_ASSURED },
50	{ "protoinfo",		IPCT_PROTOINFO },
51	{ "helper",		IPCT_HELPER },
52	{ "mark",		IPCT_MARK },
53	{ "natseqinfo",		IPCT_NATSEQADJ },
54	{ "secmark",		IPCT_SECMARK },
55};
56
57static const struct event_tbl exp_event_tbl[] = {
58	{ "new",		IPEXP_NEW },
59};
60
61static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
62				const char *events)
63{
64	char str[strlen(events) + 1], *e = str, *t;
65	unsigned int mask = 0, i;
66
67	strcpy(str, events);
68	while ((t = strsep(&e, ","))) {
69		for (i = 0; i < size; i++) {
70			if (strcmp(t, tbl->name))
71				continue;
72			mask |= 1 << tbl->event;
73			break;
74		}
75
76		if (i == size)
77			xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t);
78	}
79
80	return mask;
81}
82
83static void ct_print_events(const char *pfx, const struct event_tbl *tbl,
84			    unsigned int size, uint32_t mask)
85{
86	const char *sep = "";
87	unsigned int i;
88
89	printf("%s ", pfx);
90	for (i = 0; i < size; i++) {
91		if (mask & (1 << tbl[i].event)) {
92			printf("%s%s", sep, tbl[i].name);
93			sep = ",";
94		}
95	}
96	printf(" ");
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	default:
130		return 0;
131	}
132
133	*flags |= c;
134	return 1;
135}
136
137static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
138{
139	const struct xt_ct_target_info *info =
140		(const struct xt_ct_target_info *)target->data;
141
142	printf("CT ");
143	if (info->flags & XT_CT_NOTRACK)
144		printf("notrack ");
145	if (info->helper[0])
146		printf("helper %s ", info->helper);
147	if (info->ct_events)
148		ct_print_events("ctevents", ct_event_tbl,
149				ARRAY_SIZE(ct_event_tbl), info->ct_events);
150	if (info->exp_events)
151		ct_print_events("expevents", exp_event_tbl,
152				ARRAY_SIZE(exp_event_tbl), info->exp_events);
153	if (info->zone)
154		printf("zone %u ", info->zone);
155}
156
157static void ct_save(const void *ip, const struct xt_entry_target *target)
158{
159	const struct xt_ct_target_info *info =
160		(const struct xt_ct_target_info *)target->data;
161
162	if (info->flags & XT_CT_NOTRACK)
163		printf("--notrack ");
164	if (info->helper[0])
165		printf("--helper %s ", info->helper);
166	if (info->ct_events)
167		ct_print_events("--ctevents", ct_event_tbl,
168				ARRAY_SIZE(ct_event_tbl), info->ct_events);
169	if (info->exp_events)
170		ct_print_events("--expevents", exp_event_tbl,
171				ARRAY_SIZE(exp_event_tbl), info->exp_events);
172	if (info->zone)
173		printf("--zone %u ", info->zone);
174}
175
176static struct xtables_target ct_target = {
177	.family		= NFPROTO_UNSPEC,
178	.name		= "CT",
179	.version	= XTABLES_VERSION,
180	.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
181	.userspacesize	= offsetof(struct xt_ct_target_info, ct),
182	.help		= ct_help,
183	.parse		= ct_parse,
184	.print		= ct_print,
185	.save		= ct_save,
186	.extra_opts	= ct_opts,
187};
188
189void _init(void)
190{
191	xtables_register_target(&ct_target);
192}
193