libxt_MARK.c revision 3d915e1ac610bce44250b4aea556f4726387388d
1926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/* Shared library add-on to iptables to add MARK target support. */
2926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <stdbool.h>
3926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <stdio.h>
4926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <string.h>
5926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <stdlib.h>
6926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <getopt.h>
7926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
8926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <xtables.h>
9926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <linux/netfilter/x_tables.h>
10926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)#include <linux/netfilter/xt_MARK.h>
11926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
12926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)enum {
13926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	F_MARK = 1 << 0,
14926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)};
15926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
16926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static void MARK_help(void)
17926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
18926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	printf(
19926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"MARK target options:\n"
20926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"  --set-mark value                   Set nfmark value\n"
21926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"  --and-mark value                   Binary AND the nfmark with value\n"
22926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"  --or-mark  value                   Binary OR  the nfmark with value\n");
23926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
24926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
25926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static const struct option MARK_opts[] = {
26926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{ "set-mark", 1, NULL, '1' },
2753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	{ "and-mark", 1, NULL, '2' },
28926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{ "or-mark", 1, NULL, '3' },
2906f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)	{ .name = NULL }
30d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)};
315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
3253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)static const struct option mark_tg_opts[] = {
3353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)	{.name = "set-xmark", .has_arg = true, .val = 'X'},
34926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{.name = "set-mark",  .has_arg = true, .val = '='},
35c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)	{.name = "and-mark",  .has_arg = true, .val = '&'},
36926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{.name = "or-mark",   .has_arg = true, .val = '|'},
37926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{.name = "xor-mark",  .has_arg = true, .val = '^'},
38926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	{ .name = NULL }
398abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)};
4051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
41926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static void mark_tg_help(void)
42926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
43926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	printf(
44926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"MARK target options:\n"
45926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"  --set-xmark value[/mask]  Clear bits in mask and XOR value into nfmark\n"
46323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)"  --set-mark value[/mask]   Clear bits in mask and OR value into nfmark\n"
47926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)"  --and-mark bits           Binary AND the nfmark with bits\n"
485d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)"  --or-mark bits            Binary OR the nfmark with bits\n"
4909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)"  --xor-mask bits           Binary XOR the nfmark with bits\n"
50521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)"\n");
51521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
52926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
53926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)/* Function which parses command options; returns true if it
54521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)   ate an option */
55926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static int
56926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)MARK_parse_v0(int c, char **argv, int invert, unsigned int *flags,
57d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)              const void *entry, struct xt_entry_target **target)
58d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
59926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	struct xt_mark_target_info *markinfo
60521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)		= (struct xt_mark_target_info *)(*target)->data;
61926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	unsigned int mark = 0;
62926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
63926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	switch (c) {
64926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case '1':
65926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX))
66926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
67926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		markinfo->mark = mark;
68d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)		if (*flags)
69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)			xtables_error(PARAMETER_PROBLEM,
70926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			           "MARK target: Can't specify --set-mark twice");
71926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		*flags = 1;
72926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		break;
73926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case '2':
74926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		xtables_error(PARAMETER_PROBLEM,
75926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			   "MARK target: kernel too old for --and-mark");
76926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case '3':
77926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		xtables_error(PARAMETER_PROBLEM,
78926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)			   "MARK target: kernel too old for --or-mark");
79926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	default:
80926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		return 0;
81926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	}
82926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
83926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	return 1;
84926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
85926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
86926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static void MARK_check(unsigned int flags)
87926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
881e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)	if (!flags)
89926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		xtables_error(PARAMETER_PROBLEM,
90d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)		           "MARK target: Parameter --set/and/or-mark"
91f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles)			   " is required");
92926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)}
93926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
94926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)static int
95926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags,
96926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)              const void *entry, struct xt_entry_target **target)
97926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){
981e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)	struct xt_mark_target_info_v1 *markinfo
99926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		= (struct xt_mark_target_info_v1 *)(*target)->data;
100d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)	unsigned int mark = 0;
101d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
102926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	switch (c) {
103926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case '1':
104926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	        markinfo->mode = XT_MARK_SET;
105926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		break;
106926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case '2':
107926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	        markinfo->mode = XT_MARK_AND;
108926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		break;
109926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	case '3':
110926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	        markinfo->mode = XT_MARK_OR;
111926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		break;
112926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	default:
113926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)		return 0;
114926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)	}
1155267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)
1165267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)	if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX))
1175267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)		xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
1185267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)	markinfo->mark = mark;
1195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)	if (*flags)
120323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)		xtables_error(PARAMETER_PROBLEM,
121323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)			   "MARK target: Can't specify --set-mark twice");
122323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)
123323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)	*flags = 1;
124323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)	return 1;
125323480423219ecd77329f8326dc5e0e3b50926d4Torne (Richard Coles)}
126926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)
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 if (info->mask == 0xffffffffU)
251		printf("MARK set 0x%x ", info->mark);
252	else
253		printf("MARK xset 0x%x/0x%x ", info->mark, info->mask);
254}
255
256static void MARK_save_v1(const void *ip, const struct xt_entry_target *target)
257{
258	const struct xt_mark_target_info_v1 *markinfo =
259		(const struct xt_mark_target_info_v1 *)target->data;
260
261	switch (markinfo->mode) {
262	case XT_MARK_SET:
263		printf("--set-mark ");
264		break;
265	case XT_MARK_AND:
266		printf("--and-mark ");
267		break;
268	case XT_MARK_OR:
269		printf("--or-mark ");
270		break;
271	}
272	print_mark(markinfo->mark);
273}
274
275static void mark_tg_save(const void *ip, const struct xt_entry_target *target)
276{
277	const struct xt_mark_tginfo2 *info = (const void *)target->data;
278
279	printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask);
280}
281
282static struct xtables_target mark_tg_reg[] = {
283	{
284		.family        = NFPROTO_UNSPEC,
285		.name          = "MARK",
286		.version       = XTABLES_VERSION,
287		.revision      = 0,
288		.size          = XT_ALIGN(sizeof(struct xt_mark_target_info)),
289		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
290		.help          = MARK_help,
291		.parse         = MARK_parse_v0,
292		.final_check   = MARK_check,
293		.print         = MARK_print_v0,
294		.save          = MARK_save_v0,
295		.extra_opts    = MARK_opts,
296	},
297	{
298		.family        = NFPROTO_IPV4,
299		.name          = "MARK",
300		.version       = XTABLES_VERSION,
301		.revision      = 1,
302		.size          = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
303		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
304		.help          = MARK_help,
305		.parse         = MARK_parse_v1,
306		.final_check   = MARK_check,
307		.print         = MARK_print_v1,
308		.save          = MARK_save_v1,
309		.extra_opts    = MARK_opts,
310	},
311	{
312		.version       = XTABLES_VERSION,
313		.name          = "MARK",
314		.revision      = 2,
315		.family        = NFPROTO_UNSPEC,
316		.size          = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
317		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
318		.help          = mark_tg_help,
319		.parse         = mark_tg_parse,
320		.final_check   = mark_tg_check,
321		.print         = mark_tg_print,
322		.save          = mark_tg_save,
323		.extra_opts    = mark_tg_opts,
324	},
325};
326
327void _init(void)
328{
329	xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
330}
331