summaryrefslogtreecommitdiffstats
path: root/extensions/libebt_ip6.c
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/libebt_ip6.c')
-rw-r--r--extensions/libebt_ip6.c348
1 files changed, 88 insertions, 260 deletions
diff --git a/extensions/libebt_ip6.c b/extensions/libebt_ip6.c
index a686a285..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 = xtables_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,115 +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));
-}
-
-/* wrap xtables_ip6parse_any(), ignoring any but the first returned address */
-static void ebt_parse_ip6_address(char *address,
- struct in6_addr *addr, struct in6_addr *msk)
-{
- struct in6_addr *addrp;
- unsigned int naddrs;
-
- xtables_ip6parse_any(address, &addrp, msk, &naddrs);
- if (naddrs != 1)
- xtables_error(PARAMETER_PROBLEM,
- "Invalid IPv6 Address '%s' specified", address);
- memcpy(addr, addrp, sizeof(*addr));
- free(addrp);
-}
-
-#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)
+static void brip6_parse(struct xt_option_call *cb)
{
- 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");
}
@@ -343,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);
@@ -376,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);
}
}
@@ -561,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)