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