xref: /aosp_15_r20/external/iptables/extensions/libxt_MARK.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
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