libxt_CONNMARK.c revision e37d45ce390c2f5a7f1e64742b9100ecef0def54
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
28struct xt_connmark_target_info {
29	unsigned long mark;
30	unsigned long mask;
31	uint8_t mode;
32};
33
34enum {
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
59static 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
69static 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
82static 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
107static 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
125static 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
137static 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
160static 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
203static 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
210static void
211print_mark(unsigned long mark)
212{
213	printf("0x%lx", mark);
214}
215
216static void
217print_mask(const char *text, unsigned long mask)
218{
219	if (mask != 0xffffffffUL)
220		printf("%s0x%lx", text, mask);
221}
222
223static 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
248static void
249connmark_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
294static 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
319static 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
327static void
328connmark_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
350static 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
383void _init(void)
384{
385	xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
386}
387