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