diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index c4696e7d5..db405c083 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -525,7 +525,22 @@ enum ZT_VirtualNetworkRuleType /** * Frame size range (start-end, inclusive) */ - ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 49 + ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE = 49, + + /** + * Match a range of tag values (equality match if start==end) + */ + ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE = 50, + + /** + * Match if all bits are set in a tag value + */ + ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL = 51, + + /** + * Match if any bit from a mask is set in a tag value + */ + ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY = 52 }; /** @@ -628,6 +643,14 @@ typedef struct * Ethernet packet size in host byte order (start-end, inclusive) */ uint16_t frameSize[2]; + + /** + * For matching tag values + */ + struct { + uint32_t id; + uint32_t value[2]; // only [0] is used for BITS_ALL or BITS_ANY, [0]-[1] for range + } tag; } v; } ZT_VirtualNetworkRule; diff --git a/node/Capability.hpp b/node/Capability.hpp index 6de4e0a11..823428745 100644 --- a/node/Capability.hpp +++ b/node/Capability.hpp @@ -158,21 +158,15 @@ public: int verify(const RuntimeEnvironment *RR,const Address &verifyInChain) const; template - inline void serialize(Buffer &b,const bool forSign = false) const + static inline void serializeRules(Buffer &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) { - if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); - - b.append(_id); - b.append(_nwid); - b.append(_expiration); - - b.append((uint16_t)_ruleCount); - for(unsigned int i=0;i<_ruleCount;++i) { + b.append((uint16_t)ruleCount); + for(unsigned int i=0;i + inline void serialize(Buffer &b,const bool forSign = false) const + { + if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); + + b.append(_id); + b.append(_nwid); + b.append(_expiration); + + serializeRules(b,_rules,_ruleCount); b.append((uint8_t)_maxCustodyChainLength); for(unsigned int i=0;;++i) { @@ -268,6 +286,84 @@ public: if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL); } + template + static inline void deserializeRules(const Buffer &b,unsigned int &p,ZT_VirtualNetworkRule *rules,unsigned int &ruleCount,const unsigned int maxRuleCount) + { + ruleCount = b.template at(p); p += 2; + if (ruleCount > maxRuleCount) + throw std::runtime_error("rule count overflow"); + for(unsigned int i=0;i(p); + break; + case ZT_NETWORK_RULE_MATCH_VLAN_PCP: + rules[i].v.vlanPcp = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_VLAN_DEI: + rules[i].v.vlanDei = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_ETHERTYPE: + rules[i].v.etherType = b.template at(p); + break; + case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: + case ZT_NETWORK_RULE_MATCH_MAC_DEST: + memcpy(rules[i].v.mac,b.field(p,6),6); + break; + case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV4_DEST: + memcpy(&(rules[i].v.ipv4.ip),b.field(p,4),4); + rules[i].v.ipv4.mask = (uint8_t)b[p + 4]; + break; + case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: + case ZT_NETWORK_RULE_MATCH_IPV6_DEST: + memcpy(rules[i].v.ipv6.ip,b.field(p,16),16); + rules[i].v.ipv6.mask = (uint8_t)b[p + 16]; + break; + case ZT_NETWORK_RULE_MATCH_IP_TOS: + rules[i].v.ipTos = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: + rules[i].v.ipProtocol = (uint8_t)b[p]; + break; + case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: + case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: + rules[i].v.port[0] = b.template at(p); + rules[i].v.port[1] = b.template at(p + 2); + break; + case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: + rules[i].v.characteristics[0] = b.template at(p); + rules[i].v.characteristics[1] = b.template at(p + 8); + break; + case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: + rules[i].v.frameSize[0] = b.template at(p); + rules[i].v.frameSize[0] = b.template at(p + 2); + break; + case ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE: + rules[i].v.tag.id = b.template at(p); + rules[i].v.tag.value[0] = b.template at(p + 4); + rules[i].v.tag.value[1] = b.template at(p + 8); + break; + case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL: + case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY: + rules[i].v.tag.id = b.template at(p); + rules[i].v.tag.value[0] = b.template at(p + 4); + break; + } + p += fieldLen; + } + } + template inline unsigned int deserialize(const Buffer &b,unsigned int startAt = 0) { @@ -279,69 +375,7 @@ public: _nwid = b.template at(p); p += 8; _expiration = b.template at(p); p += 8; - _ruleCount = b.template at(p); p += 2; - if (_ruleCount > ZT_MAX_CAPABILITY_RULES) - throw std::runtime_error("rule count overflow"); - for(unsigned int i=0;i<_ruleCount;++i) { - _rules[i].t = (uint8_t)b[p++]; - const unsigned int fieldLen = (unsigned int)b[p++]; - switch((ZT_VirtualNetworkRuleType)(_rules[i].t & 0x7f)) { - default: - break; - case ZT_NETWORK_RULE_ACTION_TEE: - case ZT_NETWORK_RULE_ACTION_REDIRECT: - case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: - case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: - _rules[i].v.zt = Address(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_ID: - _rules[i].v.vlanId = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_VLAN_PCP: - _rules[i].v.vlanPcp = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_VLAN_DEI: - _rules[i].v.vlanDei = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_ETHERTYPE: - _rules[i].v.etherType = b.template at(p); - break; - case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: - case ZT_NETWORK_RULE_MATCH_MAC_DEST: - memcpy(_rules[i].v.mac,b.field(p,6),6); - break; - case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV4_DEST: - memcpy(&(_rules[i].v.ipv4.ip),b.field(p,4),4); - _rules[i].v.ipv4.mask = (uint8_t)b[p + 4]; - break; - case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: - case ZT_NETWORK_RULE_MATCH_IPV6_DEST: - memcpy(_rules[i].v.ipv6.ip,b.field(p,16),16); - _rules[i].v.ipv6.mask = (uint8_t)b[p + 16]; - break; - case ZT_NETWORK_RULE_MATCH_IP_TOS: - _rules[i].v.ipTos = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: - _rules[i].v.ipProtocol = (uint8_t)b[p]; - break; - case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: - case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: - _rules[i].v.port[0] = b.template at(p); - _rules[i].v.port[1] = b.template at(p + 2); - break; - case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: - _rules[i].v.characteristics[0] = b.template at(p); - _rules[i].v.characteristics[1] = b.template at(p + 8); - break; - case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: - _rules[i].v.frameSize[0] = b.template at(p); - _rules[i].v.frameSize[0] = b.template at(p + 2); - break; - } - p += fieldLen; - } + deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES); _maxCustodyChainLength = (unsigned int)b[p++]; if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) diff --git a/node/Filter.cpp b/node/Filter.cpp index a4de7201a..d86d1a14f 100644 --- a/node/Filter.cpp +++ b/node/Filter.cpp @@ -243,6 +243,11 @@ bool Filter::run( case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1])); break; + case ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE: + break; + case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL: + case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY: + break; } // thisSetMatches remains true if the current rule matched... or does NOT match if not bit (0x80) is 1