libxt_CONNMARK.c revision 5fdf032a02b671bc1a18cec0e803c17c64175ab1
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 <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <getopt.h>
26
27#include <xtables.h>
28#include <linux/netfilter/x_tables.h>
29#include <linux/netfilter/xt_CONNMARK.h>
30
31enum {
32	F_MARK    = 1 << 0,
33	F_SR_MARK = 1 << 1,
34};
35
36static void CONNMARK_help(void)
37{
38	printf(
39"CONNMARK target options:\n"
40"  --set-mark value[/mask]       Set conntrack mark value\n"
41"  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
42"  --restore-mark [--mask mask]  Restore saved nfmark value\n");
43}
44
45static const struct option CONNMARK_opts[] = {
46	{ "set-mark", 1, NULL, '1' },
47	{ "save-mark", 0, NULL, '2' },
48	{ "restore-mark", 0, NULL, '3' },
49	{ "mask", 1, NULL, '4' },
50	{ .name = NULL }
51};
52
53static const struct option connmark_tg_opts[] = {
54	{.name = "set-xmark",     .has_arg = true,  .val = '='},
55	{.name = "set-mark",      .has_arg = true,  .val = '-'},
56	{.name = "and-mark",      .has_arg = true,  .val = '&'},
57	{.name = "or-mark",       .has_arg = true,  .val = '|'},
58	{.name = "xor-mark",      .has_arg = true,  .val = '^'},
59	{.name = "save-mark",     .has_arg = false, .val = 'S'},
60	{.name = "restore-mark",  .has_arg = false, .val = 'R'},
61	{.name = "ctmask",        .has_arg = true,  .val = 'c'},
62	{.name = "nfmask",        .has_arg = true,  .val = 'n'},
63	{.name = "mask",          .has_arg = true,  .val = 'm'},
64	{.name = NULL},
65};
66
67static void connmark_tg_help(void)
68{
69	printf(
70"CONNMARK target options:\n"
71"  --set-xmark value[/ctmask]    Zero mask bits and XOR ctmark with value\n"
72"  --save-mark [--ctmask mask] [--nfmask mask]\n"
73"                                Copy ctmark to nfmark using masks\n"
74"  --restore-mark [--ctmask mask] [--nfmask mask]\n"
75"                                Copy nfmark to ctmark using masks\n"
76"  --set-mark value[/mask]       Set conntrack mark value\n"
77"  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
78"  --restore-mark [--mask mask]  Restore saved nfmark value\n"
79"  --and-mark value              Binary AND the ctmark with bits\n"
80"  --or-mark value               Binary OR  the ctmark with bits\n"
81"  --xor-mark value              Binary XOR the ctmark with bits\n"
82);
83}
84
85static void connmark_tg_init(struct xt_entry_target *target)
86{
87	struct xt_connmark_tginfo1 *info = (void *)target->data;
88
89	/*
90	 * Need these defaults for --save-mark/--restore-mark if no
91	 * --ctmark or --nfmask is given.
92	 */
93	info->ctmask = UINT32_MAX;
94	info->nfmask = UINT32_MAX;
95}
96
97static int
98CONNMARK_parse(int c, char **argv, int invert, unsigned int *flags,
99               const void *entry, struct xt_entry_target **target)
100{
101	struct xt_connmark_target_info *markinfo
102		= (struct xt_connmark_target_info *)(*target)->data;
103
104	switch (c) {
105		char *end;
106	case '1':
107		markinfo->mode = XT_CONNMARK_SET;
108
109		markinfo->mark = strtoul(optarg, &end, 0);
110		if (*end == '/' && end[1] != '\0')
111		    markinfo->mask = strtoul(end+1, &end, 0);
112
113		if (*end != '\0' || end == optarg)
114			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
115		if (*flags)
116			xtables_error(PARAMETER_PROBLEM,
117			           "CONNMARK target: Can't specify --set-mark twice");
118		*flags = 1;
119		break;
120	case '2':
121		markinfo->mode = XT_CONNMARK_SAVE;
122		if (*flags)
123			xtables_error(PARAMETER_PROBLEM,
124			           "CONNMARK target: Can't specify --save-mark twice");
125		*flags = 1;
126		break;
127	case '3':
128		markinfo->mode = XT_CONNMARK_RESTORE;
129		if (*flags)
130			xtables_error(PARAMETER_PROBLEM,
131			           "CONNMARK target: Can't specify --restore-mark twice");
132		*flags = 1;
133		break;
134	case '4':
135		if (!*flags)
136			xtables_error(PARAMETER_PROBLEM,
137			           "CONNMARK target: Can't specify --mask without a operation");
138		markinfo->mask = strtoul(optarg, &end, 0);
139
140		if (*end != '\0' || end == optarg)
141			xtables_error(PARAMETER_PROBLEM, "Bad MASK value \"%s\"", optarg);
142		break;
143	default:
144		return 0;
145	}
146
147	return 1;
148}
149
150static int connmark_tg_parse(int c, char **argv, int invert,
151                             unsigned int *flags, const void *entry,
152                             struct xt_entry_target **target)
153{
154	struct xt_connmark_tginfo1 *info = (void *)(*target)->data;
155	unsigned int value, mask = UINT32_MAX;
156	char *end;
157
158	switch (c) {
159	case '=': /* --set-xmark */
160	case '-': /* --set-mark */
161		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
162		if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX))
163			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
164		if (*end == '/')
165			if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
166				xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
167		if (*end != '\0')
168			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
169		info->mode   = XT_CONNMARK_SET;
170		info->ctmark = value;
171		info->ctmask = mask;
172		if (c == '-')
173			info->ctmask |= value;
174		*flags |= F_MARK;
175		return true;
176
177	case '&': /* --and-mark */
178		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
179		if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX))
180			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--and-mark", optarg);
181		info->mode   = XT_CONNMARK_SET;
182		info->ctmark = 0;
183		info->ctmask = ~mask;
184		*flags      |= F_MARK;
185		return true;
186
187	case '|': /* --or-mark */
188		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
189		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
190			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--or-mark", optarg);
191		info->mode   = XT_CONNMARK_SET;
192		info->ctmark = value;
193		info->ctmask = value;
194		*flags      |= F_MARK;
195		return true;
196
197	case '^': /* --xor-mark */
198		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
199		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
200			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--xor-mark", optarg);
201		info->mode   = XT_CONNMARK_SET;
202		info->ctmark = value;
203		info->ctmask = 0;
204		*flags      |= F_MARK;
205		return true;
206
207	case 'S': /* --save-mark */
208		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
209		info->mode = XT_CONNMARK_SAVE;
210		*flags |= F_MARK | F_SR_MARK;
211		return true;
212
213	case 'R': /* --restore-mark */
214		xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK);
215		info->mode = XT_CONNMARK_RESTORE;
216		*flags |= F_MARK | F_SR_MARK;
217		return true;
218
219	case 'n': /* --nfmask */
220		if (!(*flags & F_SR_MARK))
221			xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
222			           "or --restore-mark is required for "
223			           "--nfmask");
224		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
225			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--nfmask", optarg);
226		info->nfmask = value;
227		return true;
228
229	case 'c': /* --ctmask */
230		if (!(*flags & F_SR_MARK))
231			xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
232			           "or --restore-mark is required for "
233			           "--ctmask");
234		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
235			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--ctmask", optarg);
236		info->ctmask = value;
237		return true;
238
239	case 'm': /* --mask */
240		if (!(*flags & F_SR_MARK))
241			xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
242			           "or --restore-mark is required for "
243			           "--mask");
244		if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX))
245			xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--mask", optarg);
246		info->nfmask = info->ctmask = value;
247		return true;
248	}
249
250	return false;
251}
252
253static void connmark_tg_check(unsigned int flags)
254{
255	if (!flags)
256		xtables_error(PARAMETER_PROBLEM,
257		           "CONNMARK target: No operation specified");
258}
259
260static void
261print_mark(unsigned long mark)
262{
263	printf("0x%lx", mark);
264}
265
266static void
267print_mask(const char *text, unsigned long mask)
268{
269	if (mask != 0xffffffffUL)
270		printf("%s0x%lx", text, mask);
271}
272
273static void CONNMARK_print(const void *ip,
274                           const struct xt_entry_target *target, int numeric)
275{
276	const struct xt_connmark_target_info *markinfo =
277		(const struct xt_connmark_target_info *)target->data;
278	switch (markinfo->mode) {
279	case XT_CONNMARK_SET:
280	    printf("CONNMARK set ");
281	    print_mark(markinfo->mark);
282	    print_mask("/", markinfo->mask);
283	    printf(" ");
284	    break;
285	case XT_CONNMARK_SAVE:
286	    printf("CONNMARK save ");
287	    print_mask("mask ", markinfo->mask);
288	    printf(" ");
289	    break;
290	case XT_CONNMARK_RESTORE:
291	    printf("CONNMARK restore ");
292	    print_mask("mask ", markinfo->mask);
293	    break;
294	default:
295	    printf("ERROR: UNKNOWN CONNMARK MODE ");
296	    break;
297	}
298}
299
300static void
301connmark_tg_print(const void *ip, const struct xt_entry_target *target,
302                  int numeric)
303{
304	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
305
306	switch (info->mode) {
307	case XT_CONNMARK_SET:
308		if (info->ctmark == 0)
309			printf("CONNMARK and 0x%x ",
310			       (unsigned int)(u_int32_t)~info->ctmask);
311		else if (info->ctmark == info->ctmask)
312			printf("CONNMARK or 0x%x ", info->ctmark);
313		else if (info->ctmask == 0)
314			printf("CONNMARK xor 0x%x ", info->ctmark);
315		else if (info->ctmask == 0xFFFFFFFFU)
316			printf("CONNMARK set 0x%x ", info->ctmark);
317		else
318			printf("CONNMARK xset 0x%x/0x%x ",
319			       info->ctmark, info->ctmask);
320		break;
321	case XT_CONNMARK_SAVE:
322		if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)
323			printf("CONNMARK save ");
324		else if (info->nfmask == info->ctmask)
325			printf("CONNMARK save mask 0x%x ", info->nfmask);
326		else
327			printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ",
328			       info->nfmask, info->ctmask);
329		break;
330	case XT_CONNMARK_RESTORE:
331		if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX)
332			printf("CONNMARK restore ");
333		else if (info->ctmask == info->nfmask)
334			printf("CONNMARK restore mask 0x%x ", info->ctmask);
335		else
336			printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ",
337			       info->ctmask, info->nfmask);
338		break;
339
340	default:
341		printf("ERROR: UNKNOWN CONNMARK MODE");
342		break;
343	}
344}
345
346static void CONNMARK_save(const void *ip, const struct xt_entry_target *target)
347{
348	const struct xt_connmark_target_info *markinfo =
349		(const struct xt_connmark_target_info *)target->data;
350
351	switch (markinfo->mode) {
352	case XT_CONNMARK_SET:
353	    printf("--set-mark ");
354	    print_mark(markinfo->mark);
355	    print_mask("/", markinfo->mask);
356	    printf(" ");
357	    break;
358	case XT_CONNMARK_SAVE:
359	    printf("--save-mark ");
360	    print_mask("--mask ", markinfo->mask);
361	    break;
362	case XT_CONNMARK_RESTORE:
363	    printf("--restore-mark ");
364	    print_mask("--mask ", markinfo->mask);
365	    break;
366	default:
367	    printf("ERROR: UNKNOWN CONNMARK MODE ");
368	    break;
369	}
370}
371
372static void CONNMARK_init(struct xt_entry_target *t)
373{
374	struct xt_connmark_target_info *markinfo
375		= (struct xt_connmark_target_info *)t->data;
376
377	markinfo->mask = 0xffffffffUL;
378}
379
380static void
381connmark_tg_save(const void *ip, const struct xt_entry_target *target)
382{
383	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
384
385	switch (info->mode) {
386	case XT_CONNMARK_SET:
387		printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask);
388		break;
389	case XT_CONNMARK_SAVE:
390		printf("--save-mark --nfmask 0x%x --ctmask 0x%x ",
391		       info->nfmask, info->ctmask);
392		break;
393	case XT_CONNMARK_RESTORE:
394		printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ",
395		       info->nfmask, info->ctmask);
396		break;
397	default:
398		printf("ERROR: UNKNOWN CONNMARK MODE");
399		break;
400	}
401}
402
403static struct xtables_target connmark_tg_reg[] = {
404	{
405		.family        = NFPROTO_UNSPEC,
406		.name          = "CONNMARK",
407		.revision      = 0,
408		.version       = XTABLES_VERSION,
409		.size          = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
410		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
411		.help          = CONNMARK_help,
412		.init          = CONNMARK_init,
413		.parse         = CONNMARK_parse,
414		.final_check   = connmark_tg_check,
415		.print         = CONNMARK_print,
416		.save          = CONNMARK_save,
417		.extra_opts    = CONNMARK_opts,
418	},
419	{
420		.version       = XTABLES_VERSION,
421		.name          = "CONNMARK",
422		.revision      = 1,
423		.family        = NFPROTO_UNSPEC,
424		.size          = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
425		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
426		.help          = connmark_tg_help,
427		.init          = connmark_tg_init,
428		.parse         = connmark_tg_parse,
429		.final_check   = connmark_tg_check,
430		.print         = connmark_tg_print,
431		.save          = connmark_tg_save,
432		.extra_opts    = connmark_tg_opts,
433	},
434};
435
436void _init(void)
437{
438	xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
439}
440