浏览代码

Add overlooked MATCH_ICMP to rule set.

Adam Ierymenko 9 年之前
父节点
当前提交
8e3004591b
共有 4 个文件被更改,包括 105 次插入8 次删除
  1. 20 0
      controller/EmbeddedNetworkController.cpp
  2. 22 8
      include/ZeroTierOne.h
  3. 11 0
      node/Capability.hpp
  4. 52 0
      node/Network.cpp

+ 20 - 0
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);

+ 22 - 8
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
 		 */

+ 11 - 0
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<uint16_t>(p);

+ 52 - 0
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)) {