blob: 6b28fe1bce199f6a571da72e92216ddbe5cdcd28 [file] [log] [blame]
Patrick McHardy0c3753b2013-04-06 13:41:25 +02001/*
2 * Copyright (c) 2010-2013 Patrick McHardy <kaber@trash.net>
3 */
4
Patrick McHardy9fdbaa72010-03-08 13:57:24 +01005#include <stdio.h>
6#include <string.h>
Patrick McHardy9fdbaa72010-03-08 13:57:24 +01007#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"
Jan Engelhardt89b6c322010-03-11 00:49:48 +010017" --ctevents event[,event...] Generate specified conntrack events for connection\n"
Patrick McHardy9fdbaa72010-03-08 13:57:24 +010018" --expevents event[,event...] Generate specified expectation events for connection\n"
19" --zone ID Assign/Lookup connection in zone ID\n"
20 );
21}
22
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +010023static 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
Jan Engelhardta05562e2011-03-06 17:47:03 +010036enum {
37 O_NOTRACK = 0,
38 O_HELPER,
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +010039 O_TIMEOUT,
Jan Engelhardta05562e2011-03-06 17:47:03 +010040 O_CTEVENTS,
41 O_EXPEVENTS,
42 O_ZONE,
Patrick McHardy9fdbaa72010-03-08 13:57:24 +010043};
44
Jan Engelhardta05562e2011-03-06 17:47:03 +010045#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,
Patrick McHardy9fdbaa72010-03-08 13:57:24 +010055};
Jan Engelhardta05562e2011-03-06 17:47:03 +010056#undef s
Patrick McHardy9fdbaa72010-03-08 13:57:24 +010057
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +010058#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
Patrick McHardy9fdbaa72010-03-08 13:57:24 +010073struct 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++) {
Pablo Neira Ayusobed2ba92010-05-09 21:47:33 +0200104 if (strcmp(t, tbl[i].name))
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100105 continue;
Pablo Neira Ayusobed2ba92010-05-09 21:47:33 +0200106 mask |= 1 << tbl[i].event;
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100107 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
Jan Engelhardt73866352010-12-18 02:04:59 +0100123 printf(" %s ", pfx);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100124 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 }
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100130}
131
Jan Engelhardta05562e2011-03-06 17:47:03 +0100132static void ct_parse(struct xt_option_call *cb)
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100133{
Jan Engelhardta05562e2011-03-06 17:47:03 +0100134 struct xt_ct_target_info *info = cb->data;
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100135
Jan Engelhardta05562e2011-03-06 17:47:03 +0100136 xtables_option_parse(cb);
137 switch (cb->entry->id) {
138 case O_NOTRACK:
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100139 info->flags |= XT_CT_NOTRACK;
140 break;
Jan Engelhardta05562e2011-03-06 17:47:03 +0100141 case O_CTEVENTS:
142 info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100143 break;
Jan Engelhardta05562e2011-03-06 17:47:03 +0100144 case O_EXPEVENTS:
145 info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), cb->arg);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100146 break;
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100147 }
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100148}
149
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100150static 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
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100172static 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
Jan Engelhardt73866352010-12-18 02:04:59 +0100177 printf(" CT");
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100178 if (info->flags & XT_CT_NOTRACK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100179 printf(" notrack");
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100180 if (info->helper[0])
Jan Engelhardt73866352010-12-18 02:04:59 +0100181 printf(" helper %s", info->helper);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100182 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);
Patrick McHardy9f27e6b2010-04-20 14:26:47 +0200188 if (info->zone)
189 printf("zone %u ", info->zone);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100190}
191
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100192static 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
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100198 if (info->flags & XT_CT_NOTRACK_ALIAS) {
199 printf (" NOTRACK");
200 return;
201 }
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100202 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
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100219static 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
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100224 if (info->flags & XT_CT_NOTRACK_ALIAS)
225 return;
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100226 if (info->flags & XT_CT_NOTRACK)
Jan Engelhardt73866352010-12-18 02:04:59 +0100227 printf(" --notrack");
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100228 if (info->helper[0])
Jan Engelhardt73866352010-12-18 02:04:59 +0100229 printf(" --helper %s", info->helper);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100230 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);
Patrick McHardy9f27e6b2010-04-20 14:26:47 +0200236 if (info->zone)
Jan Engelhardt73866352010-12-18 02:04:59 +0100237 printf(" --zone %u", info->zone);
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100238}
239
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100240static 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
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100245 if (info->flags & XT_CT_NOTRACK_ALIAS)
246 return;
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100247 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
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100263static 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
Jan Engelhardt50f19192012-09-04 05:38:48 +0200271static 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
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100285static 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
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100292static 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 },
Jan Engelhardt50f19192012-09-04 05:38:48 +0200318 {
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100319 .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 {
Jan Engelhardt50f19192012-09-04 05:38:48 +0200333 .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",
Jozsef Kadlecsik7b26baf2013-01-28 21:32:55 +0100355 .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",
Jan Engelhardt50f19192012-09-04 05:38:48 +0200366 .revision = 0,
367 .version = XTABLES_VERSION,
368 },
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100369};
370
371void _init(void)
372{
Pablo Neira Ayusoe8f32982012-02-29 13:48:36 +0100373 xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg));
Patrick McHardy9fdbaa72010-03-08 13:57:24 +0100374}