libxt_addrtype.c revision 807e1f0e6ede73792337b595a99af21b01f8826e
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/xt_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 outgoing 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 xt_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 xt_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 |= XT_ADDRTYPE_INVERT_SOURCE;
128		break;
129	case O_DST_TYPE:
130		parse_types(cb->arg, &info->dest);
131		if (cb->invert)
132			info->flags |= XT_ADDRTYPE_INVERT_DEST;
133		break;
134	case O_LIMIT_IFACE_IN:
135		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
136		break;
137	case O_LIMIT_IFACE_OUT:
138		info->flags |= XT_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 xt_addrtype_info *info = (const void *)match->data;
166
167	printf(" ADDRTYPE match");
168	if (info->source) {
169		printf(" src-type ");
170		if (info->invert_source)
171			printf("!");
172		print_types(info->source);
173	}
174	if (info->dest) {
175		printf(" dst-type");
176		if (info->invert_dest)
177			printf("!");
178		print_types(info->dest);
179	}
180}
181
182static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
183                              int numeric)
184{
185	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
186
187	printf(" ADDRTYPE match");
188	if (info->source) {
189		printf(" src-type ");
190		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
191			printf("!");
192		print_types(info->source);
193	}
194	if (info->dest) {
195		printf(" dst-type ");
196		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
197			printf("!");
198		print_types(info->dest);
199	}
200	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
201		printf(" limit-in");
202	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
203		printf(" limit-out");
204}
205
206static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
207{
208	const struct xt_addrtype_info *info = (const void *)match->data;
209
210	if (info->source) {
211		if (info->invert_source)
212			printf(" !");
213		printf(" --src-type ");
214		print_types(info->source);
215	}
216	if (info->dest) {
217		if (info->invert_dest)
218			printf(" !");
219		printf(" --dst-type ");
220		print_types(info->dest);
221	}
222}
223
224static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
225{
226	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
227
228	if (info->source) {
229		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
230			printf(" !");
231		printf(" --src-type ");
232		print_types(info->source);
233	}
234	if (info->dest) {
235		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
236			printf(" !");
237		printf(" --dst-type ");
238		print_types(info->dest);
239	}
240	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
241		printf(" --limit-iface-in");
242	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
243		printf(" --limit-iface-out");
244}
245
246static const struct xt_option_entry addrtype_opts_v0[] = {
247	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
248	 .flags = XTOPT_INVERT},
249	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
250	 .flags = XTOPT_INVERT},
251	XTOPT_TABLEEND,
252};
253
254static const struct xt_option_entry addrtype_opts_v1[] = {
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	{.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
260	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
261	{.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
262	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
263	XTOPT_TABLEEND,
264};
265
266static struct xtables_match addrtype_mt_reg[] = {
267	{
268		.name          = "addrtype",
269		.version       = XTABLES_VERSION,
270		.family        = NFPROTO_IPV4,
271		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info)),
272		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
273		.help          = addrtype_help_v0,
274		.print         = addrtype_print_v0,
275		.save          = addrtype_save_v0,
276		.x6_parse      = addrtype_parse_v0,
277		.x6_fcheck     = addrtype_check,
278		.x6_options    = addrtype_opts_v0,
279	},
280	{
281		.name          = "addrtype",
282		.revision      = 1,
283		.version       = XTABLES_VERSION,
284		.family        = NFPROTO_UNSPEC,
285		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
286		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
287		.help          = addrtype_help_v1,
288		.print         = addrtype_print_v1,
289		.save          = addrtype_save_v1,
290		.x6_parse      = addrtype_parse_v1,
291		.x6_fcheck     = addrtype_check,
292		.x6_options    = addrtype_opts_v1,
293	},
294};
295
296
297void _init(void)
298{
299	xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
300}
301