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