• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2010-2013 Patrick McHardy <kaber@trash.net>
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <xtables.h>
8 #include <linux/netfilter/nf_conntrack_common.h>
9 #include <linux/netfilter/xt_CT.h>
10 
ct_help(void)11 static 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 
ct_help_v1(void)23 static void ct_help_v1(void)
24 {
25 	printf(
26 "CT target options:\n"
27 " --notrack			Don't track connection\n"
28 " --helper name			Use conntrack helper 'name' for connection\n"
29 " --timeout name 		Use timeout policy 'name' for connection\n"
30 " --ctevents event[,event...]	Generate specified conntrack events for connection\n"
31 " --expevents event[,event...]	Generate specified expectation events for connection\n"
32 " --zone ID			Assign/Lookup connection in zone ID\n"
33 	);
34 }
35 
36 enum {
37 	O_NOTRACK = 0,
38 	O_HELPER,
39 	O_TIMEOUT,
40 	O_CTEVENTS,
41 	O_EXPEVENTS,
42 	O_ZONE,
43 };
44 
45 #define s struct xt_ct_target_info
46 static const struct xt_option_entry ct_opts[] = {
47 	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
48 	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
49 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
50 	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
51 	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
52 	{.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
53 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
54 	XTOPT_TABLEEND,
55 };
56 #undef s
57 
58 #define s struct xt_ct_target_info_v1
59 static const struct xt_option_entry ct_opts_v1[] = {
60 	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
61 	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
62 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
63 	{.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_STRING,
64 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, timeout)},
65 	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
66 	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
67 	{.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16,
68 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)},
69 	XTOPT_TABLEEND,
70 };
71 #undef s
72 
73 struct event_tbl {
74 	const char	*name;
75 	unsigned int	event;
76 };
77 
78 static const struct event_tbl ct_event_tbl[] = {
79 	{ "new",		IPCT_NEW },
80 	{ "related",		IPCT_RELATED },
81 	{ "destroy",		IPCT_DESTROY },
82 	{ "reply",		IPCT_REPLY },
83 	{ "assured",		IPCT_ASSURED },
84 	{ "protoinfo",		IPCT_PROTOINFO },
85 	{ "helper",		IPCT_HELPER },
86 	{ "mark",		IPCT_MARK },
87 	{ "natseqinfo",		IPCT_NATSEQADJ },
88 	{ "secmark",		IPCT_SECMARK },
89 };
90 
91 static const struct event_tbl exp_event_tbl[] = {
92 	{ "new",		IPEXP_NEW },
93 };
94 
ct_parse_events(const struct event_tbl * tbl,unsigned int size,const char * events)95 static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
96 				const char *events)
97 {
98 	char str[strlen(events) + 1], *e = str, *t;
99 	unsigned int mask = 0, i;
100 
101 	strcpy(str, events);
102 	while ((t = strsep(&e, ","))) {
103 		for (i = 0; i < size; i++) {
104 			if (strcmp(t, tbl[i].name))
105 				continue;
106 			mask |= 1 << tbl[i].event;
107 			break;
108 		}
109 
110 		if (i == size)
111 			xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t);
112 	}
113 
114 	return mask;
115 }
116 
ct_print_events(const char * pfx,const struct event_tbl * tbl,unsigned int size,uint32_t mask)117 static void ct_print_events(const char *pfx, const struct event_tbl *tbl,
118 			    unsigned int size, uint32_t mask)
119 {
120 	const char *sep = "";
121 	unsigned int i;
122 
123 	printf(" %s ", pfx);
124 	for (i = 0; i < size; i++) {
125 		if (mask & (1 << tbl[i].event)) {
126 			printf("%s%s", sep, tbl[i].name);
127 			sep = ",";
128 		}
129 	}
130 }
131 
ct_parse(struct xt_option_call * cb)132 static void ct_parse(struct xt_option_call *cb)
133 {
134 	struct xt_ct_target_info *info = cb->data;
135 
136 	xtables_option_parse(cb);
137 	switch (cb->entry->id) {
138 	case O_NOTRACK:
139 		info->flags |= XT_CT_NOTRACK;
140 		break;
141 	case O_CTEVENTS:
142 		info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg);
143 		break;
144 	case O_EXPEVENTS:
145 		info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), cb->arg);
146 		break;
147 	}
148 }
149 
ct_parse_v1(struct xt_option_call * cb)150 static void ct_parse_v1(struct xt_option_call *cb)
151 {
152 	struct xt_ct_target_info_v1 *info = cb->data;
153 
154 	xtables_option_parse(cb);
155 	switch (cb->entry->id) {
156 	case O_NOTRACK:
157 		info->flags |= XT_CT_NOTRACK;
158 		break;
159 	case O_CTEVENTS:
160 		info->ct_events = ct_parse_events(ct_event_tbl,
161 						  ARRAY_SIZE(ct_event_tbl),
162 						  cb->arg);
163 		break;
164 	case O_EXPEVENTS:
165 		info->exp_events = ct_parse_events(exp_event_tbl,
166 						   ARRAY_SIZE(exp_event_tbl),
167 						   cb->arg);
168 		break;
169 	}
170 }
171 
ct_print(const void * ip,const struct xt_entry_target * target,int numeric)172 static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
173 {
174 	const struct xt_ct_target_info *info =
175 		(const struct xt_ct_target_info *)target->data;
176 
177 	printf(" CT");
178 	if (info->flags & XT_CT_NOTRACK)
179 		printf(" notrack");
180 	if (info->helper[0])
181 		printf(" helper %s", info->helper);
182 	if (info->ct_events)
183 		ct_print_events("ctevents", ct_event_tbl,
184 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
185 	if (info->exp_events)
186 		ct_print_events("expevents", exp_event_tbl,
187 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
188 	if (info->zone)
189 		printf("zone %u ", info->zone);
190 }
191 
192 static void
ct_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)193 ct_print_v1(const void *ip, const struct xt_entry_target *target, int numeric)
194 {
195 	const struct xt_ct_target_info_v1 *info =
196 		(const struct xt_ct_target_info_v1 *)target->data;
197 
198 	if (info->flags & XT_CT_NOTRACK_ALIAS) {
199 		printf (" NOTRACK");
200 		return;
201 	}
202 	printf(" CT");
203 	if (info->flags & XT_CT_NOTRACK)
204 		printf(" notrack");
205 	if (info->helper[0])
206 		printf(" helper %s", info->helper);
207 	if (info->timeout[0])
208 		printf(" timeout %s", info->timeout);
209 	if (info->ct_events)
210 		ct_print_events("ctevents", ct_event_tbl,
211 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
212 	if (info->exp_events)
213 		ct_print_events("expevents", exp_event_tbl,
214 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
215 	if (info->zone)
216 		printf("zone %u ", info->zone);
217 }
218 
ct_save(const void * ip,const struct xt_entry_target * target)219 static void ct_save(const void *ip, const struct xt_entry_target *target)
220 {
221 	const struct xt_ct_target_info *info =
222 		(const struct xt_ct_target_info *)target->data;
223 
224 	if (info->flags & XT_CT_NOTRACK_ALIAS)
225 		return;
226 	if (info->flags & XT_CT_NOTRACK)
227 		printf(" --notrack");
228 	if (info->helper[0])
229 		printf(" --helper %s", info->helper);
230 	if (info->ct_events)
231 		ct_print_events("--ctevents", ct_event_tbl,
232 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
233 	if (info->exp_events)
234 		ct_print_events("--expevents", exp_event_tbl,
235 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
236 	if (info->zone)
237 		printf(" --zone %u", info->zone);
238 }
239 
ct_save_v1(const void * ip,const struct xt_entry_target * target)240 static void ct_save_v1(const void *ip, const struct xt_entry_target *target)
241 {
242 	const struct xt_ct_target_info_v1 *info =
243 		(const struct xt_ct_target_info_v1 *)target->data;
244 
245 	if (info->flags & XT_CT_NOTRACK_ALIAS)
246 		return;
247 	if (info->flags & XT_CT_NOTRACK)
248 		printf(" --notrack");
249 	if (info->helper[0])
250 		printf(" --helper %s", info->helper);
251 	if (info->timeout[0])
252 		printf(" --timeout %s", info->timeout);
253 	if (info->ct_events)
254 		ct_print_events("--ctevents", ct_event_tbl,
255 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
256 	if (info->exp_events)
257 		ct_print_events("--expevents", exp_event_tbl,
258 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
259 	if (info->zone)
260 		printf(" --zone %u", info->zone);
261 }
262 
263 static const char *
ct_print_name_alias(const struct xt_entry_target * target)264 ct_print_name_alias(const struct xt_entry_target *target)
265 {
266 	struct xt_ct_target_info *info = (void *)target->data;
267 
268 	return info->flags & XT_CT_NOTRACK_ALIAS ? "NOTRACK" : "CT";
269 }
270 
notrack_ct0_tg_init(struct xt_entry_target * target)271 static void notrack_ct0_tg_init(struct xt_entry_target *target)
272 {
273 	struct xt_ct_target_info *info = (void *)target->data;
274 
275 	info->flags = XT_CT_NOTRACK;
276 }
277 
notrack_ct1_tg_init(struct xt_entry_target * target)278 static void notrack_ct1_tg_init(struct xt_entry_target *target)
279 {
280 	struct xt_ct_target_info_v1 *info = (void *)target->data;
281 
282 	info->flags = XT_CT_NOTRACK;
283 }
284 
notrack_ct2_tg_init(struct xt_entry_target * target)285 static void notrack_ct2_tg_init(struct xt_entry_target *target)
286 {
287 	struct xt_ct_target_info_v1 *info = (void *)target->data;
288 
289 	info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS;
290 }
291 
292 static struct xtables_target ct_target_reg[] = {
293 	{
294 		.family		= NFPROTO_UNSPEC,
295 		.name		= "CT",
296 		.version	= XTABLES_VERSION,
297 		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
298 		.userspacesize	= offsetof(struct xt_ct_target_info, ct),
299 		.help		= ct_help,
300 		.print		= ct_print,
301 		.save		= ct_save,
302 		.x6_parse	= ct_parse,
303 		.x6_options	= ct_opts,
304 	},
305 	{
306 		.family		= NFPROTO_UNSPEC,
307 		.name		= "CT",
308 		.revision	= 1,
309 		.version	= XTABLES_VERSION,
310 		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
311 		.userspacesize	= offsetof(struct xt_ct_target_info_v1, ct),
312 		.help		= ct_help_v1,
313 		.print		= ct_print_v1,
314 		.save		= ct_save_v1,
315 		.x6_parse	= ct_parse_v1,
316 		.x6_options	= ct_opts_v1,
317 	},
318 	{
319 		.family		= NFPROTO_UNSPEC,
320 		.name		= "CT",
321 		.revision	= 2,
322 		.version	= XTABLES_VERSION,
323 		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
324 		.userspacesize	= offsetof(struct xt_ct_target_info_v1, ct),
325 		.help		= ct_help_v1,
326 		.print		= ct_print_v1,
327 		.save		= ct_save_v1,
328 		.alias		= ct_print_name_alias,
329 		.x6_parse	= ct_parse_v1,
330 		.x6_options	= ct_opts_v1,
331 	},
332 	{
333 		.family        = NFPROTO_UNSPEC,
334 		.name          = "NOTRACK",
335 		.real_name     = "CT",
336 		.revision      = 0,
337 		.version       = XTABLES_VERSION,
338 		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info)),
339 		.userspacesize = offsetof(struct xt_ct_target_info, ct),
340 		.init          = notrack_ct0_tg_init,
341 	},
342 	{
343 		.family        = NFPROTO_UNSPEC,
344 		.name          = "NOTRACK",
345 		.real_name     = "CT",
346 		.revision      = 1,
347 		.version       = XTABLES_VERSION,
348 		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
349 		.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
350 		.init          = notrack_ct1_tg_init,
351 	},
352 	{
353 		.family        = NFPROTO_UNSPEC,
354 		.name          = "NOTRACK",
355 		.real_name     = "CT",
356 		.revision      = 2,
357 		.ext_flags     = XTABLES_EXT_ALIAS,
358 		.version       = XTABLES_VERSION,
359 		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
360 		.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
361 		.init          = notrack_ct2_tg_init,
362 	},
363 	{
364 		.family        = NFPROTO_UNSPEC,
365 		.name          = "NOTRACK",
366 		.revision      = 0,
367 		.version       = XTABLES_VERSION,
368 	},
369 };
370 
_init(void)371 void _init(void)
372 {
373 	xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg));
374 }
375