1 #include <getopt.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <xtables.h>
5 #include <linux/netfilter/xt_MARK.h>
6
7 /* Version 0 */
8 struct xt_mark_target_info {
9 unsigned long mark;
10 };
11
12 /* Version 1 */
13 enum {
14 XT_MARK_SET=0,
15 XT_MARK_AND,
16 XT_MARK_OR,
17 };
18
19 struct xt_mark_target_info_v1 {
20 unsigned long mark;
21 uint8_t mode;
22 };
23
24 enum {
25 O_SET_MARK = 0,
26 O_AND_MARK,
27 O_OR_MARK,
28 O_XOR_MARK,
29 O_SET_XMARK,
30 F_SET_MARK = 1 << O_SET_MARK,
31 F_AND_MARK = 1 << O_AND_MARK,
32 F_OR_MARK = 1 << O_OR_MARK,
33 F_XOR_MARK = 1 << O_XOR_MARK,
34 F_SET_XMARK = 1 << O_SET_XMARK,
35 F_ANY = F_SET_MARK | F_AND_MARK | F_OR_MARK |
36 F_XOR_MARK | F_SET_XMARK,
37 };
38
MARK_help(void)39 static void MARK_help(void)
40 {
41 printf(
42 "MARK target options:\n"
43 " --set-mark value Set nfmark value\n"
44 " --and-mark value Binary AND the nfmark with value\n"
45 " --or-mark value Binary OR the nfmark with value\n");
46 }
47
48 static const struct xt_option_entry MARK_opts[] = {
49 {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_UINT32,
50 .excl = F_ANY},
51 {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32,
52 .excl = F_ANY},
53 {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32,
54 .excl = F_ANY},
55 XTOPT_TABLEEND,
56 };
57
58 static const struct xt_option_entry mark_tg_opts[] = {
59 {.name = "set-xmark", .id = O_SET_XMARK, .type = XTTYPE_MARKMASK32,
60 .excl = F_ANY},
61 {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32,
62 .excl = F_ANY},
63 {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32,
64 .excl = F_ANY},
65 {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32,
66 .excl = F_ANY},
67 {.name = "xor-mark", .id = O_XOR_MARK, .type = XTTYPE_UINT32,
68 .excl = F_ANY},
69 XTOPT_TABLEEND,
70 };
71
mark_tg_help(void)72 static void mark_tg_help(void)
73 {
74 printf(
75 "MARK target options:\n"
76 " --set-xmark value[/mask] Clear bits in mask and XOR value into nfmark\n"
77 " --set-mark value[/mask] Clear bits in mask and OR value into nfmark\n"
78 " --and-mark bits Binary AND the nfmark with bits\n"
79 " --or-mark bits Binary OR the nfmark with bits\n"
80 " --xor-mark bits Binary XOR the nfmark with bits\n");
81 }
82
MARK_parse_v0(struct xt_option_call * cb)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
MARK_check(struct xt_fcheck_call * cb)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
MARK_parse_v1(struct xt_option_call * cb)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
mark_tg_parse(struct xt_option_call * cb)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
mark_tg_check(struct xt_fcheck_call * cb)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
print_mark(unsigned long mark)162 print_mark(unsigned long mark)
163 {
164 printf(" 0x%lx", mark);
165 }
166
MARK_print_v0(const void * ip,const struct xt_entry_target * target,int numeric)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
MARK_save_v0(const void * ip,const struct xt_entry_target * target)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
MARK_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)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
mark_tg_print(const void * ip,const struct xt_entry_target * target,int numeric)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
MARK_save_v1(const void * ip,const struct xt_entry_target * target)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
mark_tg_save(const void * ip,const struct xt_entry_target * target)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
mark_tg_arp_save(const void * ip,const struct xt_entry_target * target)248 static void mark_tg_arp_save(const void *ip, const struct xt_entry_target *target)
249 {
250 const struct xt_mark_tginfo2 *info = (const void *)target->data;
251
252 if (info->mark == 0)
253 printf(" --and-mark %x", (unsigned int)(uint32_t)~info->mask);
254 else if (info->mark == info->mask)
255 printf(" --or-mark %x", info->mark);
256 else
257 printf(" --set-mark %x", info->mark);
258 }
259
mark_tg_arp_print(const void * ip,const struct xt_entry_target * target,int numeric)260 static void mark_tg_arp_print(const void *ip,
261 const struct xt_entry_target *target, int numeric)
262 {
263 mark_tg_arp_save(ip, target);
264 }
265
266 #define MARK_OPT 1
267 #define AND_MARK_OPT 2
268 #define OR_MARK_OPT 3
269
270 static struct option mark_tg_arp_opts[] = {
271 { .name = "set-mark", .has_arg = required_argument, .flag = 0, .val = MARK_OPT },
272 { .name = "and-mark", .has_arg = required_argument, .flag = 0, .val = AND_MARK_OPT },
273 { .name = "or-mark", .has_arg = required_argument, .flag = 0, .val = OR_MARK_OPT },
274 { .name = NULL}
275 };
276
277 static int
mark_tg_arp_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)278 mark_tg_arp_parse(int c, char **argv, int invert, unsigned int *flags,
279 const void *entry, struct xt_entry_target **target)
280 {
281 struct xt_mark_tginfo2 *info =
282 (struct xt_mark_tginfo2 *)(*target)->data;
283 int i;
284
285 switch (c) {
286 case MARK_OPT:
287 if (sscanf(argv[optind-1], "%x", &i) != 1) {
288 xtables_error(PARAMETER_PROBLEM,
289 "Bad mark value `%s'", optarg);
290 return 0;
291 }
292 info->mark = i;
293 if (*flags)
294 xtables_error(PARAMETER_PROBLEM,
295 "MARK: Can't specify --set-mark twice");
296 *flags = 1;
297 break;
298 case AND_MARK_OPT:
299 if (sscanf(argv[optind-1], "%x", &i) != 1) {
300 xtables_error(PARAMETER_PROBLEM,
301 "Bad mark value `%s'", optarg);
302 return 0;
303 }
304 info->mark = 0;
305 info->mask = ~i;
306 if (*flags)
307 xtables_error(PARAMETER_PROBLEM,
308 "MARK: Can't specify --and-mark twice");
309 *flags = 1;
310 break;
311 case OR_MARK_OPT:
312 if (sscanf(argv[optind-1], "%x", &i) != 1) {
313 xtables_error(PARAMETER_PROBLEM,
314 "Bad mark value `%s'", optarg);
315 return 0;
316 }
317 info->mark = info->mask = i;
318 if (*flags)
319 xtables_error(PARAMETER_PROBLEM,
320 "MARK: Can't specify --or-mark twice");
321 *flags = 1;
322 break;
323 default:
324 return 0;
325 }
326 return 1;
327 }
328
mark_tg_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)329 static int mark_tg_xlate(struct xt_xlate *xl,
330 const struct xt_xlate_tg_params *params)
331 {
332 const struct xt_mark_tginfo2 *info = (const void *)params->target->data;
333
334 xt_xlate_add(xl, "meta mark set ");
335
336 if (info->mask == 0xffffffffU)
337 xt_xlate_add(xl, "0x%x ", info->mark);
338 else if (info->mark == 0)
339 xt_xlate_add(xl, "mark and 0x%x ", ~info->mask);
340 else if (info->mark == info->mask)
341 xt_xlate_add(xl, "mark or 0x%x ", info->mark);
342 else if (info->mask == 0)
343 xt_xlate_add(xl, "mark xor 0x%x ", info->mark);
344 else
345 xt_xlate_add(xl, "mark and 0x%x xor 0x%x ", ~info->mask,
346 info->mark);
347
348 return 1;
349 }
350
MARK_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)351 static int MARK_xlate(struct xt_xlate *xl,
352 const struct xt_xlate_tg_params *params)
353 {
354 const struct xt_mark_target_info_v1 *markinfo =
355 (const struct xt_mark_target_info_v1 *)params->target->data;
356
357 xt_xlate_add(xl, "meta mark set ");
358
359 switch(markinfo->mode) {
360 case XT_MARK_SET:
361 xt_xlate_add(xl, "0x%x ", (uint32_t)markinfo->mark);
362 break;
363 case XT_MARK_AND:
364 xt_xlate_add(xl, "mark and 0x%x ", (uint32_t)markinfo->mark);
365 break;
366 case XT_MARK_OR:
367 xt_xlate_add(xl, "mark or 0x%x ", (uint32_t)markinfo->mark);
368 break;
369 default:
370 return 0;
371 }
372
373 return 1;
374 }
375
376 static struct xtables_target mark_tg_reg[] = {
377 {
378 .family = NFPROTO_UNSPEC,
379 .name = "MARK",
380 .version = XTABLES_VERSION,
381 .revision = 0,
382 .size = XT_ALIGN(sizeof(struct xt_mark_target_info)),
383 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
384 .help = MARK_help,
385 .print = MARK_print_v0,
386 .save = MARK_save_v0,
387 .x6_parse = MARK_parse_v0,
388 .x6_fcheck = MARK_check,
389 .x6_options = MARK_opts,
390 },
391 {
392 .family = NFPROTO_IPV4,
393 .name = "MARK",
394 .version = XTABLES_VERSION,
395 .revision = 1,
396 .size = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
397 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
398 .help = MARK_help,
399 .print = MARK_print_v1,
400 .save = MARK_save_v1,
401 .x6_parse = MARK_parse_v1,
402 .x6_fcheck = MARK_check,
403 .x6_options = MARK_opts,
404 .xlate = MARK_xlate,
405 },
406 {
407 .version = XTABLES_VERSION,
408 .name = "MARK",
409 .revision = 2,
410 .family = NFPROTO_UNSPEC,
411 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
412 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
413 .help = mark_tg_help,
414 .print = mark_tg_print,
415 .save = mark_tg_save,
416 .x6_parse = mark_tg_parse,
417 .x6_fcheck = mark_tg_check,
418 .x6_options = mark_tg_opts,
419 .xlate = mark_tg_xlate,
420 },
421 {
422 .version = XTABLES_VERSION,
423 .name = "MARK",
424 .revision = 2,
425 .family = NFPROTO_ARP,
426 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
427 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
428 .help = mark_tg_help,
429 .print = mark_tg_arp_print,
430 .save = mark_tg_arp_save,
431 .parse = mark_tg_arp_parse,
432 .extra_opts = mark_tg_arp_opts,
433 },
434 };
435
_init(void)436 void _init(void)
437 {
438 xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
439 }
440