From 4ef0ed9b3a8494fd33b8990523f5054dd023f4f3 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Sat, 6 Jan 2018 12:58:02 +0800 Subject: [PATCH] ipfw: Support all possible ICMP types. --- sbin/ipfw/ipfw.8 | 4 ++-- sbin/ipfw/ipfw2.c | 35 +++++++++++++++++++++++------------ sys/net/ipfw/ip_fw2.c | 12 ++++++++++-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8 index e5ebf00334..8781a16ff9 100644 --- a/sbin/ipfw/ipfw.8 +++ b/sbin/ipfw/ipfw.8 @@ -1,7 +1,7 @@ .\" .\" $FreeBSD: src/sbin/ipfw/ipfw.8,v 1.63.2.33 2003/02/04 01:36:02 brueffer Exp $ .\" -.Dd October 15, 2017 +.Dd January 6, 2018 .Dt IPFW 8 .Os .Sh NAME @@ -926,7 +926,7 @@ Matches ICMP packets whose ICMP type is in the list .Ar types . The list may be specified as any combination of ranges or individual types separated by commas. -The supported ICMP types are: +Commonly used ICMP types are: .Pp echo reply .Pq Cm 0 , diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c index 6e01db941d..da840da02e 100644 --- a/sbin/ipfw/ipfw2.c +++ b/sbin/ipfw/ipfw2.c @@ -734,38 +734,49 @@ static void fill_icmptypes(ipfw_insn_u32 *cmd, char *av) { u_int8_t type; + int idx_max = 0, idx; + + /* 256 / 32, (max icmp types / 32 bits). */ + for (idx = 0; idx < 8; ++idx) + cmd->d[idx] = 0; - cmd->d[0] = 0; while (*av) { if (*av == ',') av++; type = strtoul(av, &av, 0); - if (*av != ',' && *av != '\0') errx(EX_DATAERR, "invalid ICMP type"); - if (type > 31) - errx(EX_DATAERR, "ICMP type out of range"); + idx = type / 32; + cmd->d[idx] |= 1 << (type % 32); - cmd->d[0] |= 1 << type; + if (idx > idx_max) + idx_max = idx; } cmd->o.opcode = O_ICMPTYPE; - cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32); + cmd->o.len |= (F_INSN_SIZE(ipfw_insn_u32) + idx_max); } static void print_icmptypes(ipfw_insn_u32 *cmd) { - int i; + int idx, idx_max; char sep= ' '; + idx_max = F_LEN(&cmd->o) - F_INSN_SIZE(ipfw_insn); + printf(" icmptypes"); - for (i = 0; i < 32; i++) { - if ( (cmd->d[0] & (1 << (i))) == 0) - continue; - printf("%c%d", sep, i); - sep = ','; + for (idx = 0; idx < idx_max; ++idx) { + uint32_t types = cmd->d[idx]; + + while (types != 0) { + int type_shift = ffs(types) - 1; + + types &= ~(1 << type_shift); + printf("%c%d", sep, (idx * 32) + type_shift); + sep = ','; + } } } diff --git a/sys/net/ipfw/ip_fw2.c b/sys/net/ipfw/ip_fw2.c index f9d61888cb..470d5f621e 100644 --- a/sys/net/ipfw/ip_fw2.c +++ b/sys/net/ipfw/ip_fw2.c @@ -1186,8 +1186,12 @@ static __inline int icmptype_match(struct ip *ip, ipfw_insn_u32 *cmd) { int type = L3HDR(struct icmp,ip)->icmp_type; + int idx_max = F_LEN(&cmd->o) - F_INSN_SIZE(ipfw_insn); + int idx = type / 32; - return (type <= ICMP_MAXTYPE && (cmd->d[0] & (1 << type))); + if (idx >= idx_max) + return (0); + return (cmd->d[idx] & (1 << (type % 32))); } #define TT ((1 << ICMP_ECHO) | \ @@ -5430,6 +5434,11 @@ ipfw_check_ioc_rule(struct ipfw_ioc_rule *rule, int size, uint32_t *rule_flags) goto bad_size; break; + case O_ICMPTYPE: + if (cmdlen < F_INSN_SIZE(ipfw_insn_u32)) + goto bad_size; + break; + case O_UID: case O_GID: case O_IP_SRC: @@ -5437,7 +5446,6 @@ ipfw_check_ioc_rule(struct ipfw_ioc_rule *rule, int size, uint32_t *rule_flags) case O_TCPSEQ: case O_TCPACK: case O_PROB: - case O_ICMPTYPE: if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) goto bad_size; break; -- 2.11.4.GIT