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 "\n");
82 }
83
MARK_parse_v0(struct xt_option_call * cb)84 static void MARK_parse_v0(struct xt_option_call *cb)
85 {
86 struct xt_mark_target_info *markinfo = cb->data;
87
88 xtables_option_parse(cb);
89 switch (cb->entry->id) {
90 case O_SET_MARK:
91 markinfo->mark = cb->val.mark;
92 break;
93 default:
94 xtables_error(PARAMETER_PROBLEM,
95 "MARK target: kernel too old for --%s",
96 cb->entry->name);
97 }
98 }
99
MARK_check(struct xt_fcheck_call * cb)100 static void MARK_check(struct xt_fcheck_call *cb)
101 {
102 if (cb->xflags == 0)
103 xtables_error(PARAMETER_PROBLEM,
104 "MARK target: Parameter --set/and/or-mark"
105 " is required");
106 }
107
MARK_parse_v1(struct xt_option_call * cb)108 static void MARK_parse_v1(struct xt_option_call *cb)
109 {
110 struct xt_mark_target_info_v1 *markinfo = cb->data;
111
112 xtables_option_parse(cb);
113 switch (cb->entry->id) {
114 case O_SET_MARK:
115 markinfo->mode = XT_MARK_SET;
116 break;
117 case O_AND_MARK:
118 markinfo->mode = XT_MARK_AND;
119 break;
120 case O_OR_MARK:
121 markinfo->mode = XT_MARK_OR;
122 break;
123 }
124 markinfo->mark = cb->val.u32;
125 }
126
mark_tg_parse(struct xt_option_call * cb)127 static void mark_tg_parse(struct xt_option_call *cb)
128 {
129 struct xt_mark_tginfo2 *info = cb->data;
130
131 xtables_option_parse(cb);
132 switch (cb->entry->id) {
133 case O_SET_XMARK:
134 info->mark = cb->val.mark;
135 info->mask = cb->val.mask;
136 break;
137 case O_SET_MARK:
138 info->mark = cb->val.mark;
139 info->mask = cb->val.mark | cb->val.mask;
140 break;
141 case O_AND_MARK:
142 info->mark = 0;
143 info->mask = ~cb->val.u32;
144 break;
145 case O_OR_MARK:
146 info->mark = info->mask = cb->val.u32;
147 break;
148 case O_XOR_MARK:
149 info->mark = cb->val.u32;
150 info->mask = 0;
151 break;
152 }
153 }
154
mark_tg_check(struct xt_fcheck_call * cb)155 static void mark_tg_check(struct xt_fcheck_call *cb)
156 {
157 if (cb->xflags == 0)
158 xtables_error(PARAMETER_PROBLEM, "MARK: One of the --set-xmark, "
159 "--{and,or,xor,set}-mark options is required");
160 }
161
162 static void
print_mark(unsigned long mark)163 print_mark(unsigned long mark)
164 {
165 printf(" 0x%lx", mark);
166 }
167
MARK_print_v0(const void * ip,const struct xt_entry_target * target,int numeric)168 static void MARK_print_v0(const void *ip,
169 const struct xt_entry_target *target, int numeric)
170 {
171 const struct xt_mark_target_info *markinfo =
172 (const struct xt_mark_target_info *)target->data;
173 printf(" MARK set");
174 print_mark(markinfo->mark);
175 }
176
MARK_save_v0(const void * ip,const struct xt_entry_target * target)177 static void MARK_save_v0(const void *ip, const struct xt_entry_target *target)
178 {
179 const struct xt_mark_target_info *markinfo =
180 (const struct xt_mark_target_info *)target->data;
181
182 printf(" --set-mark");
183 print_mark(markinfo->mark);
184 }
185
MARK_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)186 static void MARK_print_v1(const void *ip, const struct xt_entry_target *target,
187 int numeric)
188 {
189 const struct xt_mark_target_info_v1 *markinfo =
190 (const struct xt_mark_target_info_v1 *)target->data;
191
192 switch (markinfo->mode) {
193 case XT_MARK_SET:
194 printf(" MARK set");
195 break;
196 case XT_MARK_AND:
197 printf(" MARK and");
198 break;
199 case XT_MARK_OR:
200 printf(" MARK or");
201 break;
202 }
203 print_mark(markinfo->mark);
204 }
205
mark_tg_print(const void * ip,const struct xt_entry_target * target,int numeric)206 static void mark_tg_print(const void *ip, const struct xt_entry_target *target,
207 int numeric)
208 {
209 const struct xt_mark_tginfo2 *info = (const void *)target->data;
210
211 if (info->mark == 0)
212 printf(" MARK and 0x%x", (unsigned int)(uint32_t)~info->mask);
213 else if (info->mark == info->mask)
214 printf(" MARK or 0x%x", info->mark);
215 else if (info->mask == 0)
216 printf(" MARK xor 0x%x", info->mark);
217 else if (info->mask == 0xffffffffU)
218 printf(" MARK set 0x%x", info->mark);
219 else
220 printf(" MARK xset 0x%x/0x%x", info->mark, info->mask);
221 }
222
MARK_save_v1(const void * ip,const struct xt_entry_target * target)223 static void MARK_save_v1(const void *ip, const struct xt_entry_target *target)
224 {
225 const struct xt_mark_target_info_v1 *markinfo =
226 (const struct xt_mark_target_info_v1 *)target->data;
227
228 switch (markinfo->mode) {
229 case XT_MARK_SET:
230 printf(" --set-mark");
231 break;
232 case XT_MARK_AND:
233 printf(" --and-mark");
234 break;
235 case XT_MARK_OR:
236 printf(" --or-mark");
237 break;
238 }
239 print_mark(markinfo->mark);
240 }
241
mark_tg_save(const void * ip,const struct xt_entry_target * target)242 static void mark_tg_save(const void *ip, const struct xt_entry_target *target)
243 {
244 const struct xt_mark_tginfo2 *info = (const void *)target->data;
245
246 printf(" --set-xmark 0x%x/0x%x", info->mark, info->mask);
247 }
248
mark_tg_arp_save(const void * ip,const struct xt_entry_target * target)249 static void mark_tg_arp_save(const void *ip, const struct xt_entry_target *target)
250 {
251 const struct xt_mark_tginfo2 *info = (const void *)target->data;
252
253 if (info->mark == 0)
254 printf(" --and-mark %x", (unsigned int)(uint32_t)~info->mask);
255 else if (info->mark == info->mask)
256 printf(" --or-mark %x", info->mark);
257 else
258 printf(" --set-mark %x", info->mark);
259 }
260
mark_tg_arp_print(const void * ip,const struct xt_entry_target * target,int numeric)261 static void mark_tg_arp_print(const void *ip,
262 const struct xt_entry_target *target, int numeric)
263 {
264 mark_tg_arp_save(ip, target);
265 }
266
267 #define MARK_OPT 1
268 #define AND_MARK_OPT 2
269 #define OR_MARK_OPT 3
270
271 static struct option mark_tg_arp_opts[] = {
272 { .name = "set-mark", .has_arg = required_argument, .flag = 0, .val = MARK_OPT },
273 { .name = "and-mark", .has_arg = required_argument, .flag = 0, .val = AND_MARK_OPT },
274 { .name = "or-mark", .has_arg = required_argument, .flag = 0, .val = OR_MARK_OPT },
275 { .name = NULL}
276 };
277
278 static int
mark_tg_arp_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_target ** target)279 mark_tg_arp_parse(int c, char **argv, int invert, unsigned int *flags,
280 const void *entry, struct xt_entry_target **target)
281 {
282 struct xt_mark_tginfo2 *info =
283 (struct xt_mark_tginfo2 *)(*target)->data;
284 int i;
285
286 switch (c) {
287 case MARK_OPT:
288 if (sscanf(argv[optind-1], "%x", &i) != 1) {
289 xtables_error(PARAMETER_PROBLEM,
290 "Bad mark value `%s'", optarg);
291 return 0;
292 }
293 info->mark = i;
294 if (*flags)
295 xtables_error(PARAMETER_PROBLEM,
296 "MARK: Can't specify --set-mark twice");
297 *flags = 1;
298 break;
299 case AND_MARK_OPT:
300 if (sscanf(argv[optind-1], "%x", &i) != 1) {
301 xtables_error(PARAMETER_PROBLEM,
302 "Bad mark value `%s'", optarg);
303 return 0;
304 }
305 info->mark = 0;
306 info->mask = ~i;
307 if (*flags)
308 xtables_error(PARAMETER_PROBLEM,
309 "MARK: Can't specify --and-mark twice");
310 *flags = 1;
311 break;
312 case OR_MARK_OPT:
313 if (sscanf(argv[optind-1], "%x", &i) != 1) {
314 xtables_error(PARAMETER_PROBLEM,
315 "Bad mark value `%s'", optarg);
316 return 0;
317 }
318 info->mark = info->mask = i;
319 if (*flags)
320 xtables_error(PARAMETER_PROBLEM,
321 "MARK: Can't specify --or-mark twice");
322 *flags = 1;
323 break;
324 default:
325 return 0;
326 }
327 return 1;
328 }
329
mark_tg_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)330 static int mark_tg_xlate(struct xt_xlate *xl,
331 const struct xt_xlate_tg_params *params)
332 {
333 const struct xt_mark_tginfo2 *info = (const void *)params->target->data;
334
335 xt_xlate_add(xl, "meta mark set ");
336
337 if (info->mask == 0xffffffffU)
338 xt_xlate_add(xl, "0x%x ", info->mark);
339 else if (info->mark == 0)
340 xt_xlate_add(xl, "mark and 0x%x ", ~info->mask);
341 else if (info->mark == info->mask)
342 xt_xlate_add(xl, "mark or 0x%x ", info->mark);
343 else if (info->mask == 0)
344 xt_xlate_add(xl, "mark xor 0x%x ", info->mark);
345 else
346 xt_xlate_add(xl, "mark and 0x%x xor 0x%x ", ~info->mask,
347 info->mark);
348
349 return 1;
350 }
351
MARK_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)352 static int MARK_xlate(struct xt_xlate *xl,
353 const struct xt_xlate_tg_params *params)
354 {
355 const struct xt_mark_target_info_v1 *markinfo =
356 (const struct xt_mark_target_info_v1 *)params->target->data;
357
358 xt_xlate_add(xl, "meta mark set ");
359
360 switch(markinfo->mode) {
361 case XT_MARK_SET:
362 xt_xlate_add(xl, "0x%x ", (uint32_t)markinfo->mark);
363 break;
364 case XT_MARK_AND:
365 xt_xlate_add(xl, "mark and 0x%x ", (uint32_t)markinfo->mark);
366 break;
367 case XT_MARK_OR:
368 xt_xlate_add(xl, "mark or 0x%x ", (uint32_t)markinfo->mark);
369 break;
370 }
371
372 return 1;
373 }
374
375 static struct xtables_target mark_tg_reg[] = {
376 {
377 .family = NFPROTO_UNSPEC,
378 .name = "MARK",
379 .version = XTABLES_VERSION,
380 .revision = 0,
381 .size = XT_ALIGN(sizeof(struct xt_mark_target_info)),
382 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
383 .help = MARK_help,
384 .print = MARK_print_v0,
385 .save = MARK_save_v0,
386 .x6_parse = MARK_parse_v0,
387 .x6_fcheck = MARK_check,
388 .x6_options = MARK_opts,
389 },
390 {
391 .family = NFPROTO_IPV4,
392 .name = "MARK",
393 .version = XTABLES_VERSION,
394 .revision = 1,
395 .size = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
396 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
397 .help = MARK_help,
398 .print = MARK_print_v1,
399 .save = MARK_save_v1,
400 .x6_parse = MARK_parse_v1,
401 .x6_fcheck = MARK_check,
402 .x6_options = MARK_opts,
403 .xlate = MARK_xlate,
404 },
405 {
406 .version = XTABLES_VERSION,
407 .name = "MARK",
408 .revision = 2,
409 .family = NFPROTO_UNSPEC,
410 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
411 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
412 .help = mark_tg_help,
413 .print = mark_tg_print,
414 .save = mark_tg_save,
415 .x6_parse = mark_tg_parse,
416 .x6_fcheck = mark_tg_check,
417 .x6_options = mark_tg_opts,
418 .xlate = mark_tg_xlate,
419 },
420 {
421 .version = XTABLES_VERSION,
422 .name = "MARK",
423 .revision = 2,
424 .family = NFPROTO_ARP,
425 .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
426 .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
427 .help = mark_tg_help,
428 .print = mark_tg_arp_print,
429 .save = mark_tg_arp_save,
430 .parse = mark_tg_arp_parse,
431 .extra_opts = mark_tg_arp_opts,
432 },
433 };
434
_init(void)435 void _init(void)
436 {
437 xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
438 }
439