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