From b5fbb8d786c914d67fa98db2a205f6cc983a166c Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 4 Mar 2018 09:28:57 +0100 Subject: 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 Signed-off-by: Pablo Neira Ayuso --- 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 59559fe..42660d4 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; } -- cgit v1.2.3