• 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|mark}		Assign/Lookup connection in zone ID/packet nfmark\n"
20 " --zone-orig {ID|mark}		Same as 'zone' option, but only applies to ORIGINAL direction\n"
21 " --zone-reply {ID|mark} 	Same as 'zone' option, but only applies to REPLY direction\n"
22 	);
23 }
24 
ct_help_v1(void)25 static void ct_help_v1(void)
26 {
27 	printf(
28 "CT target options:\n"
29 " --notrack			Don't track connection\n"
30 " --helper name			Use conntrack helper 'name' for connection\n"
31 " --timeout name 		Use timeout policy 'name' for connection\n"
32 " --ctevents event[,event...]	Generate specified conntrack events for connection\n"
33 " --expevents event[,event...]	Generate specified expectation events for connection\n"
34 " --zone {ID|mark}		Assign/Lookup connection in zone ID/packet nfmark\n"
35 " --zone-orig {ID|mark}		Same as 'zone' option, but only applies to ORIGINAL direction\n"
36 " --zone-reply {ID|mark} 	Same as 'zone' option, but only applies to REPLY direction\n"
37 	);
38 }
39 
40 enum {
41 	O_NOTRACK = 0,
42 	O_HELPER,
43 	O_TIMEOUT,
44 	O_CTEVENTS,
45 	O_EXPEVENTS,
46 	O_ZONE,
47 	O_ZONE_ORIG,
48 	O_ZONE_REPLY,
49 };
50 
51 #define s struct xt_ct_target_info
52 static const struct xt_option_entry ct_opts[] = {
53 	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
54 	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
55 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
56 	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
57 	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
58 	{.name = "zone-orig", .id = O_ZONE_ORIG, .type = XTTYPE_STRING},
59 	{.name = "zone-reply", .id = O_ZONE_REPLY, .type = XTTYPE_STRING},
60 	{.name = "zone", .id = O_ZONE, .type = XTTYPE_STRING},
61 	XTOPT_TABLEEND,
62 };
63 #undef s
64 
65 #define s struct xt_ct_target_info_v1
66 static const struct xt_option_entry ct_opts_v1[] = {
67 	{.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE},
68 	{.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING,
69 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)},
70 	{.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_STRING,
71 	 .flags = XTOPT_PUT, XTOPT_POINTER(s, timeout)},
72 	{.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING},
73 	{.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING},
74 	{.name = "zone-orig", .id = O_ZONE_ORIG, .type = XTTYPE_STRING},
75 	{.name = "zone-reply", .id = O_ZONE_REPLY, .type = XTTYPE_STRING},
76 	{.name = "zone", .id = O_ZONE, .type = XTTYPE_STRING},
77 	XTOPT_TABLEEND,
78 };
79 #undef s
80 
81 struct event_tbl {
82 	const char	*name;
83 	unsigned int	event;
84 };
85 
86 static const struct event_tbl ct_event_tbl[] = {
87 	{ "new",		IPCT_NEW },
88 	{ "related",		IPCT_RELATED },
89 	{ "destroy",		IPCT_DESTROY },
90 	{ "reply",		IPCT_REPLY },
91 	{ "assured",		IPCT_ASSURED },
92 	{ "protoinfo",		IPCT_PROTOINFO },
93 	{ "helper",		IPCT_HELPER },
94 	{ "mark",		IPCT_MARK },
95 	{ "natseqinfo",		IPCT_NATSEQADJ },
96 	{ "secmark",		IPCT_SECMARK },
97 };
98 
99 static const struct event_tbl exp_event_tbl[] = {
100 	{ "new",		IPEXP_NEW },
101 };
102 
ct_parse_zone_id(const char * opt,unsigned int opt_id,uint16_t * zone_id,uint16_t * flags)103 static void ct_parse_zone_id(const char *opt, unsigned int opt_id,
104 			     uint16_t *zone_id, uint16_t *flags)
105 {
106 	if (opt_id == O_ZONE_ORIG)
107 		*flags |= XT_CT_ZONE_DIR_ORIG;
108 	if (opt_id == O_ZONE_REPLY)
109 		*flags |= XT_CT_ZONE_DIR_REPL;
110 
111 	*zone_id = 0;
112 
113 	if (strcasecmp(opt, "mark") == 0) {
114 		*flags |= XT_CT_ZONE_MARK;
115 	} else {
116 		uintmax_t val;
117 
118 		if (!xtables_strtoul(opt, NULL, &val, 0, UINT16_MAX))
119 			xtables_error(PARAMETER_PROBLEM,
120 				      "Cannot parse %s as a zone ID\n", opt);
121 
122 		*zone_id = (uint16_t)val;
123 	}
124 }
125 
ct_print_zone_id(const char * pfx,uint16_t zone_id,uint16_t flags)126 static void ct_print_zone_id(const char *pfx, uint16_t zone_id, uint16_t flags)
127 {
128 	printf(" %s", pfx);
129 
130 	if ((flags & (XT_CT_ZONE_DIR_ORIG |
131 		      XT_CT_ZONE_DIR_REPL)) == XT_CT_ZONE_DIR_ORIG)
132 		printf("-orig");
133 	if ((flags & (XT_CT_ZONE_DIR_ORIG |
134 		      XT_CT_ZONE_DIR_REPL)) == XT_CT_ZONE_DIR_REPL)
135 		printf("-reply");
136 	if (flags & XT_CT_ZONE_MARK)
137 		printf(" mark");
138 	else
139 		printf(" %u", zone_id);
140 }
141 
ct_parse_events(const struct event_tbl * tbl,unsigned int size,const char * events)142 static uint32_t ct_parse_events(const struct event_tbl *tbl, unsigned int size,
143 				const char *events)
144 {
145 	char str[strlen(events) + 1], *e = str, *t;
146 	unsigned int mask = 0, i;
147 
148 	strcpy(str, events);
149 	while ((t = strsep(&e, ","))) {
150 		for (i = 0; i < size; i++) {
151 			if (strcmp(t, tbl[i].name))
152 				continue;
153 			mask |= 1 << tbl[i].event;
154 			break;
155 		}
156 
157 		if (i == size)
158 			xtables_error(PARAMETER_PROBLEM, "Unknown event type \"%s\"", t);
159 	}
160 
161 	return mask;
162 }
163 
ct_print_events(const char * pfx,const struct event_tbl * tbl,unsigned int size,uint32_t mask)164 static void ct_print_events(const char *pfx, const struct event_tbl *tbl,
165 			    unsigned int size, uint32_t mask)
166 {
167 	const char *sep = "";
168 	unsigned int i;
169 
170 	printf(" %s ", pfx);
171 	for (i = 0; i < size; i++) {
172 		if (mask & (1 << tbl[i].event)) {
173 			printf("%s%s", sep, tbl[i].name);
174 			sep = ",";
175 		}
176 	}
177 }
178 
ct_parse(struct xt_option_call * cb)179 static void ct_parse(struct xt_option_call *cb)
180 {
181 	struct xt_ct_target_info *info = cb->data;
182 
183 	xtables_option_parse(cb);
184 	switch (cb->entry->id) {
185 	case O_NOTRACK:
186 		info->flags |= XT_CT_NOTRACK;
187 		break;
188 	case O_ZONE_ORIG:
189 	case O_ZONE_REPLY:
190 	case O_ZONE:
191 		ct_parse_zone_id(cb->arg, cb->entry->id, &info->zone,
192 				 &info->flags);
193 		break;
194 	case O_CTEVENTS:
195 		info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg);
196 		break;
197 	case O_EXPEVENTS:
198 		info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), cb->arg);
199 		break;
200 	}
201 }
202 
ct_parse_v1(struct xt_option_call * cb)203 static void ct_parse_v1(struct xt_option_call *cb)
204 {
205 	struct xt_ct_target_info_v1 *info = cb->data;
206 
207 	xtables_option_parse(cb);
208 	switch (cb->entry->id) {
209 	case O_NOTRACK:
210 		info->flags |= XT_CT_NOTRACK;
211 		break;
212 	case O_ZONE_ORIG:
213 	case O_ZONE_REPLY:
214 	case O_ZONE:
215 		ct_parse_zone_id(cb->arg, cb->entry->id, &info->zone,
216 				 &info->flags);
217 		break;
218 	case O_CTEVENTS:
219 		info->ct_events = ct_parse_events(ct_event_tbl,
220 						  ARRAY_SIZE(ct_event_tbl),
221 						  cb->arg);
222 		break;
223 	case O_EXPEVENTS:
224 		info->exp_events = ct_parse_events(exp_event_tbl,
225 						   ARRAY_SIZE(exp_event_tbl),
226 						   cb->arg);
227 		break;
228 	}
229 }
230 
ct_print(const void * ip,const struct xt_entry_target * target,int numeric)231 static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric)
232 {
233 	const struct xt_ct_target_info *info =
234 		(const struct xt_ct_target_info *)target->data;
235 
236 	printf(" CT");
237 	if (info->flags & XT_CT_NOTRACK)
238 		printf(" notrack");
239 	if (info->helper[0])
240 		printf(" helper %s", info->helper);
241 	if (info->ct_events)
242 		ct_print_events("ctevents", ct_event_tbl,
243 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
244 	if (info->exp_events)
245 		ct_print_events("expevents", exp_event_tbl,
246 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
247 	if (info->flags & XT_CT_ZONE_MARK || info->zone)
248 		ct_print_zone_id("zone", info->zone, info->flags);
249 }
250 
251 static void
ct_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)252 ct_print_v1(const void *ip, const struct xt_entry_target *target, int numeric)
253 {
254 	const struct xt_ct_target_info_v1 *info =
255 		(const struct xt_ct_target_info_v1 *)target->data;
256 
257 	if (info->flags & XT_CT_NOTRACK_ALIAS) {
258 		printf (" NOTRACK");
259 		return;
260 	}
261 	printf(" CT");
262 	if (info->flags & XT_CT_NOTRACK)
263 		printf(" notrack");
264 	if (info->helper[0])
265 		printf(" helper %s", info->helper);
266 	if (info->timeout[0])
267 		printf(" timeout %s", info->timeout);
268 	if (info->ct_events)
269 		ct_print_events("ctevents", ct_event_tbl,
270 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
271 	if (info->exp_events)
272 		ct_print_events("expevents", exp_event_tbl,
273 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
274 	if (info->flags & XT_CT_ZONE_MARK || info->zone)
275 		ct_print_zone_id("zone", info->zone, info->flags);
276 }
277 
ct_save(const void * ip,const struct xt_entry_target * target)278 static void ct_save(const void *ip, const struct xt_entry_target *target)
279 {
280 	const struct xt_ct_target_info *info =
281 		(const struct xt_ct_target_info *)target->data;
282 
283 	if (info->flags & XT_CT_NOTRACK_ALIAS)
284 		return;
285 	if (info->flags & XT_CT_NOTRACK)
286 		printf(" --notrack");
287 	if (info->helper[0])
288 		printf(" --helper %s", info->helper);
289 	if (info->ct_events)
290 		ct_print_events("--ctevents", ct_event_tbl,
291 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
292 	if (info->exp_events)
293 		ct_print_events("--expevents", exp_event_tbl,
294 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
295 	if (info->flags & XT_CT_ZONE_MARK || info->zone)
296 		ct_print_zone_id("--zone", info->zone, info->flags);
297 }
298 
ct_save_v1(const void * ip,const struct xt_entry_target * target)299 static void ct_save_v1(const void *ip, const struct xt_entry_target *target)
300 {
301 	const struct xt_ct_target_info_v1 *info =
302 		(const struct xt_ct_target_info_v1 *)target->data;
303 
304 	if (info->flags & XT_CT_NOTRACK_ALIAS)
305 		return;
306 	if (info->flags & XT_CT_NOTRACK)
307 		printf(" --notrack");
308 	if (info->helper[0])
309 		printf(" --helper %s", info->helper);
310 	if (info->timeout[0])
311 		printf(" --timeout %s", info->timeout);
312 	if (info->ct_events)
313 		ct_print_events("--ctevents", ct_event_tbl,
314 				ARRAY_SIZE(ct_event_tbl), info->ct_events);
315 	if (info->exp_events)
316 		ct_print_events("--expevents", exp_event_tbl,
317 				ARRAY_SIZE(exp_event_tbl), info->exp_events);
318 	if (info->flags & XT_CT_ZONE_MARK || info->zone)
319 		ct_print_zone_id("--zone", info->zone, info->flags);
320 }
321 
322 static const char *
ct_print_name_alias(const struct xt_entry_target * target)323 ct_print_name_alias(const struct xt_entry_target *target)
324 {
325 	struct xt_ct_target_info *info = (void *)target->data;
326 
327 	return info->flags & XT_CT_NOTRACK_ALIAS ? "NOTRACK" : "CT";
328 }
329 
notrack_ct0_tg_init(struct xt_entry_target * target)330 static void notrack_ct0_tg_init(struct xt_entry_target *target)
331 {
332 	struct xt_ct_target_info *info = (void *)target->data;
333 
334 	info->flags = XT_CT_NOTRACK;
335 }
336 
notrack_ct1_tg_init(struct xt_entry_target * target)337 static void notrack_ct1_tg_init(struct xt_entry_target *target)
338 {
339 	struct xt_ct_target_info_v1 *info = (void *)target->data;
340 
341 	info->flags = XT_CT_NOTRACK;
342 }
343 
notrack_ct2_tg_init(struct xt_entry_target * target)344 static void notrack_ct2_tg_init(struct xt_entry_target *target)
345 {
346 	struct xt_ct_target_info_v1 *info = (void *)target->data;
347 
348 	info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS;
349 }
350 
xlate_ct1_tg(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)351 static int xlate_ct1_tg(struct xt_xlate *xl,
352 			const struct xt_xlate_tg_params *params)
353 {
354 	struct xt_ct_target_info_v1 *info =
355 		(struct xt_ct_target_info_v1 *)params->target->data;
356 
357 	if (info->flags & XT_CT_NOTRACK)
358 		xt_xlate_add(xl, "notrack");
359 	else
360 		return 0;
361 
362 	return 1;
363 }
364 
365 static struct xtables_target ct_target_reg[] = {
366 	{
367 		.family		= NFPROTO_UNSPEC,
368 		.name		= "CT",
369 		.version	= XTABLES_VERSION,
370 		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info)),
371 		.userspacesize	= offsetof(struct xt_ct_target_info, ct),
372 		.help		= ct_help,
373 		.print		= ct_print,
374 		.save		= ct_save,
375 		.x6_parse	= ct_parse,
376 		.x6_options	= ct_opts,
377 	},
378 	{
379 		.family		= NFPROTO_UNSPEC,
380 		.name		= "CT",
381 		.revision	= 1,
382 		.version	= XTABLES_VERSION,
383 		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
384 		.userspacesize	= offsetof(struct xt_ct_target_info_v1, ct),
385 		.help		= ct_help_v1,
386 		.print		= ct_print_v1,
387 		.save		= ct_save_v1,
388 		.x6_parse	= ct_parse_v1,
389 		.x6_options	= ct_opts_v1,
390 	},
391 	{
392 		.family		= NFPROTO_UNSPEC,
393 		.name		= "CT",
394 		.revision	= 2,
395 		.version	= XTABLES_VERSION,
396 		.size		= XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
397 		.userspacesize	= offsetof(struct xt_ct_target_info_v1, ct),
398 		.help		= ct_help_v1,
399 		.print		= ct_print_v1,
400 		.save		= ct_save_v1,
401 		.alias		= ct_print_name_alias,
402 		.x6_parse	= ct_parse_v1,
403 		.x6_options	= ct_opts_v1,
404 		.xlate		= xlate_ct1_tg,
405 	},
406 	{
407 		.family        = NFPROTO_UNSPEC,
408 		.name          = "NOTRACK",
409 		.real_name     = "CT",
410 		.revision      = 0,
411 		.version       = XTABLES_VERSION,
412 		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info)),
413 		.userspacesize = offsetof(struct xt_ct_target_info, ct),
414 		.init          = notrack_ct0_tg_init,
415 	},
416 	{
417 		.family        = NFPROTO_UNSPEC,
418 		.name          = "NOTRACK",
419 		.real_name     = "CT",
420 		.revision      = 1,
421 		.version       = XTABLES_VERSION,
422 		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
423 		.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
424 		.init          = notrack_ct1_tg_init,
425 	},
426 	{
427 		.family        = NFPROTO_UNSPEC,
428 		.name          = "NOTRACK",
429 		.real_name     = "CT",
430 		.revision      = 2,
431 		.ext_flags     = XTABLES_EXT_ALIAS,
432 		.version       = XTABLES_VERSION,
433 		.size          = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)),
434 		.userspacesize = offsetof(struct xt_ct_target_info_v1, ct),
435 		.init          = notrack_ct2_tg_init,
436 		.xlate	       = xlate_ct1_tg,
437 	},
438 	{
439 		.family        = NFPROTO_UNSPEC,
440 		.name          = "NOTRACK",
441 		.revision      = 0,
442 		.version       = XTABLES_VERSION,
443 	},
444 };
445 
_init(void)446 void _init(void)
447 {
448 	xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg));
449 }
450