changing trunk/trunk to trunk
[iptables.git] / extensions / libxt_CONNMARK.c
1 /* Shared library add-on to iptables to add CONNMARK target support.
2  *
3  * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
4  * by Henrik Nordstrom <hno@marasystems.com>
5  *
6  * Version 1.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <getopt.h>
26
27 #include <xtables.h>
28 #include <linux/netfilter/x_tables.h>
29 #include <linux/netfilter/xt_CONNMARK.h>
30
31 enum {
32         F_MARK    = 1 << 0,
33         F_SR_MARK = 1 << 1,
34 };
35
36 /* Function which prints out usage message. */
37 static void CONNMARK_help(void)
38 {
39         printf(
40 "CONNMARK target options:\n"
41 "  --set-mark value[/mask]       Set conntrack mark value\n"
42 "  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
43 "  --restore-mark [--mask mask]  Restore saved nfmark value\n");
44 }
45
46 static const struct option CONNMARK_opts[] = {
47         { "set-mark", 1, NULL, '1' },
48         { "save-mark", 0, NULL, '2' },
49         { "restore-mark", 0, NULL, '3' },
50         { "mask", 1, NULL, '4' },
51         { .name = NULL }
52 };
53
54 static const struct option connmark_tg_opts[] = {
55         {.name = "set-xmark",     .has_arg = true,  .val = '='},
56         {.name = "set-mark",      .has_arg = true,  .val = '-'},
57         {.name = "and-mark",      .has_arg = true,  .val = '&'},
58         {.name = "or-mark",       .has_arg = true,  .val = '|'},
59         {.name = "xor-mark",      .has_arg = true,  .val = '^'},
60         {.name = "save-mark",     .has_arg = false, .val = 'S'},
61         {.name = "restore-mark",  .has_arg = false, .val = 'R'},
62         {.name = "ctmask",        .has_arg = true,  .val = 'c'},
63         {.name = "nfmask",        .has_arg = true,  .val = 'n'},
64         {.name = "mask",          .has_arg = true,  .val = 'm'},
65         {.name = NULL},
66 };
67
68 static void connmark_tg_help(void)
69 {
70         printf(
71 "CONNMARK target options:\n"
72 "  --set-xmark value[/ctmask]    Zero mask bits and XOR ctmark with value\n"
73 "  --save-mark [--ctmask mask] [--nfmask mask]\n"
74 "                                Copy ctmark to nfmark using masks\n"
75 "  --restore-mark [--ctmask mask] [--nfmask mask]\n"
76 "                                Copy nfmark to ctmark using masks\n"
77 "  --set-mark value[/mask]       Set conntrack mark value\n"
78 "  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
79 "  --restore-mark [--mask mask]  Restore saved nfmark value\n"
80 "  --and-mark value              Binary AND the ctmark with bits\n"
81 "  --or-mark value               Binary OR  the ctmark with bits\n"
82 "  --xor-mark value              Binary XOR the ctmark with bits\n"
83 );
84 }
85
86 static void connmark_tg_init(struct xt_entry_target *target)
87 {
88         struct xt_connmark_tginfo1 *info = (void *)target->data;
89
90         /*
91          * Need these defaults for --save-mark/--restore-mark if no
92          * --ctmark or --nfmask is given.
93          */
94         info->ctmask = ~0U;
95         info->nfmask = ~0U;
96 }
97
98 /* Function which parses command options; returns true if it
99    ate an option */
100 static int
101 CONNMARK_parse(int c, char **argv, int invert, unsigned int *flags,
102                const void *entry, struct xt_entry_target **target)
103 {
104         struct xt_connmark_target_info *markinfo
105                 = (struct xt_connmark_target_info *)(*target)->data;
106
107         switch (c) {
108                 char *end;
109         case '1':
110                 markinfo->mode = XT_CONNMARK_SET;
111
112                 markinfo->mark = strtoul(optarg, &end, 0);
113                 if (*end == '/' && end[1] != '\0')
114                     markinfo->mask = strtoul(end+1, &end, 0);
115
116                 if (*end != '\0' || end == optarg)
117                         exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
118                 if (*flags)
119                         exit_error(PARAMETER_PROBLEM,
120                                    "CONNMARK target: Can't specify --set-mark twice");
121                 *flags = 1;
122                 break;
123         case '2':
124                 markinfo->mode = XT_CONNMARK_SAVE;
125                 if (*flags)
126                         exit_error(PARAMETER_PROBLEM,
127                                    "CONNMARK target: Can't specify --save-mark twice");
128                 *flags = 1;
129                 break;
130         case '3':
131                 markinfo->mode = XT_CONNMARK_RESTORE;
132                 if (*flags)
133                         exit_error(PARAMETER_PROBLEM,
134                                    "CONNMARK target: Can't specify --restore-mark twice");
135                 *flags = 1;
136                 break;
137         case '4':
138                 if (!*flags)
139                         exit_error(PARAMETER_PROBLEM,
140                                    "CONNMARK target: Can't specify --mask without a operation");
141                 markinfo->mask = strtoul(optarg, &end, 0);
142
143                 if (*end != '\0' || end == optarg)
144                         exit_error(PARAMETER_PROBLEM, "Bad MASK value `%s'", optarg);
145                 break;
146         default:
147                 return 0;
148         }
149
150         return 1;
151 }
152
153 static int connmark_tg_parse(int c, char **argv, int invert,
154                              unsigned int *flags, const void *entry,
155                              struct xt_entry_target **target)
156 {
157         struct xt_connmark_tginfo1 *info = (void *)(*target)->data;
158         unsigned int value, mask = ~0U;
159         char *end;
160
161         switch (c) {
162         case '=': /* --set-xmark */
163         case '-': /* --set-mark */
164                 param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
165                 if (!strtonum(optarg, &end, &value, 0, ~0U))
166                         param_act(P_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
167                 if (*end == '/')
168                         if (!strtonum(end + 1, &end, &mask, 0, ~0U))
169                                 param_act(P_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
170                 if (*end != '\0')
171                         param_act(P_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
172                 info->mode   = XT_CONNMARK_SET;
173                 info->ctmark = value;
174                 info->ctmask = mask;
175                 if (c == '-')
176                         info->ctmask |= value;
177                 *flags |= F_MARK;
178                 return true;
179
180         case '&': /* --and-mark */
181                 param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
182                 if (!strtonum(optarg, NULL, &mask, 0, ~0U))
183                         param_act(P_BAD_VALUE, "CONNMARK", "--and-mark", optarg);
184                 info->mode   = XT_CONNMARK_SET;
185                 info->ctmark = 0;
186                 info->ctmask = ~mask;
187                 *flags      |= F_MARK;
188                 return true;
189
190         case '|': /* --or-mark */
191                 param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
192                 if (!strtonum(optarg, NULL, &value, 0, ~0U))
193                         param_act(P_BAD_VALUE, "CONNMARK", "--or-mark", optarg);
194                 info->mode   = XT_CONNMARK_SET;
195                 info->ctmark = value;
196                 info->ctmask = value;
197                 *flags      |= F_MARK;
198                 return true;
199
200         case '^': /* --xor-mark */
201                 param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
202                 if (!strtonum(optarg, NULL, &value, 0, ~0U))
203                         param_act(P_BAD_VALUE, "CONNMARK", "--xor-mark", optarg);
204                 info->mode   = XT_CONNMARK_SET;
205                 info->ctmark = value;
206                 info->ctmask = 0;
207                 *flags      |= F_MARK;
208                 return true;
209
210         case 'S': /* --save-mark */
211                 param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
212                 info->mode = XT_CONNMARK_SAVE;
213                 *flags |= F_MARK | F_SR_MARK;
214                 return true;
215
216         case 'R': /* --restore-mark */
217                 param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
218                 info->mode = XT_CONNMARK_RESTORE;
219                 *flags |= F_MARK | F_SR_MARK;
220                 return true;
221
222         case 'n': /* --nfmask */
223                 if (!(*flags & F_SR_MARK))
224                         exit_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
225                                    "or --restore-mark is required for "
226                                    "--nfmask");
227                 if (!strtonum(optarg, NULL, &value, 0, ~0U))
228                         param_act(P_BAD_VALUE, "CONNMARK", "--nfmask", optarg);
229                 info->nfmask = value;
230                 return true;
231
232         case 'c': /* --ctmask */
233                 if (!(*flags & F_SR_MARK))
234                         exit_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
235                                    "or --restore-mark is required for "
236                                    "--ctmask");
237                 if (!strtonum(optarg, NULL, &value, 0, ~0U))
238                         param_act(P_BAD_VALUE, "CONNMARK", "--ctmask", optarg);
239                 info->ctmask = value;
240                 return true;
241
242         case 'm': /* --mask */
243                 if (!(*flags & F_SR_MARK))
244                         exit_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
245                                    "or --restore-mark is required for "
246                                    "--mask");
247                 if (!strtonum(optarg, NULL, &value, 0, ~0U))
248                         param_act(P_BAD_VALUE, "CONNMARK", "--mask", optarg);
249                 info->nfmask = info->ctmask = value;
250                 return true;
251         }
252
253         return false;
254 }
255
256 static void connmark_tg_check(unsigned int flags)
257 {
258         if (!flags)
259                 exit_error(PARAMETER_PROBLEM,
260                            "CONNMARK target: No operation specified");
261 }
262
263 static void
264 print_mark(unsigned long mark)
265 {
266         printf("0x%lx", mark);
267 }
268
269 static void
270 print_mask(const char *text, unsigned long mask)
271 {
272         if (mask != 0xffffffffUL)
273                 printf("%s0x%lx", text, mask);
274 }
275
276
277 /* Prints out the target info. */
278 static void CONNMARK_print(const void *ip,
279                            const struct xt_entry_target *target, int numeric)
280 {
281         const struct xt_connmark_target_info *markinfo =
282                 (const struct xt_connmark_target_info *)target->data;
283         switch (markinfo->mode) {
284         case XT_CONNMARK_SET:
285             printf("CONNMARK set ");
286             print_mark(markinfo->mark);
287             print_mask("/", markinfo->mask);
288             printf(" ");
289             break;
290         case XT_CONNMARK_SAVE:
291             printf("CONNMARK save ");
292             print_mask("mask ", markinfo->mask);
293             printf(" ");
294             break;
295         case XT_CONNMARK_RESTORE:
296             printf("CONNMARK restore ");
297             print_mask("mask ", markinfo->mask);
298             break;
299         default:
300             printf("ERROR: UNKNOWN CONNMARK MODE ");
301             break;
302         }
303 }
304
305 static void
306 connmark_tg_print(const void *ip, const struct xt_entry_target *target,
307                   int numeric)
308 {
309         const struct xt_connmark_tginfo1 *info = (const void *)target->data;
310
311         switch (info->mode) {
312         case XT_CONNMARK_SET:
313                 if (info->ctmark == 0)
314                         printf("CONNMARK and 0x%x ",
315                                (unsigned int)(u_int32_t)~info->ctmask);
316                 else if (info->ctmark == info->ctmask)
317                         printf("CONNMARK or 0x%x ", info->ctmark);
318                 else if (info->ctmask == 0)
319                         printf("CONNMARK xor 0x%x ", info->ctmark);
320                 else
321                         printf("CONNMARK xset 0x%x/0x%x ",
322                                info->ctmark, info->ctmask);
323                 break;
324         case XT_CONNMARK_SAVE:
325                 if (info->nfmask == ~0U && info->ctmask == ~0U)
326                         printf("CONNMARK save ");
327                 else if (info->nfmask == info->ctmask)
328                         printf("CONNMARK save mask 0x%x ", info->nfmask);
329                 else
330                         printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ",
331                                info->nfmask, info->ctmask);
332                 break;
333         case XT_CONNMARK_RESTORE:
334                 if (info->ctmask == ~0U && info->nfmask == ~0U)
335                         printf("CONNMARK restore ");
336                 else if (info->ctmask == info->nfmask)
337                         printf("CONNMARK restore mask 0x%x ", info->ctmask);
338                 else
339                         printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ",
340                                info->ctmask, info->nfmask);
341                 break;
342
343         default:
344                 printf("ERROR: UNKNOWN CONNMARK MODE");
345                 break;
346         }
347 }
348
349 /* Saves the target into in parsable form to stdout. */
350 static void CONNMARK_save(const void *ip, const struct xt_entry_target *target)
351 {
352         const struct xt_connmark_target_info *markinfo =
353                 (const struct xt_connmark_target_info *)target->data;
354
355         switch (markinfo->mode) {
356         case XT_CONNMARK_SET:
357             printf("--set-mark ");
358             print_mark(markinfo->mark);
359             print_mask("/", markinfo->mask);
360             printf(" ");
361             break;
362         case XT_CONNMARK_SAVE:
363             printf("--save-mark ");
364             print_mask("--mask ", markinfo->mask);
365             break;
366         case XT_CONNMARK_RESTORE:
367             printf("--restore-mark ");
368             print_mask("--mask ", markinfo->mask);
369             break;
370         default:
371             printf("ERROR: UNKNOWN CONNMARK MODE ");
372             break;
373         }
374 }
375
376 static void CONNMARK_init(struct xt_entry_target *t)
377 {
378         struct xt_connmark_target_info *markinfo
379                 = (struct xt_connmark_target_info *)t->data;
380
381         markinfo->mask = 0xffffffffUL;
382 }
383
384 static void
385 connmark_tg_save(const void *ip, const struct xt_entry_target *target)
386 {
387         const struct xt_connmark_tginfo1 *info = (const void *)target->data;
388
389         switch (info->mode) {
390         case XT_CONNMARK_SET:
391                 printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask);
392                 break;
393         case XT_CONNMARK_SAVE:
394                 printf("--save-mark --nfmask 0x%x --ctmask 0x%x ",
395                        info->nfmask, info->ctmask);
396                 break;
397         case XT_CONNMARK_RESTORE:
398                 printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ",
399                        info->nfmask, info->ctmask);
400                 break;
401         default:
402                 printf("ERROR: UNKNOWN CONNMARK MODE");
403                 break;
404         }
405 }
406
407 static struct xtables_target connmark_target = {
408         .family         = AF_INET,
409         .name           = "CONNMARK",
410         .revision       = 0,
411         .version        = XTABLES_VERSION,
412         .size           = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
413         .userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
414         .help           = CONNMARK_help,
415         .init           = CONNMARK_init,
416         .parse          = CONNMARK_parse,
417         .final_check    = connmark_tg_check,
418         .print          = CONNMARK_print,
419         .save           = CONNMARK_save,
420         .extra_opts     = CONNMARK_opts,
421 };
422
423 static struct xtables_target connmark_target6 = {
424         .family         = AF_INET6,
425         .name           = "CONNMARK",
426         .revision       = 0,
427         .version        = XTABLES_VERSION,
428         .size           = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
429         .userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
430         .help           = CONNMARK_help,
431         .init           = CONNMARK_init,
432         .parse          = CONNMARK_parse,
433         .final_check    = connmark_tg_check,
434         .print          = CONNMARK_print,
435         .save           = CONNMARK_save,
436         .extra_opts     = CONNMARK_opts,
437 };
438
439 static struct xtables_target connmark_tg_reg = {
440         .version        = XTABLES_VERSION,
441         .name           = "CONNMARK",
442         .revision       = 1,
443         .family         = AF_INET,
444         .size           = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
445         .userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
446         .help           = connmark_tg_help,
447         .init           = connmark_tg_init,
448         .parse          = connmark_tg_parse,
449         .final_check    = connmark_tg_check,
450         .print          = connmark_tg_print,
451         .save           = connmark_tg_save,
452         .extra_opts     = connmark_tg_opts,
453 };
454
455 static struct xtables_target connmark_tg6_reg = {
456         .version        = XTABLES_VERSION,
457         .name           = "CONNMARK",
458         .revision       = 1,
459         .family         = AF_INET6,
460         .size           = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
461         .userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
462         .help           = connmark_tg_help,
463         .init           = connmark_tg_init,
464         .parse          = connmark_tg_parse,
465         .final_check    = connmark_tg_check,
466         .print          = connmark_tg_print,
467         .save           = connmark_tg_save,
468         .extra_opts     = connmark_tg_opts,
469 };
470
471 void _init(void)
472 {
473         xtables_register_target(&connmark_target);
474         xtables_register_target(&connmark_target6);
475         xtables_register_target(&connmark_tg_reg);
476         xtables_register_target(&connmark_tg6_reg);
477 }