1 #include <stdbool.h>
2 #include <stdio.h>
3 #include <xtables.h>
4 #include <linux/netfilter/xt_MARK.h>
5 
6 /* Version 0 */
7 struct xt_mark_target_info {
8 	unsigned long mark;
9 };
10 
11 /* Version 1 */
12 enum {
13 	XT_MARK_SET=0,
14 	XT_MARK_AND,
15 	XT_MARK_OR,
16 };
17 
18 struct xt_mark_target_info_v1 {
19 	unsigned long mark;
20 	uint8_t mode;
21 };
22 
23 enum {
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 
MARK_help(void)38 static 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 
47 static 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 
57 static 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 
mark_tg_help(void)71 static 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 
MARK_parse_v0(struct xt_option_call * cb)83 static 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 
MARK_check(struct xt_fcheck_call * cb)99 static 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 
MARK_parse_v1(struct xt_option_call * cb)107 static 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 
mark_tg_parse(struct xt_option_call * cb)126 static 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 
mark_tg_check(struct xt_fcheck_call * cb)154 static 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 
161 static void
print_mark(unsigned long mark)162 print_mark(unsigned long mark)
163 {
164 	printf(" 0x%lx", mark);
165 }
166 
MARK_print_v0(const void * ip,const struct xt_entry_target * target,int numeric)167 static 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 
MARK_save_v0(const void * ip,const struct xt_entry_target * target)176 static 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 
MARK_print_v1(const void * ip,const struct xt_entry_target * target,int numeric)185 static 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 
mark_tg_print(const void * ip,const struct xt_entry_target * target,int numeric)205 static 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 
MARK_save_v1(const void * ip,const struct xt_entry_target * target)222 static 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 
mark_tg_save(const void * ip,const struct xt_entry_target * target)241 static 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 
mark_tg_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)248 static int mark_tg_xlate(struct xt_xlate *xl,
249 			 const struct xt_xlate_tg_params *params)
250 {
251 	const struct xt_mark_tginfo2 *info = (const void *)params->target->data;
252 
253 	xt_xlate_add(xl, "meta mark set ");
254 
255 	if (info->mark == 0)
256 		xt_xlate_add(xl, "mark and 0x%x ", ~info->mask);
257 	else if (info->mark == info->mask)
258 		xt_xlate_add(xl, "mark or 0x%x ", info->mark);
259 	else if (info->mask == 0)
260 		xt_xlate_add(xl, "mark xor 0x%x ", info->mark);
261 	else if (info->mask == 0xffffffffU)
262 		xt_xlate_add(xl, "0x%x ", info->mark);
263 	else
264 		xt_xlate_add(xl, "mark and 0x%x xor 0x%x ", ~info->mask,
265 			     info->mark);
266 
267 	return 1;
268 }
269 
MARK_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)270 static int MARK_xlate(struct xt_xlate *xl,
271 		      const struct xt_xlate_tg_params *params)
272 {
273 	const struct xt_mark_target_info_v1 *markinfo =
274 		(const struct xt_mark_target_info_v1 *)params->target->data;
275 
276 	xt_xlate_add(xl, "meta mark set ");
277 
278 	switch(markinfo->mode) {
279 	case XT_MARK_SET:
280 		xt_xlate_add(xl, "0x%x ", markinfo->mark);
281 		break;
282 	case XT_MARK_AND:
283 		xt_xlate_add(xl, "mark and 0x%x ", markinfo->mark);
284 		break;
285 	case XT_MARK_OR:
286 		xt_xlate_add(xl, "mark or 0x%x ", markinfo->mark);
287 		break;
288 	}
289 
290 	return 1;
291 }
292 
293 static struct xtables_target mark_tg_reg[] = {
294 	{
295 		.family        = NFPROTO_UNSPEC,
296 		.name          = "MARK",
297 		.version       = XTABLES_VERSION,
298 		.revision      = 0,
299 		.size          = XT_ALIGN(sizeof(struct xt_mark_target_info)),
300 		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)),
301 		.help          = MARK_help,
302 		.print         = MARK_print_v0,
303 		.save          = MARK_save_v0,
304 		.x6_parse      = MARK_parse_v0,
305 		.x6_fcheck     = MARK_check,
306 		.x6_options    = MARK_opts,
307 	},
308 	{
309 		.family        = NFPROTO_IPV4,
310 		.name          = "MARK",
311 		.version       = XTABLES_VERSION,
312 		.revision      = 1,
313 		.size          = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
314 		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)),
315 		.help          = MARK_help,
316 		.print         = MARK_print_v1,
317 		.save          = MARK_save_v1,
318 		.x6_parse      = MARK_parse_v1,
319 		.x6_fcheck     = MARK_check,
320 		.x6_options    = MARK_opts,
321 		.xlate	       = MARK_xlate,
322 	},
323 	{
324 		.version       = XTABLES_VERSION,
325 		.name          = "MARK",
326 		.revision      = 2,
327 		.family        = NFPROTO_UNSPEC,
328 		.size          = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
329 		.userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)),
330 		.help          = mark_tg_help,
331 		.print         = mark_tg_print,
332 		.save          = mark_tg_save,
333 		.x6_parse      = mark_tg_parse,
334 		.x6_fcheck     = mark_tg_check,
335 		.x6_options    = mark_tg_opts,
336 		.xlate	       = mark_tg_xlate,
337 	},
338 };
339 
_init(void)340 void _init(void)
341 {
342 	xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
343 }
344