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