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 
11 enum {
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 */
23 static 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 
addrtype_help_types(void)39 static 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 
addrtype_help_v0(void)47 static 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 
addrtype_help_v1(void)58 static 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 
71 static int
parse_type(const char * name,size_t len,uint16_t * mask)72 parse_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 
parse_types(const char * arg,uint16_t * mask)86 static 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 
addrtype_parse_v0(struct xt_option_call * cb)101 static 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 
addrtype_parse_v1(struct xt_option_call * cb)120 static 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 
addrtype_check(struct xt_fcheck_call * cb)145 static 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 
print_types(uint16_t mask)152 static 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 
addrtype_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)164 static 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 
addrtype_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)184 static 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 
addrtype_save_v0(const void * ip,const struct xt_entry_match * match)208 static 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 
addrtype_save_v1(const void * ip,const struct xt_entry_match * match)226 static 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 
248 static 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 
256 static 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 
268 static 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 
_init(void)299 void _init(void)
300 {
301 	xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
302 }
303