libxt_CONNMARK.c revision f2a77520693f0a6dd1df1f87be4b81913961c1f5
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
316			printf("CONNMARK xset 0x%x/0x%x ",
317			       info->ctmark, info->ctmask);
318		break;
319	case XT_CONNMARK_SAVE:
320		if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX)
321			printf("CONNMARK save ");
322		else if (info->nfmask == info->ctmask)
323			printf("CONNMARK save mask 0x%x ", info->nfmask);
324		else
325			printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ",
326			       info->nfmask, info->ctmask);
327		break;
328	case XT_CONNMARK_RESTORE:
329		if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX)
330			printf("CONNMARK restore ");
331		else if (info->ctmask == info->nfmask)
332			printf("CONNMARK restore mask 0x%x ", info->ctmask);
333		else
334			printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ",
335			       info->ctmask, info->nfmask);
336		break;
337
338	default:
339		printf("ERROR: UNKNOWN CONNMARK MODE");
340		break;
341	}
342}
343
344static void CONNMARK_save(const void *ip, const struct xt_entry_target *target)
345{
346	const struct xt_connmark_target_info *markinfo =
347		(const struct xt_connmark_target_info *)target->data;
348
349	switch (markinfo->mode) {
350	case XT_CONNMARK_SET:
351	    printf("--set-mark ");
352	    print_mark(markinfo->mark);
353	    print_mask("/", markinfo->mask);
354	    printf(" ");
355	    break;
356	case XT_CONNMARK_SAVE:
357	    printf("--save-mark ");
358	    print_mask("--mask ", markinfo->mask);
359	    break;
360	case XT_CONNMARK_RESTORE:
361	    printf("--restore-mark ");
362	    print_mask("--mask ", markinfo->mask);
363	    break;
364	default:
365	    printf("ERROR: UNKNOWN CONNMARK MODE ");
366	    break;
367	}
368}
369
370static void CONNMARK_init(struct xt_entry_target *t)
371{
372	struct xt_connmark_target_info *markinfo
373		= (struct xt_connmark_target_info *)t->data;
374
375	markinfo->mask = 0xffffffffUL;
376}
377
378static void
379connmark_tg_save(const void *ip, const struct xt_entry_target *target)
380{
381	const struct xt_connmark_tginfo1 *info = (const void *)target->data;
382
383	switch (info->mode) {
384	case XT_CONNMARK_SET:
385		printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask);
386		break;
387	case XT_CONNMARK_SAVE:
388		printf("--save-mark --nfmask 0x%x --ctmask 0x%x ",
389		       info->nfmask, info->ctmask);
390		break;
391	case XT_CONNMARK_RESTORE:
392		printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ",
393		       info->nfmask, info->ctmask);
394		break;
395	default:
396		printf("ERROR: UNKNOWN CONNMARK MODE");
397		break;
398	}
399}
400
401static struct xtables_target connmark_tg_reg[] = {
402	{
403		.family        = NFPROTO_UNSPEC,
404		.name          = "CONNMARK",
405		.revision      = 0,
406		.version       = XTABLES_VERSION,
407		.size          = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
408		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)),
409		.help          = CONNMARK_help,
410		.init          = CONNMARK_init,
411		.parse         = CONNMARK_parse,
412		.final_check   = connmark_tg_check,
413		.print         = CONNMARK_print,
414		.save          = CONNMARK_save,
415		.extra_opts    = CONNMARK_opts,
416	},
417	{
418		.version       = XTABLES_VERSION,
419		.name          = "CONNMARK",
420		.revision      = 1,
421		.family        = NFPROTO_UNSPEC,
422		.size          = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
423		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
424		.help          = connmark_tg_help,
425		.init          = connmark_tg_init,
426		.parse         = connmark_tg_parse,
427		.final_check   = connmark_tg_check,
428		.print         = connmark_tg_print,
429		.save          = connmark_tg_save,
430		.extra_opts    = connmark_tg_opts,
431	},
432};
433
434void _init(void)
435{
436	xtables_register_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg));
437}
438