From 7c9e1e1007d149106aacc167bc4f264b23a2bdd5 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 4 Mar 2018 10:27:05 +0100 Subject: [PATCH] ebtables: add support for ICMP/IGMP type matches --- ...d-support-for-ICMP-IGMP-type-matches.patch | 1183 +++++++++++++++++ 1 file changed, 1183 insertions(+) create mode 100644 patches/lede/0067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch diff --git a/patches/lede/0067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch b/patches/lede/0067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch new file mode 100644 index 00000000..c5b4de9a --- /dev/null +++ b/patches/lede/0067-ebtables-add-support-for-ICMP-IGMP-type-matches.patch @@ -0,0 +1,1183 @@ +From: Matthias Schiffer +Date: Sun, 4 Mar 2018 10:26:34 +0100 +Subject: ebtables: add support for ICMP/IGMP type matches + +Signed-off-by: Matthias Schiffer + +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: ++References: ++From: Matthias Schiffer ++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 ++--- ++ 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: ++In-Reply-To: ++References: ++From: Matthias Schiffer ++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 ++--- ++ 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 ++-#include ++-#include ++ #include ++ #include ++ #include ++@@ -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 +++#include +++#include ++ #include ++ #include ++ #include ++@@ -34,6 +37,7 @@ ++ #include ++ #include ++ +++ ++ 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: ++References: ++From: Matthias Schiffer ++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 ++--- ++ 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: ++In-Reply-To: ++References: ++From: Matthias Schiffer ++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 ++--- ++ 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: ++References: ++From: Matthias Schiffer ++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 ++--- ++ 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 ++ #include ++ ++-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: ++References: ++From: Matthias Schiffer ++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 ++--- ++ 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; ++ } ++