Fork for IVI and add .changes file
[profile/ivi/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 struct xt_connmark_target_info {
32         unsigned long mark;
33         unsigned long mask;
34         u_int8_t mode;
35 };
36
37 enum {
38         F_MARK    = 1 << 0,
39         F_SR_MARK = 1 << 1,
40 };
41
42 static void CONNMARK_help(void)
43 {
44         printf(
45 "CONNMARK target options:\n"
46 "  --set-mark value[/mask]       Set conntrack mark value\n"
47 "  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
48 "  --restore-mark [--mask mask]  Restore saved nfmark value\n");
49 }
50
51 static const struct option CONNMARK_opts[] = {
52         { "set-mark", 1, NULL, '1' },
53         { "save-mark", 0, NULL, '2' },
54         { "restore-mark", 0, NULL, '3' },
55         { "mask", 1, NULL, '4' },
56         { .name = NULL }
57 };
58
59 static const struct option connmark_tg_opts[] = {
60         {.name = "set-xmark",     .has_arg = true,  .val = '='},
61         {.name = "set-mark",      .has_arg = true,  .val = '-'},
62         {.name = "and-mark",      .has_arg = true,  .val = '&'},
63         {.name = "or-mark",       .has_arg = true,  .val = '|'},
64         {.name = "xor-mark",      .has_arg = true,  .val = '^'},
65         {.name = "save-mark",     .has_arg = false, .val = 'S'},
66         {.name = "restore-mark",  .has_arg = false, .val = 'R'},
67         {.name = "ctmask",        .has_arg = true,  .val = 'c'},
68         {.name = "nfmask",        .has_arg = true,  .val = 'n'},
69         {.name = "mask",          .has_arg = true,  .val = 'm'},
70         {.name = NULL},
71 };
72
73 static void connmark_tg_help(void)
74 {
75         printf(
76 "CONNMARK target options:\n"
77 "  --set-xmark value[/ctmask]    Zero mask bits and XOR ctmark with value\n"
78 "  --save-mark [--ctmask mask] [--nfmask mask]\n"
79 "                                Copy ctmark to nfmark using masks\n"
80 "  --restore-mark [--ctmask mask] [--nfmask mask]\n"
81 "                                Copy nfmark to ctmark using masks\n"
82 "  --set-mark value[/mask]       Set conntrack mark value\n"
83 "  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
84 "  --restore-mark [--mask mask]  Restore saved nfmark value\n"
85 "  --and-mark value              Binary AND the ctmark with bits\n"
86 "  --or-mark value               Binary OR  the ctmark with bits\n"
87 "  --xor-mark value              Binary XOR the ctmark with bits\n"
88 );
89 }
90
91 static void connmark_tg_init(struct xt_entry_target *target)
92 {
93         struct xt_connmark_tginfo1 *info = (void *)target->data;
94
95         /*
96          * Need these defaults for --save-mark/--restore-mark if no
97          * --ctmark or --nfmask is given.
98          */
99         info->ctmask = UINT32_MAX;
100         info->nfmask = UINT32_MAX;
101 }
102
103 static int
104 CONNMARK_parse(int c, char **argv, int invert, unsigned int *flags,
105                const void *entry, struct xt_entry_target **target)
106 {
107         struct xt_connmark_target_info *markinfo
108                 = (struct xt_connmark_target_info *)(*target)->data;
109
110         switch (c) {
111                 char *end;
112         case '1':
113                 markinfo->mode = XT_CONNMARK_SET;
114
115                 markinfo->mark = strtoul(optarg, &end, 0);
116                 if (*end == '/' && end[1] != '\0')
117                     markinfo->mask = strtoul(end+1, &end, 0);
118
119                 if (*end != '\0' || end == optarg)
120                         xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
121                 if (*flags)
122                         xtables_error(PARAMETER_PROBLEM,
123                                    "CONNMARK target: Can't specify --set-mark twice");
124                 *flags = 1;
125                 break;
126         case '2':
127                 markinfo->mode = XT_CONNMARK_SAVE;
128                 if (*flags)
129                         xtables_error(PARAMETER_PROBLEM,
130                                    "CONNMARK target: Can't specify --save-mark twice");
131                 *flags = 1;
132                 break;
133         case '3':
134                 markinfo->mode = XT_CONNMARK_RESTORE;
135                 if (*flags)
136                         xtables_error(PARAMETER_PROBLEM,
137                                    "CONNMARK target: Can't specify --restore-mark twice");
138                 *flags = 1;
139                 break;
140         case '4':
141                 if (!*flags)
142                         xtables_error(PARAMETER_PROBLEM,
143                                    "CONNMARK target: Can't specify --mask without a operation");
144                 markinfo->mask = strtoul(optarg, &end, 0);
145
146                 if (*end != '\0' || end == optarg)
147                         xtables_error(PARAMETER_PROBLEM, "Bad MASK value \"%s\"", optarg);
148                 break;
149         default:
150                 return 0;
151         }
152
153         return 1;
154 }
155
156 static int connmark_tg_parse(int c, char **argv, int invert,
157                              unsigned int *flags, const void *entry,
158                              struct xt_entry_target **target)
159 {
160         struct xt_connmark_tginfo1 *info = (void *)(*target)->data;
161         unsigned int value, mask = UINT32_MAX;
162         char *end;
163
164         switch (c) {
165         case '=': /* --set-xmark */
166         case '-': /* --set-mark */
167                 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
168                 if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX))
169                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
170                 if (*end == '/')
171                         if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
172                                 xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
173                 if (*end != '\0')
174                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
175                 info->mode   = XT_CONNMARK_SET;
176                 info->ctmark = value;
177                 info->ctmask = mask;
178                 if (c == '-')
179                         info->ctmask |= value;
180                 *flags |= F_MARK;
181                 return true;
182
183         case '&': /* --and-mark */
184                 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
185                 if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX))
186                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--and-mark", optarg);
187                 info->mode   = XT_CONNMARK_SET;
188                 info->ctmark = 0;
189                 info->ctmask = ~mask;
190                 *flags      |= F_MARK;
191                 return true;
192
193         case '|': /* --or-mark */
194                 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
195                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
196                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--or-mark", optarg);
197                 info->mode   = XT_CONNMARK_SET;
198                 info->ctmark = value;
199                 info->ctmask = value;
200                 *flags      |= F_MARK;
201                 return true;
202
203         case '^': /* --xor-mark */
204                 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
205                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
206                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--xor-mark", optarg);
207                 info->mode   = XT_CONNMARK_SET;
208                 info->ctmark = value;
209                 info->ctmask = 0;
210                 *flags      |= F_MARK;
211                 return true;
212
213         case 'S': /* --save-mark */
214                 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
215                 info->mode = XT_CONNMARK_SAVE;
216                 *flags |= F_MARK | F_SR_MARK;
217                 return true;
218
219         case 'R': /* --restore-mark */
220                 xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
221                 info->mode = XT_CONNMARK_RESTORE;
222                 *flags |= F_MARK | F_SR_MARK;
223                 return true;
224
225         case 'n': /* --nfmask */
226                 if (!(*flags & F_SR_MARK))
227                         xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
228                                    "or --restore-mark is required for "
229                                    "--nfmask");
230                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
231                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--nfmask", optarg);
232                 info->nfmask = value;
233                 return true;
234
235         case 'c': /* --ctmask */
236                 if (!(*flags & F_SR_MARK))
237                         xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
238                                    "or --restore-mark is required for "
239                                    "--ctmask");
240                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
241                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--ctmask", optarg);
242                 info->ctmask = value;
243                 return true;
244
245         case 'm': /* --mask */
246                 if (!(*flags & F_SR_MARK))
247                         xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
248                                    "or --restore-mark is required for "
249                                    "--mask");
250                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
251                         xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--mask", optarg);
252                 info->nfmask = info->ctmask = value;
253                 return true;
254         }
255
256         return false;
257 }
258
259 static void connmark_tg_check(unsigned int flags)
260 {
261         if (!flags)
262                 xtables_error(PARAMETER_PROBLEM,
263                            "CONNMARK target: No operation specified");
264 }
265
266 static void
267 print_mark(unsigned long mark)
268 {
269         printf("0x%lx", mark);
270 }
271
272 static void
273 print_mask(const char *text, unsigned long mask)
274 {
275         if (mask != 0xffffffffUL)
276                 printf("%s0x%lx", text, mask);
277 }
278
279 static void CONNMARK_print(const void *ip,
280                            const struct xt_entry_target *target, int numeric)
281 {
282         const struct xt_connmark_target_info *markinfo =
283                 (const struct xt_connmark_target_info *)target->data;
284         switch (markinfo->mode) {
285         case XT_CONNMARK_SET:
286             printf("CONNMARK set ");
287             print_mark(markinfo->mark);
288             print_mask("/", markinfo->mask);
289             printf(" ");
290             break;
291         case XT_CONNMARK_SAVE:
292             printf("CONNMARK save ");
293             print_mask("mask ", markinfo->mask);
294             printf(" ");
295             break;
296         case XT_CONNMARK_RESTORE:
297             printf("CONNMARK restore ");
298             print_mask("mask ", markinfo->mask);
299             break;
300         default:
301             printf("ERROR: UNKNOWN CONNMARK MODE ");
302             break;
303         }
304 }
305
306 static void
307 connmark_tg_print(const void *ip, const struct xt_entry_target *target,
308                   int numeric)
309 {
310         const struct xt_connmark_tginfo1 *info = (const void *)target->data;
311
312         switch (info->mode) {
313         case XT_CONNMARK_SET:
314                 if (info->ctmark == 0)
315                         printf("CONNMARK and 0x%x ",
316                                (unsigned int)(u_int32_t)~info->ctmask);
317                 else if (info->ctmark == info->ctmask)
318                         printf("CONNMARK or 0x%x ", info->ctmark);
319                 else if (info->ctmask == 0)
320                         printf("CONNMARK xor 0x%x ", info->ctmark);
321                 else if (info->ctmask == 0xFFFFFFFFU)
322                         printf("CONNMARK set 0x%x ", info->ctmark);
323                 else
324                         printf("CONNMARK xset 0x%x/0x%x ",
325                                info->ctmark, info->ctmask);
326                 break;
327         case XT_CONNMARK_SAVE:
328                 if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)
329                         printf("CONNMARK save ");
330                 else if (info->nfmask == info->ctmask)
331                         printf("CONNMARK save mask 0x%x ", info->nfmask);
332                 else
333                         printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ",
334                                info->nfmask, info->ctmask);
335                 break;
336         case XT_CONNMARK_RESTORE:
337                 if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX)
338                         printf("CONNMARK restore ");
339                 else if (info->ctmask == info->nfmask)
340                         printf("CONNMARK restore mask 0x%x ", info->ctmask);
341                 else
342                         printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ",
343                                info->ctmask, info->nfmask);
344                 break;
345
346         default:
347                 printf("ERROR: UNKNOWN CONNMARK MODE");
348                 break;
349         }
350 }
351
352 static void CONNMARK_save(const void *ip, const struct xt_entry_target *target)
353 {
354         const struct xt_connmark_target_info *markinfo =
355                 (const struct xt_connmark_target_info *)target->data;
356
357         switch (markinfo->mode) {
358         case XT_CONNMARK_SET:
359             printf("--set-mark ");
360             print_mark(markinfo->mark);
361             print_mask("/", markinfo->mask);
362             printf(" ");
363             break;
364         case XT_CONNMARK_SAVE:
365             printf("--save-mark ");
366             print_mask("--mask ", markinfo->mask);
367             break;
368         case XT_CONNMARK_RESTORE:
369             printf("--restore-mark ");
370             print_mask("--mask ", markinfo->mask);
371             break;
372         default:
373             printf("ERROR: UNKNOWN CONNMARK MODE ");
374             break;
375         }
376 }
377
378 static void CONNMARK_init(struct xt_entry_target *t)
379 {
380         struct xt_connmark_target_info *markinfo
381                 = (struct xt_connmark_target_info *)t->data;
382
383         markinfo->mask = 0xffffffffUL;
384 }
385
386 static void
387 connmark_tg_save(const void *ip, const struct xt_entry_target *target)
388 {
389         const struct xt_connmark_tginfo1 *info = (const void *)target->data;
390
391         switch (info->mode) {
392         case XT_CONNMARK_SET:
393                 printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask);
394                 break;
395         case XT_CONNMARK_SAVE:
396                 printf("--save-mark --nfmask 0x%x --ctmask 0x%x ",
397                        info->nfmask, info->ctmask);
398                 break;
399         case XT_CONNMARK_RESTORE:
400                 printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ",
401                        info->nfmask, info->ctmask);
402                 break;
403         default:
404                 printf("ERROR: UNKNOWN CONNMARK MODE");
405                 break;
406         }
407 }
408
409 static struct xtables_target connmark_tg_reg[] = {
410         {
411                 .family        = NFPROTO_UNSPEC,
412                 .name          = "CONNMARK",
413                 .revision      = 0,
414                 .version       = XTABLES_VERSION,
415                 .size          = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
416                 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
417                 .help          = CONNMARK_help,
418                 .init          = CONNMARK_init,
419                 .parse         = CONNMARK_parse,
420                 .final_check   = connmark_tg_check,
421                 .print         = CONNMARK_print,
422                 .save          = CONNMARK_save,
423                 .extra_opts    = CONNMARK_opts,
424         },
425         {
426                 .version       = XTABLES_VERSION,
427                 .name          = "CONNMARK",
428                 .revision      = 1,
429                 .family        = NFPROTO_UNSPEC,
430                 .size          = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
431                 .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
432                 .help          = connmark_tg_help,
433                 .init          = connmark_tg_init,
434                 .parse         = connmark_tg_parse,
435                 .final_check   = connmark_tg_check,
436                 .print         = connmark_tg_print,
437                 .save          = connmark_tg_save,
438                 .extra_opts    = connmark_tg_opts,
439         },
440 };
441
442 void _init(void)
443 {
444         xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
445 }