libxt_addrtype.c revision 0c3753b1d4226a6e7bea9619415cf40cadee1e58
1/* Shared library add-on to iptables to add addrtype matching support
2 *
3 * Copyright (c) 2003-2013 Patrick McHardy <kaber@trash.net>
4 *
5 * This program is released under the terms of GNU GPL */
6#include <stdio.h>
7#include <string.h>
8#include <xtables.h>
9#include <linux/netfilter/xt_addrtype.h>
10
11enum {
12	O_SRC_TYPE = 0,
13	O_DST_TYPE,
14	O_LIMIT_IFACE_IN,
15	O_LIMIT_IFACE_OUT,
16	F_SRC_TYPE        = 1 << O_SRC_TYPE,
17	F_DST_TYPE        = 1 << O_DST_TYPE,
18	F_LIMIT_IFACE_IN  = 1 << O_LIMIT_IFACE_IN,
19	F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
20};
21
22/* from linux/rtnetlink.h, must match order of enumeration */
23static const char *const rtn_names[] = {
24	"UNSPEC",
25	"UNICAST",
26	"LOCAL",
27	"BROADCAST",
28	"ANYCAST",
29	"MULTICAST",
30	"BLACKHOLE",
31	"UNREACHABLE",
32	"PROHIBIT",
33	"THROW",
34	"NAT",
35	"XRESOLVE",
36	NULL
37};
38
39static void addrtype_help_types(void)
40{
41	int i;
42
43	for (i = 0; rtn_names[i]; i++)
44		printf("                                %s\n", rtn_names[i]);
45}
46
47static void addrtype_help_v0(void)
48{
49	printf(
50"Address type match options:\n"
51" [!] --src-type type[,...]      Match source address type\n"
52" [!] --dst-type type[,...]      Match destination address type\n"
53"\n"
54"Valid types:           \n");
55	addrtype_help_types();
56}
57
58static void addrtype_help_v1(void)
59{
60	printf(
61"Address type match options:\n"
62" [!] --src-type type[,...]      Match source address type\n"
63" [!] --dst-type type[,...]      Match destination address type\n"
64"     --limit-iface-in           Match only on the packet's incoming device\n"
65"     --limit-iface-out          Match only on the packet's outgoing device\n"
66"\n"
67"Valid types:           \n");
68	addrtype_help_types();
69}
70
71static int
72parse_type(const char *name, size_t len, uint16_t *mask)
73{
74	int i;
75
76	for (i = 0; rtn_names[i]; i++)
77		if (strncasecmp(name, rtn_names[i], len) == 0) {
78			/* build up bitmask for kernel module */
79			*mask |= (1 << i);
80			return 1;
81		}
82
83	return 0;
84}
85
86static void parse_types(const char *arg, uint16_t *mask)
87{
88	const char *comma;
89
90	while ((comma = strchr(arg, ',')) != NULL) {
91		if (comma == arg || !parse_type(arg, comma-arg, mask))
92			xtables_error(PARAMETER_PROBLEM,
93			           "addrtype: bad type `%s'", arg);
94		arg = comma + 1;
95	}
96
97	if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
98		xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
99}
100
101static void addrtype_parse_v0(struct xt_option_call *cb)
102{
103	struct xt_addrtype_info *info = cb->data;
104
105	xtables_option_parse(cb);
106	switch (cb->entry->id) {
107	case O_SRC_TYPE:
108		parse_types(cb->arg, &info->source);
109		if (cb->invert)
110			info->invert_source = 1;
111		break;
112	case O_DST_TYPE:
113		parse_types(cb->arg, &info->dest);
114		if (cb->invert)
115			info->invert_dest = 1;
116		break;
117	}
118}
119
120static void addrtype_parse_v1(struct xt_option_call *cb)
121{
122	struct xt_addrtype_info_v1 *info = cb->data;
123
124	xtables_option_parse(cb);
125	switch (cb->entry->id) {
126	case O_SRC_TYPE:
127		parse_types(cb->arg, &info->source);
128		if (cb->invert)
129			info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
130		break;
131	case O_DST_TYPE:
132		parse_types(cb->arg, &info->dest);
133		if (cb->invert)
134			info->flags |= XT_ADDRTYPE_INVERT_DEST;
135		break;
136	case O_LIMIT_IFACE_IN:
137		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
138		break;
139	case O_LIMIT_IFACE_OUT:
140		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
141		break;
142	}
143}
144
145static void addrtype_check(struct xt_fcheck_call *cb)
146{
147	if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
148		xtables_error(PARAMETER_PROBLEM,
149			   "addrtype: you must specify --src-type or --dst-type");
150}
151
152static void print_types(uint16_t mask)
153{
154	const char *sep = "";
155	int i;
156
157	for (i = 0; rtn_names[i]; i++)
158		if (mask & (1 << i)) {
159			printf("%s%s", sep, rtn_names[i]);
160			sep = ",";
161		}
162}
163
164static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
165                              int numeric)
166{
167	const struct xt_addrtype_info *info = (const void *)match->data;
168
169	printf(" ADDRTYPE match");
170	if (info->source) {
171		printf(" src-type ");
172		if (info->invert_source)
173			printf("!");
174		print_types(info->source);
175	}
176	if (info->dest) {
177		printf(" dst-type");
178		if (info->invert_dest)
179			printf("!");
180		print_types(info->dest);
181	}
182}
183
184static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
185                              int numeric)
186{
187	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
188
189	printf(" ADDRTYPE match");
190	if (info->source) {
191		printf(" src-type ");
192		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
193			printf("!");
194		print_types(info->source);
195	}
196	if (info->dest) {
197		printf(" dst-type ");
198		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
199			printf("!");
200		print_types(info->dest);
201	}
202	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
203		printf(" limit-in");
204	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
205		printf(" limit-out");
206}
207
208static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
209{
210	const struct xt_addrtype_info *info = (const void *)match->data;
211
212	if (info->source) {
213		if (info->invert_source)
214			printf(" !");
215		printf(" --src-type ");
216		print_types(info->source);
217	}
218	if (info->dest) {
219		if (info->invert_dest)
220			printf(" !");
221		printf(" --dst-type ");
222		print_types(info->dest);
223	}
224}
225
226static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
227{
228	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
229
230	if (info->source) {
231		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
232			printf(" !");
233		printf(" --src-type ");
234		print_types(info->source);
235	}
236	if (info->dest) {
237		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
238			printf(" !");
239		printf(" --dst-type ");
240		print_types(info->dest);
241	}
242	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
243		printf(" --limit-iface-in");
244	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
245		printf(" --limit-iface-out");
246}
247
248static const struct xt_option_entry addrtype_opts_v0[] = {
249	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
250	 .flags = XTOPT_INVERT},
251	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
252	 .flags = XTOPT_INVERT},
253	XTOPT_TABLEEND,
254};
255
256static const struct xt_option_entry addrtype_opts_v1[] = {
257	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
258	 .flags = XTOPT_INVERT},
259	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
260	 .flags = XTOPT_INVERT},
261	{.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
262	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
263	{.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
264	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
265	XTOPT_TABLEEND,
266};
267
268static struct xtables_match addrtype_mt_reg[] = {
269	{
270		.name          = "addrtype",
271		.version       = XTABLES_VERSION,
272		.family        = NFPROTO_IPV4,
273		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info)),
274		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
275		.help          = addrtype_help_v0,
276		.print         = addrtype_print_v0,
277		.save          = addrtype_save_v0,
278		.x6_parse      = addrtype_parse_v0,
279		.x6_fcheck     = addrtype_check,
280		.x6_options    = addrtype_opts_v0,
281	},
282	{
283		.name          = "addrtype",
284		.revision      = 1,
285		.version       = XTABLES_VERSION,
286		.family        = NFPROTO_UNSPEC,
287		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
288		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
289		.help          = addrtype_help_v1,
290		.print         = addrtype_print_v1,
291		.save          = addrtype_save_v1,
292		.x6_parse      = addrtype_parse_v1,
293		.x6_fcheck     = addrtype_check,
294		.x6_options    = addrtype_opts_v1,
295	},
296};
297
298
299void _init(void)
300{
301	xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
302}
303