1#include <stdbool.h>
2#include <stdio.h>
3#include <xtables.h>
4#include <linux/netfilter/xt_MARK.h>
5
6/* Version 0 */
7struct xt_mark_target_info {
8	unsigned long mark;
9};
10
11/* Version 1 */
12enum {
13	XT_MARK_SET=0,
14	XT_MARK_AND,
15	XT_MARK_OR,
16};
17
18struct xt_mark_target_info_v1 {
19	unsigned long mark;
20	uint8_t mode;
21};
22
23enum {
24	O_SET_MARK = 0,
25	O_AND_MARK,
26	O_OR_MARK,
27	O_XOR_MARK,
28	O_SET_XMARK,
29	F_SET_MARK  = 1 << O_SET_MARK,
30	F_AND_MARK  = 1 << O_AND_MARK,
31	F_OR_MARK   = 1 << O_OR_MARK,
32	F_XOR_MARK  = 1 << O_XOR_MARK,
33	F_SET_XMARK = 1 << O_SET_XMARK,
34	F_ANY       = F_SET_MARK | F_AND_MARK | F_OR_MARK |
35	              F_XOR_MARK | F_SET_XMARK,
36};
37
38static void MARK_help(void)
39{
40	printf(
41"MARK target options:\n"
42"  --set-mark value                   Set nfmark value\n"
43"  --and-mark value                   Binary AND the nfmark with value\n"
44"  --or-mark  value                   Binary OR  the nfmark with value\n");
45}
46
47static const struct xt_option_entry MARK_opts[] = {
48	{.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_UINT32,
49	 .excl = F_ANY},
50	{.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32,
51	 .excl = F_ANY},
52	{.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32,
53	 .excl = F_ANY},
54	XTOPT_TABLEEND,
55};
56
57static const struct xt_option_entry mark_tg_opts[] = {
58	{.name = "set-xmark", .id = O_SET_XMARK, .type = XTTYPE_MARKMASK32,
59	 .excl = F_ANY},
60	{.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32,
61	 .excl = F_ANY},
62	{.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32,
63	 .excl = F_ANY},
64	{.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32,
65	 .excl = F_ANY},
66	{.name = "xor-mark", .id = O_XOR_MARK, .type = XTTYPE_UINT32,
67	 .excl = F_ANY},
68	XTOPT_TABLEEND,
69};
70
71static void mark_tg_help(void)
72{
73	printf(
74"MARK target options:\n"
75"  --set-xmark value[/mask]  Clear bits in mask and XOR value into nfmark\n"
76"  --set-mark value[/mask]   Clear bits in mask and OR value into nfmark\n"
77"  --and-mark bits           Binary AND the nfmark with bits\n"
78"  --or-mark bits            Binary OR the nfmark with bits\n"
79"  --xor-mask bits           Binary XOR the nfmark with bits\n"
80"\n");
81}
82
83static 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
99static 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
107static 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
126static 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
154static 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
161static void
162print_mark(unsigned long mark)
163{
164	printf(" 0x%lx", mark);
165}
166
167static 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
176static 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
185static 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
205static 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
222static 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
241static 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
248static struct xtables_target mark_tg_reg[] = {
249	{
250		.family        = NFPROTO_UNSPEC,
251		.name          = "MARK",
252		.version       = XTABLES_VERSION,
253		.revision      = 0,
254		.size          = XT_ALIGN(sizeof(struct xt_mark_target_info)),
255		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
256		.help          = MARK_help,
257		.print         = MARK_print_v0,
258		.save          = MARK_save_v0,
259		.x6_parse      = MARK_parse_v0,
260		.x6_fcheck     = MARK_check,
261		.x6_options    = MARK_opts,
262	},
263	{
264		.family        = NFPROTO_IPV4,
265		.name          = "MARK",
266		.version       = XTABLES_VERSION,
267		.revision      = 1,
268		.size          = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
269		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
270		.help          = MARK_help,
271		.print         = MARK_print_v1,
272		.save          = MARK_save_v1,
273		.x6_parse      = MARK_parse_v1,
274		.x6_fcheck     = MARK_check,
275		.x6_options    = MARK_opts,
276	},
277	{
278		.version       = XTABLES_VERSION,
279		.name          = "MARK",
280		.revision      = 2,
281		.family        = NFPROTO_UNSPEC,
282		.size          = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
283		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
284		.help          = mark_tg_help,
285		.print         = mark_tg_print,
286		.save          = mark_tg_save,
287		.x6_parse      = mark_tg_parse,
288		.x6_fcheck     = mark_tg_check,
289		.x6_options    = mark_tg_opts,
290	},
291};
292
293void _init(void)
294{
295	xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
296}
297