libxt_connmark.c revision 32b8e61e4e5bd405d9ad07bf9468498dfbb19f9e
1/* Shared library add-on to iptables to add connmark matching 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 <netdb.h>
25#include <string.h>
26#include <stdlib.h>
27#include <getopt.h>
28
29#include <xtables.h>
30#include <linux/netfilter/xt_connmark.h>
31
32struct xt_connmark_info {
33	unsigned long mark, mask;
34	u_int8_t invert;
35};
36
37enum {
38	F_MARK = 1 << 0,
39};
40
41static void connmark_mt_help(void)
42{
43	printf(
44"connmark match options:\n"
45"[!] --mark value[/mask]    Match ctmark value with optional mask\n");
46}
47
48static const struct option connmark_mt_opts[] = {
49	{.name = "mark", .has_arg = true, .val = '1'},
50	XT_GETOPT_TABLEEND,
51};
52
53static int
54connmark_mt_parse(int c, char **argv, int invert, unsigned int *flags,
55                  const void *entry, struct xt_entry_match **match)
56{
57	struct xt_connmark_mtinfo1 *info = (void *)(*match)->data;
58	unsigned int mark, mask = UINT32_MAX;
59	char *end;
60
61	switch (c) {
62	case '1': /* --mark */
63		xtables_param_act(XTF_ONLY_ONCE, "connmark", "--mark", *flags & F_MARK);
64		if (!xtables_strtoui(optarg, &end, &mark, 0, UINT32_MAX))
65			xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg);
66		if (*end == '/')
67			if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX))
68				xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg);
69		if (*end != '\0')
70			xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg);
71
72		if (invert)
73			info->invert = true;
74		info->mark = mark;
75		info->mask = mask;
76		*flags    |= F_MARK;
77		return true;
78	}
79	return false;
80}
81
82static int
83connmark_parse(int c, char **argv, int invert, unsigned int *flags,
84               const void *entry, struct xt_entry_match **match)
85{
86	struct xt_connmark_info *markinfo = (struct xt_connmark_info *)(*match)->data;
87
88	switch (c) {
89		char *end;
90	case '1':
91		xtables_check_inverse(optarg, &invert, &optind, 0, argv);
92
93		markinfo->mark = strtoul(optarg, &end, 0);
94		markinfo->mask = 0xffffffffUL;
95
96		if (*end == '/')
97			markinfo->mask = strtoul(end+1, &end, 0);
98
99		if (*end != '\0' || end == optarg)
100			xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg);
101		if (invert)
102			markinfo->invert = 1;
103		*flags = 1;
104		break;
105
106	default:
107		return 0;
108	}
109	return 1;
110}
111
112static void print_mark(unsigned int mark, unsigned int mask)
113{
114	if (mask != 0xffffffffU)
115		printf("0x%x/0x%x ", mark, mask);
116	else
117		printf("0x%x ", mark);
118}
119
120static void connmark_mt_check(unsigned int flags)
121{
122	if (flags == 0)
123		xtables_error(PARAMETER_PROBLEM,
124		           "connmark: The --mark option is required");
125}
126
127static void
128connmark_print(const void *ip, const struct xt_entry_match *match, int numeric)
129{
130	const struct xt_connmark_info *info = (const void *)match->data;
131
132	printf("CONNMARK match ");
133	if (info->invert)
134		printf("!");
135	print_mark(info->mark, info->mask);
136}
137
138static void
139connmark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
140{
141	const struct xt_connmark_mtinfo1 *info = (const void *)match->data;
142
143	printf("connmark match ");
144	if (info->invert)
145		printf("!");
146	print_mark(info->mark, info->mask);
147}
148
149static void connmark_save(const void *ip, const struct xt_entry_match *match)
150{
151	const struct xt_connmark_info *info = (const void *)match->data;
152
153	if (info->invert)
154		printf("! ");
155
156	printf("--mark ");
157	print_mark(info->mark, info->mask);
158}
159
160static void
161connmark_mt_save(const void *ip, const struct xt_entry_match *match)
162{
163	const struct xt_connmark_mtinfo1 *info = (const void *)match->data;
164
165	if (info->invert)
166		printf("! ");
167
168	printf("--mark ");
169	print_mark(info->mark, info->mask);
170}
171
172static struct xtables_match connmark_mt_reg[] = {
173	{
174		.family        = NFPROTO_UNSPEC,
175		.name          = "connmark",
176		.revision      = 0,
177		.version       = XTABLES_VERSION,
178		.size          = XT_ALIGN(sizeof(struct xt_connmark_info)),
179		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_info)),
180		.help          = connmark_mt_help,
181		.parse         = connmark_parse,
182		.final_check   = connmark_mt_check,
183		.print         = connmark_print,
184		.save          = connmark_save,
185		.extra_opts    = connmark_mt_opts,
186	},
187	{
188		.version       = XTABLES_VERSION,
189		.name          = "connmark",
190		.revision      = 1,
191		.family        = NFPROTO_UNSPEC,
192		.size          = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)),
193		.userspacesize = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)),
194		.help          = connmark_mt_help,
195		.parse         = connmark_mt_parse,
196		.final_check   = connmark_mt_check,
197		.print         = connmark_mt_print,
198		.save          = connmark_mt_save,
199		.extra_opts    = connmark_mt_opts,
200	},
201};
202
203void _init(void)
204{
205	xtables_register_matches(connmark_mt_reg, ARRAY_SIZE(connmark_mt_reg));
206}
207