Fork for IVI and add .changes file
[profile/ivi/iptables.git] / extensions / libxt_MARK.c
1 /* Shared library add-on to iptables to add MARK target support. */
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <getopt.h>
7
8 #include <xtables.h>
9 #include <linux/netfilter/x_tables.h>
10 #include <linux/netfilter/xt_MARK.h>
11
12 /* Version 0 */
13 struct xt_mark_target_info {
14         unsigned long mark;
15 };
16
17 /* Version 1 */
18 enum {
19         XT_MARK_SET=0,
20         XT_MARK_AND,
21         XT_MARK_OR,
22 };
23
24 struct xt_mark_target_info_v1 {
25         unsigned long mark;
26         u_int8_t mode;
27 };
28
29 enum {
30         F_MARK = 1 << 0,
31 };
32
33 static void MARK_help(void)
34 {
35         printf(
36 "MARK target options:\n"
37 "  --set-mark value                   Set nfmark value\n"
38 "  --and-mark value                   Binary AND the nfmark with value\n"
39 "  --or-mark  value                   Binary OR  the nfmark with value\n");
40 }
41
42 static const struct option MARK_opts[] = {
43         { "set-mark", 1, NULL, '1' },
44         { "and-mark", 1, NULL, '2' },
45         { "or-mark", 1, NULL, '3' },
46         { .name = NULL }
47 };
48
49 static const struct option mark_tg_opts[] = {
50         {.name = "set-xmark", .has_arg = true, .val = 'X'},
51         {.name = "set-mark",  .has_arg = true, .val = '='},
52         {.name = "and-mark",  .has_arg = true, .val = '&'},
53         {.name = "or-mark",   .has_arg = true, .val = '|'},
54         {.name = "xor-mark",  .has_arg = true, .val = '^'},
55         { .name = NULL }
56 };
57
58 static void mark_tg_help(void)
59 {
60         printf(
61 "MARK target options:\n"
62 "  --set-xmark value[/mask]  Clear bits in mask and XOR value into nfmark\n"
63 "  --set-mark value[/mask]   Clear bits in mask and OR value into nfmark\n"
64 "  --and-mark bits           Binary AND the nfmark with bits\n"
65 "  --or-mark bits            Binary OR the nfmark with bits\n"
66 "  --xor-mask bits           Binary XOR the nfmark with bits\n"
67 "\n");
68 }
69
70 /* Function which parses command options; returns true if it
71    ate an option */
72 static int
73 MARK_parse_v0(int c, char **argv, int invert, unsigned int *flags,
74               const void *entry, struct xt_entry_target **target)
75 {
76         struct xt_mark_target_info *markinfo
77                 = (struct xt_mark_target_info *)(*target)->data;
78         unsigned int mark = 0;
79
80         switch (c) {
81         case '1':
82                 if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX))
83                         xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
84                 markinfo->mark = mark;
85                 if (*flags)
86                         xtables_error(PARAMETER_PROBLEM,
87                                    "MARK target: Can't specify --set-mark twice");
88                 *flags = 1;
89                 break;
90         case '2':
91                 xtables_error(PARAMETER_PROBLEM,
92                            "MARK target: kernel too old for --and-mark");
93         case '3':
94                 xtables_error(PARAMETER_PROBLEM,
95                            "MARK target: kernel too old for --or-mark");
96         default:
97                 return 0;
98         }
99
100         return 1;
101 }
102
103 static void MARK_check(unsigned int flags)
104 {
105         if (!flags)
106                 xtables_error(PARAMETER_PROBLEM,
107                            "MARK target: Parameter --set/and/or-mark"
108                            " is required");
109 }
110
111 static int
112 MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags,
113               const void *entry, struct xt_entry_target **target)
114 {
115         struct xt_mark_target_info_v1 *markinfo
116                 = (struct xt_mark_target_info_v1 *)(*target)->data;
117         unsigned int mark = 0;
118
119         switch (c) {
120         case '1':
121                 markinfo->mode = XT_MARK_SET;
122                 break;
123         case '2':
124                 markinfo->mode = XT_MARK_AND;
125                 break;
126         case '3':
127                 markinfo->mode = XT_MARK_OR;
128                 break;
129         default:
130                 return 0;
131         }
132
133         if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX))
134                 xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
135         markinfo->mark = mark;
136         if (*flags)
137                 xtables_error(PARAMETER_PROBLEM,
138                            "MARK target: Can't specify --set-mark twice");
139
140         *flags = 1;
141         return 1;
142 }
143
144 static int mark_tg_parse(int c, char **argv, int invert, unsigned int *flags,
145                          const void *entry, struct xt_entry_target **target)
146 {
147         struct xt_mark_tginfo2 *info = (void *)(*target)->data;
148         unsigned int value, mask = UINT32_MAX;
149         char *end;
150
151         switch (c) {
152         case 'X': /* --set-xmark */
153         case '=': /* --set-mark */
154                 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
155                 xtables_param_act(XTF_NO_INVERT, "MARK", "--set-xmark/--set-mark", invert);
156                 if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX))
157                         xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg);
158                 if (*end == '/')
159                         if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
160                                 xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg);
161                 if (*end != '\0')
162                         xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg);
163                 info->mark = value;
164                 info->mask = mask;
165
166                 if (c == '=')
167                         info->mask = value | mask;
168                 break;
169
170         case '&': /* --and-mark */
171                 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
172                 xtables_param_act(XTF_NO_INVERT, "MARK", "--and-mark", invert);
173                 if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX))
174                         xtables_param_act(XTF_BAD_VALUE, "MARK", "--and-mark", optarg);
175                 info->mark = 0;
176                 info->mask = ~mask;
177                 break;
178
179         case '|': /* --or-mark */
180                 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
181                 xtables_param_act(XTF_NO_INVERT, "MARK", "--or-mark", invert);
182                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
183                         xtables_param_act(XTF_BAD_VALUE, "MARK", "--or-mark", optarg);
184                 info->mark = value;
185                 info->mask = value;
186                 break;
187
188         case '^': /* --xor-mark */
189                 xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK);
190                 xtables_param_act(XTF_NO_INVERT, "MARK", "--xor-mark", invert);
191                 if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
192                         xtables_param_act(XTF_BAD_VALUE, "MARK", "--xor-mark", optarg);
193                 info->mark = value;
194                 info->mask = 0;
195                 break;
196
197         default:
198                 return false;
199         }
200
201         *flags |= F_MARK;
202         return true;
203 }
204
205 static void mark_tg_check(unsigned int flags)
206 {
207         if (flags == 0)
208                 xtables_error(PARAMETER_PROBLEM, "MARK: One of the --set-xmark, "
209                            "--{and,or,xor,set}-mark options is required");
210 }
211
212 static void
213 print_mark(unsigned long mark)
214 {
215         printf("0x%lx ", mark);
216 }
217
218 static void MARK_print_v0(const void *ip,
219                           const struct xt_entry_target *target, int numeric)
220 {
221         const struct xt_mark_target_info *markinfo =
222                 (const struct xt_mark_target_info *)target->data;
223         printf("MARK set ");
224         print_mark(markinfo->mark);
225 }
226
227 static void MARK_save_v0(const void *ip, const struct xt_entry_target *target)
228 {
229         const struct xt_mark_target_info *markinfo =
230                 (const struct xt_mark_target_info *)target->data;
231
232         printf("--set-mark ");
233         print_mark(markinfo->mark);
234 }
235
236 static void MARK_print_v1(const void *ip, const struct xt_entry_target *target,
237                           int numeric)
238 {
239         const struct xt_mark_target_info_v1 *markinfo =
240                 (const struct xt_mark_target_info_v1 *)target->data;
241
242         switch (markinfo->mode) {
243         case XT_MARK_SET:
244                 printf("MARK set ");
245                 break;
246         case XT_MARK_AND:
247                 printf("MARK and ");
248                 break;
249         case XT_MARK_OR: 
250                 printf("MARK or ");
251                 break;
252         }
253         print_mark(markinfo->mark);
254 }
255
256 static void mark_tg_print(const void *ip, const struct xt_entry_target *target,
257                           int numeric)
258 {
259         const struct xt_mark_tginfo2 *info = (const void *)target->data;
260
261         if (info->mark == 0)
262                 printf("MARK and 0x%x ", (unsigned int)(u_int32_t)~info->mask);
263         else if (info->mark == info->mask)
264                 printf("MARK or 0x%x ", info->mark);
265         else if (info->mask == 0)
266                 printf("MARK xor 0x%x ", info->mark);
267         else if (info->mask == 0xffffffffU)
268                 printf("MARK set 0x%x ", info->mark);
269         else
270                 printf("MARK xset 0x%x/0x%x ", info->mark, info->mask);
271 }
272
273 static void MARK_save_v1(const void *ip, const struct xt_entry_target *target)
274 {
275         const struct xt_mark_target_info_v1 *markinfo =
276                 (const struct xt_mark_target_info_v1 *)target->data;
277
278         switch (markinfo->mode) {
279         case XT_MARK_SET:
280                 printf("--set-mark ");
281                 break;
282         case XT_MARK_AND:
283                 printf("--and-mark ");
284                 break;
285         case XT_MARK_OR: 
286                 printf("--or-mark ");
287                 break;
288         }
289         print_mark(markinfo->mark);
290 }
291
292 static void mark_tg_save(const void *ip, const struct xt_entry_target *target)
293 {
294         const struct xt_mark_tginfo2 *info = (const void *)target->data;
295
296         printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask);
297 }
298
299 static struct xtables_target mark_tg_reg[] = {
300         {
301                 .family        = NFPROTO_UNSPEC,
302                 .name          = "MARK",
303                 .version       = XTABLES_VERSION,
304                 .revision      = 0,
305                 .size          = XT_ALIGN(sizeof(struct xt_mark_target_info)),
306                 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
307                 .help          = MARK_help,
308                 .parse         = MARK_parse_v0,
309                 .final_check   = MARK_check,
310                 .print         = MARK_print_v0,
311                 .save          = MARK_save_v0,
312                 .extra_opts    = MARK_opts,
313         },
314         {
315                 .family        = NFPROTO_IPV4,
316                 .name          = "MARK",
317                 .version       = XTABLES_VERSION,
318                 .revision      = 1,
319                 .size          = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
320                 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
321                 .help          = MARK_help,
322                 .parse         = MARK_parse_v1,
323                 .final_check   = MARK_check,
324                 .print         = MARK_print_v1,
325                 .save          = MARK_save_v1,
326                 .extra_opts    = MARK_opts,
327         },
328         {
329                 .version       = XTABLES_VERSION,
330                 .name          = "MARK",
331                 .revision      = 2,
332                 .family        = NFPROTO_UNSPEC,
333                 .size          = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
334                 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
335                 .help          = mark_tg_help,
336                 .parse         = mark_tg_parse,
337                 .final_check   = mark_tg_check,
338                 .print         = mark_tg_print,
339                 .save          = mark_tg_save,
340                 .extra_opts    = mark_tg_opts,
341         },
342 };
343
344 void _init(void)
345 {
346         xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
347 }