From: Bart De Schuymer <bdschuym@pandora.be>
To: Florian Westphal <fw@strlen.de>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [PATCH] ebtables: extend ebt_ip6 to allow matching on ipv6-icmp types/codes
Date: Sat, 18 Dec 2010 17:35:16 +0100 [thread overview]
Message-ID: <4D0CE2C4.2050007@pandora.be> (raw)
In-Reply-To: <20101217162427.GA16467@Chamillionaire.breakpoint.cc>
Hi Florian,
This patch looks good. I'll apply it once the kernel patch is applied.
cheers,
Bart
On 17-12-10 17:24, Florian Westphal wrote:
> adds a --ip6-icmp-type option to match on ipv6-icmp types/codes.
> The ipv6-icmp name list was taken from iptables 1.4.9.
>
> Signed-off-by: Florian Westphal<fwestphal@astaro.com>
> ---
> ebtables.8 | 11 +++
> extensions/ebt_ip6.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++-
> include/ebtables_u.h | 4 +
> 3 files changed, 240 insertions(+), 2 deletions(-)
>
> diff --git a/ebtables.8 b/ebtables.8
> index 957c445..6c7acf7 100644
> --- a/ebtables.8
> +++ b/ebtables.8
> @@ -700,6 +700,17 @@ If
> The flag
> .B --ip6-dport
> is an alias for this option.
> +.TP
> +.BR "--ip6-icmp-type " "[!] {\fItype\fP[:\fItype\fP]/\fIcode\fP[:\fIcode\fP]|\fItypename\fP}"
> +Specify ipv6\-icmp type and code to match.
> +Ranges for both type and code are supported. Type and code are
> +separated by a slash. Valid numbers for type and range are 0 to 255.
> +To match a single type including all valid codes, symbolic names can
> +be used instead of numbers. The list of known type names is shown by the command
> +.nf
> + ebtables \-\-help ip6
> +.fi
> +This option is only valid for \-\-ip6-prococol ipv6-icmp.
> .SS limit
> This module matches at a limited rate using a token bucket filter.
> A rule using this extension will match until this limit is reached.
> diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
> index 5850523..9ab177d 100644
> --- a/extensions/ebt_ip6.c
> +++ b/extensions/ebt_ip6.c
> @@ -11,6 +11,9 @@
> *
> */
>
> +#include<errno.h>
> +#include<inttypes.h>
> +#include<limits.h>
> #include<stdio.h>
> #include<stdlib.h>
> #include<string.h>
> @@ -27,8 +30,9 @@
> #define IP_PROTO '4'
> #define IP_SPORT '5'
> #define IP_DPORT '6'
> +#define IP_ICMP6 '7'
>
> -static struct option opts[] =
> +static const struct option opts[] =
> {
> { "ip6-source" , required_argument, 0, IP_SOURCE },
> { "ip6-src" , required_argument, 0, IP_SOURCE },
> @@ -42,9 +46,55 @@ static struct option opts[] =
> { "ip6-sport" , required_argument, 0, IP_SPORT },
> { "ip6-destination-port" , required_argument, 0, IP_DPORT },
> { "ip6-dport" , required_argument, 0, IP_DPORT },
> + { "ip6-icmp-type" , required_argument, 0, IP_ICMP6 },
> { 0 }
> };
>
> +
> +struct icmpv6_names {
> + const char *name;
> + u_int8_t type;
> + u_int8_t code_min, code_max;
> +};
> +
> +static const struct icmpv6_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 },
> +};
> +
> /* transform a protocol and service name into a port number */
> static uint16_t parse_port(const char *protocol, const char *name)
> {
> @@ -91,6 +141,97 @@ parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
> free(buffer);
> }
>
> +static char*
> +parse_num(const char *str, long min, long max, long *num)
> +{
> + char *end;
> +
> + errno = 0;
> + *num = strtol(str,&end, 10);
> + if (errno&& (*num == LONG_MIN || *num == LONG_MAX)) {
> + ebt_print_error("Invalid number %s: %s", str, strerror(errno));
> + return NULL;
> + }
> + if (min<= max) {
> + if (*num> max || *num< min) {
> + ebt_print_error("Value %ld out of range (%ld, %ld)", *num, min, max);
> + return NULL;
> + }
> + }
> + if (*num == 0&& str == end)
> + return NULL;
> + return end;
> +}
> +
> +static char *
> +parse_range(const char *str, long min, long max, long num[])
> +{
> + char *next;
> +
> + next = parse_num(str, min, max, num);
> + if (next == NULL)
> + return NULL;
> + if (next&& *next == ':')
> + next = parse_num(next+1, min, max,&num[1]);
> + else
> + num[1] = num[0];
> + 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;
> + long number[2];
> +
> + for (i = 0; i< limit; i++) {
> + if (strncasecmp(icmpv6_codes[i].name, icmpv6type, strlen(icmpv6type)))
> + continue;
> + if (match != limit)
> + ebt_print_error("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, 0, 255, number);
> + if (!next) {
> + ebt_print_error("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, 0, 255, 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:
> + ebt_print_error("unknown character %c", *next);
> + return -1;
> + }
> + }
> + return 0;
> +}
> +
> static void print_port_range(uint16_t *ports)
> {
> if (ports[0] == ports[1])
> @@ -99,6 +240,58 @@ static void print_port_range(uint16_t *ports)
> printf("%d:%d ", ports[0], ports[1]);
> }
>
> +static void print_icmp_code(uint8_t *code)
> +{
> + if (code[0] == code[1])
> + printf("/%"PRIu8 " ", code[0]);
> + else
> + printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
> +}
> +
> +static void print_icmp_type(uint8_t *type, uint8_t *code)
> +{
> + unsigned int i;
> +
> + if (type[0] != type[1]) {
> + printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
> + print_icmp_code(code);
> + return;
> + }
> +
> + for (i = 0; i< ARRAY_SIZE(icmpv6_codes); i++) {
> + if (icmpv6_codes[i].type != type[0])
> + continue;
> +
> + if (icmpv6_codes[i].code_min == code[0]&&
> + icmpv6_codes[i].code_max == code[1]) {
> + printf("%s ", icmpv6_codes[i].name);
> + return;
> + }
> + }
> + printf("%"PRIu8, type[0]);
> + print_icmp_code(code);
> +}
> +
> +static void print_icmpv6types(void)
> +{
> + unsigned int i;
> + printf("Valid ICMPv6 Types:");
> +
> + for (i=0; i< ARRAY_SIZE(icmpv6_codes); i++) {
> + if (i&& icmpv6_codes[i].type == icmpv6_codes[i-1].type) {
> + if (icmpv6_codes[i].code_min == icmpv6_codes[i-1].code_min
> + && (icmpv6_codes[i].code_max
> + == icmpv6_codes[i-1].code_max))
> + printf(" (%s)", icmpv6_codes[i].name);
> + else
> + printf("\n %s", icmpv6_codes[i].name);
> + }
> + else
> + printf("\n%s", icmpv6_codes[i].name);
> + }
> + printf("\n");
> +}
> +
> static void print_help()
> {
> printf(
> @@ -108,7 +301,9 @@ static void print_help()
> "--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-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");
> +print_icmpv6types();
> }
>
> static void init(struct ebt_entry_match *match)
> @@ -170,6 +365,15 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
> parse_port_range(NULL, optarg, ipinfo->dport);
> break;
>
> + case IP_ICMP6:
> + ebt_check_option2(flags, EBT_IP6_ICMP6);
> + ipinfo->bitmask |= EBT_IP6_ICMP6;
> + if (ebt_check_inverse2(optarg))
> + ipinfo->invflags |= EBT_IP6_ICMP6;
> + if (parse_icmpv6(optarg, ipinfo->icmpv6_type, ipinfo->icmpv6_code))
> + return 0;
> + break;
> +
> case IP_TCLASS:
> ebt_check_option2(flags, OPT_TCLASS);
> if (ebt_check_inverse2(optarg))
> @@ -223,6 +427,12 @@ static void final_check(const struct ebt_u_entry *entry,
> ebt_print_error("For port filtering the IP protocol must be "
> "either 6 (tcp), 17 (udp), 33 (dccp) or "
> "132 (sctp)");
> + if ((ipinfo->bitmask& EBT_IP6_ICMP6)&&
> + (!(ipinfo->bitmask& EBT_IP6_PROTO) ||
> + ipinfo->invflags& EBT_IP6_PROTO ||
> + ipinfo->protocol != IPPROTO_ICMPV6))
> + ebt_print_error("For ipv6-icmp filtering the IP protocol must be "
> + "58 (ipv6-icmp)");
> }
>
> static void print(const struct ebt_u_entry *entry,
> @@ -275,6 +485,12 @@ static void print(const struct ebt_u_entry *entry,
> printf("! ");
> print_port_range(ipinfo->dport);
> }
> + if (ipinfo->bitmask& EBT_IP6_ICMP6) {
> + printf("--ip6-icmp-type ");
> + if (ipinfo->invflags& EBT_IP6_ICMP6)
> + printf("! ");
> + print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
> + }
> }
>
> static int compare(const struct ebt_entry_match *m1,
> @@ -317,6 +533,13 @@ static int compare(const struct ebt_entry_match *m1,
> ipinfo1->dport[1] != ipinfo2->dport[1])
> return 0;
> }
> + if (ipinfo1->bitmask& EBT_IP6_ICMP6) {
> + if (ipinfo1->icmpv6_type[0] != ipinfo2->icmpv6_type[0] ||
> + ipinfo1->icmpv6_type[1] != ipinfo2->icmpv6_type[1] ||
> + ipinfo1->icmpv6_code[0] != ipinfo2->icmpv6_code[0] ||
> + ipinfo1->icmpv6_code[1] != ipinfo2->icmpv6_code[1])
> + return 0;
> + }
> return 1;
> }
>
> diff --git a/include/ebtables_u.h b/include/ebtables_u.h
> index 910c213..c29476d 100644
> --- a/include/ebtables_u.h
> +++ b/include/ebtables_u.h
> @@ -376,4 +376,8 @@ extern int ebt_printstyle_mac;
> #define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
> #endif
> #define ATOMIC_ENV_VARIABLE "EBTABLES_ATOMIC_FILE"
> +
> +#ifndef ARRAY_SIZE
> +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +#endif
> #endif /* EBTABLES_U_H */
--
Bart De Schuymer
www.artinalgorithms.be
prev parent reply other threads:[~2010-12-18 16:40 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-17 16:24 [PATCH] ebtables: extend ebt_ip6 to allow matching on ipv6-icmp types/codes Florian Westphal
2010-12-18 16:35 ` Bart De Schuymer [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4D0CE2C4.2050007@pandora.be \
--to=bdschuym@pandora.be \
--cc=fw@strlen.de \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.