• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <strings.h>
9 #include <xtables.h>
10 #include <linux/netfilter/xt_addrtype.h>
11 
12 enum {
13 	O_SRC_TYPE = 0,
14 	O_DST_TYPE,
15 	O_LIMIT_IFACE_IN,
16 	O_LIMIT_IFACE_OUT,
17 	F_SRC_TYPE        = 1 << O_SRC_TYPE,
18 	F_DST_TYPE        = 1 << O_DST_TYPE,
19 	F_LIMIT_IFACE_IN  = 1 << O_LIMIT_IFACE_IN,
20 	F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT,
21 };
22 
23 /* from linux/rtnetlink.h, must match order of enumeration */
24 static const char *const rtn_names[] = {
25 	"UNSPEC",
26 	"UNICAST",
27 	"LOCAL",
28 	"BROADCAST",
29 	"ANYCAST",
30 	"MULTICAST",
31 	"BLACKHOLE",
32 	"UNREACHABLE",
33 	"PROHIBIT",
34 	"THROW",
35 	"NAT",
36 	"XRESOLVE",
37 	NULL
38 };
39 
addrtype_help_types(void)40 static void addrtype_help_types(void)
41 {
42 	int i;
43 
44 	for (i = 0; rtn_names[i]; i++)
45 		printf("                                %s\n", rtn_names[i]);
46 }
47 
addrtype_help_v0(void)48 static void addrtype_help_v0(void)
49 {
50 	printf(
51 "Address type match options:\n"
52 " [!] --src-type type[,...]      Match source address type\n"
53 " [!] --dst-type type[,...]      Match destination address type\n"
54 "\n"
55 "Valid types:           \n");
56 	addrtype_help_types();
57 }
58 
addrtype_help_v1(void)59 static void addrtype_help_v1(void)
60 {
61 	printf(
62 "Address type match options:\n"
63 " [!] --src-type type[,...]      Match source address type\n"
64 " [!] --dst-type type[,...]      Match destination address type\n"
65 "     --limit-iface-in           Match only on the packet's incoming device\n"
66 "     --limit-iface-out          Match only on the packet's outgoing device\n"
67 "\n"
68 "Valid types:           \n");
69 	addrtype_help_types();
70 }
71 
72 static int
parse_type(const char * name,size_t len,uint16_t * mask)73 parse_type(const char *name, size_t len, uint16_t *mask)
74 {
75 	int i;
76 
77 	for (i = 0; rtn_names[i]; i++)
78 		if (strncasecmp(name, rtn_names[i], len) == 0) {
79 			/* build up bitmask for kernel module */
80 			*mask |= (1 << i);
81 			return 1;
82 		}
83 
84 	return 0;
85 }
86 
parse_types(const char * arg,uint16_t * mask)87 static void parse_types(const char *arg, uint16_t *mask)
88 {
89 	const char *comma;
90 
91 	while ((comma = strchr(arg, ',')) != NULL) {
92 		if (comma == arg || !parse_type(arg, comma-arg, mask))
93 			xtables_error(PARAMETER_PROBLEM,
94 			           "addrtype: bad type `%s'", arg);
95 		arg = comma + 1;
96 	}
97 
98 	if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask))
99 		xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg);
100 }
101 
addrtype_parse_v0(struct xt_option_call * cb)102 static void addrtype_parse_v0(struct xt_option_call *cb)
103 {
104 	struct xt_addrtype_info *info = cb->data;
105 
106 	xtables_option_parse(cb);
107 	switch (cb->entry->id) {
108 	case O_SRC_TYPE:
109 		parse_types(cb->arg, &info->source);
110 		if (cb->invert)
111 			info->invert_source = 1;
112 		break;
113 	case O_DST_TYPE:
114 		parse_types(cb->arg, &info->dest);
115 		if (cb->invert)
116 			info->invert_dest = 1;
117 		break;
118 	}
119 }
120 
addrtype_parse_v1(struct xt_option_call * cb)121 static void addrtype_parse_v1(struct xt_option_call *cb)
122 {
123 	struct xt_addrtype_info_v1 *info = cb->data;
124 
125 	xtables_option_parse(cb);
126 	switch (cb->entry->id) {
127 	case O_SRC_TYPE:
128 		parse_types(cb->arg, &info->source);
129 		if (cb->invert)
130 			info->flags |= XT_ADDRTYPE_INVERT_SOURCE;
131 		break;
132 	case O_DST_TYPE:
133 		parse_types(cb->arg, &info->dest);
134 		if (cb->invert)
135 			info->flags |= XT_ADDRTYPE_INVERT_DEST;
136 		break;
137 	case O_LIMIT_IFACE_IN:
138 		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN;
139 		break;
140 	case O_LIMIT_IFACE_OUT:
141 		info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT;
142 		break;
143 	}
144 }
145 
addrtype_check(struct xt_fcheck_call * cb)146 static void addrtype_check(struct xt_fcheck_call *cb)
147 {
148 	if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE)))
149 		xtables_error(PARAMETER_PROBLEM,
150 			   "addrtype: you must specify --src-type or --dst-type");
151 }
152 
print_types(uint16_t mask)153 static void print_types(uint16_t mask)
154 {
155 	const char *sep = "";
156 	int i;
157 
158 	for (i = 0; rtn_names[i]; i++)
159 		if (mask & (1 << i)) {
160 			printf("%s%s", sep, rtn_names[i]);
161 			sep = ",";
162 		}
163 }
164 
addrtype_print_v0(const void * ip,const struct xt_entry_match * match,int numeric)165 static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match,
166                               int numeric)
167 {
168 	const struct xt_addrtype_info *info = (const void *)match->data;
169 
170 	printf(" ADDRTYPE match");
171 	if (info->source) {
172 		printf(" src-type ");
173 		if (info->invert_source)
174 			printf("!");
175 		print_types(info->source);
176 	}
177 	if (info->dest) {
178 		printf(" dst-type");
179 		if (info->invert_dest)
180 			printf("!");
181 		print_types(info->dest);
182 	}
183 }
184 
addrtype_print_v1(const void * ip,const struct xt_entry_match * match,int numeric)185 static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match,
186                               int numeric)
187 {
188 	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
189 
190 	printf(" ADDRTYPE match");
191 	if (info->source) {
192 		printf(" src-type ");
193 		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
194 			printf("!");
195 		print_types(info->source);
196 	}
197 	if (info->dest) {
198 		printf(" dst-type ");
199 		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
200 			printf("!");
201 		print_types(info->dest);
202 	}
203 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
204 		printf(" limit-in");
205 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
206 		printf(" limit-out");
207 }
208 
addrtype_save_v0(const void * ip,const struct xt_entry_match * match)209 static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match)
210 {
211 	const struct xt_addrtype_info *info = (const void *)match->data;
212 
213 	if (info->source) {
214 		if (info->invert_source)
215 			printf(" !");
216 		printf(" --src-type ");
217 		print_types(info->source);
218 	}
219 	if (info->dest) {
220 		if (info->invert_dest)
221 			printf(" !");
222 		printf(" --dst-type ");
223 		print_types(info->dest);
224 	}
225 }
226 
addrtype_save_v1(const void * ip,const struct xt_entry_match * match)227 static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match)
228 {
229 	const struct xt_addrtype_info_v1 *info = (const void *)match->data;
230 
231 	if (info->source) {
232 		if (info->flags & XT_ADDRTYPE_INVERT_SOURCE)
233 			printf(" !");
234 		printf(" --src-type ");
235 		print_types(info->source);
236 	}
237 	if (info->dest) {
238 		if (info->flags & XT_ADDRTYPE_INVERT_DEST)
239 			printf(" !");
240 		printf(" --dst-type ");
241 		print_types(info->dest);
242 	}
243 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
244 		printf(" --limit-iface-in");
245 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
246 		printf(" --limit-iface-out");
247 }
248 
249 static const char *const rtn_lnames[] = {
250 	"unspec",
251 	"unicast",
252 	"local",
253 	"broadcast",
254 	"anycast",
255 	"multicast",
256 	"blackhole",
257 	"unreachable",
258 	"prohibit",
259 	NULL,
260 };
261 
multiple_bits_set(uint16_t val)262 static bool multiple_bits_set(uint16_t val)
263 {
264 	int first = ffs(val);
265 
266 	return first && (val >> first) > 0;
267 }
268 
addrtype_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)269 static int addrtype_xlate(struct xt_xlate *xl,
270 			  const struct xt_xlate_mt_params *params)
271 {
272 	const struct xt_addrtype_info_v1 *info =
273 		(const void *)params->match->data;
274 	const char *sep = "";
275 	bool need_braces;
276 	uint16_t val;
277 	int i;
278 
279 	xt_xlate_add(xl, "fib ");
280 
281 	if (info->source) {
282 		xt_xlate_add(xl, "saddr ");
283 		val = info->source;
284 	} else {
285 		xt_xlate_add(xl, "daddr ");
286 		val = info->dest;
287 	}
288 
289 	if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)
290 		xt_xlate_add(xl, ". iif ");
291 	else if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
292 		xt_xlate_add(xl, ". oif ");
293 
294 	xt_xlate_add(xl, "type ");
295 
296 	if (info->flags & (XT_ADDRTYPE_INVERT_SOURCE | XT_ADDRTYPE_INVERT_DEST))
297 			xt_xlate_add(xl, "!= ");
298 
299 	need_braces = multiple_bits_set(val);
300 
301 	if (need_braces)
302 		xt_xlate_add(xl, "{ ");
303 
304 	for (i = 0; rtn_lnames[i]; i++) {
305 		if (val & (1 << i)) {
306 			xt_xlate_add(xl, "%s%s", sep, rtn_lnames[i]);
307 			sep = ", ";
308 		}
309 	}
310 
311 	if (need_braces)
312 		xt_xlate_add(xl, " }");
313 
314 	return 1;
315 }
316 
317 static const struct xt_option_entry addrtype_opts_v0[] = {
318 	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
319 	 .flags = XTOPT_INVERT},
320 	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
321 	 .flags = XTOPT_INVERT},
322 	XTOPT_TABLEEND,
323 };
324 
325 static const struct xt_option_entry addrtype_opts_v1[] = {
326 	{.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING,
327 	 .flags = XTOPT_INVERT},
328 	{.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING,
329 	 .flags = XTOPT_INVERT},
330 	{.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN,
331 	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT},
332 	{.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT,
333 	 .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN},
334 	XTOPT_TABLEEND,
335 };
336 
337 static struct xtables_match addrtype_mt_reg[] = {
338 	{
339 		.name          = "addrtype",
340 		.version       = XTABLES_VERSION,
341 		.family        = NFPROTO_IPV4,
342 		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info)),
343 		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)),
344 		.help          = addrtype_help_v0,
345 		.print         = addrtype_print_v0,
346 		.save          = addrtype_save_v0,
347 		.x6_parse      = addrtype_parse_v0,
348 		.x6_fcheck     = addrtype_check,
349 		.x6_options    = addrtype_opts_v0,
350 	},
351 	{
352 		.name          = "addrtype",
353 		.revision      = 1,
354 		.version       = XTABLES_VERSION,
355 		.family        = NFPROTO_UNSPEC,
356 		.size          = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
357 		.userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)),
358 		.help          = addrtype_help_v1,
359 		.print         = addrtype_print_v1,
360 		.save          = addrtype_save_v1,
361 		.x6_parse      = addrtype_parse_v1,
362 		.x6_fcheck     = addrtype_check,
363 		.x6_options    = addrtype_opts_v1,
364 		.xlate         = addrtype_xlate,
365 	},
366 };
367 
368 
_init(void)369 void _init(void)
370 {
371 	xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg));
372 }
373