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