4 * Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
5 * Manohar Castelino <manohar.castelino@intel.com>
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
22 #include "../include/ebtables_u.h"
23 #include <linux/netfilter_bridge/ebt_ip6.h>
35 static const struct option opts
[] =
37 { "ip6-source" , required_argument
, 0, IP_SOURCE
},
38 { "ip6-src" , required_argument
, 0, IP_SOURCE
},
39 { "ip6-destination" , required_argument
, 0, IP_DEST
},
40 { "ip6-dst" , required_argument
, 0, IP_DEST
},
41 { "ip6-traffic-class" , required_argument
, 0, IP_TCLASS
},
42 { "ip6-tclass" , required_argument
, 0, IP_TCLASS
},
43 { "ip6-protocol" , required_argument
, 0, IP_PROTO
},
44 { "ip6-proto" , required_argument
, 0, IP_PROTO
},
45 { "ip6-source-port" , required_argument
, 0, IP_SPORT
},
46 { "ip6-sport" , required_argument
, 0, IP_SPORT
},
47 { "ip6-destination-port" , required_argument
, 0, IP_DPORT
},
48 { "ip6-dport" , required_argument
, 0, IP_DPORT
},
49 { "ip6-icmp-type" , required_argument
, 0, IP_ICMP6
},
57 u_int8_t code_min
, code_max
;
60 static const struct icmpv6_names icmpv6_codes
[] = {
61 { "destination-unreachable", 1, 0, 0xFF },
62 { "no-route", 1, 0, 0 },
63 { "communication-prohibited", 1, 1, 1 },
64 { "address-unreachable", 1, 3, 3 },
65 { "port-unreachable", 1, 4, 4 },
67 { "packet-too-big", 2, 0, 0xFF },
69 { "time-exceeded", 3, 0, 0xFF },
70 /* Alias */ { "ttl-exceeded", 3, 0, 0xFF },
71 { "ttl-zero-during-transit", 3, 0, 0 },
72 { "ttl-zero-during-reassembly", 3, 1, 1 },
74 { "parameter-problem", 4, 0, 0xFF },
75 { "bad-header", 4, 0, 0 },
76 { "unknown-header-type", 4, 1, 1 },
77 { "unknown-option", 4, 2, 2 },
79 { "echo-request", 128, 0, 0xFF },
80 /* Alias */ { "ping", 128, 0, 0xFF },
82 { "echo-reply", 129, 0, 0xFF },
83 /* Alias */ { "pong", 129, 0, 0xFF },
85 { "router-solicitation", 133, 0, 0xFF },
87 { "router-advertisement", 134, 0, 0xFF },
89 { "neighbour-solicitation", 135, 0, 0xFF },
90 /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF },
92 { "neighbour-advertisement", 136, 0, 0xFF },
93 /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF },
95 { "redirect", 137, 0, 0xFF },
98 /* transform a protocol and service name into a port number */
99 static uint16_t parse_port(const char *protocol
, const char *name
)
101 struct servent
*service
;
105 port
= strtol(name
, &end
, 10);
108 (service
= getservbyname(name
, protocol
)) != NULL
)
109 return ntohs(service
->s_port
);
111 else if (port
>= 0 || port
<= 0xFFFF) {
114 ebt_print_error("Problem with specified %s port '%s'",
115 protocol
?protocol
:"", name
);
120 parse_port_range(const char *protocol
, const char *portstring
, uint16_t *ports
)
125 buffer
= strdup(portstring
);
126 if ((cp
= strchr(buffer
, ':')) == NULL
)
127 ports
[0] = ports
[1] = parse_port(protocol
, buffer
);
131 ports
[0] = buffer
[0] ? parse_port(protocol
, buffer
) : 0;
132 if (ebt_errormsg
[0] != '\0')
134 ports
[1] = cp
[0] ? parse_port(protocol
, cp
) : 0xFFFF;
135 if (ebt_errormsg
[0] != '\0')
138 if (ports
[0] > ports
[1])
139 ebt_print_error("Invalid portrange (min > max)");
145 parse_num(const char *str
, long min
, long max
, long *num
)
150 *num
= strtol(str
, &end
, 10);
151 if (errno
&& (*num
== LONG_MIN
|| *num
== LONG_MAX
)) {
152 ebt_print_error("Invalid number %s: %s", str
, strerror(errno
));
156 if (*num
> max
|| *num
< min
) {
157 ebt_print_error("Value %ld out of range (%ld, %ld)", *num
, min
, max
);
161 if (*num
== 0 && str
== end
)
167 parse_range(const char *str
, long min
, long max
, long num
[])
171 next
= parse_num(str
, min
, max
, num
);
174 if (next
&& *next
== ':')
175 next
= parse_num(next
+1, min
, max
, &num
[1]);
182 parse_icmpv6(const char *icmpv6type
, uint8_t type
[], uint8_t code
[])
184 static const unsigned int limit
= ARRAY_SIZE(icmpv6_codes
);
185 unsigned int match
= limit
;
189 for (i
= 0; i
< limit
; i
++) {
190 if (strncasecmp(icmpv6_codes
[i
].name
, icmpv6type
, strlen(icmpv6type
)))
193 ebt_print_error("Ambiguous ICMPv6 type `%s':"
195 icmpv6type
, icmpv6_codes
[match
].name
,
196 icmpv6_codes
[i
].name
);
201 type
[0] = type
[1] = icmpv6_codes
[match
].type
;
202 code
[0] = icmpv6_codes
[match
].code_min
;
203 code
[1] = icmpv6_codes
[match
].code_max
;
205 char *next
= parse_range(icmpv6type
, 0, 255, number
);
207 ebt_print_error("Unknown ICMPv6 type `%s'",
211 type
[0] = (uint8_t) number
[0];
212 type
[1] = (uint8_t) number
[1];
219 next
= parse_range(next
+1, 0, 255, number
);
220 code
[0] = (uint8_t) number
[0];
221 code
[1] = (uint8_t) number
[1];
224 if (next
&& *next
== 0)
228 ebt_print_error("unknown character %c", *next
);
235 static void print_port_range(uint16_t *ports
)
237 if (ports
[0] == ports
[1])
238 printf("%d ", ports
[0]);
240 printf("%d:%d ", ports
[0], ports
[1]);
243 static void print_icmp_code(uint8_t *code
)
245 if (code
[0] == code
[1])
246 printf("/%"PRIu8
" ", code
[0]);
248 printf("/%"PRIu8
":%"PRIu8
" ", code
[0], code
[1]);
251 static void print_icmp_type(uint8_t *type
, uint8_t *code
)
255 if (type
[0] != type
[1]) {
256 printf("%"PRIu8
":%" PRIu8
, type
[0], type
[1]);
257 print_icmp_code(code
);
261 for (i
= 0; i
< ARRAY_SIZE(icmpv6_codes
); i
++) {
262 if (icmpv6_codes
[i
].type
!= type
[0])
265 if (icmpv6_codes
[i
].code_min
== code
[0] &&
266 icmpv6_codes
[i
].code_max
== code
[1]) {
267 printf("%s ", icmpv6_codes
[i
].name
);
271 printf("%"PRIu8
, type
[0]);
272 print_icmp_code(code
);
275 static void print_icmpv6types(void)
278 printf("Valid ICMPv6 Types:");
280 for (i
=0; i
< ARRAY_SIZE(icmpv6_codes
); i
++) {
281 if (i
&& icmpv6_codes
[i
].type
== icmpv6_codes
[i
-1].type
) {
282 if (icmpv6_codes
[i
].code_min
== icmpv6_codes
[i
-1].code_min
283 && (icmpv6_codes
[i
].code_max
284 == icmpv6_codes
[i
-1].code_max
))
285 printf(" (%s)", icmpv6_codes
[i
].name
);
287 printf("\n %s", icmpv6_codes
[i
].name
);
290 printf("\n%s", icmpv6_codes
[i
].name
);
295 static void print_help()
299 "--ip6-src [!] address[/mask]: ipv6 source specification\n"
300 "--ip6-dst [!] address[/mask]: ipv6 destination specification\n"
301 "--ip6-tclass [!] tclass : ipv6 traffic class specification\n"
302 "--ip6-proto [!] protocol : ipv6 protocol specification\n"
303 "--ip6-sport [!] port[:port] : tcp/udp source port or port range\n"
304 "--ip6-dport [!] port[:port] : tcp/udp destination port or port range\n"
305 "--ip6-icmp-type [!] type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n");
309 static void init(struct ebt_entry_match
*match
)
311 struct ebt_ip6_info
*ipinfo
= (struct ebt_ip6_info
*)match
->data
;
313 ipinfo
->invflags
= 0;
317 #define OPT_SOURCE 0x01
318 #define OPT_DEST 0x02
319 #define OPT_TCLASS 0x04
320 #define OPT_PROTO 0x08
321 #define OPT_SPORT 0x10
322 #define OPT_DPORT 0x20
323 static int parse(int c
, char **argv
, int argc
, const struct ebt_u_entry
*entry
,
324 unsigned int *flags
, struct ebt_entry_match
**match
)
326 struct ebt_ip6_info
*ipinfo
= (struct ebt_ip6_info
*)(*match
)->data
;
332 ebt_check_option2(flags
, OPT_SOURCE
);
333 ipinfo
->bitmask
|= EBT_IP6_SOURCE
;
334 if (ebt_check_inverse2(optarg
)) {
335 ipinfo
->invflags
|= EBT_IP6_SOURCE
;
337 ebt_parse_ip6_address(optarg
, &ipinfo
->saddr
, &ipinfo
->smsk
);
341 ebt_check_option2(flags
, OPT_DEST
);
342 ipinfo
->bitmask
|= EBT_IP6_DEST
;
343 if (ebt_check_inverse2(optarg
)) {
344 ipinfo
->invflags
|= EBT_IP6_DEST
;
346 ebt_parse_ip6_address(optarg
, &ipinfo
->daddr
, &ipinfo
->dmsk
);
352 ebt_check_option2(flags
, OPT_SPORT
);
353 ipinfo
->bitmask
|= EBT_IP6_SPORT
;
354 if (ebt_check_inverse2(optarg
))
355 ipinfo
->invflags
|= EBT_IP6_SPORT
;
357 ebt_check_option2(flags
, OPT_DPORT
);
358 ipinfo
->bitmask
|= EBT_IP6_DPORT
;
359 if (ebt_check_inverse2(optarg
))
360 ipinfo
->invflags
|= EBT_IP6_DPORT
;
363 parse_port_range(NULL
, optarg
, ipinfo
->sport
);
365 parse_port_range(NULL
, optarg
, ipinfo
->dport
);
369 ebt_check_option2(flags
, EBT_IP6_ICMP6
);
370 ipinfo
->bitmask
|= EBT_IP6_ICMP6
;
371 if (ebt_check_inverse2(optarg
))
372 ipinfo
->invflags
|= EBT_IP6_ICMP6
;
373 if (parse_icmpv6(optarg
, ipinfo
->icmpv6_type
, ipinfo
->icmpv6_code
))
378 ebt_check_option2(flags
, OPT_TCLASS
);
379 if (ebt_check_inverse2(optarg
))
380 ipinfo
->invflags
|= EBT_IP6_TCLASS
;
381 i
= strtol(optarg
, &end
, 16);
382 if (i
< 0 || i
> 255 || *end
!= '\0')
383 ebt_print_error2("Problem with specified IPv6 traffic class");
385 ipinfo
->bitmask
|= EBT_IP6_TCLASS
;
389 ebt_check_option2(flags
, OPT_PROTO
);
390 if (ebt_check_inverse2(optarg
))
391 ipinfo
->invflags
|= EBT_IP6_PROTO
;
392 i
= strtoul(optarg
, &end
, 10);
396 pe
= getprotobyname(optarg
);
398 ebt_print_error("Unknown specified IP protocol - %s", argv
[optind
- 1]);
399 ipinfo
->protocol
= pe
->p_proto
;
401 ipinfo
->protocol
= (unsigned char) i
;
403 ipinfo
->bitmask
|= EBT_IP6_PROTO
;
411 static void final_check(const struct ebt_u_entry
*entry
,
412 const struct ebt_entry_match
*match
, const char *name
,
413 unsigned int hookmask
, unsigned int time
)
415 struct ebt_ip6_info
*ipinfo
= (struct ebt_ip6_info
*)match
->data
;
417 if (entry
->ethproto
!= ETH_P_IPV6
|| entry
->invflags
& EBT_IPROTO
) {
418 ebt_print_error("For IPv6 filtering the protocol must be "
419 "specified as IPv6");
420 } else if (ipinfo
->bitmask
& (EBT_IP6_SPORT
|EBT_IP6_DPORT
) &&
421 (!(ipinfo
->bitmask
& EBT_IP6_PROTO
) ||
422 ipinfo
->invflags
& EBT_IP6_PROTO
||
423 (ipinfo
->protocol
!=IPPROTO_TCP
&&
424 ipinfo
->protocol
!=IPPROTO_UDP
&&
425 ipinfo
->protocol
!=IPPROTO_SCTP
&&
426 ipinfo
->protocol
!=IPPROTO_DCCP
)))
427 ebt_print_error("For port filtering the IP protocol must be "
428 "either 6 (tcp), 17 (udp), 33 (dccp) or "
430 if ((ipinfo
->bitmask
& EBT_IP6_ICMP6
) &&
431 (!(ipinfo
->bitmask
& EBT_IP6_PROTO
) ||
432 ipinfo
->invflags
& EBT_IP6_PROTO
||
433 ipinfo
->protocol
!= IPPROTO_ICMPV6
))
434 ebt_print_error("For ipv6-icmp filtering the IP protocol must be "
438 static void print(const struct ebt_u_entry
*entry
,
439 const struct ebt_entry_match
*match
)
441 struct ebt_ip6_info
*ipinfo
= (struct ebt_ip6_info
*)match
->data
;
443 if (ipinfo
->bitmask
& EBT_IP6_SOURCE
) {
444 printf("--ip6-src ");
445 if (ipinfo
->invflags
& EBT_IP6_SOURCE
)
447 printf("%s", ebt_ip6_to_numeric(&ipinfo
->saddr
));
448 printf("/%s ", ebt_ip6_to_numeric(&ipinfo
->smsk
));
450 if (ipinfo
->bitmask
& EBT_IP6_DEST
) {
451 printf("--ip6-dst ");
452 if (ipinfo
->invflags
& EBT_IP6_DEST
)
454 printf("%s", ebt_ip6_to_numeric(&ipinfo
->daddr
));
455 printf("/%s ", ebt_ip6_to_numeric(&ipinfo
->dmsk
));
457 if (ipinfo
->bitmask
& EBT_IP6_TCLASS
) {
458 printf("--ip6-tclass ");
459 if (ipinfo
->invflags
& EBT_IP6_TCLASS
)
461 printf("0x%02X ", ipinfo
->tclass
);
463 if (ipinfo
->bitmask
& EBT_IP6_PROTO
) {
466 printf("--ip6-proto ");
467 if (ipinfo
->invflags
& EBT_IP6_PROTO
)
469 pe
= getprotobynumber(ipinfo
->protocol
);
471 printf("%d ", ipinfo
->protocol
);
473 printf("%s ", pe
->p_name
);
476 if (ipinfo
->bitmask
& EBT_IP6_SPORT
) {
477 printf("--ip6-sport ");
478 if (ipinfo
->invflags
& EBT_IP6_SPORT
)
480 print_port_range(ipinfo
->sport
);
482 if (ipinfo
->bitmask
& EBT_IP6_DPORT
) {
483 printf("--ip6-dport ");
484 if (ipinfo
->invflags
& EBT_IP6_DPORT
)
486 print_port_range(ipinfo
->dport
);
488 if (ipinfo
->bitmask
& EBT_IP6_ICMP6
) {
489 printf("--ip6-icmp-type ");
490 if (ipinfo
->invflags
& EBT_IP6_ICMP6
)
492 print_icmp_type(ipinfo
->icmpv6_type
, ipinfo
->icmpv6_code
);
496 static int compare(const struct ebt_entry_match
*m1
,
497 const struct ebt_entry_match
*m2
)
499 struct ebt_ip6_info
*ipinfo1
= (struct ebt_ip6_info
*)m1
->data
;
500 struct ebt_ip6_info
*ipinfo2
= (struct ebt_ip6_info
*)m2
->data
;
502 if (ipinfo1
->bitmask
!= ipinfo2
->bitmask
)
504 if (ipinfo1
->invflags
!= ipinfo2
->invflags
)
506 if (ipinfo1
->bitmask
& EBT_IP6_SOURCE
) {
507 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1
->saddr
, &ipinfo2
->saddr
))
509 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1
->smsk
, &ipinfo2
->smsk
))
512 if (ipinfo1
->bitmask
& EBT_IP6_DEST
) {
513 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1
->daddr
, &ipinfo2
->daddr
))
515 if (!IN6_ARE_ADDR_EQUAL(&ipinfo1
->dmsk
, &ipinfo2
->dmsk
))
518 if (ipinfo1
->bitmask
& EBT_IP6_TCLASS
) {
519 if (ipinfo1
->tclass
!= ipinfo2
->tclass
)
522 if (ipinfo1
->bitmask
& EBT_IP6_PROTO
) {
523 if (ipinfo1
->protocol
!= ipinfo2
->protocol
)
526 if (ipinfo1
->bitmask
& EBT_IP6_SPORT
) {
527 if (ipinfo1
->sport
[0] != ipinfo2
->sport
[0] ||
528 ipinfo1
->sport
[1] != ipinfo2
->sport
[1])
531 if (ipinfo1
->bitmask
& EBT_IP6_DPORT
) {
532 if (ipinfo1
->dport
[0] != ipinfo2
->dport
[0] ||
533 ipinfo1
->dport
[1] != ipinfo2
->dport
[1])
536 if (ipinfo1
->bitmask
& EBT_IP6_ICMP6
) {
537 if (ipinfo1
->icmpv6_type
[0] != ipinfo2
->icmpv6_type
[0] ||
538 ipinfo1
->icmpv6_type
[1] != ipinfo2
->icmpv6_type
[1] ||
539 ipinfo1
->icmpv6_code
[0] != ipinfo2
->icmpv6_code
[0] ||
540 ipinfo1
->icmpv6_code
[1] != ipinfo2
->icmpv6_code
[1])
546 static struct ebt_u_match ip6_match
=
548 .name
= EBT_IP6_MATCH
,
549 .size
= sizeof(struct ebt_ip6_info
),
553 .final_check
= final_check
,
561 ebt_register_match(&ip6_match
);