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 Assign/Lookup connection in zone ID\n"
20 );
21 }
22
ct_help_v1(void)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
ct_parse_events(const struct event_tbl * tbl,unsigned int size,const char * events)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
ct_print_events(const char * pfx,const struct event_tbl * tbl,unsigned int size,uint32_t mask)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
ct_parse(struct xt_option_call * cb)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
ct_parse_v1(struct xt_option_call * cb)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
ct_print(const void * ip,const struct xt_entry_target * target,int numeric)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
ct_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)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
ct_save(const void * ip,const struct xt_entry_target * target)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
ct_save_v1(const void * ip,const struct xt_entry_target * target)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 *
ct_print_name_alias(const struct xt_entry_target * target)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
notrack_ct0_tg_init(struct xt_entry_target * target)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
notrack_ct1_tg_init(struct xt_entry_target * target)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
notrack_ct2_tg_init(struct xt_entry_target * target)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
_init(void)371 void _init(void)
372 {
373 xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg));
374 }
375