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 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 23static 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 36enum { 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 46static 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 59static 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 73struct event_tbl { 74 const char *name; 75 unsigned int event; 76}; 77 78static 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 91static const struct event_tbl exp_event_tbl[] = { 92 { "new", IPEXP_NEW }, 93}; 94 95static 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 117static 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 132static 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 150static 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 172static 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 192static void 193ct_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 219static 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 240static 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 263static const char * 264ct_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 271static 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 278static 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 285static 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 292static 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 371void _init(void) 372{ 373 xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg)); 374} 375