diff options
Diffstat (limited to 'extensions/libebt_ip6.c')
-rw-r--r-- | extensions/libebt_ip6.c | 404 |
1 files changed, 88 insertions, 316 deletions
diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c index b8a5a5d8..247a99eb 100644 --- a/extensions/libebt_ip6.c +++ b/extensions/libebt_ip6.c @@ -18,168 +18,60 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <getopt.h> #include <netdb.h> #include <xtables.h> #include <linux/netfilter_bridge/ebt_ip6.h> #include "libxt_icmp.h" -#define IP_SOURCE '1' -#define IP_DEST '2' -#define IP_TCLASS '3' -#define IP_PROTO '4' -#define IP_SPORT '5' -#define IP_DPORT '6' -#define IP_ICMP6 '7' - -static const struct option brip6_opts[] = { - { .name = "ip6-source", .has_arg = true, .val = IP_SOURCE }, - { .name = "ip6-src", .has_arg = true, .val = IP_SOURCE }, - { .name = "ip6-destination", .has_arg = true, .val = IP_DEST }, - { .name = "ip6-dst", .has_arg = true, .val = IP_DEST }, - { .name = "ip6-tclass", .has_arg = true, .val = IP_TCLASS }, - { .name = "ip6-protocol", .has_arg = true, .val = IP_PROTO }, - { .name = "ip6-proto", .has_arg = true, .val = IP_PROTO }, - { .name = "ip6-source-port", .has_arg = true, .val = IP_SPORT }, - { .name = "ip6-sport", .has_arg = true, .val = IP_SPORT }, - { .name = "ip6-destination-port",.has_arg = true,.val = IP_DPORT }, - { .name = "ip6-dport", .has_arg = true, .val = IP_DPORT }, - { .name = "ip6-icmp-type", .has_arg = true, .val = IP_ICMP6 }, - XT_GETOPT_TABLEEND, +/* must correspond to the bit position in EBT_IP6_* defines */ +enum { + O_SOURCE = 0, + O_DEST, + O_TCLASS, + O_PROTO, + O_SPORT, + O_DPORT, + O_ICMP6, + F_PORT = 1 << O_ICMP6, + F_ICMP6 = 1 << O_SPORT | 1 << O_DPORT, }; -static const struct xt_icmp_names icmpv6_codes[] = { - { "destination-unreachable", 1, 0, 0xFF }, - { "no-route", 1, 0, 0 }, - { "communication-prohibited", 1, 1, 1 }, - { "address-unreachable", 1, 3, 3 }, - { "port-unreachable", 1, 4, 4 }, - - { "packet-too-big", 2, 0, 0xFF }, - - { "time-exceeded", 3, 0, 0xFF }, - /* Alias */ { "ttl-exceeded", 3, 0, 0xFF }, - { "ttl-zero-during-transit", 3, 0, 0 }, - { "ttl-zero-during-reassembly", 3, 1, 1 }, - - { "parameter-problem", 4, 0, 0xFF }, - { "bad-header", 4, 0, 0 }, - { "unknown-header-type", 4, 1, 1 }, - { "unknown-option", 4, 2, 2 }, - - { "echo-request", 128, 0, 0xFF }, - /* Alias */ { "ping", 128, 0, 0xFF }, - - { "echo-reply", 129, 0, 0xFF }, - /* Alias */ { "pong", 129, 0, 0xFF }, - - { "router-solicitation", 133, 0, 0xFF }, - - { "router-advertisement", 134, 0, 0xFF }, - - { "neighbour-solicitation", 135, 0, 0xFF }, - /* Alias */ { "neighbor-solicitation", 135, 0, 0xFF }, - - { "neighbour-advertisement", 136, 0, 0xFF }, - /* Alias */ { "neighbor-advertisement", 136, 0, 0xFF }, - - { "redirect", 137, 0, 0xFF }, +static const struct xt_option_entry brip6_opts[] = { + { .name = "ip6-source", .id = O_SOURCE, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT }, + { .name = "ip6-src", .id = O_SOURCE, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT }, + { .name = "ip6-destination", .id = O_DEST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT }, + { .name = "ip6-dst", .id = O_DEST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT }, + { .name = "ip6-tclass", .id = O_TCLASS, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, tclass) }, + { .name = "ip6-protocol", .id = O_PROTO, .type = XTTYPE_PROTOCOL, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, protocol) }, + { .name = "ip6-proto", .id = O_PROTO, .type = XTTYPE_PROTOCOL, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, protocol) }, + { .name = "ip6-source-port", .id = O_SPORT, .type = XTTYPE_PORTRC, + .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, sport) }, + { .name = "ip6-sport", .id = O_SPORT, .type = XTTYPE_PORTRC, + .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, sport) }, + { .name = "ip6-destination-port",.id = O_DPORT, .type = XTTYPE_PORTRC, + .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, dport) }, + { .name = "ip6-dport", .id = O_DPORT, .type = XTTYPE_PORTRC, + .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ebt_ip6_info, dport) }, + { .name = "ip6-icmp-type", .id = O_ICMP6, .type = XTTYPE_STRING, + .excl = F_ICMP6, .flags = XTOPT_INVERT }, + XTOPT_TABLEEND, }; -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] = xtables_parse_port(buffer, NULL); - else { - *cp = '\0'; - cp++; - - ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0; - ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF; - - if (ports[0] > ports[1]) - xtables_error(PARAMETER_PROBLEM, - "invalid portrange (min > max)"); - } - free(buffer); -} - -static char *parse_range(const char *str, unsigned int res[]) -{ - char *next; - - if (!xtables_strtoui(str, &next, &res[0], 0, 255)) - return NULL; - - res[1] = res[0]; - if (*next == ':') { - str = next + 1; - if (!xtables_strtoui(str, &next, &res[1], 0, 255)) - return NULL; - } - - return next; -} - -static int -parse_icmpv6(const char *icmpv6type, uint8_t type[], uint8_t code[]) -{ - static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); - unsigned int match = limit; - unsigned int i, number[2]; - - for (i = 0; i < limit; i++) { - if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type))) - continue; - if (match != limit) - xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMPv6 type `%s':" - " `%s' or `%s'?", - icmpv6type, icmpv6_codes[match].name, - icmpv6_codes[i].name); - match = i; - } - - if (match < limit) { - type[0] = type[1] = icmpv6_codes[match].type; - code[0] = icmpv6_codes[match].code_min; - code[1] = icmpv6_codes[match].code_max; - } else { - char *next = parse_range(icmpv6type, number); - if (!next) { - xtables_error(PARAMETER_PROBLEM, "Unknown ICMPv6 type `%s'", - icmpv6type); - return -1; - } - type[0] = (uint8_t) number[0]; - type[1] = (uint8_t) number[1]; - switch (*next) { - case 0: - code[0] = 0; - code[1] = 255; - return 0; - case '/': - next = parse_range(next+1, number); - code[0] = (uint8_t) number[0]; - code[1] = (uint8_t) number[1]; - if (next == NULL) - return -1; - if (next && *next == 0) - return 0; - /* fallthrough */ - default: - xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next); - return -1; - } - } - return 0; -} - static void print_port_range(uint16_t *ports) { if (ports[0] == ports[1]) @@ -224,171 +116,53 @@ static void brip6_print_help(void) { 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" -"--ip6-icmp-type [!] type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\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" +"[!] --ip6-icmp-type type[[:type]/code[:code]] : ipv6-icmp type/code or type/code range\n"); printf("Valid ICMPv6 Types:"); xt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes)); } -static void brip6_init(struct xt_entry_match *match) -{ - struct ebt_ip6_info *ipinfo = (struct ebt_ip6_info *)match->data; - - ipinfo->invflags = 0; - ipinfo->bitmask = 0; - memset(ipinfo->saddr.s6_addr, 0, sizeof(ipinfo->saddr.s6_addr)); - memset(ipinfo->smsk.s6_addr, 0, sizeof(ipinfo->smsk.s6_addr)); - memset(ipinfo->daddr.s6_addr, 0, sizeof(ipinfo->daddr.s6_addr)); - memset(ipinfo->dmsk.s6_addr, 0, sizeof(ipinfo->dmsk.s6_addr)); -} - -static struct in6_addr *numeric_to_addr(const char *num) +static void brip6_parse(struct xt_option_call *cb) { - static struct in6_addr ap; - int err; - - if ((err=inet_pton(AF_INET6, num, &ap)) == 1) - return ≈ - return (struct in6_addr *)NULL; -} - -static struct in6_addr *parse_ip6_mask(char *mask) -{ - static struct in6_addr maskaddr; - struct in6_addr *addrp; - unsigned int bits; - - if (mask == NULL) { - /* no mask at all defaults to 128 bits */ - memset(&maskaddr, 0xff, sizeof maskaddr); - return &maskaddr; - } - if ((addrp = numeric_to_addr(mask)) != NULL) - return addrp; - if (!xtables_strtoui(mask, NULL, &bits, 0, 128)) - xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Mask '%s' specified", mask); - if (bits != 0) { - char *p = (char *)&maskaddr; - memset(p, 0xff, bits / 8); - memset(p + (bits / 8) + 1, 0, (128 - bits) / 8); - p[bits / 8] = 0xff << (8 - (bits & 7)); - return &maskaddr; - } - - memset(&maskaddr, 0, sizeof maskaddr); - return &maskaddr; -} - -/* Set the ipv6 mask and address. Callers should check ebt_errormsg[0]. - * The string pointed to by address can be altered. */ -static void ebt_parse_ip6_address(char *address, struct in6_addr *addr, struct in6_addr *msk) -{ - struct in6_addr *tmp_addr; - char buf[256]; - char *p; - int i; - int err; - - strncpy(buf, address, sizeof(buf) - 1); - /* first the mask */ - buf[sizeof(buf) - 1] = '\0'; - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - tmp_addr = parse_ip6_mask(p + 1); - } else - tmp_addr = parse_ip6_mask(NULL); - - *msk = *tmp_addr; - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (!memcmp(msk, &in6addr_any, sizeof(in6addr_any))) - strcpy(buf, "::"); - - if ((err=inet_pton(AF_INET6, buf, addr)) < 1) { - xtables_error(PARAMETER_PROBLEM, "Invalid IPv6 Address '%s' specified", buf); - return; - } - - for (i = 0; i < 4; i++) - addr->s6_addr32[i] &= msk->s6_addr32[i]; -} - -#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 -brip6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ebt_ip6_info *info = (struct ebt_ip6_info *)(*match)->data; + struct ebt_ip6_info *info = cb->data; unsigned int i; - char *end; - - switch (c) { - case IP_SOURCE: - if (invert) - info->invflags |= EBT_IP6_SOURCE; - ebt_parse_ip6_address(optarg, &info->saddr, &info->smsk); - info->bitmask |= EBT_IP6_SOURCE; - break; - case IP_DEST: - if (invert) - info->invflags |= EBT_IP6_DEST; - ebt_parse_ip6_address(optarg, &info->daddr, &info->dmsk); - info->bitmask |= EBT_IP6_DEST; - break; - case IP_SPORT: - if (invert) - info->invflags |= EBT_IP6_SPORT; - parse_port_range(NULL, optarg, info->sport); - info->bitmask |= EBT_IP6_SPORT; - break; - case IP_DPORT: - if (invert) - info->invflags |= EBT_IP6_DPORT; - parse_port_range(NULL, optarg, info->dport); - info->bitmask |= EBT_IP6_DPORT; - break; - case IP_ICMP6: - if (invert) - info->invflags |= EBT_IP6_ICMP6; - if (parse_icmpv6(optarg, info->icmpv6_type, info->icmpv6_code)) - return 0; - info->bitmask |= EBT_IP6_ICMP6; + + /* XXX: overriding afinfo family is dangerous, but + * required for XTTYPE_HOSTMASK parsing */ + xtables_set_nfproto(NFPROTO_IPV6); + xtables_option_parse(cb); + xtables_set_nfproto(NFPROTO_BRIDGE); + + info->bitmask |= 1 << cb->entry->id; + info->invflags |= cb->invert ? 1 << cb->entry->id : 0; + + switch (cb->entry->id) { + case O_SOURCE: + for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++) + cb->val.haddr.all[i] &= cb->val.hmask.all[i]; + info->saddr = cb->val.haddr.in6; + info->smsk = cb->val.hmask.in6; break; - case IP_TCLASS: - if (invert) - info->invflags |= EBT_IP6_TCLASS; - if (!xtables_strtoui(optarg, &end, &i, 0, 255)) - xtables_error(PARAMETER_PROBLEM, "Problem with specified IPv6 traffic class '%s'", optarg); - info->tclass = i; - info->bitmask |= EBT_IP6_TCLASS; + case O_DEST: + for (i = 0; i < ARRAY_SIZE(cb->val.haddr.all); i++) + cb->val.haddr.all[i] &= cb->val.hmask.all[i]; + info->daddr = cb->val.haddr.in6; + info->dmsk = cb->val.hmask.in6; break; - case IP_PROTO: - if (invert) - info->invflags |= EBT_IP6_PROTO; - info->protocol = xtables_parse_protocol(optarg); - info->bitmask |= EBT_IP6_PROTO; + case O_ICMP6: + ebt_parse_icmpv6(cb->arg, info->icmpv6_type, info->icmpv6_code); break; - default: - return 0; } - - *flags |= info->bitmask; - return 1; } -static void brip6_final_check(unsigned int flags) +static void brip6_final_check(struct xt_fcheck_call *fc) { - if (!flags) + if (!fc->xflags) xtables_error(PARAMETER_PROBLEM, "You must specify proper arguments"); } @@ -399,31 +173,30 @@ static void brip6_print(const void *ip, const struct xt_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("--ip6-src "); printf("%s", xtables_ip6addr_to_numeric(&ipinfo->saddr)); printf("%s ", xtables_ip6mask_to_numeric(&ipinfo->smsk)); } if (ipinfo->bitmask & EBT_IP6_DEST) { - printf("--ip6-dst "); if (ipinfo->invflags & EBT_IP6_DEST) printf("! "); + printf("--ip6-dst "); printf("%s", xtables_ip6addr_to_numeric(&ipinfo->daddr)); printf("%s ", xtables_ip6mask_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); + printf("--ip6-tclass 0x%02X ", ipinfo->tclass); } if (ipinfo->bitmask & EBT_IP6_PROTO) { struct protoent *pe; - printf("--ip6-proto "); if (ipinfo->invflags & EBT_IP6_PROTO) printf("! "); + printf("--ip6-proto "); pe = getprotobynumber(ipinfo->protocol); if (pe == NULL) { printf("%d ", ipinfo->protocol); @@ -432,21 +205,21 @@ static void brip6_print(const void *ip, const struct xt_entry_match *match, } } if (ipinfo->bitmask & EBT_IP6_SPORT) { - printf("--ip6-sport "); if (ipinfo->invflags & EBT_IP6_SPORT) printf("! "); + printf("--ip6-sport "); print_port_range(ipinfo->sport); } if (ipinfo->bitmask & EBT_IP6_DPORT) { - printf("--ip6-dport "); if (ipinfo->invflags & EBT_IP6_DPORT) printf("! "); + printf("--ip6-dport "); print_port_range(ipinfo->dport); } if (ipinfo->bitmask & EBT_IP6_ICMP6) { - printf("--ip6-icmp-type "); if (ipinfo->invflags & EBT_IP6_ICMP6) printf("! "); + printf("--ip6-icmp-type "); print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code); } } @@ -617,13 +390,12 @@ static struct xtables_match brip6_match = { .family = NFPROTO_BRIDGE, .size = XT_ALIGN(sizeof(struct ebt_ip6_info)), .userspacesize = XT_ALIGN(sizeof(struct ebt_ip6_info)), - .init = brip6_init, .help = brip6_print_help, - .parse = brip6_parse, - .final_check = brip6_final_check, + .x6_parse = brip6_parse, + .x6_fcheck = brip6_final_check, .print = brip6_print, .xlate = brip6_xlate, - .extra_opts = brip6_opts, + .x6_options = brip6_opts, }; void _init(void) |