netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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


      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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).