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