diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index c60f73225..d656bad33 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -260,6 +260,11 @@ 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_RANDOM: + r["type"] = "MATCH_RANDOM"; + r["not"] = ((rule.t & 0x80) != 0); + r["probability"] = (unsigned long)rule.v.randomProbability; + break; case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: r["type"] = "MATCH_TAGS_DIFFERENCE"; r["not"] = ((rule.t & 0x80) != 0); @@ -441,6 +446,9 @@ 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_RANDOM") { + rule.t |= ZT_NETWORK_RULE_MATCH_RANDOM; + rule.v.randomProbability = (uint32_t)(_jI(r["probability"],0ULL) & 0xffffffffULL); } 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); diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index c66b90799..ee03c3b18 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -633,25 +633,30 @@ enum ZT_VirtualNetworkRuleType */ ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 50, + /** + * Random match with selectable probability + */ + ZT_NETWORK_RULE_MATCH_RANDOM = 51, + /** * Match if local and remote tags differ by no more than value, use 0 to check for equality */ - ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 51, + ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE = 52, /** * Match if local and remote tags ANDed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 52, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND = 53, /** * Match if local and remote tags ANDed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 53, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR = 54, /** * Match if local and remote tags XORed together equal value. */ - ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 54, + ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR = 55, /** * Maximum ID allowed for a MATCH entry in the rules table @@ -720,6 +725,11 @@ typedef struct */ uint64_t zt; + /** + * 0 = never, UINT32_MAX = always + */ + uint32_t randomProbability; + /** * 48-bit Ethernet MAC address in big-endian order */ diff --git a/node/Capability.hpp b/node/Capability.hpp index 2cf54b5c2..e808ad40f 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -249,6 +249,10 @@ 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_RANDOM: + b.append((uint8_t)4); + b.append((uint32_t)rules[i].v.randomProbability); + break; case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: @@ -331,6 +335,9 @@ 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_RANDOM: + rules[ruleCount].v.randomProbability = b.template at(p); + break; case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: diff --git a/node/Network.cpp b/node/Network.cpp index d38a3fdd5..fe899dccc 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -504,6 +504,10 @@ static _doZtFilterResult _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_RANDOM: + thisRuleMatches = (uint8_t)((uint32_t)(RR->node->prng() & 0xffffffffULL) <= rules[rn].v.randomProbability); + FILTER_TRACE("%u %s %c -> %u",rn,_rtn(rt),(((rules[rn].t & 0x80) != 0) ? '!' : '='),(unsigned int)thisRuleMatches); + break; case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND: case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_OR: