libxt_MARK.c revision 42979363f3958b4436c6d2503753c182c58e55ea
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_target_v0 = {
281	.family		= NFPROTO_IPV4,
282	.name		= "MARK",
283	.version	= XTABLES_VERSION,
284	.revision	= 0,
285	.size		= XT_ALIGN(sizeof(struct xt_mark_target_info)),
286	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_target_info)),
287	.help		= MARK_help,
288	.parse		= MARK_parse_v0,
289	.final_check	= MARK_check,
290	.print		= MARK_print_v0,
291	.save		= MARK_save_v0,
292	.extra_opts	= MARK_opts,
293};
294
295static struct xtables_target mark_target_v1 = {
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
310static struct xtables_target mark_target6_v0 = {
311	.family		= NFPROTO_IPV6,
312	.name		= "MARK",
313	.version	= XTABLES_VERSION,
314	.revision	= 0,
315	.size		= XT_ALIGN(sizeof(struct xt_mark_target_info)),
316	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_target_info)),
317	.help		= MARK_help,
318	.parse		= MARK_parse_v0,
319	.final_check	= MARK_check,
320	.print		= MARK_print_v0,
321	.save		= MARK_save_v0,
322	.extra_opts	= MARK_opts,
323};
324
325static struct xtables_target mark_tg_reg_v2 = {
326	.version       = XTABLES_VERSION,
327	.name          = "MARK",
328	.revision      = 2,
329	.family        = NFPROTO_UNSPEC,
330	.size          = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
331	.userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
332	.help          = mark_tg_help,
333	.parse         = mark_tg_parse,
334	.final_check   = mark_tg_check,
335	.print         = mark_tg_print,
336	.save          = mark_tg_save,
337	.extra_opts    = mark_tg_opts,
338};
339
340void _init(void)
341{
342	xtables_register_target(&mark_target_v0);
343	xtables_register_target(&mark_target_v1);
344	xtables_register_target(&mark_target6_v0);
345	xtables_register_target(&mark_tg_reg_v2);
346}
347