Home | History | Annotate | Download | only in extensions
      1 /*
      2  * Copyright (c) 2010-2013 Patrick McHardy <kaber (at) 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 
     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 
     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 
     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 
    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 
    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 
    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 
    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
    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 
    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 
    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 *
    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 
    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 
    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 
    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 
    371 void _init(void)
    372 {
    373 	xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg));
    374 }
    375