libxt_CONNMARK.c revision 03d99486d8283552705b58dc55b6085dffc38792
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 = ~0U;
94	info->nfmask = ~0U;
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			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
115		if (*flags)
116			exit_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			exit_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			exit_error(PARAMETER_PROBLEM,
131			           "CONNMARK target: Can't specify --restore-mark twice");
132		*flags = 1;
133		break;
134	case '4':
135		if (!*flags)
136			exit_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			exit_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 = ~0U;
156	char *end;
157
158	switch (c) {
159	case '=': /* --set-xmark */
160	case '-': /* --set-mark */
161		param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
162		if (!strtonum(optarg, &end, &value, 0, ~0U))
163			param_act(P_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
164		if (*end == '/')
165			if (!strtonum(end + 1, &end, &mask, 0, ~0U))
166				param_act(P_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg);
167		if (*end != '\0')
168			param_act(P_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		param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
179		if (!strtonum(optarg, NULL, &mask, 0, ~0U))
180			param_act(P_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		param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
189		if (!strtonum(optarg, NULL, &value, 0, ~0U))
190			param_act(P_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		param_act(P_ONE_ACTION, "CONNMARK", *flags & F_MARK);
199		if (!strtonum(optarg, NULL, &value, 0, ~0U))
200			param_act(P_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		param_act(P_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		param_act(P_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			exit_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
222			           "or --restore-mark is required for "
223			           "--nfmask");
224		if (!strtonum(optarg, NULL, &value, 0, ~0U))
225			param_act(P_BAD_VALUE, "CONNMARK", "--nfmask", optarg);
226		info->nfmask = value;
227		return true;
228
229	case 'c': /* --ctmask */
230		if (!(*flags & F_SR_MARK))
231			exit_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
232			           "or --restore-mark is required for "
233			           "--ctmask");
234		if (!strtonum(optarg, NULL, &value, 0, ~0U))
235			param_act(P_BAD_VALUE, "CONNMARK", "--ctmask", optarg);
236		info->ctmask = value;
237		return true;
238
239	case 'm': /* --mask */
240		if (!(*flags & F_SR_MARK))
241			exit_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark "
242			           "or --restore-mark is required for "
243			           "--mask");
244		if (!strtonum(optarg, NULL, &value, 0, ~0U))
245			param_act(P_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		exit_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 == ~0U && info->ctmask == ~0U)
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 == ~0U && info->nfmask == ~0U)
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_target = {
402	.family		= NFPROTO_IPV4,
403	.name		= "CONNMARK",
404	.revision	= 0,
405	.version	= XTABLES_VERSION,
406	.size		= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
407	.userspacesize	= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
408	.help		= CONNMARK_help,
409	.init           = CONNMARK_init,
410	.parse		= CONNMARK_parse,
411	.final_check	= connmark_tg_check,
412	.print		= CONNMARK_print,
413	.save		= CONNMARK_save,
414	.extra_opts	= CONNMARK_opts,
415};
416
417static struct xtables_target connmark_target6 = {
418	.family		= NFPROTO_IPV6,
419	.name		= "CONNMARK",
420	.revision	= 0,
421	.version	= XTABLES_VERSION,
422	.size		= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
423	.userspacesize	= XT_ALIGN(sizeof(struct xt_connmark_target_info)),
424	.help		= CONNMARK_help,
425	.init           = CONNMARK_init,
426	.parse		= CONNMARK_parse,
427	.final_check	= connmark_tg_check,
428	.print		= CONNMARK_print,
429	.save		= CONNMARK_save,
430	.extra_opts	= CONNMARK_opts,
431};
432
433static struct xtables_target connmark_tg_reg = {
434	.version        = XTABLES_VERSION,
435	.name           = "CONNMARK",
436	.revision       = 1,
437	.family         = NFPROTO_IPV4,
438	.size           = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
439	.userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
440	.help           = connmark_tg_help,
441	.init           = connmark_tg_init,
442	.parse          = connmark_tg_parse,
443	.final_check    = connmark_tg_check,
444	.print          = connmark_tg_print,
445	.save           = connmark_tg_save,
446	.extra_opts     = connmark_tg_opts,
447};
448
449static struct xtables_target connmark_tg6_reg = {
450	.version        = XTABLES_VERSION,
451	.name           = "CONNMARK",
452	.revision       = 1,
453	.family         = NFPROTO_IPV6,
454	.size           = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
455	.userspacesize  = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)),
456	.help           = connmark_tg_help,
457	.init           = connmark_tg_init,
458	.parse          = connmark_tg_parse,
459	.final_check    = connmark_tg_check,
460	.print          = connmark_tg_print,
461	.save           = connmark_tg_save,
462	.extra_opts     = connmark_tg_opts,
463};
464
465void _init(void)
466{
467	xtables_register_target(&connmark_target);
468	xtables_register_target(&connmark_target6);
469	xtables_register_target(&connmark_tg_reg);
470	xtables_register_target(&connmark_tg6_reg);
471}
472