From 005837ee38584e53460a985a2932b23d03a51c3c Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Thu, 21 Feb 2008 21:32:25 +0000 Subject: Kuo-Lang Tseng et al: add ipv6 support --- extensions/ebt_ip6.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 extensions/ebt_ip6.c (limited to 'extensions/ebt_ip6.c') diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c new file mode 100644 index 0000000..5850523 --- /dev/null +++ b/extensions/ebt_ip6.c @@ -0,0 +1,339 @@ +/* ebt_ip6 + * + * Authors: + * Kuo-Lang Tseng + * Manohar Castelino + * + * Summary: + * This is just a modification of the IPv4 code written by + * Bart De Schuymer + * with the changes required to support IPv6 + * + */ + +#include +#include +#include +#include +#include +#include "../include/ebtables_u.h" +#include + + + +#define IP_SOURCE '1' +#define IP_DEST '2' +#define IP_TCLASS '3' +#define IP_PROTO '4' +#define IP_SPORT '5' +#define IP_DPORT '6' + +static struct option opts[] = +{ + { "ip6-source" , required_argument, 0, IP_SOURCE }, + { "ip6-src" , required_argument, 0, IP_SOURCE }, + { "ip6-destination" , required_argument, 0, IP_DEST }, + { "ip6-dst" , required_argument, 0, IP_DEST }, + { "ip6-traffic-class" , required_argument, 0, IP_TCLASS }, + { "ip6-tclass" , required_argument, 0, IP_TCLASS }, + { "ip6-protocol" , required_argument, 0, IP_PROTO }, + { "ip6-proto" , required_argument, 0, IP_PROTO }, + { "ip6-source-port" , required_argument, 0, IP_SPORT }, + { "ip6-sport" , required_argument, 0, IP_SPORT }, + { "ip6-destination-port" , required_argument, 0, IP_DPORT }, + { "ip6-dport" , required_argument, 0, IP_DPORT }, + { 0 } +}; + +/* transform a protocol and service name into a port number */ +static uint16_t parse_port(const char *protocol, const char *name) +{ + struct servent *service; + char *end; + int port; + + port = strtol(name, &end, 10); + if (*end != '\0') { + if (protocol && + (service = getservbyname(name, protocol)) != NULL) + return ntohs(service->s_port); + } + else if (port >= 0 || port <= 0xFFFF) { + return port; + } + ebt_print_error("Problem with specified %s port '%s'", + protocol?protocol:"", name); + return 0; +} + +static void +parse_port_range(const char *protocol, const char *portstring, uint16_t *ports) +{ + char *buffer; + char *cp; + + buffer = strdup(portstring); + if ((cp = strchr(buffer, ':')) == NULL) + ports[0] = ports[1] = parse_port(protocol, buffer); + else { + *cp = '\0'; + cp++; + ports[0] = buffer[0] ? parse_port(protocol, buffer) : 0; + if (ebt_errormsg[0] != '\0') + return; + ports[1] = cp[0] ? parse_port(protocol, cp) : 0xFFFF; + if (ebt_errormsg[0] != '\0') + return; + + if (ports[0] > ports[1]) + ebt_print_error("Invalid portrange (min > max)"); + } + free(buffer); +} + +static void print_port_range(uint16_t *ports) +{ + if (ports[0] == ports[1]) + printf("%d ", ports[0]); + else + printf("%d:%d ", ports[0], ports[1]); +} + +static void print_help() +{ + printf( +"ip6 options:\n" +"--ip6-src [!] address[/mask]: ipv6 source specification\n" +"--ip6-dst [!] address[/mask]: ipv6 destination specification\n" +"--ip6-tclass [!] tclass : ipv6 traffic class specification\n" +"--ip6-proto [!] protocol : ipv6 protocol specification\n" +"--ip6-sport [!] port[:port] : tcp/udp source port or port range\n" +"--ip6-dport [!] port[:port] : tcp/udp destination port or port range\n"); +} + +static void init(struct ebt_entry_match *match) +{ + struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; + + ipinfo->invflags = 0; + ipinfo->bitmask = 0; +} + +#define OPT_SOURCE 0x01 +#define OPT_DEST 0x02 +#define OPT_TCLASS 0x04 +#define OPT_PROTO 0x08 +#define OPT_SPORT 0x10 +#define OPT_DPORT 0x20 +static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, + unsigned int *flags, struct ebt_entry_match **match) +{ + struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)(*match)->data; + char *end; + long int i; + + switch (c) { + case IP_SOURCE: + ebt_check_option2(flags, OPT_SOURCE); + ipinfo->bitmask |= EBT_IP6_SOURCE; + if (ebt_check_inverse2(optarg)) { + ipinfo->invflags |= EBT_IP6_SOURCE; + } + ebt_parse_ip6_address(optarg, &ipinfo->saddr, &ipinfo->smsk); + break; + + case IP_DEST: + ebt_check_option2(flags, OPT_DEST); + ipinfo->bitmask |= EBT_IP6_DEST; + if (ebt_check_inverse2(optarg)) { + ipinfo->invflags |= EBT_IP6_DEST; + } + ebt_parse_ip6_address(optarg, &ipinfo->daddr, &ipinfo->dmsk); + break; + + case IP_SPORT: + case IP_DPORT: + if (c == IP_SPORT) { + ebt_check_option2(flags, OPT_SPORT); + ipinfo->bitmask |= EBT_IP6_SPORT; + if (ebt_check_inverse2(optarg)) + ipinfo->invflags |= EBT_IP6_SPORT; + } else { + ebt_check_option2(flags, OPT_DPORT); + ipinfo->bitmask |= EBT_IP6_DPORT; + if (ebt_check_inverse2(optarg)) + ipinfo->invflags |= EBT_IP6_DPORT; + } + if (c == IP_SPORT) + parse_port_range(NULL, optarg, ipinfo->sport); + else + parse_port_range(NULL, optarg, ipinfo->dport); + break; + + case IP_TCLASS: + ebt_check_option2(flags, OPT_TCLASS); + if (ebt_check_inverse2(optarg)) + ipinfo->invflags |= EBT_IP6_TCLASS; + i = strtol(optarg, &end, 16); + if (i < 0 || i > 255 || *end != '\0') + ebt_print_error2("Problem with specified IPv6 traffic class"); + ipinfo->tclass = i; + ipinfo->bitmask |= EBT_IP6_TCLASS; + break; + + case IP_PROTO: + ebt_check_option2(flags, OPT_PROTO); + if (ebt_check_inverse2(optarg)) + ipinfo->invflags |= EBT_IP6_PROTO; + i = strtoul(optarg, &end, 10); + if (*end != '\0') { + struct protoent *pe; + + pe = getprotobyname(optarg); + if (pe == NULL) + ebt_print_error("Unknown specified IP protocol - %s", argv[optind - 1]); + ipinfo->protocol = pe->p_proto; + } else { + ipinfo->protocol = (unsigned char) i; + } + ipinfo->bitmask |= EBT_IP6_PROTO; + break; + default: + return 0; + } + return 1; +} + +static void final_check(const struct ebt_u_entry *entry, + const struct ebt_entry_match *match, const char *name, + unsigned int hookmask, unsigned int time) +{ + struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; + + if (entry->ethproto != ETH_P_IPV6 || entry->invflags & EBT_IPROTO) { + ebt_print_error("For IPv6 filtering the protocol must be " + "specified as IPv6"); + } else if (ipinfo->bitmask & (EBT_IP6_SPORT|EBT_IP6_DPORT) && + (!(ipinfo->bitmask & EBT_IP6_PROTO) || + ipinfo->invflags & EBT_IP6_PROTO || + (ipinfo->protocol!=IPPROTO_TCP && + ipinfo->protocol!=IPPROTO_UDP && + ipinfo->protocol!=IPPROTO_SCTP && + ipinfo->protocol!=IPPROTO_DCCP))) + ebt_print_error("For port filtering the IP protocol must be " + "either 6 (tcp), 17 (udp), 33 (dccp) or " + "132 (sctp)"); +} + +static void print(const struct ebt_u_entry *entry, + const struct ebt_entry_match *match) +{ + struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; + + if (ipinfo->bitmask & EBT_IP6_SOURCE) { + printf("--ip6-src "); + if (ipinfo->invflags & EBT_IP6_SOURCE) + printf("! "); + printf("%s", ebt_ip6_to_numeric(&ipinfo->saddr)); + printf("/%s ", ebt_ip6_to_numeric(&ipinfo->smsk)); + } + if (ipinfo->bitmask & EBT_IP6_DEST) { + printf("--ip6-dst "); + if (ipinfo->invflags & EBT_IP6_DEST) + printf("! "); + printf("%s", ebt_ip6_to_numeric(&ipinfo->daddr)); + printf("/%s ", ebt_ip6_to_numeric(&ipinfo->dmsk)); + } + if (ipinfo->bitmask & EBT_IP6_TCLASS) { + printf("--ip6-tclass "); + if (ipinfo->invflags & EBT_IP6_TCLASS) + printf("! "); + printf("0x%02X ", ipinfo->tclass); + } + if (ipinfo->bitmask & EBT_IP6_PROTO) { + struct protoent *pe; + + printf("--ip6-proto "); + if (ipinfo->invflags & EBT_IP6_PROTO) + printf("! "); + pe = getprotobynumber(ipinfo->protocol); + if (pe == NULL) { + printf("%d ", ipinfo->protocol); + } else { + printf("%s ", pe->p_name); + } + } + if (ipinfo->bitmask & EBT_IP6_SPORT) { + printf("--ip6-sport "); + if (ipinfo->invflags & EBT_IP6_SPORT) + printf("! "); + print_port_range(ipinfo->sport); + } + if (ipinfo->bitmask & EBT_IP6_DPORT) { + printf("--ip6-dport "); + if (ipinfo->invflags & EBT_IP6_DPORT) + printf("! "); + print_port_range(ipinfo->dport); + } +} + +static int compare(const struct ebt_entry_match *m1, + const struct ebt_entry_match *m2) +{ + struct ebt_ip6_info *ipinfo1 = (struct ebt_ip6_info *)m1->data; + struct ebt_ip6_info *ipinfo2 = (struct ebt_ip6_info *)m2->data; + + if (ipinfo1->bitmask != ipinfo2->bitmask) + return 0; + if (ipinfo1->invflags != ipinfo2->invflags) + return 0; + if (ipinfo1->bitmask & EBT_IP6_SOURCE) { + if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->saddr, &ipinfo2->saddr)) + return 0; + if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->smsk, &ipinfo2->smsk)) + return 0; + } + if (ipinfo1->bitmask & EBT_IP6_DEST) { + if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->daddr, &ipinfo2->daddr)) + return 0; + if (!IN6_ARE_ADDR_EQUAL(&ipinfo1->dmsk, &ipinfo2->dmsk)) + return 0; + } + if (ipinfo1->bitmask & EBT_IP6_TCLASS) { + if (ipinfo1->tclass != ipinfo2->tclass) + return 0; + } + if (ipinfo1->bitmask & EBT_IP6_PROTO) { + if (ipinfo1->protocol != ipinfo2->protocol) + return 0; + } + if (ipinfo1->bitmask & EBT_IP6_SPORT) { + if (ipinfo1->sport[0] != ipinfo2->sport[0] || + ipinfo1->sport[1] != ipinfo2->sport[1]) + return 0; + } + if (ipinfo1->bitmask & EBT_IP6_DPORT) { + if (ipinfo1->dport[0] != ipinfo2->dport[0] || + ipinfo1->dport[1] != ipinfo2->dport[1]) + return 0; + } + return 1; +} + +static struct ebt_u_match ip6_match = +{ + .name = EBT_IP6_MATCH, + .size = sizeof(struct ebt_ip6_info), + .help = print_help, + .init = init, + .parse = parse, + .final_check = final_check, + .print = print, + .compare = compare, + .extra_ops = opts, +}; + +void _init(void) +{ + ebt_register_match(&ip6_match); +} -- cgit v1.2.3