libxt_CT.c revision 0c3753b1d4226a6e7bea9619415cf40cadee1e58
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 printf(" CT"); 199 if (info->flags & XT_CT_NOTRACK) 200 printf(" notrack"); 201 if (info->helper[0]) 202 printf(" helper %s", info->helper); 203 if (info->timeout[0]) 204 printf(" timeout %s", info->timeout); 205 if (info->ct_events) 206 ct_print_events("ctevents", ct_event_tbl, 207 ARRAY_SIZE(ct_event_tbl), info->ct_events); 208 if (info->exp_events) 209 ct_print_events("expevents", exp_event_tbl, 210 ARRAY_SIZE(exp_event_tbl), info->exp_events); 211 if (info->zone) 212 printf("zone %u ", info->zone); 213} 214 215static void ct_save(const void *ip, const struct xt_entry_target *target) 216{ 217 const struct xt_ct_target_info *info = 218 (const struct xt_ct_target_info *)target->data; 219 220 if (info->flags & XT_CT_NOTRACK) 221 printf(" --notrack"); 222 if (info->helper[0]) 223 printf(" --helper %s", info->helper); 224 if (info->ct_events) 225 ct_print_events("--ctevents", ct_event_tbl, 226 ARRAY_SIZE(ct_event_tbl), info->ct_events); 227 if (info->exp_events) 228 ct_print_events("--expevents", exp_event_tbl, 229 ARRAY_SIZE(exp_event_tbl), info->exp_events); 230 if (info->zone) 231 printf(" --zone %u", info->zone); 232} 233 234static void ct_save_v1(const void *ip, const struct xt_entry_target *target) 235{ 236 const struct xt_ct_target_info_v1 *info = 237 (const struct xt_ct_target_info_v1 *)target->data; 238 239 if (info->flags & XT_CT_NOTRACK) 240 printf(" --notrack"); 241 if (info->helper[0]) 242 printf(" --helper %s", info->helper); 243 if (info->timeout[0]) 244 printf(" --timeout %s", info->timeout); 245 if (info->ct_events) 246 ct_print_events("--ctevents", ct_event_tbl, 247 ARRAY_SIZE(ct_event_tbl), info->ct_events); 248 if (info->exp_events) 249 ct_print_events("--expevents", exp_event_tbl, 250 ARRAY_SIZE(exp_event_tbl), info->exp_events); 251 if (info->zone) 252 printf(" --zone %u", info->zone); 253} 254 255static void notrack_ct0_tg_init(struct xt_entry_target *target) 256{ 257 struct xt_ct_target_info *info = (void *)target->data; 258 259 info->flags = XT_CT_NOTRACK; 260} 261 262static void notrack_ct1_tg_init(struct xt_entry_target *target) 263{ 264 struct xt_ct_target_info_v1 *info = (void *)target->data; 265 266 info->flags = XT_CT_NOTRACK; 267} 268 269static struct xtables_target ct_target_reg[] = { 270 { 271 .family = NFPROTO_UNSPEC, 272 .name = "CT", 273 .version = XTABLES_VERSION, 274 .size = XT_ALIGN(sizeof(struct xt_ct_target_info)), 275 .userspacesize = offsetof(struct xt_ct_target_info, ct), 276 .help = ct_help, 277 .print = ct_print, 278 .save = ct_save, 279 .x6_parse = ct_parse, 280 .x6_options = ct_opts, 281 }, 282 { 283 .family = NFPROTO_UNSPEC, 284 .name = "CT", 285 .revision = 1, 286 .version = XTABLES_VERSION, 287 .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), 288 .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), 289 .help = ct_help_v1, 290 .print = ct_print_v1, 291 .save = ct_save_v1, 292 .x6_parse = ct_parse_v1, 293 .x6_options = ct_opts_v1, 294 }, 295 { 296 .family = NFPROTO_UNSPEC, 297 .name = "NOTRACK", 298 .real_name = "CT", 299 .revision = 0, 300 .version = XTABLES_VERSION, 301 .size = XT_ALIGN(sizeof(struct xt_ct_target_info)), 302 .userspacesize = offsetof(struct xt_ct_target_info, ct), 303 .init = notrack_ct0_tg_init, 304 }, 305 { 306 .family = NFPROTO_UNSPEC, 307 .name = "NOTRACK", 308 .real_name = "CT", 309 .revision = 1, 310 .version = XTABLES_VERSION, 311 .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), 312 .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), 313 .init = notrack_ct1_tg_init, 314 }, 315 { 316 .family = NFPROTO_UNSPEC, 317 .name = "NOTRACK", 318 .revision = 0, 319 .version = XTABLES_VERSION, 320 }, 321}; 322 323void _init(void) 324{ 325 xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg)); 326} 327