From 8e3004591bae72e20232200b74fe145f5574d02e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 31 Aug 2016 14:01:15 -0700 Subject: [PATCH] Add overlooked MATCH_ICMP to rule set. --- controller/EmbeddedNetworkController.cpp | 20 +++++++++ include/ZeroTierOne.h | 30 ++++++++++---- node/Capability.hpp | 11 +++++ node/Network.cpp | 52 ++++++++++++++++++++++++ 4 files changed, 105 insertions(+), 8 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 5c52cfcbf..0a1ee2ef8 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -221,6 +221,14 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) r["not"] = ((rule.t & 0x80) != 0); r["ipProtocol"] = (unsigned int)rule.v.ipProtocol; break; + case ZT_NETWORK_RULE_MATCH_ICMP: + r["type"] = "MATCH_ICMP"; + r["not"] = ((rule.t & 0x80) != 0); + r["type"] = (unsigned int)rule.v.icmp.type; + if ((rule.v.icmp.flags & 0x01) != 0) + r["code"] = (unsigned int)rule.v.icmp.code; + else r["code"] = json(); + break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: r["type"] = "MATCH_IP_SOURCE_PORT_RANGE"; r["not"] = ((rule.t & 0x80) != 0); @@ -375,6 +383,18 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) rule.t |= ZT_NETWORK_RULE_MATCH_IP_PROTOCOL; rule.v.ipProtocol = (uint8_t)(_jI(r["ipProtocol"],0ULL) & 0xffULL); return true; + } else if (t == "MATCH_ICMP") { + rule.t |= ZT_NETWORK_RULE_MATCH_ICMP; + rule.v.icmp.type = (uint8_t)(_jI(r["type"],0ULL) & 0xffULL); + json &code = r["code"]; + if (code.is_null()) { + rule.v.icmp.code = 0; + rule.v.icmp.flags = 0x00; + } else { + rule.v.icmp.code = (uint8_t)(_jI(code,0ULL) & 0xffULL); + rule.v.icmp.flags = 0x01; + } + return true; } else if (t == "MATCH_IP_SOURCE_PORT_RANGE") { rule.t |= ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE; rule.v.port[0] = (uint16_t)(_jI(r["start"],0ULL) & 0xffffULL); diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 9dafcaa63..121de7a26 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -597,45 +597,50 @@ enum ZT_VirtualNetworkRuleType */ ZT_NETWORK_RULE_MATCH_IP_PROTOCOL = 45, + /** + * ICMP type and possibly code (does not match if not ICMP) + */ + ZT_NETWORK_RULE_MATCH_ICMP = 46, + /** * IP source port range (start-end, inclusive) */ - ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 46, + ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE = 47, /** * IP destination port range (start-end, inclusive) */ - ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 47, + ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE = 48, /** * Packet characteristics (set of flags) */ - ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 48, + ZT_NETWORK_RULE_MATCH_CHARACTERISTICS = 49, /** * Frame size range (start-end, inclusive) */ - ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 49, + ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 50, /** * Match if local and remote tags differ by no more than value, use 0 to check for equality */ - ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS = 50, + ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS = 51, /** * Match if local and remote tags ANDed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 51, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 52, /** * Match if local and remote tags ANDed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 52, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 53, /** * Match if local and remote tags XORed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 53 + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 54 }; /** @@ -739,6 +744,15 @@ typedef struct */ uint16_t frameSize[2]; + /** + * ICMP type and code + */ + struct { + uint8_t type; // ICMP type, always matched + uint8_t code; // ICMP code if matched + uint8_t flags; // flag 0x01 means also match code, otherwise only match type + } icmp; + /** * For tag-related rules */ diff --git a/node/Capability.hpp b/node/Capability.hpp index 46fa9da61..f62ed30b6 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -233,6 +233,12 @@ public: b.append((uint8_t)1); b.append((uint8_t)rules[i].v.ipProtocol); break; + case ZT_NETWORK_RULE_MATCH_ICMP: + b.append((uint8_t)3); + b.append((uint8_t)rules[i].v.icmp.type); + b.append((uint8_t)rules[i].v.icmp.code); + b.append((uint8_t)rules[i].v.icmp.flags); + break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: b.append((uint8_t)4); @@ -312,6 +318,11 @@ public: case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: rules[ruleCount].v.ipProtocol = (uint8_t)b[p]; break; + case ZT_NETWORK_RULE_MATCH_ICMP: + rules[ruleCount].v.icmp.type = (uint8_t)b[p]; + rules[ruleCount].v.icmp.code = (uint8_t)b[p+1]; + rules[ruleCount].v.icmp.flags = (uint8_t)b[p+2]; + break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: rules[ruleCount].v.port[0] = b.template at(p); diff --git a/node/Network.cpp b/node/Network.cpp index 0279bc530..026a07fce 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -64,6 +64,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) case ZT_NETWORK_RULE_MATCH_IPV6_DEST: return "MATCH_IPV6_DEST"; case ZT_NETWORK_RULE_MATCH_IP_TOS: return "MATCH_IP_TOS"; case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: return "MATCH_IP_PROTOCOL"; + case ZT_NETWORK_RULE_MATCH_ICMP: return "MATCH_ICMP"; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: return "MATCH_IP_SOURCE_PORT_RANGE"; case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: return "MATCH_IP_DEST_PORT_RANGE"; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: return "MATCH_CHARACTERISTICS"; @@ -362,6 +363,57 @@ static int _doZtFilter( FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); } break; + case ZT_NETWORK_RULE_MATCH_ICMP: + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + if (frameData[9] == 0x01) { + const unsigned int ihl = (frameData[0] & 0xf) * 32; + if (frameLen >= (ihl + 2)) { + if (rules[rn].v.icmp.type == frameData[ihl]) { + if ((rules[rn].v.icmp.flags & 0x01) != 0) { + thisRuleMatches = (uint8_t)(frameData[ihl+1] == rules[rn].v.icmp.code); + } else { + thisRuleMatches = 1; + } + } else { + thisRuleMatches = 0; + } + FILTER_TRACE("%u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[ihl],(int)rules[rn].v.icmp.type,(int)frameData[ihl+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); + } else { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c [IPv4 frame invalid] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); + } + } else { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c [frame not ICMP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); + } + } else if (etherType == ZT_ETHERTYPE_IPV6) { + unsigned int pos = 0,proto = 0; + if (_ipv6GetPayload(frameData,frameLen,pos,proto)) { + if ((proto == 0x3a)&&(frameLen >= (pos+2))) { + if (rules[rn].v.icmp.type == frameData[pos]) { + if ((rules[rn].v.icmp.flags & 0x01) != 0) { + thisRuleMatches = (uint8_t)(frameData[pos+1] == rules[rn].v.icmp.code); + } else { + thisRuleMatches = 1; + } + } else { + thisRuleMatches = 0; + } + FILTER_TRACE("%u %s %c (IPv4) icmp-type:%d==%d icmp-code:%d==%d -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(int)frameData[pos],(int)rules[rn].v.icmp.type,(int)frameData[pos+1],(((rules[rn].v.icmp.flags & 0x01) != 0) ? (int)rules[rn].v.icmp.code : -1),(unsigned int)thisRuleMatches); + } else { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c [frame not ICMPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); + } + } else { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c [invalid IPv6] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); + } + } else { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c [frame not IP] -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '=')); + } + break; + break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {