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