From patchwork Sun Mar 4 08:28:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Schiffer X-Patchwork-Id: 881143 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=universe-factory.net Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3zvGZ53Y8Sz9s8J for ; Sun, 4 Mar 2018 19:35:09 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752539AbeCDIfE (ORCPT ); Sun, 4 Mar 2018 03:35:04 -0500 Received: from orthanc.universe-factory.net ([104.238.176.138]:33520 "EHLO orthanc.universe-factory.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751819AbeCDIfC (ORCPT ); Sun, 4 Mar 2018 03:35:02 -0500 X-Greylist: delayed 342 seconds by postgrey-1.27 at vger.kernel.org; Sun, 04 Mar 2018 03:35:01 EST Received: from localhost.localdomain (unknown [IPv6:2001:19f0:6c01:100::2]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by orthanc.universe-factory.net (Postfix) with ESMTPSA id DBFFA1F4EF; Sun, 4 Mar 2018 09:29:19 +0100 (CET) From: Matthias Schiffer To: pablo@netfilter.org Cc: kadlec@blackhole.kfki.hu, fw@strlen.de, netfilter-devel@vger.kernel.org Subject: [PATCH ebtables 4/4] ebt_ip: add support for matching IGMP type Date: Sun, 4 Mar 2018 09:28:58 +0100 Message-Id: X-Mailer: git-send-email 2.16.2 In-Reply-To: References: In-Reply-To: References: Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org 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; }