libxt_mark.c revision 5180032804c03225542368aaaf19060fe7a47a1c
1/* Shared library add-on to iptables to add NFMARK matching support. */
2#include <stdbool.h>
3#include <stdio.h>
4#include <netdb.h>
5#include <string.h>
6#include <stdlib.h>
7#include <getopt.h>
8
9#include <xtables.h>
10#include <linux/netfilter/xt_mark.h>
11
12enum {
13	F_MARK = 1 << 0,
14};
15
16static void mark_mt_help(void)
17{
18	printf(
19"mark match options:\n"
20"[!] --mark value[/mask]    Match nfmark value with optional mask\n"
21"\n");
22}
23
24static const struct option mark_mt_opts[] = {
25	{.name = "mark", .has_arg = true, .val = '1'},
26	{ .name = NULL }
27};
28
29static int mark_mt_parse(int c, char **argv, int invert, unsigned int *flags,
30                         const void *entry, struct xt_entry_match **match)
31{
32	struct xt_mark_mtinfo1 *info = (void *)(*match)->data;
33	unsigned int mark, mask = ~0U;
34	char *end;
35
36	switch (c) {
37	case '1': /* --mark */
38		param_act(P_ONLY_ONCE, "mark", "--mark", *flags & F_MARK);
39		if (!strtonum(optarg, &end, &mark, 0, ~0U))
40			param_act(P_BAD_VALUE, "mark", "--mark", optarg);
41		if (*end == '/')
42			if (!strtonum(end + 1, &end, &mask, 0, ~0U))
43				param_act(P_BAD_VALUE, "mark", "--mark", optarg);
44		if (*end != '\0')
45			param_act(P_BAD_VALUE, "mark", "--mark", optarg);
46
47		if (invert)
48			info->invert = true;
49		info->mark = mark;
50		info->mask = mask;
51		*flags    |= F_MARK;
52		return true;
53	}
54	return false;
55}
56
57/* Function which parses command options; returns true if it
58   ate an option */
59static int
60mark_parse(int c, char **argv, int invert, unsigned int *flags,
61           const void *entry, struct xt_entry_match **match)
62{
63	struct xt_mark_info *markinfo = (struct xt_mark_info *)(*match)->data;
64
65	switch (c) {
66		char *end;
67	case '1':
68		check_inverse(optarg, &invert, &optind, 0);
69		markinfo->mark = strtoul(optarg, &end, 0);
70		if (*end == '/') {
71			markinfo->mask = strtoul(end+1, &end, 0);
72		} else
73			markinfo->mask = 0xffffffff;
74		if (*end != '\0' || end == optarg)
75			exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
76		if (invert)
77			markinfo->invert = 1;
78		*flags = 1;
79		break;
80
81	default:
82		return 0;
83	}
84	return 1;
85}
86
87static void print_mark(unsigned int mark, unsigned int mask)
88{
89	if (mask != 0xffffffffU)
90		printf("0x%x/0x%x ", mark, mask);
91	else
92		printf("0x%x ", mark);
93}
94
95static void mark_mt_check(unsigned int flags)
96{
97	if (flags == 0)
98		exit_error(PARAMETER_PROBLEM,
99			   "mark match: The --mark option is required");
100}
101
102static void
103mark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric)
104{
105	const struct xt_mark_mtinfo1 *info = (const void *)match->data;
106
107	printf("mark match ");
108	if (info->invert)
109		printf("!");
110	print_mark(info->mark, info->mask);
111}
112
113/* Prints out the matchinfo. */
114static void
115mark_print(const void *ip, const struct xt_entry_match *match, int numeric)
116{
117	struct xt_mark_info *info = (struct xt_mark_info *)match->data;
118
119	printf("MARK match ");
120
121	if (info->invert)
122		printf("!");
123
124	print_mark(info->mark, info->mask);
125}
126
127static void mark_mt_save(const void *ip, const struct xt_entry_match *match)
128{
129	const struct xt_mark_mtinfo1 *info = (const void *)match->data;
130
131	if (info->invert)
132		printf("!");
133
134	printf("--mark ");
135	print_mark(info->mark, info->mask);
136}
137
138/* Saves the union ipt_matchinfo in parsable form to stdout. */
139static void
140mark_save(const void *ip, const struct xt_entry_match *match)
141{
142	struct xt_mark_info *info = (struct xt_mark_info *)match->data;
143
144	if (info->invert)
145		printf("! ");
146
147	printf("--mark ");
148	print_mark(info->mark, info->mask);
149}
150
151static struct xtables_match mark_match = {
152	.family		= AF_INET,
153	.name		= "mark",
154	.revision	= 0,
155	.version	= IPTABLES_VERSION,
156	.size		= XT_ALIGN(sizeof(struct xt_mark_info)),
157	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_info)),
158	.help		= mark_mt_help,
159	.parse		= mark_parse,
160	.final_check	= mark_mt_check,
161	.print		= mark_print,
162	.save		= mark_save,
163	.extra_opts	= mark_mt_opts,
164};
165
166static struct xtables_match mark_match6 = {
167	.family		= AF_INET6,
168	.name		= "mark",
169	.revision	= 0,
170	.version	= IPTABLES_VERSION,
171	.size		= XT_ALIGN(sizeof(struct xt_mark_info)),
172	.userspacesize	= XT_ALIGN(sizeof(struct xt_mark_info)),
173	.help		= mark_mt_help,
174	.parse		= mark_parse,
175	.final_check	= mark_mt_check,
176	.print		= mark_print,
177	.save		= mark_save,
178	.extra_opts	= mark_mt_opts,
179};
180
181static struct xtables_match mark_mt_reg = {
182	.version        = IPTABLES_VERSION,
183	.name           = "mark",
184	.revision       = 1,
185	.family         = AF_INET,
186	.size           = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
187	.userspacesize  = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
188	.help           = mark_mt_help,
189	.parse          = mark_mt_parse,
190	.final_check    = mark_mt_check,
191	.print          = mark_mt_print,
192	.save           = mark_mt_save,
193	.extra_opts     = mark_mt_opts,
194};
195
196static struct xtables_match mark_mt6_reg = {
197	.version        = IPTABLES_VERSION,
198	.name           = "mark",
199	.revision       = 1,
200	.family         = AF_INET6,
201	.size           = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
202	.userspacesize  = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)),
203	.help           = mark_mt_help,
204	.parse          = mark_mt_parse,
205	.final_check    = mark_mt_check,
206	.print          = mark_mt_print,
207	.save           = mark_mt_save,
208	.extra_opts     = mark_mt_opts,
209};
210
211void _init(void)
212{
213	xtables_register_match(&mark_match);
214	xtables_register_match(&mark_match6);
215	xtables_register_match(&mark_mt_reg);
216	xtables_register_match(&mark_mt6_reg);
217}
218