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