diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 0a1ee2ef8..29dd8ad70 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -255,8 +255,8 @@ static json _renderRule(ZT_VirtualNetworkRule &rule) r["start"] = (unsigned int)rule.v.frameSize[0]; r["end"] = (unsigned int)rule.v.frameSize[1]; break; - case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: - r["type"] = "MATCH_TAGS_SAMENESS"; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: + r["type"] = "MATCH_TAGS_DIFFERENCE"; r["not"] = ((rule.t & 0x80) != 0); r["id"] = rule.v.tag.id; r["value"] = rule.v.tag.value; @@ -431,8 +431,8 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule) rule.v.frameSize[0] = (uint16_t)(_jI(r["start"],0ULL) & 0xffffULL); rule.v.frameSize[1] = (uint16_t)(_jI(r["end"],(uint64_t)rule.v.frameSize[0]) & 0xffffULL); return true; - } else if (t == "MATCH_TAGS_SAMENESS") { - rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS; + } else if (t == "MATCH_TAGS_DIFFERENCE") { + rule.t |= ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE; rule.v.tag.id = (uint32_t)(_jI(r["id"],0ULL) & 0xffffffffULL); rule.v.tag.value = (uint32_t)(_jI(r["value"],0ULL) & 0xffffffffULL); return true; diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 121de7a26..734500060 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -625,7 +625,7 @@ enum ZT_VirtualNetworkRuleType /** * Match if local and remote tags differ by no more than value, use 0 to check for equality */ - ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS = 51, + ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 51, /** * Match if local and remote tags ANDed together equal value. diff --git a/node/Capability.hpp b/node/Capability.hpp index f62ed30b6..8e749e809 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -38,9 +38,6 @@ class RuntimeEnvironment; /** * A set of grouped and signed network flow rules * - * The use of capabilities implements capability-based security on ZeroTIer - * virtual networks for efficient and manageable network micro-segmentation. - * * On the sending side the sender does the following for each packet: * * (1) Evaluates its capabilities in ascending order of ID to determine @@ -49,16 +46,12 @@ class RuntimeEnvironment; * receving peer ("presents" it). * (3) The sender then sends the packet. * - * On the receiving side the receiver does the following for each packet: + * On the receiving side the receiver evaluates the capabilities presented + * by the sender. If any valid un-expired capability allows this packet it + * is accepted. * - * (1) Evaluates the capabilities of the sender (that the sender has - * presented) to determine if it should received this packet. - * (2) Evaluates its own capabilities to determine if it should receive - * this packet. - * (3) If both check out, it receives the packet. - * - * Note that rules in capabilities can do other things as well such as TEE - * or REDIRECT packets. See filter code and ZT_VirtualNetworkRule. + * Note that this is after evaluation of network scope rules and only if + * network scope rules do not deliver an explicit match. */ class Capability { @@ -255,7 +248,7 @@ public: b.append((uint16_t)rules[i].v.frameSize[0]); b.append((uint16_t)rules[i].v.frameSize[1]); break; - case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: @@ -336,7 +329,7 @@ public: rules[ruleCount].v.frameSize[0] = b.template at(p); rules[ruleCount].v.frameSize[1] = b.template at(p + 2); break; - case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: diff --git a/node/Network.cpp b/node/Network.cpp index 026a07fce..f8b7c1d52 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -69,7 +69,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: return "MATCH_IP_DEST_PORT_RANGE"; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: return "MATCH_CHARACTERISTICS"; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: return "MATCH_FRAME_SIZE_RANGE"; - case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: return "MATCH_TAGS_SAMENESS"; + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: return "MATCH_TAGS_DIFFERENCE"; case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: return "MATCH_TAGS_BITWISE_AND"; case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: return "MATCH_TAGS_BITWISE_OR"; case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: return "MATCH_TAGS_BITWISE_XOR"; @@ -487,7 +487,7 @@ static int _doZtFilter( thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); FILTER_TRACE("%u %s %c %u in %u-%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),frameLen,(unsigned int)rules[rn].v.frameSize[0],(unsigned int)rules[rn].v.frameSize[1],(unsigned int)thisRuleMatches); break; - case ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS: + case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR: { @@ -510,13 +510,18 @@ static int _doZtFilter( } } if (!rtv) { - thisRuleMatches = 0; - FILTER_TRACE("%u %s %c remote tag %u not found -> 0",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); + if (inbound) { + thisRuleMatches = 0; + FILTER_TRACE("%u %s %c remote tag %u not found -> 0 (inbound side is strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); + } else { + thisRuleMatches = 1; + FILTER_TRACE("%u %s %c remote tag %u not found -> 1 (outbound side is not strict)",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id); + } } else { - if (rt == ZT_NETWORK_RULE_MATCH_TAGS_SAMENESS) { - const uint32_t sameness = (lt->value() > *rtv) ? (lt->value() - *rtv) : (*rtv - lt->value()); - thisRuleMatches = (uint8_t)(sameness <= rules[rn].v.tag.value); - FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u sameness:%u <= %u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,sameness,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); + if (rt == ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE) { + const uint32_t diff = (lt->value() > *rtv) ? (lt->value() - *rtv) : (*rtv - lt->value()); + thisRuleMatches = (uint8_t)(diff <= rules[rn].v.tag.value); + FILTER_TRACE("%u %s %c TAG %u local:%u remote:%u difference:%u<=%u -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,diff,(unsigned int)rules[rn].v.tag.value,thisRuleMatches); } else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND) { thisRuleMatches = (uint8_t)((lt->value() & *rtv) == rules[rn].v.tag.value); FILTER_TRACE("%u %s %c TAG %u local:%.8x & remote:%.8x == %.8x -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)rules[rn].v.tag.id,lt->value(),*rtv,(unsigned int)rules[rn].v.tag.value,(unsigned int)thisRuleMatches); @@ -675,22 +680,22 @@ int Network::filterIncomingPacket( const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS); switch (_doZtFilter(RR,false,_config,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: return 0; - case 1: return 1; - case 2: return 2; + case -1: return 0; // DROP + case 1: return 1; // ACCEPT + case 2: return 2; // super-ACCEPT } Membership::CapabilityIterator mci(m); const Capability *c; while ((c = mci.next(_config))) { - switch(_doZtFilter(RR,false,_config,false,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { - case -1: return 0; - case 1: return 1; - case 2: return 2; + switch(_doZtFilter(RR,false,_config,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount)) { + case -1: return 0; // DROP + case 1: return 1; // ACCEPT + case 2: return 2; // super-ACCEPT } } - return 0; + return 0; // DROP } bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBridgedGroups) const