• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ebt_ip6
2  *
3  * Authors:
4  * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
5  * Manohar Castelino <manohar.castelino@intel.com>
6  *
7  * Summary:
8  * This is just a modification of the IPv4 code written by
9  * Bart De Schuymer <bdschuym@pandora.be>
10  * with the changes required to support IPv6
11  *
12  */
13 
14 #include <errno.h>
15 #include <arpa/inet.h>
16 #include <inttypes.h>
17 #include <limits.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <netdb.h>
22 #include <xtables.h>
23 #include <linux/netfilter_bridge/ebt_ip6.h>
24 
25 #include "libxt_icmp.h"
26 
27 /* must correspond to the bit position in EBT_IP6_* defines */
28 enum {
29 	O_SOURCE = 0,
30 	O_DEST,
31 	O_TCLASS,
32 	O_PROTO,
33 	O_SPORT,
34 	O_DPORT,
35 	O_ICMP6,
36 	F_PORT = 1 << O_ICMP6,
37 	F_ICMP6 = 1 << O_SPORT | 1 << O_DPORT,
38 };
39 
40 static const struct xt_option_entry brip6_opts[] = {
41 	{ .name = "ip6-source",		.id = O_SOURCE, .type = XTTYPE_HOSTMASK,
42 	  .flags = XTOPT_INVERT },
43 	{ .name = "ip6-src",		.id = O_SOURCE, .type = XTTYPE_HOSTMASK,
44 	  .flags = XTOPT_INVERT },
45 	{ .name = "ip6-destination",	.id = O_DEST, .type = XTTYPE_HOSTMASK,
46 	  .flags = XTOPT_INVERT },
47 	{ .name = "ip6-dst",		.id = O_DEST, .type = XTTYPE_HOSTMASK,
48 	  .flags = XTOPT_INVERT },
49 	{ .name = "ip6-tclass",		.id = O_TCLASS, .type = XTTYPE_UINT8,
50 	  .flags = XTOPT_INVERT | XTOPT_PUT,
51 	  XTOPT_POINTER(struct ebt_ip6_info, tclass) },
52 	{ .name = "ip6-protocol",	.id = O_PROTO, .type = XTTYPE_PROTOCOL,
53 	  .flags = XTOPT_INVERT | XTOPT_PUT,
54 	  XTOPT_POINTER(struct ebt_ip6_info, protocol) },
55 	{ .name = "ip6-proto",		.id = O_PROTO, .type = XTTYPE_PROTOCOL,
56 	  .flags = XTOPT_INVERT | XTOPT_PUT,
57 	  XTOPT_POINTER(struct ebt_ip6_info, protocol) },
58 	{ .name = "ip6-source-port",	.id = O_SPORT, .type = XTTYPE_PORTRC,
59 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
60 	  XTOPT_POINTER(struct ebt_ip6_info, sport) },
61 	{ .name = "ip6-sport",		.id = O_SPORT, .type = XTTYPE_PORTRC,
62 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
63 	  XTOPT_POINTER(struct ebt_ip6_info, sport) },
64 	{ .name = "ip6-destination-port",.id = O_DPORT, .type = XTTYPE_PORTRC,
65 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
66 	  XTOPT_POINTER(struct ebt_ip6_info, dport) },
67 	{ .name = "ip6-dport",		.id = O_DPORT, .type = XTTYPE_PORTRC,
68 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
69 	  XTOPT_POINTER(struct ebt_ip6_info, dport) },
70 	{ .name = "ip6-icmp-type",	.id = O_ICMP6, .type = XTTYPE_STRING,
71 	  .excl = F_ICMP6, .flags = XTOPT_INVERT },
72 	XTOPT_TABLEEND,
73 };
74 
print_port_range(uint16_t * ports)75 static void print_port_range(uint16_t *ports)
76 {
77 	if (ports[0] == ports[1])
78 		printf("%d ", ports[0]);
79 	else
80 		printf("%d:%d ", ports[0], ports[1]);
81 }
82 
print_icmp_code(uint8_t * code)83 static void print_icmp_code(uint8_t *code)
84 {
85 	if (code[0] == code[1])
86 		printf("/%"PRIu8 " ", code[0]);
87 	else
88 		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
89 }
90 
print_icmp_type(uint8_t * type,uint8_t * code)91 static void print_icmp_type(uint8_t *type, uint8_t *code)
92 {
93 	unsigned int i;
94 
95 	if (type[0] != type[1]) {
96 		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
97 		print_icmp_code(code);
98 		return;
99 	}
100 
101 	for (i = 0; i < ARRAY_SIZE(icmpv6_codes); i++) {
102 		if (icmpv6_codes[i].type != type[0])
103 			continue;
104 
105 		if (icmpv6_codes[i].code_min == code[0] &&
106 		    icmpv6_codes[i].code_max == code[1]) {
107 			printf("%s ", icmpv6_codes[i].name);
108 			return;
109 		}
110 	}
111 	printf("%"PRIu8, type[0]);
112 	print_icmp_code(code);
113 }
114 
brip6_print_help(void)115 static void brip6_print_help(void)
116 {
117 	printf(
118 "ip6 options:\n"
119 "[!] --ip6-src    address[/mask]: ipv6 source specification\n"
120 "[!] --ip6-dst    address[/mask]: ipv6 destination specification\n"
121 "[!] --ip6-tclass tclass        : ipv6 traffic class specification\n"
122 "[!] --ip6-proto  protocol      : ipv6 protocol specification\n"
123 "[!] --ip6-sport  port[:port]   : tcp/udp source port or port range\n"
124 "[!] --ip6-dport  port[:port]   : tcp/udp destination port or port range\n"
125 "[!] --ip6-icmp-type type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
126 	printf("Valid ICMPv6 Types:");
127 	xt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
128 }
129 
brip6_parse(struct xt_option_call * cb)130 static void brip6_parse(struct xt_option_call *cb)
131 {
132 	struct ebt_ip6_info *info = cb->data;
133 	unsigned int i;
134 
135 	/* XXX: overriding afinfo family is dangerous, but
136 	 *      required for XTTYPE_HOSTMASK parsing */
137 	xtables_set_nfproto(NFPROTO_IPV6);
138 	xtables_option_parse(cb);
139 	xtables_set_nfproto(NFPROTO_BRIDGE);
140 
141 	info->bitmask |= 1 << cb->entry->id;
142 	info->invflags |= cb->invert ? 1 << cb->entry->id : 0;
143 
144 	switch (cb->entry->id) {
145 	case O_SOURCE:
146 		for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++)
147 			cb->val.haddr.all[i] &= cb->val.hmask.all[i];
148 		info->saddr = cb->val.haddr.in6;
149 		info->smsk = cb->val.hmask.in6;
150 		break;
151 	case O_DEST:
152 		for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++)
153 			cb->val.haddr.all[i] &= cb->val.hmask.all[i];
154 		info->daddr = cb->val.haddr.in6;
155 		info->dmsk = cb->val.hmask.in6;
156 		break;
157 	case O_ICMP6:
158 		ebt_parse_icmpv6(cb->arg, info->icmpv6_type, info->icmpv6_code);
159 		break;
160 	}
161 }
162 
brip6_final_check(struct xt_fcheck_call * fc)163 static void brip6_final_check(struct xt_fcheck_call *fc)
164 {
165 	if (!fc->xflags)
166 		xtables_error(PARAMETER_PROBLEM,
167 			      "You must specify proper arguments");
168 }
169 
brip6_print(const void * ip,const struct xt_entry_match * match,int numeric)170 static void brip6_print(const void *ip, const struct xt_entry_match *match,
171 		       int numeric)
172 {
173 	struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data;
174 
175 	if (ipinfo->bitmask & EBT_IP6_SOURCE) {
176 		if (ipinfo->invflags & EBT_IP6_SOURCE)
177 			printf("! ");
178 		printf("--ip6-src ");
179 		printf("%s", xtables_ip6addr_to_numeric(&ipinfo->saddr));
180 		printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->smsk));
181 	}
182 	if (ipinfo->bitmask & EBT_IP6_DEST) {
183 		if (ipinfo->invflags & EBT_IP6_DEST)
184 			printf("! ");
185 		printf("--ip6-dst ");
186 		printf("%s", xtables_ip6addr_to_numeric(&ipinfo->daddr));
187 		printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->dmsk));
188 	}
189 	if (ipinfo->bitmask & EBT_IP6_TCLASS) {
190 		if (ipinfo->invflags & EBT_IP6_TCLASS)
191 			printf("! ");
192 		printf("--ip6-tclass 0x%02X ", ipinfo->tclass);
193 	}
194 	if (ipinfo->bitmask & EBT_IP6_PROTO) {
195 		struct protoent *pe;
196 
197 		if (ipinfo->invflags & EBT_IP6_PROTO)
198 			printf("! ");
199 		printf("--ip6-proto ");
200 		pe = getprotobynumber(ipinfo->protocol);
201 		if (pe == NULL) {
202 			printf("%d ", ipinfo->protocol);
203 		} else {
204 			printf("%s ", pe->p_name);
205 		}
206 	}
207 	if (ipinfo->bitmask & EBT_IP6_SPORT) {
208 		if (ipinfo->invflags & EBT_IP6_SPORT)
209 			printf("! ");
210 		printf("--ip6-sport ");
211 		print_port_range(ipinfo->sport);
212 	}
213 	if (ipinfo->bitmask & EBT_IP6_DPORT) {
214 		if (ipinfo->invflags & EBT_IP6_DPORT)
215 			printf("! ");
216 		printf("--ip6-dport ");
217 		print_port_range(ipinfo->dport);
218 	}
219 	if (ipinfo->bitmask & EBT_IP6_ICMP6) {
220 		if (ipinfo->invflags & EBT_IP6_ICMP6)
221 			printf("! ");
222 		printf("--ip6-icmp-type ");
223 		print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
224 	}
225 }
226 
brip_xlate_th(struct xt_xlate * xl,const struct ebt_ip6_info * info,int bit,const char * pname)227 static void brip_xlate_th(struct xt_xlate *xl,
228 			  const struct ebt_ip6_info *info, int bit,
229 			  const char *pname)
230 {
231 	const uint16_t *ports;
232 
233 	if ((info->bitmask & bit) == 0)
234 		return;
235 
236 	switch (bit) {
237 	case EBT_IP6_SPORT:
238 		if (pname)
239 			xt_xlate_add(xl, "%s sport ", pname);
240 		else
241 			xt_xlate_add(xl, "@th,0,16 ");
242 
243 		ports = info->sport;
244 		break;
245 	case EBT_IP6_DPORT:
246 		if (pname)
247 			xt_xlate_add(xl, "%s dport ", pname);
248 		else
249 			xt_xlate_add(xl, "@th,16,16 ");
250 
251 		ports = info->dport;
252 		break;
253 	default:
254 		return;
255 	}
256 
257 	if (info->invflags & bit)
258 		xt_xlate_add(xl, "!= ");
259 
260 	if (ports[0] == ports[1])
261 		xt_xlate_add(xl, "%d ", ports[0]);
262 	else
263 		xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
264 }
265 
brip_xlate_nh(struct xt_xlate * xl,const struct ebt_ip6_info * info,int bit)266 static void brip_xlate_nh(struct xt_xlate *xl,
267 			  const struct ebt_ip6_info *info, int bit)
268 {
269 	struct in6_addr *addrp, *maskp;
270 
271 	if ((info->bitmask & bit) == 0)
272 		return;
273 
274 	switch (bit) {
275 	case EBT_IP6_SOURCE:
276 		xt_xlate_add(xl, "ip6 saddr ");
277 		addrp = (struct in6_addr *)&info->saddr;
278 		maskp = (struct in6_addr *)&info->smsk;
279 		break;
280 	case EBT_IP6_DEST:
281 		xt_xlate_add(xl, "ip6 daddr ");
282 		addrp = (struct in6_addr *)&info->daddr;
283 		maskp = (struct in6_addr *)&info->dmsk;
284 		break;
285 	default:
286 		return;
287 	}
288 
289 	if (info->invflags & bit)
290 		xt_xlate_add(xl, "!= ");
291 
292 	xt_xlate_add(xl, "%s%s ", xtables_ip6addr_to_numeric(addrp),
293 				  xtables_ip6mask_to_numeric(maskp));
294 }
295 
brip6_xlate_proto_to_name(uint8_t proto)296 static const char *brip6_xlate_proto_to_name(uint8_t proto)
297 {
298 	switch (proto) {
299 	case IPPROTO_TCP:
300 		return "tcp";
301 	case IPPROTO_UDP:
302 		return "udp";
303 	case IPPROTO_UDPLITE:
304 		return "udplite";
305 	case IPPROTO_SCTP:
306 		return "sctp";
307 	case IPPROTO_DCCP:
308 		return "dccp";
309 	default:
310 		return NULL;
311 	}
312 }
313 
brip6_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)314 static int brip6_xlate(struct xt_xlate *xl,
315 		      const struct xt_xlate_mt_params *params)
316 {
317 	const struct ebt_ip6_info *info = (const void *)params->match->data;
318 	const char *pname = NULL;
319 
320 	if ((info->bitmask & (EBT_IP6_SOURCE|EBT_IP6_DEST|EBT_IP6_ICMP6|EBT_IP6_TCLASS)) == 0)
321 		xt_xlate_add(xl, "ether type ip6 ");
322 
323 	brip_xlate_nh(xl, info, EBT_IP6_SOURCE);
324 	brip_xlate_nh(xl, info, EBT_IP6_DEST);
325 
326 	if (info->bitmask & EBT_IP6_TCLASS) {
327 		xt_xlate_add(xl, "ip6 dscp ");
328 		if (info->invflags & EBT_IP6_TCLASS)
329 			xt_xlate_add(xl, "!= ");
330 		xt_xlate_add(xl, "0x%02x ", info->tclass & 0x3f); /* remove ECN bits */
331 	}
332 
333 	if (info->bitmask & EBT_IP6_PROTO) {
334 		struct protoent *pe;
335 
336 		if (info->bitmask & (EBT_IP6_SPORT|EBT_IP6_DPORT|EBT_IP6_ICMP6) &&
337 		    (info->invflags & EBT_IP6_PROTO) == 0) {
338 			/* port number given and not inverted, no need to
339 			 * add explicit 'meta l4proto'.
340 			 */
341 			pname = brip6_xlate_proto_to_name(info->protocol);
342 		} else {
343 			xt_xlate_add(xl, "meta l4proto ");
344 			if (info->invflags & EBT_IP6_PROTO)
345 				xt_xlate_add(xl, "!= ");
346 			pe = getprotobynumber(info->protocol);
347 			if (pe == NULL)
348 				xt_xlate_add(xl, "%d ", info->protocol);
349 			else
350 				xt_xlate_add(xl, "%s ", pe->p_name);
351 		}
352 	}
353 
354 	brip_xlate_th(xl, info, EBT_IP6_SPORT, pname);
355 	brip_xlate_th(xl, info, EBT_IP6_DPORT, pname);
356 
357 	if (info->bitmask & EBT_IP6_ICMP6) {
358 		xt_xlate_add(xl, "icmpv6 type ");
359 		if (info->invflags & EBT_IP6_ICMP6)
360 			xt_xlate_add(xl, "!= ");
361 
362 		if (info->icmpv6_type[0] == info->icmpv6_type[1])
363 			xt_xlate_add(xl, "%d ", info->icmpv6_type[0]);
364 		else
365 			xt_xlate_add(xl, "%d-%d ", info->icmpv6_type[0],
366 						   info->icmpv6_type[1]);
367 
368 		if (info->icmpv6_code[0] == 0 &&
369 		    info->icmpv6_code[1] == 0xff)
370 			return 1;
371 
372 		xt_xlate_add(xl, "icmpv6 code ");
373 		if (info->invflags & EBT_IP6_ICMP6)
374 			xt_xlate_add(xl, "!= ");
375 
376 		if (info->icmpv6_code[0] == info->icmpv6_code[1])
377 			xt_xlate_add(xl, "%d ", info->icmpv6_code[0]);
378 		else
379 			xt_xlate_add(xl, "%d-%d ", info->icmpv6_code[0],
380 						   info->icmpv6_code[1]);
381 	}
382 
383 	return 1;
384 }
385 
386 static struct xtables_match brip6_match = {
387 	.name		= "ip6",
388 	.revision	= 0,
389 	.version	= XTABLES_VERSION,
390 	.family		= NFPROTO_BRIDGE,
391 	.size		= XT_ALIGN(sizeof(struct ebt_ip6_info)),
392 	.userspacesize	= XT_ALIGN(sizeof(struct ebt_ip6_info)),
393 	.help		= brip6_print_help,
394 	.x6_parse	= brip6_parse,
395 	.x6_fcheck	= brip6_final_check,
396 	.print		= brip6_print,
397 	.xlate		= brip6_xlate,
398 	.x6_options	= brip6_opts,
399 };
400 
_init(void)401 void _init(void)
402 {
403 	xtables_register_match(&brip6_match);
404 }
405