Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
FFS Gluon
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
firmware
FFS Gluon
Commits
7c9e1e10
Unverified
Commit
7c9e1e10
authored
7 years ago
by
Matthias Schiffer
Browse files
Options
Downloads
Patches
Plain Diff
ebtables: add support for ICMP/IGMP type matches
parent
0d07d179
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
patches/lede/0067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch
+1183
-0
1183 additions, 0 deletions
...067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch
with
1183 additions
and
0 deletions
patches/lede/0067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch
0 → 100644
+
1183
−
0
View file @
7c9e1e10
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Sun, 4 Mar 2018 10:26:34 +0100
Subject: ebtables: add support for ICMP/IGMP type matches
Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
diff --git a/package/network/utils/ebtables/patches/301-0001-include-sync-linux-netfilter_bridge-ebt_ip.h-with-ke.patch b/package/network/utils/ebtables/patches/301-0001-include-sync-linux-netfilter_bridge-ebt_ip.h-with-ke.patch
new file mode 100644
index 0000000000000000000000000000000000000000..b6f42c6a4affc9bb04a6ac9269698e751a932f2a
--- /dev/null
+++ b/package/network/utils/ebtables/patches/301-0001-include-sync-linux-netfilter_bridge-ebt_ip.h-with-ke.patch
@@ -0,0 +1,56 @@
+From 44fcc3392bb7d52df2ad52b8e9437255b8c29d5a Mon Sep 17 00:00:00 2001
+Message-Id: <44fcc3392bb7d52df2ad52b8e9437255b8c29d5a.1520151963.git.mschiffer@universe-factory.net>
+In-Reply-To: <cover.1520150717.git.mschiffer@universe-factory.net>
+References: <cover.1520150717.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 3 Mar 2018 12:14:48 +0100
+Subject: [PATCH ebtables 1/4] include: sync linux/netfilter_bridge/ebt_ip.h
+ with kernel
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ include/linux/netfilter_bridge/ebt_ip.h | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/include/linux/netfilter_bridge/ebt_ip.h b/include/linux/netfilter_bridge/ebt_ip.h
+index c4bbc41b0ea4..46d6261370b0 100644
+--- a/include/linux/netfilter_bridge/ebt_ip.h
++++ b/include/linux/netfilter_bridge/ebt_ip.h
+@@ -1,3 +1,4 @@
++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+ /*
+ * ebt_ip
+ *
+@@ -23,8 +24,10 @@
+ #define EBT_IP_PROTO 0x08
+ #define EBT_IP_SPORT 0x10
+ #define EBT_IP_DPORT 0x20
++#define EBT_IP_ICMP 0x40
++#define EBT_IP_IGMP 0x80
+ #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+- EBT_IP_SPORT | EBT_IP_DPORT )
++ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
+ #define EBT_IP_MATCH "ip"
+
+ /* the same values are used for the invflags */
+@@ -37,8 +40,15 @@ struct ebt_ip_info {
+ __u8 protocol;
+ __u8 bitmask;
+ __u8 invflags;
+- __u16 sport[2];
+- __u16 dport[2];
++ union {
++ __u16 sport[2];
++ __u8 icmp_type[2];
++ __u8 igmp_type[2];
++ };
++ union {
++ __u16 dport[2];
++ __u8 icmp_code[2];
++ };
+ };
+
+ #endif
+--
+2.16.2
+
diff --git a/package/network/utils/ebtables/patches/301-0002-Move-ICMP-type-handling-functions-from-ebt_ip6-to-us.patch b/package/network/utils/ebtables/patches/301-0002-Move-ICMP-type-handling-functions-from-ebt_ip6-to-us.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c3eaec4412fcaebffa84b409a0a66e2f714a0e8d
--- /dev/null
+++ b/package/network/utils/ebtables/patches/301-0002-Move-ICMP-type-handling-functions-from-ebt_ip6-to-us.patch
@@ -0,0 +1,465 @@
+From e40c68fcf13e2244ab6c87844126167e998ccb56 Mon Sep 17 00:00:00 2001
+Message-Id: <e40c68fcf13e2244ab6c87844126167e998ccb56.1520151963.git.mschiffer@universe-factory.net>
+In-Reply-To: <cover.1520150717.git.mschiffer@universe-factory.net>
+References: <cover.1520150717.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 4 Mar 2018 08:18:18 +0100
+Subject: [PATCH ebtables 2/4] Move ICMP type handling functions from ebt_ip6
+ to useful_functions.c
+
+Allow using these functions for ebt_ip as well.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ extensions/ebt_ip6.c | 165 +++------------------------------------------------
+ include/ebtables_u.h | 17 +++++-
+ useful_functions.c | 151 +++++++++++++++++++++++++++++++++++++++++++++-
+ 3 files changed, 174 insertions(+), 159 deletions(-)
+
+diff --git a/extensions/ebt_ip6.c b/extensions/ebt_ip6.c
+index dd48547b0010..347797b4afe1 100644
+--- a/extensions/ebt_ip6.c
++++ b/extensions/ebt_ip6.c
+@@ -11,9 +11,6 @@
+ *
+ */
+
+-#include <errno.h>
+-#include <inttypes.h>
+-#include <limits.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -51,13 +48,7 @@ static const struct option opts[] =
+ };
+
+
+-struct icmpv6_names {
+- const char *name;
+- uint8_t type;
+- uint8_t code_min, code_max;
+-};
+-
+-static const struct icmpv6_names icmpv6_codes[] = {
++static const struct ebt_icmp_names icmpv6_codes[] = {
+ { "destination-unreachable", 1, 0, 0xFF },
+ { "no-route", 1, 0, 0 },
+ { "communication-prohibited", 1, 1, 1 },
+@@ -141,97 +132,6 @@ 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])
+@@ -240,58 +140,6 @@ 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(
+@@ -303,7 +151,9 @@ static void print_help()
+ "--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");
+-print_icmpv6types();
++
++ printf("\nValid ICMPv6 Types:\n");
++ ebt_print_icmp_types(icmpv6_codes, ARRAY_SIZE(icmpv6_codes));
+ }
+
+ static void init(struct ebt_entry_match *match)
+@@ -374,7 +224,9 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ 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))
++ if (ebt_parse_icmp(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
++ optarg, ipinfo->icmpv6_type,
++ ipinfo->icmpv6_code))
+ return 0;
+ break;
+
+@@ -493,7 +345,8 @@ static void print(const struct ebt_u_entry *entry,
+ printf("--ip6-icmp-type ");
+ if (ipinfo->invflags & EBT_IP6_ICMP6)
+ printf("! ");
+- print_icmp_type(ipinfo->icmpv6_type, ipinfo->icmpv6_code);
++ ebt_print_icmp_type(icmpv6_codes, ARRAY_SIZE(icmpv6_codes),
++ ipinfo->icmpv6_type, ipinfo->icmpv6_code);
+ }
+ }
+
+diff --git a/include/ebtables_u.h b/include/ebtables_u.h
+index 35a5bcc54c86..17afa9487f5a 100644
+--- a/include/ebtables_u.h
++++ b/include/ebtables_u.h
+@@ -222,6 +222,15 @@ struct ebt_u_target
+ struct ebt_u_target *next;
+ };
+
++
++struct ebt_icmp_names {
++ const char *name;
++ uint8_t type;
++ uint8_t code_min, code_max;
++};
++
++
++
+ /* libebtc.c */
+
+ extern struct ebt_u_table *ebt_tables;
+@@ -300,11 +309,17 @@ void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
+ int ebt_get_mac_and_mask(const char *from, unsigned char *to, unsigned char *mask);
+ void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk);
+ char *ebt_mask_to_dotted(uint32_t mask);
+-void ebt_parse_ip6_address(char *address, struct in6_addr *addr,
++void ebt_parse_ip6_address(char *address, struct in6_addr *addr,
+ struct in6_addr *msk);
+ char *ebt_ip6_to_numeric(const struct in6_addr *addrp);
+ char *ebt_ip6_mask_to_string(const struct in6_addr *msk);
+
++int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
++ const char *icmptype, uint8_t type[], uint8_t code[]);
++void ebt_print_icmp_type(const struct ebt_icmp_names *icmp_codes,
++ size_t n_codes, uint8_t *type, uint8_t *code);
++void ebt_print_icmp_types(const struct ebt_icmp_names *icmp_codes,
++ size_t n_codes);
+
+ int do_command(int argc, char *argv[], int exec_style,
+ struct ebt_u_replace *replace_);
+diff --git a/useful_functions.c b/useful_functions.c
+index d14cbe9dbdba..8f54bae83fae 100644
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -24,6 +24,9 @@
+ */
+ #include "include/ebtables_u.h"
+ #include "include/ethernetdb.h"
++#include <errno.h>
++#include <inttypes.h>
++#include <limits.h>
+ #include <stdio.h>
+ #include <netinet/ether.h>
+ #include <string.h>
+@@ -34,6 +37,7 @@
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+
++
+ const unsigned char mac_type_unicast[ETH_ALEN] = {0,0,0,0,0,0};
+ const unsigned char msk_type_unicast[ETH_ALEN] = {1,0,0,0,0,0};
+ const unsigned char mac_type_multicast[ETH_ALEN] = {1,0,0,0,0,0};
+@@ -188,7 +192,7 @@ static int undot_ip(char *ip, unsigned char *ip2)
+ return -1;
+ *q = '\0';
+ onebyte = strtol(p, &end, 10);
+- if (*end != '\0' || onebyte > 255 || onebyte < 0)
++ if (*end != '\0' || onebyte > 255 || onebyte < 0)
+ return -1;
+ ip2[i] = (unsigned char)onebyte;
+ p = q + 1;
+@@ -275,7 +279,7 @@ char *ebt_mask_to_dotted(uint32_t mask)
+ *buf = '\0';
+ else
+ /* Mask was not a decent combination of 1's and 0's */
+- sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
++ sprintf(buf, "/%d.%d.%d.%d", ((unsigned char *)&mask)[0],
+ ((unsigned char *)&mask)[1], ((unsigned char *)&mask)[2],
+ ((unsigned char *)&mask)[3]);
+
+@@ -424,3 +428,146 @@ char *ebt_ip6_mask_to_string(const struct in6_addr *msk)
+ sprintf(buf, "/%s", ebt_ip6_to_numeric(msk));
+ return buf;
+ }
++
++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;
++}
++
++int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
++ const char *icmptype, uint8_t type[], uint8_t code[])
++{
++ unsigned int match = n_codes;
++ unsigned int i;
++ long number[2];
++
++ for (i = 0; i < n_codes; i++) {
++ if (strncasecmp(icmp_codes[i].name, icmptype, strlen(icmptype)))
++ continue;
++ if (match != n_codes)
++ ebt_print_error("Ambiguous ICMP type `%s':"
++ " `%s' or `%s'?",
++ icmptype, icmp_codes[match].name,
++ icmp_codes[i].name);
++ match = i;
++ }
++
++ if (match < n_codes) {
++ type[0] = type[1] = icmp_codes[match].type;
++ code[0] = icmp_codes[match].code_min;
++ code[1] = icmp_codes[match].code_max;
++ } else {
++ char *next = parse_range(icmptype, 0, 255, number);
++ if (!next) {
++ ebt_print_error("Unknown ICMP type `%s'",
++ icmptype);
++ 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_icmp_code(uint8_t *code)
++{
++ if (code[0] == code[1])
++ printf("/%"PRIu8 " ", code[0]);
++ else
++ printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
++}
++
++void ebt_print_icmp_type(const struct ebt_icmp_names *icmp_codes,
++ size_t n_codes, 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 < n_codes; i++) {
++ if (icmp_codes[i].type != type[0])
++ continue;
++
++ if (icmp_codes[i].code_min == code[0] &&
++ icmp_codes[i].code_max == code[1]) {
++ printf("%s ", icmp_codes[i].name);
++ return;
++ }
++ }
++ printf("%"PRIu8, type[0]);
++ print_icmp_code(code);
++}
++
++void ebt_print_icmp_types(const struct ebt_icmp_names *icmp_codes,
++ size_t n_codes)
++{
++ unsigned int i;
++
++ for (i = 0; i < n_codes; i++) {
++ if (i && icmp_codes[i].type == icmp_codes[i-1].type) {
++ if (icmp_codes[i].code_min == icmp_codes[i-1].code_min
++ && (icmp_codes[i].code_max
++ == icmp_codes[i-1].code_max))
++ printf(" (%s)", icmp_codes[i].name);
++ else
++ printf("\n %s", icmp_codes[i].name);
++ }
++ else
++ printf("\n%s", icmp_codes[i].name);
++ }
++ printf("\n");
++}
+--
+2.16.2
+
diff --git a/package/network/utils/ebtables/patches/301-0003-ebt_ip-add-support-for-matching-ICMP-type-and-code.patch b/package/network/utils/ebtables/patches/301-0003-ebt_ip-add-support-for-matching-ICMP-type-and-code.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2c83168933d88535747f0bc18d3ebbe03c6b1f30
--- /dev/null
+++ b/package/network/utils/ebtables/patches/301-0003-ebt_ip-add-support-for-matching-ICMP-type-and-code.patch
@@ -0,0 +1,182 @@
+From 76bc7b4ede217228e782a6d4dfaa67f772a08441 Mon Sep 17 00:00:00 2001
+Message-Id: <76bc7b4ede217228e782a6d4dfaa67f772a08441.1520151963.git.mschiffer@universe-factory.net>
+In-Reply-To: <cover.1520150717.git.mschiffer@universe-factory.net>
+References: <cover.1520150717.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 3 Mar 2018 12:42:46 +0100
+Subject: [PATCH ebtables 3/4] ebt_ip: add support for matching ICMP type and
+ code
+
+We already have ICMPv6 type/code matches. This adds support for IPv4 ICMP
+matches in the same way.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ extensions/ebt_ip.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 94 insertions(+), 2 deletions(-)
+
+diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
+index 59559feffa50..42660d4564fb 100644
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -24,6 +24,7 @@
+ #define IP_PROTO '4'
+ #define IP_SPORT '5'
+ #define IP_DPORT '6'
++#define IP_ICMP '7'
+
+ static const struct option opts[] =
+ {
+@@ -38,9 +39,64 @@ static const struct option opts[] =
+ { "ip-sport" , required_argument, 0, IP_SPORT },
+ { "ip-destination-port" , required_argument, 0, IP_DPORT },
+ { "ip-dport" , required_argument, 0, IP_DPORT },
++ { "ip-icmp-type" , required_argument, 0, IP_ICMP },
+ { 0 }
+ };
+
++static const struct ebt_icmp_names icmp_codes[] = {
++ { "echo-reply", 0, 0, 0xFF },
++ /* Alias */ { "pong", 0, 0, 0xFF },
++
++ { "destination-unreachable", 3, 0, 0xFF },
++ { "network-unreachable", 3, 0, 0 },
++ { "host-unreachable", 3, 1, 1 },
++ { "protocol-unreachable", 3, 2, 2 },
++ { "port-unreachable", 3, 3, 3 },
++ { "fragmentation-needed", 3, 4, 4 },
++ { "source-route-failed", 3, 5, 5 },
++ { "network-unknown", 3, 6, 6 },
++ { "host-unknown", 3, 7, 7 },
++ { "network-prohibited", 3, 9, 9 },
++ { "host-prohibited", 3, 10, 10 },
++ { "TOS-network-unreachable", 3, 11, 11 },
++ { "TOS-host-unreachable", 3, 12, 12 },
++ { "communication-prohibited", 3, 13, 13 },
++ { "host-precedence-violation", 3, 14, 14 },
++ { "precedence-cutoff", 3, 15, 15 },
++
++ { "source-quench", 4, 0, 0xFF },
++
++ { "redirect", 5, 0, 0xFF },
++ { "network-redirect", 5, 0, 0 },
++ { "host-redirect", 5, 1, 1 },
++ { "TOS-network-redirect", 5, 2, 2 },
++ { "TOS-host-redirect", 5, 3, 3 },
++
++ { "echo-request", 8, 0, 0xFF },
++ /* Alias */ { "ping", 8, 0, 0xFF },
++
++ { "router-advertisement", 9, 0, 0xFF },
++
++ { "router-solicitation", 10, 0, 0xFF },
++
++ { "time-exceeded", 11, 0, 0xFF },
++ /* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
++ { "ttl-zero-during-transit", 11, 0, 0 },
++ { "ttl-zero-during-reassembly", 11, 1, 1 },
++
++ { "parameter-problem", 12, 0, 0xFF },
++ { "ip-header-bad", 12, 0, 0 },
++ { "required-option-missing", 12, 1, 1 },
++
++ { "timestamp-request", 13, 0, 0xFF },
++
++ { "timestamp-reply", 14, 0, 0xFF },
++
++ { "address-mask-request", 17, 0, 0xFF },
++
++ { "address-mask-reply", 18, 0, 0xFF }
++};
++
+ /* put the mask into 4 bytes */
+ /* transform a protocol and service name into a port number */
+ static uint16_t parse_port(const char *protocol, const char *name)
+@@ -105,7 +161,11 @@ static void print_help()
+ "--ip-tos [!] tos : ip tos specification\n"
+ "--ip-proto [!] protocol : ip protocol specification\n"
+ "--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
+-"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n");
++"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n"
++"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n");
++
++ printf("\nValid ICMP Types:\n");
++ ebt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
+ }
+
+ static void init(struct ebt_entry_match *match)
+@@ -122,6 +182,7 @@ static void init(struct ebt_entry_match *match)
+ #define OPT_PROTO 0x08
+ #define OPT_SPORT 0x10
+ #define OPT_DPORT 0x20
++#define OPT_ICMP 0x40
+ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ unsigned int *flags, struct ebt_entry_match **match)
+ {
+@@ -170,6 +231,16 @@ 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_ICMP:
++ ebt_check_option2(flags, OPT_ICMP);
++ ipinfo->bitmask |= EBT_IP_ICMP;
++ if (ebt_check_inverse2(optarg))
++ ipinfo->invflags |= EBT_IP_ICMP;
++ if (ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
++ ipinfo->icmp_type, ipinfo->icmp_code))
++ return 0;
++ break;
++
+ case IP_myTOS:
+ ebt_check_option2(flags, OPT_TOS);
+ if (ebt_check_inverse2(optarg))
+@@ -219,10 +290,17 @@ static void final_check(const struct ebt_u_entry *entry,
+ (ipinfo->protocol!=IPPROTO_TCP &&
+ ipinfo->protocol!=IPPROTO_UDP &&
+ ipinfo->protocol!=IPPROTO_SCTP &&
+- ipinfo->protocol!=IPPROTO_DCCP)))
++ 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)");
++ } else if ((ipinfo->bitmask & EBT_IP_ICMP) &&
++ (!(ipinfo->bitmask & EBT_IP_PROTO) ||
++ ipinfo->invflags & EBT_IP_PROTO ||
++ ipinfo->protocol != IPPROTO_ICMP)) {
++ ebt_print_error("For ICMP filtering the IP protocol must be "
++ "1 (icmp)");
++ }
+ }
+
+ static void print(const struct ebt_u_entry *entry,
+@@ -280,6 +358,13 @@ static void print(const struct ebt_u_entry *entry,
+ printf("! ");
+ print_port_range(ipinfo->dport);
+ }
++ if (ipinfo->bitmask & EBT_IP_ICMP) {
++ printf("--ip-icmp-type ");
++ if (ipinfo->invflags & EBT_IP_ICMP)
++ printf("! ");
++ ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
++ ipinfo->icmp_type, ipinfo->icmp_code);
++ }
+ }
+
+ static int compare(const struct ebt_entry_match *m1,
+@@ -322,6 +407,13 @@ static int compare(const struct ebt_entry_match *m1,
+ ipinfo1->dport[1] != ipinfo2->dport[1])
+ return 0;
+ }
++ if (ipinfo1->bitmask & EBT_IP_ICMP) {
++ if (ipinfo1->icmp_type[0] != ipinfo2->icmp_type[0] ||
++ ipinfo1->icmp_type[1] != ipinfo2->icmp_type[1] ||
++ ipinfo1->icmp_code[0] != ipinfo2->icmp_code[0] ||
++ ipinfo1->icmp_code[1] != ipinfo2->icmp_code[1])
++ return 0;
++ }
+ return 1;
+ }
+
+--
+2.16.2
+
diff --git a/package/network/utils/ebtables/patches/301-0004-ebt_ip-add-support-for-matching-IGMP-type.patch b/package/network/utils/ebtables/patches/301-0004-ebt_ip-add-support-for-matching-IGMP-type.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1a7fe6d2ffcd0baf620dd36d6d3ba200f8b823e9
--- /dev/null
+++ b/package/network/utils/ebtables/patches/301-0004-ebt_ip-add-support-for-matching-IGMP-type.patch
@@ -0,0 +1,207 @@
+From b20e495bdf0c5eec3244cf7f98bae24316ffc3ab Mon Sep 17 00:00:00 2001
+Message-Id: <b20e495bdf0c5eec3244cf7f98bae24316ffc3ab.1520151963.git.mschiffer@universe-factory.net>
+In-Reply-To: <cover.1520150717.git.mschiffer@universe-factory.net>
+References: <cover.1520150717.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 3 Mar 2018 13:50:23 +0100
+Subject: [PATCH ebtables 4/4] ebt_ip: add support for matching IGMP type
+
+We already have ICMPv6 type/code matches (which can be used to distinguish
+different types of MLD packets). Add support for IPv4 IGMP matches in the
+same way.
+
+To reuse as much code as possible, the ICMP type/code handling functions
+are extended to allow passing a NULL code range.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ extensions/ebt_ip.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
+ useful_functions.c | 35 ++++++++++++++++++++++-------------
+ 2 files changed, 65 insertions(+), 14 deletions(-)
+
+diff --git a/extensions/ebt_ip.c b/extensions/ebt_ip.c
+index 42660d4564fb..1ffdb95f156d 100644
+--- a/extensions/ebt_ip.c
++++ b/extensions/ebt_ip.c
+@@ -25,6 +25,7 @@
+ #define IP_SPORT '5'
+ #define IP_DPORT '6'
+ #define IP_ICMP '7'
++#define IP_IGMP '8'
+
+ static const struct option opts[] =
+ {
+@@ -40,6 +41,7 @@ static const struct option opts[] =
+ { "ip-destination-port" , required_argument, 0, IP_DPORT },
+ { "ip-dport" , required_argument, 0, IP_DPORT },
+ { "ip-icmp-type" , required_argument, 0, IP_ICMP },
++ { "ip-igmp-type" , required_argument, 0, IP_IGMP },
+ { 0 }
+ };
+
+@@ -97,6 +99,14 @@ static const struct ebt_icmp_names icmp_codes[] = {
+ { "address-mask-reply", 18, 0, 0xFF }
+ };
+
++static const struct ebt_icmp_names igmp_types[] = {
++ { "membership-query", 0x11 },
++ { "membership-report-v1", 0x12 },
++ { "membership-report-v2", 0x16 },
++ { "leave-group", 0x17 },
++ { "membership-report-v3", 0x22 },
++};
++
+ /* put the mask into 4 bytes */
+ /* transform a protocol and service name into a port number */
+ static uint16_t parse_port(const char *protocol, const char *name)
+@@ -162,10 +172,13 @@ static void print_help()
+ "--ip-proto [!] protocol : ip protocol specification\n"
+ "--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
+ "--ip-dport [!] port[:port] : tcp/udp destination port or port range\n"
+-"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n");
++"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
++"--ip-igmp-type [!] type[:type] : igmp type or type range\n");
+
+ printf("\nValid ICMP Types:\n");
+ ebt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
++ printf("\nValid IGMP Types:\n");
++ ebt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
+ }
+
+ static void init(struct ebt_entry_match *match)
+@@ -183,6 +196,7 @@ static void init(struct ebt_entry_match *match)
+ #define OPT_SPORT 0x10
+ #define OPT_DPORT 0x20
+ #define OPT_ICMP 0x40
++#define OPT_IGMP 0x80
+ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ unsigned int *flags, struct ebt_entry_match **match)
+ {
+@@ -241,6 +255,16 @@ static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
+ return 0;
+ break;
+
++ case IP_IGMP:
++ ebt_check_option2(flags, OPT_IGMP);
++ ipinfo->bitmask |= EBT_IP_IGMP;
++ if (ebt_check_inverse2(optarg))
++ ipinfo->invflags |= EBT_IP_IGMP;
++ if (ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
++ ipinfo->igmp_type, NULL))
++ return 0;
++ break;
++
+ case IP_myTOS:
+ ebt_check_option2(flags, OPT_TOS);
+ if (ebt_check_inverse2(optarg))
+@@ -300,6 +324,12 @@ static void final_check(const struct ebt_u_entry *entry,
+ ipinfo->protocol != IPPROTO_ICMP)) {
+ ebt_print_error("For ICMP filtering the IP protocol must be "
+ "1 (icmp)");
++ } else if ((ipinfo->bitmask & EBT_IP_IGMP) &&
++ (!(ipinfo->bitmask & EBT_IP_PROTO) ||
++ ipinfo->invflags & EBT_IP_PROTO ||
++ ipinfo->protocol != IPPROTO_IGMP)) {
++ ebt_print_error("For IGMP filtering the IP protocol must be "
++ "2 (igmp)");
+ }
+ }
+
+@@ -365,6 +395,13 @@ static void print(const struct ebt_u_entry *entry,
+ ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
+ ipinfo->icmp_type, ipinfo->icmp_code);
+ }
++ if (ipinfo->bitmask & EBT_IP_IGMP) {
++ printf("--ip-igmp-type ");
++ if (ipinfo->invflags & EBT_IP_IGMP)
++ printf("! ");
++ ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
++ ipinfo->igmp_type, NULL);
++ }
+ }
+
+ static int compare(const struct ebt_entry_match *m1,
+@@ -414,6 +451,11 @@ static int compare(const struct ebt_entry_match *m1,
+ ipinfo1->icmp_code[1] != ipinfo2->icmp_code[1])
+ return 0;
+ }
++ if (ipinfo1->bitmask & EBT_IP_IGMP) {
++ if (ipinfo1->igmp_type[0] != ipinfo2->igmp_type[0] ||
++ ipinfo1->igmp_type[1] != ipinfo2->igmp_type[1])
++ return 0;
++ }
+ return 1;
+ }
+
+diff --git a/useful_functions.c b/useful_functions.c
+index 8f54bae83fae..8a34f820f230 100644
+--- a/useful_functions.c
++++ b/useful_functions.c
+@@ -486,8 +486,10 @@ int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
+
+ if (match < n_codes) {
+ type[0] = type[1] = icmp_codes[match].type;
+- code[0] = icmp_codes[match].code_min;
+- code[1] = icmp_codes[match].code_max;
++ if (code) {
++ code[0] = icmp_codes[match].code_min;
++ code[1] = icmp_codes[match].code_max;
++ }
+ } else {
+ char *next = parse_range(icmptype, 0, 255, number);
+ if (!next) {
+@@ -499,17 +501,21 @@ int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
+ type[1] = (uint8_t) number[1];
+ switch (*next) {
+ case 0:
+- code[0] = 0;
+- code[1] = 255;
++ if (code) {
++ 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;
++ if (code) {
++ 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);
+@@ -521,6 +527,9 @@ int ebt_parse_icmp(const struct ebt_icmp_names *icmp_codes, size_t n_codes,
+
+ static void print_icmp_code(uint8_t *code)
+ {
++ if (!code)
++ return;
++
+ if (code[0] == code[1])
+ printf("/%"PRIu8 " ", code[0]);
+ else
+@@ -542,8 +551,8 @@ void ebt_print_icmp_type(const struct ebt_icmp_names *icmp_codes,
+ if (icmp_codes[i].type != type[0])
+ continue;
+
+- if (icmp_codes[i].code_min == code[0] &&
+- icmp_codes[i].code_max == code[1]) {
++ if (!code || (icmp_codes[i].code_min == code[0] &&
++ icmp_codes[i].code_max == code[1])) {
+ printf("%s ", icmp_codes[i].name);
+ return;
+ }
+--
+2.16.2
+
diff --git a/target/linux/generic/patches-4.4/614-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch b/target/linux/generic/patches-4.4/614-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1f3d1a2fea50154238c03707b0d7a96db8d1f5d9
--- /dev/null
+++ b/target/linux/generic/patches-4.4/614-0001-ebtables-add-support-for-matching-ICMP-type-and-code.patch
@@ -0,0 +1,139 @@
+From 4f8fa78149e0921c8efdc1adc5e12686ffe7667f Mon Sep 17 00:00:00 2001
+Message-Id: <4f8fa78149e0921c8efdc1adc5e12686ffe7667f.1520150717.git.mschiffer@universe-factory.net>
+In-Reply-To: <cover.1520150717.git.mschiffer@universe-factory.net>
+References: <cover.1520150717.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 3 Mar 2018 11:55:21 +0100
+Subject: [PATCH nf-next 1/2] ebtables: add support for matching ICMP type and
+ code
+
+We already have ICMPv6 type/code matches. This adds support for IPv4 ICMP
+matches in the same way.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ include/uapi/linux/netfilter_bridge/ebt_ip.h | 13 +++++++--
+ net/bridge/netfilter/ebt_ip.c | 43 +++++++++++++++++++++-------
+ 2 files changed, 43 insertions(+), 13 deletions(-)
+
+--- a/include/uapi/linux/netfilter_bridge/ebt_ip.h
++++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h
+@@ -23,8 +23,9 @@
+ #define EBT_IP_PROTO 0x08
+ #define EBT_IP_SPORT 0x10
+ #define EBT_IP_DPORT 0x20
++#define EBT_IP_ICMP 0x40
+ #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+- EBT_IP_SPORT | EBT_IP_DPORT )
++ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP)
+ #define EBT_IP_MATCH "ip"
+
+ /* the same values are used for the invflags */
+@@ -37,8 +38,14 @@ struct ebt_ip_info {
+ __u8 protocol;
+ __u8 bitmask;
+ __u8 invflags;
+- __u16 sport[2];
+- __u16 dport[2];
++ union {
++ __u16 sport[2];
++ __u8 icmp_type[2];
++ };
++ union {
++ __u16 dport[2];
++ __u8 icmp_code[2];
++ };
+ };
+
+ #endif
+--- a/net/bridge/netfilter/ebt_ip.c
++++ b/net/bridge/netfilter/ebt_ip.c
+@@ -19,9 +19,15 @@
+ #include <linux/netfilter_bridge/ebtables.h>
+ #include <linux/netfilter_bridge/ebt_ip.h>
+
+-struct tcpudphdr {
+- __be16 src;
+- __be16 dst;
++union pkthdr {
++ struct {
++ __be16 src;
++ __be16 dst;
++ } tcpudphdr;
++ struct {
++ u8 type;
++ u8 code;
++ } icmphdr;
+ };
+
+ static bool
+@@ -30,8 +36,8 @@ ebt_ip_mt(const struct sk_buff *skb, str
+ const struct ebt_ip_info *info = par->matchinfo;
+ const struct iphdr *ih;
+ struct iphdr _iph;
+- const struct tcpudphdr *pptr;
+- struct tcpudphdr _ports;
++ const union pkthdr *pptr;
++ union pkthdr _pkthdr;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL)
+@@ -50,29 +56,38 @@ ebt_ip_mt(const struct sk_buff *skb, str
+ if (info->bitmask & EBT_IP_PROTO) {
+ if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO))
+ return false;
+- if (!(info->bitmask & EBT_IP_DPORT) &&
+- !(info->bitmask & EBT_IP_SPORT))
++ if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT |
++ EBT_IP_ICMP)))
+ return true;
+ if (ntohs(ih->frag_off) & IP_OFFSET)
+ return false;
++
++ /* min icmp headersize is 4, so sizeof(_pkthdr) is ok. */
+ pptr = skb_header_pointer(skb, ih->ihl*4,
+- sizeof(_ports), &_ports);
++ sizeof(_pkthdr), &_pkthdr);
+ if (pptr == NULL)
+ return false;
+ if (info->bitmask & EBT_IP_DPORT) {
+- u32 dst = ntohs(pptr->dst);
++ u32 dst = ntohs(pptr->tcpudphdr.dst);
+ if (FWINV(dst < info->dport[0] ||
+ dst > info->dport[1],
+ EBT_IP_DPORT))
+ return false;
+ }
+ if (info->bitmask & EBT_IP_SPORT) {
+- u32 src = ntohs(pptr->src);
++ u32 src = ntohs(pptr->tcpudphdr.src);
+ if (FWINV(src < info->sport[0] ||
+ src > info->sport[1],
+ EBT_IP_SPORT))
+ return false;
+ }
++ if ((info->bitmask & EBT_IP_ICMP) &&
++ FWINV(pptr->icmphdr.type < info->icmp_type[0] ||
++ pptr->icmphdr.type > info->icmp_type[1] ||
++ pptr->icmphdr.code < info->icmp_code[0] ||
++ pptr->icmphdr.code > info->icmp_code[1],
++ EBT_IP_ICMP))
++ return false;
+ }
+ return true;
+ }
+@@ -101,6 +116,14 @@ static int ebt_ip_mt_check(const struct
+ return -EINVAL;
+ if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1])
+ return -EINVAL;
++ if (info->bitmask & EBT_IP_ICMP) {
++ if ((info->invflags & EBT_IP_PROTO) ||
++ info->protocol != IPPROTO_ICMP)
++ return -EINVAL;
++ if (info->icmp_type[0] > info->icmp_type[1] ||
++ info->icmp_code[0] > info->icmp_code[1])
++ return -EINVAL;
++ }
+ return 0;
+ }
+
diff --git a/target/linux/generic/patches-4.4/614-0002-ebtables-add-support-for-matching-IGMP-type.patch b/target/linux/generic/patches-4.4/614-0002-ebtables-add-support-for-matching-IGMP-type.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3c8760dbebefddb9bb6a0b9bb724210c573d854c
--- /dev/null
+++ b/target/linux/generic/patches-4.4/614-0002-ebtables-add-support-for-matching-IGMP-type.patch
@@ -0,0 +1,92 @@
+From 68c6d1b60803e9690f2a6168b80a92ae45c6578b Mon Sep 17 00:00:00 2001
+Message-Id: <68c6d1b60803e9690f2a6168b80a92ae45c6578b.1520150717.git.mschiffer@universe-factory.net>
+In-Reply-To: <cover.1520150717.git.mschiffer@universe-factory.net>
+References: <cover.1520150717.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 3 Mar 2018 12:02:21 +0100
+Subject: [PATCH nf-next 2/2] ebtables: add support for matching IGMP type
+
+We already have ICMPv6 type/code matches (which can be used to distinguish
+different types of MLD packets). Add support for IPv4 IGMP matches in the
+same way.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ include/uapi/linux/netfilter_bridge/ebt_ip.h | 4 +++-
+ net/bridge/netfilter/ebt_ip.c | 19 +++++++++++++++++--
+ 2 files changed, 20 insertions(+), 3 deletions(-)
+
+--- a/include/uapi/linux/netfilter_bridge/ebt_ip.h
++++ b/include/uapi/linux/netfilter_bridge/ebt_ip.h
+@@ -24,8 +24,9 @@
+ #define EBT_IP_SPORT 0x10
+ #define EBT_IP_DPORT 0x20
+ #define EBT_IP_ICMP 0x40
++#define EBT_IP_IGMP 0x80
+ #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+- EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP)
++ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
+ #define EBT_IP_MATCH "ip"
+
+ /* the same values are used for the invflags */
+@@ -41,6 +42,7 @@ struct ebt_ip_info {
+ union {
+ __u16 sport[2];
+ __u8 icmp_type[2];
++ __u8 igmp_type[2];
+ };
+ union {
+ __u16 dport[2];
+--- a/net/bridge/netfilter/ebt_ip.c
++++ b/net/bridge/netfilter/ebt_ip.c
+@@ -28,6 +28,9 @@ union pkthdr {
+ u8 type;
+ u8 code;
+ } icmphdr;
++ struct {
++ u8 type;
++ } igmphdr;
+ };
+
+ static bool
+@@ -57,12 +60,12 @@ ebt_ip_mt(const struct sk_buff *skb, str
+ if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO))
+ return false;
+ if (!(info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT |
+- EBT_IP_ICMP)))
++ EBT_IP_ICMP | EBT_IP_IGMP)))
+ return true;
+ if (ntohs(ih->frag_off) & IP_OFFSET)
+ return false;
+
+- /* min icmp headersize is 4, so sizeof(_pkthdr) is ok. */
++ /* min icmp/igmp headersize is 4, so sizeof(_pkthdr) is ok. */
+ pptr = skb_header_pointer(skb, ih->ihl*4,
+ sizeof(_pkthdr), &_pkthdr);
+ if (pptr == NULL)
+@@ -88,6 +91,11 @@ ebt_ip_mt(const struct sk_buff *skb, str
+ pptr->icmphdr.code > info->icmp_code[1],
+ EBT_IP_ICMP))
+ return false;
++ if ((info->bitmask & EBT_IP_IGMP) &&
++ FWINV(pptr->igmphdr.type < info->igmp_type[0] ||
++ pptr->igmphdr.type > info->igmp_type[1],
++ EBT_IP_IGMP))
++ return false;
+ }
+ return true;
+ }
+@@ -124,6 +132,13 @@ static int ebt_ip_mt_check(const struct
+ info->icmp_code[0] > info->icmp_code[1])
+ return -EINVAL;
+ }
++ if (info->bitmask & EBT_IP_IGMP) {
++ if ((info->invflags & EBT_IP_PROTO) ||
++ info->protocol != IPPROTO_IGMP)
++ return -EINVAL;
++ if (info->igmp_type[0] > info->igmp_type[1])
++ return -EINVAL;
++ }
+ return 0;
+ }
+
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment