1 /* Shared library add-on to iptables to add CONNMARK target support.
2  *
3  * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
4  * by Henrik Nordstrom <hno@marasystems.com>
5  *
6  * Version 1.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 #include <stdbool.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <xtables.h>
26 #include <linux/netfilter/xt_CONNMARK.h>
27 
28 struct xt_connmark_target_info {
29 	unsigned long mark;
30 	unsigned long mask;
31 	uint8_t mode;
32 };
33 
34 enum {
35 	O_SET_MARK = 0,
36 	O_SAVE_MARK,
37 	O_RESTORE_MARK,
38 	O_AND_MARK,
39 	O_OR_MARK,
40 	O_XOR_MARK,
41 	O_SET_XMARK,
42 	O_CTMASK,
43 	O_NFMASK,
44 	O_MASK,
45 	F_SET_MARK     = 1 << O_SET_MARK,
46 	F_SAVE_MARK    = 1 << O_SAVE_MARK,
47 	F_RESTORE_MARK = 1 << O_RESTORE_MARK,
48 	F_AND_MARK     = 1 << O_AND_MARK,
49 	F_OR_MARK      = 1 << O_OR_MARK,
50 	F_XOR_MARK     = 1 << O_XOR_MARK,
51 	F_SET_XMARK    = 1 << O_SET_XMARK,
52 	F_CTMASK       = 1 << O_CTMASK,
53 	F_NFMASK       = 1 << O_NFMASK,
54 	F_MASK         = 1 << O_MASK,
55 	F_OP_ANY       = F_SET_MARK | F_SAVE_MARK | F_RESTORE_MARK |
56 	                 F_AND_MARK | F_OR_MARK | F_XOR_MARK | F_SET_XMARK,
57 };
58 
CONNMARK_help(void)59 static void CONNMARK_help(void)
60 {
61 	printf(
62 "CONNMARK target options:\n"
63 "  --set-mark value[/mask]       Set conntrack mark value\n"
64 "  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
65 "  --restore-mark [--mask mask]  Restore saved nfmark value\n");
66 }
67 
68 #define s struct xt_connmark_target_info
69 static const struct xt_option_entry CONNMARK_opts[] = {
70 	{.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32,
71 	 .excl = F_OP_ANY},
72 	{.name = "save-mark", .id = O_SAVE_MARK, .type = XTTYPE_NONE,
73 	 .excl = F_OP_ANY},
74 	{.name = "restore-mark", .id = O_RESTORE_MARK, .type = XTTYPE_NONE,
75 	 .excl = F_OP_ANY},
76 	{.name = "mask", .id = O_MASK, .type = XTTYPE_UINT32},
77 	XTOPT_TABLEEND,
78 };
79 #undef s
80 
81 #define s struct xt_connmark_tginfo1
82 static const struct xt_option_entry connmark_tg_opts[] = {
83 	{.name = "set-xmark", .id = O_SET_XMARK, .type = XTTYPE_MARKMASK32,
84 	 .excl = F_OP_ANY},
85 	{.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32,
86 	 .excl = F_OP_ANY},
87 	{.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32,
88 	 .excl = F_OP_ANY},
89 	{.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32,
90 	 .excl = F_OP_ANY},
91 	{.name = "xor-mark", .id = O_XOR_MARK, .type = XTTYPE_UINT32,
92 	 .excl = F_OP_ANY},
93 	{.name = "save-mark", .id = O_SAVE_MARK, .type = XTTYPE_NONE,
94 	 .excl = F_OP_ANY},
95 	{.name = "restore-mark", .id = O_RESTORE_MARK, .type = XTTYPE_NONE,
96 	 .excl = F_OP_ANY},
97 	{.name = "ctmask", .id = O_CTMASK, .type = XTTYPE_UINT32,
98 	 .excl = F_MASK, .flags = XTOPT_PUT, XTOPT_POINTER(s, ctmask)},
99 	{.name = "nfmask", .id = O_NFMASK, .type = XTTYPE_UINT32,
100 	 .excl = F_MASK, .flags = XTOPT_PUT, XTOPT_POINTER(s, nfmask)},
101 	{.name = "mask", .id = O_MASK, .type = XTTYPE_UINT32,
102 	 .excl = F_CTMASK | F_NFMASK},
103 	XTOPT_TABLEEND,
104 };
105 #undef s
106 
connmark_tg_help(void)107 static void connmark_tg_help(void)
108 {
109 	printf(
110 "CONNMARK target options:\n"
111 "  --set-xmark value[/ctmask]    Zero mask bits and XOR ctmark with value\n"
112 "  --save-mark [--ctmask mask] [--nfmask mask]\n"
113 "                                Copy ctmark to nfmark using masks\n"
114 "  --restore-mark [--ctmask mask] [--nfmask mask]\n"
115 "                                Copy nfmark to ctmark using masks\n"
116 "  --set-mark value[/mask]       Set conntrack mark value\n"
117 "  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
118 "  --restore-mark [--mask mask]  Restore saved nfmark value\n"
119 "  --and-mark value              Binary AND the ctmark with bits\n"
120 "  --or-mark value               Binary OR  the ctmark with bits\n"
121 "  --xor-mark value              Binary XOR the ctmark with bits\n"
122 );
123 }
124 
connmark_tg_init(struct xt_entry_target * target)125 static void connmark_tg_init(struct xt_entry_target *target)
126 {
127 	struct xt_connmark_tginfo1 *info = (void *)target->data;
128 
129 	/*
130 	 * Need these defaults for --save-mark/--restore-mark if no
131 	 * --ctmark or --nfmask is given.
132 	 */
133 	info->ctmask = UINT32_MAX;
134 	info->nfmask = UINT32_MAX;
135 }
136 
CONNMARK_parse(struct xt_option_call * cb)137 static void CONNMARK_parse(struct xt_option_call *cb)
138 {
139 	struct xt_connmark_target_info *markinfo = cb->data;
140 
141 	xtables_option_parse(cb);
142 	switch (cb->entry->id) {
143 	case O_SET_MARK:
144 		markinfo->mode = XT_CONNMARK_SET;
145 		markinfo->mark = cb->val.mark;
146 		markinfo->mask = cb->val.mask;
147 		break;
148 	case O_SAVE_MARK:
149 		markinfo->mode = XT_CONNMARK_SAVE;
150 		break;
151 	case O_RESTORE_MARK:
152 		markinfo->mode = XT_CONNMARK_RESTORE;
153 		break;
154 	case O_MASK:
155 		markinfo->mask = cb->val.u32;
156 		break;
157 	}
158 }
159 
connmark_tg_parse(struct xt_option_call * cb)160 static void connmark_tg_parse(struct xt_option_call *cb)
161 {
162 	struct xt_connmark_tginfo1 *info = cb->data;
163 
164 	xtables_option_parse(cb);
165 	switch (cb->entry->id) {
166 	case O_SET_XMARK:
167 		info->mode   = XT_CONNMARK_SET;
168 		info->ctmark = cb->val.mark;
169 		info->ctmask = cb->val.mask;
170 		break;
171 	case O_SET_MARK:
172 		info->mode   = XT_CONNMARK_SET;
173 		info->ctmark = cb->val.mark;
174 		info->ctmask = cb->val.mark | cb->val.mask;
175 		break;
176 	case O_AND_MARK:
177 		info->mode   = XT_CONNMARK_SET;
178 		info->ctmark = 0;
179 		info->ctmask = ~cb->val.u32;
180 		break;
181 	case O_OR_MARK:
182 		info->mode   = XT_CONNMARK_SET;
183 		info->ctmark = cb->val.u32;
184 		info->ctmask = cb->val.u32;
185 		break;
186 	case O_XOR_MARK:
187 		info->mode   = XT_CONNMARK_SET;
188 		info->ctmark = cb->val.u32;
189 		info->ctmask = 0;
190 		break;
191 	case O_SAVE_MARK:
192 		info->mode = XT_CONNMARK_SAVE;
193 		break;
194 	case O_RESTORE_MARK:
195 		info->mode = XT_CONNMARK_RESTORE;
196 		break;
197 	case O_MASK:
198 		info->nfmask = info->ctmask = cb->val.u32;
199 		break;
200 	}
201 }
202 
connmark_tg_check(struct xt_fcheck_call * cb)203 static void connmark_tg_check(struct xt_fcheck_call *cb)
204 {
205 	if (!(cb->xflags & F_OP_ANY))
206 		xtables_error(PARAMETER_PROBLEM,
207 		           "CONNMARK target: No operation specified");
208 }
209 
210 static void
print_mark(unsigned long mark)211 print_mark(unsigned long mark)
212 {
213 	printf("0x%lx", mark);
214 }
215 
216 static void
print_mask(const char * text,unsigned long mask)217 print_mask(const char *text, unsigned long mask)
218 {
219 	if (mask != 0xffffffffUL)
220 		printf("%s0x%lx", text, mask);
221 }
222 
CONNMARK_print(const void * ip,const struct xt_entry_target * target,int numeric)223 static void CONNMARK_print(const void *ip,
224                            const struct xt_entry_target *target, int numeric)
225 {
226 	const struct xt_connmark_target_info *markinfo =
227 		(const struct xt_connmark_target_info *)target->data;
228 	switch (markinfo->mode) {
229 	case XT_CONNMARK_SET:
230 	    printf(" CONNMARK set ");
231 	    print_mark(markinfo->mark);
232 	    print_mask("/", markinfo->mask);
233 	    break;
234 	case XT_CONNMARK_SAVE:
235 	    printf(" CONNMARK save ");
236 	    print_mask("mask ", markinfo->mask);
237 	    break;
238 	case XT_CONNMARK_RESTORE:
239 	    printf(" CONNMARK restore ");
240 	    print_mask("mask ", markinfo->mask);
241 	    break;
242 	default:
243 	    printf(" ERROR: UNKNOWN CONNMARK MODE");
244 	    break;
245 	}
246 }
247 
248 static void
connmark_tg_print(const void * ip,const struct xt_entry_target * target,int numeric)249 connmark_tg_print(const void *ip, const struct xt_entry_target *target,
250                   int numeric)
251 {
252 	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
253 
254 	switch (info->mode) {
255 	case XT_CONNMARK_SET:
256 		if (info->ctmark == 0)
257 			printf(" CONNMARK and 0x%x",
258 			       (unsigned int)(uint32_t)~info->ctmask);
259 		else if (info->ctmark == info->ctmask)
260 			printf(" CONNMARK or 0x%x", info->ctmark);
261 		else if (info->ctmask == 0)
262 			printf(" CONNMARK xor 0x%x", info->ctmark);
263 		else if (info->ctmask == 0xFFFFFFFFU)
264 			printf(" CONNMARK set 0x%x", info->ctmark);
265 		else
266 			printf(" CONNMARK xset 0x%x/0x%x",
267 			       info->ctmark, info->ctmask);
268 		break;
269 	case XT_CONNMARK_SAVE:
270 		if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)
271 			printf(" CONNMARK save");
272 		else if (info->nfmask == info->ctmask)
273 			printf(" CONNMARK save mask 0x%x", info->nfmask);
274 		else
275 			printf(" CONNMARK save nfmask 0x%x ctmask ~0x%x",
276 			       info->nfmask, info->ctmask);
277 		break;
278 	case XT_CONNMARK_RESTORE:
279 		if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX)
280 			printf(" CONNMARK restore");
281 		else if (info->ctmask == info->nfmask)
282 			printf(" CONNMARK restore mask 0x%x", info->ctmask);
283 		else
284 			printf(" CONNMARK restore ctmask 0x%x nfmask ~0x%x",
285 			       info->ctmask, info->nfmask);
286 		break;
287 
288 	default:
289 		printf(" ERROR: UNKNOWN CONNMARK MODE");
290 		break;
291 	}
292 }
293 
CONNMARK_save(const void * ip,const struct xt_entry_target * target)294 static void CONNMARK_save(const void *ip, const struct xt_entry_target *target)
295 {
296 	const struct xt_connmark_target_info *markinfo =
297 		(const struct xt_connmark_target_info *)target->data;
298 
299 	switch (markinfo->mode) {
300 	case XT_CONNMARK_SET:
301 	    printf(" --set-mark ");
302 	    print_mark(markinfo->mark);
303 	    print_mask("/", markinfo->mask);
304 	    break;
305 	case XT_CONNMARK_SAVE:
306 	    printf(" --save-mark ");
307 	    print_mask("--mask ", markinfo->mask);
308 	    break;
309 	case XT_CONNMARK_RESTORE:
310 	    printf(" --restore-mark ");
311 	    print_mask("--mask ", markinfo->mask);
312 	    break;
313 	default:
314 	    printf(" ERROR: UNKNOWN CONNMARK MODE");
315 	    break;
316 	}
317 }
318 
CONNMARK_init(struct xt_entry_target * t)319 static void CONNMARK_init(struct xt_entry_target *t)
320 {
321 	struct xt_connmark_target_info *markinfo
322 		= (struct xt_connmark_target_info *)t->data;
323 
324 	markinfo->mask = 0xffffffffUL;
325 }
326 
327 static void
connmark_tg_save(const void * ip,const struct xt_entry_target * target)328 connmark_tg_save(const void *ip, const struct xt_entry_target *target)
329 {
330 	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
331 
332 	switch (info->mode) {
333 	case XT_CONNMARK_SET:
334 		printf(" --set-xmark 0x%x/0x%x", info->ctmark, info->ctmask);
335 		break;
336 	case XT_CONNMARK_SAVE:
337 		printf(" --save-mark --nfmask 0x%x --ctmask 0x%x",
338 		       info->nfmask, info->ctmask);
339 		break;
340 	case XT_CONNMARK_RESTORE:
341 		printf(" --restore-mark --nfmask 0x%x --ctmask 0x%x",
342 		       info->nfmask, info->ctmask);
343 		break;
344 	default:
345 		printf(" ERROR: UNKNOWN CONNMARK MODE");
346 		break;
347 	}
348 }
349 
350 static struct xtables_target connmark_tg_reg[] = {
351 	{
352 		.family        = NFPROTO_UNSPEC,
353 		.name          = "CONNMARK",
354 		.revision      = 0,
355 		.version       = XTABLES_VERSION,
356 		.size          = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
357 		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
358 		.help          = CONNMARK_help,
359 		.init          = CONNMARK_init,
360 		.print         = CONNMARK_print,
361 		.save          = CONNMARK_save,
362 		.x6_parse      = CONNMARK_parse,
363 		.x6_fcheck     = connmark_tg_check,
364 		.x6_options    = CONNMARK_opts,
365 	},
366 	{
367 		.version       = XTABLES_VERSION,
368 		.name          = "CONNMARK",
369 		.revision      = 1,
370 		.family        = NFPROTO_UNSPEC,
371 		.size          = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
372 		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
373 		.help          = connmark_tg_help,
374 		.init          = connmark_tg_init,
375 		.print         = connmark_tg_print,
376 		.save          = connmark_tg_save,
377 		.x6_parse      = connmark_tg_parse,
378 		.x6_fcheck     = connmark_tg_check,
379 		.x6_options    = connmark_tg_opts,
380 	},
381 };
382 
_init(void)383 void _init(void)
384 {
385 	xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
386 }
387