/* * Copyright (c)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. * * Change Date: 2024-01-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. */ /****/ #include "Capability.hpp" #include "Utils.hpp" #include "Constants.hpp" #include "MAC.hpp" namespace ZeroTier { bool Capability::sign(const Identity &from,const Address &to) noexcept { uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16]; try { for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i(data + p,_nwid); p += 8; Utils::storeBigEndian(data + p,(uint64_t)_ts); p += 8; Utils::storeBigEndian(data + p,_id); p += 4; Utils::storeBigEndian(data + p,(uint16_t)_ruleCount); p += 2; p += Capability::marshalVirtualNetworkRules(data + 22,_rules,_ruleCount); data[p++] = (uint8_t)_maxCustodyChainLength; if (!forSign) { for(unsigned int i=0;;++i) { if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) { _custody[i].to.copyTo(data + p); p += ZT_ADDRESS_LENGTH; _custody[i].from.copyTo(data + p); p += ZT_ADDRESS_LENGTH; data[p++] = 1; Utils::storeBigEndian(data + p,(uint16_t)_custody[i].signatureLength); p += 2; for(unsigned int k=0;k<_custody[i].signatureLength;++k) data[p++] = _custody[i].signature[k]; } else { for(int k=0;k(data); _ts = (int64_t)Utils::loadBigEndian(data + 8); _id = Utils::loadBigEndian(data + 16); const unsigned int rc = Utils::loadBigEndian(data + 20);; if (rc > ZT_MAX_CAPABILITY_RULES) return -1; const int rulesLen = unmarshalVirtualNetworkRules(data + 22,len - 22,_rules,_ruleCount,rc); if (rulesLen < 0) return rulesLen; int p = 22 + rulesLen; if (p >= len) return -1; _maxCustodyChainLength = data[p++]; for(unsigned int i=0;;++i) { if ((p + ZT_ADDRESS_LENGTH) > len) return -1; const Address to(data + p); p += ZT_ADDRESS_LENGTH; if (!to) break; if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)) return -1; _custody[i].to = to; if ((p + ZT_ADDRESS_LENGTH) > len) return -1; _custody[i].from.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1; if ((p + 2) > len) return -1; const unsigned int sl = Utils::loadBigEndian(data + p); p += 2; _custody[i].signatureLength = sl; if ((sl > sizeof(_custody[i].signature))||((p + (int)sl) > len)) return -1; Utils::copy(_custody[i].signature,data + p,sl); p += (int)sl; } if ((p + 2) > len) return -1; p += 2 + Utils::loadBigEndian(data + p); if (p > len) return -1; return p; } int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) noexcept { int p = 0; for(unsigned int i=0;i(data + p,rules[i].v.fwd.address); p += 8; Utils::storeBigEndian(data + p,rules[i].v.fwd.flags); p += 4; Utils::storeBigEndian(data + p,rules[i].v.fwd.length); p += 2; break; case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: data[p++] = 5; Address(rules[i].v.zt).copyTo(data + p); p += ZT_ADDRESS_LENGTH; break; case ZT_NETWORK_RULE_MATCH_VLAN_ID: data[p++] = 2; Utils::storeBigEndian(data + p,rules[i].v.vlanId); p += 2; break; case ZT_NETWORK_RULE_MATCH_VLAN_PCP: data[p++] = 1; data[p++] = rules[i].v.vlanPcp; break; case ZT_NETWORK_RULE_MATCH_VLAN_DEI: data[p++] = 1; data[p++] = rules[i].v.vlanDei; break; case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: case ZT_NETWORK_RULE_MATCH_MAC_DEST: data[p++] = 6; MAC(rules[i].v.mac).copyTo(data + p); p += 6; break; case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_DEST: data[p++] = 5; data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[0]; data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[1]; data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[2]; data[p++] = reinterpret_cast(&(rules[i].v.ipv4.ip))[3]; data[p++] = rules[i].v.ipv4.mask; break; case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_DEST: data[p++] = 17; for(int k=0;k<16;++k) data[p++] = rules[i].v.ipv6.ip[k]; data[p++] = rules[i].v.ipv6.mask; break; case ZT_NETWORK_RULE_MATCH_IP_TOS: data[p++] = 3; data[p++] = rules[i].v.ipTos.mask; data[p++] = rules[i].v.ipTos.value[0]; data[p++] = rules[i].v.ipTos.value[1]; break; case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: data[p++] = 1; data[p++] = rules[i].v.ipProtocol; break; case ZT_NETWORK_RULE_MATCH_ETHERTYPE: data[p++] = 2; Utils::storeBigEndian(data + p,rules[i].v.etherType); p += 2; break; case ZT_NETWORK_RULE_MATCH_ICMP: data[p++] = 3; data[p++] = rules[i].v.icmp.type; data[p++] = rules[i].v.icmp.code; data[p++] = rules[i].v.icmp.flags; break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: data[p++] = 4; Utils::storeBigEndian(data + p,rules[i].v.port[0]); p += 2; Utils::storeBigEndian(data + p,rules[i].v.port[1]); p += 2; break; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: data[p++] = 8; Utils::storeBigEndian(data + p,rules[i].v.characteristics); p += 8; break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: data[p++] = 4; Utils::storeBigEndian(data + p,rules[i].v.frameSize[0]); p += 2; Utils::storeBigEndian(data + p,rules[i].v.frameSize[1]); p += 2; break; case ZT_NETWORK_RULE_MATCH_RANDOM: data[p++] = 4; Utils::storeBigEndian(data + p,rules[i].v.randomProbability); p += 4; break; 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: case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: case ZT_NETWORK_RULE_MATCH_TAG_SENDER: case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: data[p++] = 8; Utils::storeBigEndian(data + p,rules[i].v.tag.id); p += 4; Utils::storeBigEndian(data + p,rules[i].v.tag.value); p += 4; break; case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: data[p++] = 19; Utils::storeBigEndian(data + p,rules[i].v.intRange.start); p += 8; Utils::storeBigEndian(data + p,rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end); p += 8; Utils::storeBigEndian(data + p,rules[i].v.intRange.idx); p += 2; data[p++] = rules[i].v.intRange.format; break; } } return p; } int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int len,ZT_VirtualNetworkRule *const rules,unsigned int &ruleCount,const unsigned int maxRuleCount) noexcept { int p = 0; unsigned int rc = 0; while (rc < maxRuleCount) { if (p >= len) return -1; rules[ruleCount].t = data[p++]; const int fieldLen = (int)data[p++]; if ((p + fieldLen) > len) return -1; switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) { default: break; case ZT_NETWORK_RULE_ACTION_TEE: case ZT_NETWORK_RULE_ACTION_WATCH: case ZT_NETWORK_RULE_ACTION_REDIRECT: if ((p + 14) > len) return -1; rules[ruleCount].v.fwd.address = Utils::loadBigEndian(data + p); p += 8; rules[ruleCount].v.fwd.flags = Utils::loadBigEndian(data + p); p += 4; rules[ruleCount].v.fwd.length = Utils::loadBigEndian(data + p); p += 2; break; case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: if ((p + ZT_ADDRESS_LENGTH) > len) return -1; rules[ruleCount].v.zt = Address(data + p).toInt(); p += ZT_ADDRESS_LENGTH; break; case ZT_NETWORK_RULE_MATCH_VLAN_ID: if ((p + 2) > len) return -1; rules[ruleCount].v.vlanId = Utils::loadBigEndian(data + p); p += 2; break; case ZT_NETWORK_RULE_MATCH_VLAN_PCP: if ((p + 1) > len) return -1; rules[ruleCount].v.vlanPcp = data[p++]; break; case ZT_NETWORK_RULE_MATCH_VLAN_DEI: if ((p + 1) > len) return -1; rules[ruleCount].v.vlanDei = data[p++]; break; case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: case ZT_NETWORK_RULE_MATCH_MAC_DEST: if ((p + 6) > len) return -1; Utils::copy<6>(rules[ruleCount].v.mac,data + p); p += 6; break; case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_DEST: if ((p + 5) > len) return -1; Utils::copy<4>(&(rules[ruleCount].v.ipv4.ip),data + p); p += 4; rules[ruleCount].v.ipv4.mask = data[p++]; break; case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_DEST: if ((p + 17) > len) return -1; Utils::copy<16>(rules[ruleCount].v.ipv6.ip,data + p); p += 16; rules[ruleCount].v.ipv6.mask = data[p++]; break; case ZT_NETWORK_RULE_MATCH_IP_TOS: if ((p + 3) > len) return -1; rules[ruleCount].v.ipTos.mask = data[p++]; rules[ruleCount].v.ipTos.value[0] = data[p++]; rules[ruleCount].v.ipTos.value[1] = data[p++]; break; case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: if ((p + 1) > len) return -1; rules[ruleCount].v.ipProtocol = data[p++]; break; case ZT_NETWORK_RULE_MATCH_ETHERTYPE: if ((p + 2) > len) return -1; rules[ruleCount].v.etherType = Utils::loadBigEndian(data + p); p += 2; break; case ZT_NETWORK_RULE_MATCH_ICMP: if ((p + 3) > len) return -1; rules[ruleCount].v.icmp.type = data[p++]; rules[ruleCount].v.icmp.code = data[p++]; rules[ruleCount].v.icmp.flags = data[p++]; break; case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: if ((p + 4) > len) return -1; rules[ruleCount].v.port[0] = Utils::loadBigEndian(data + p); p += 2; rules[ruleCount].v.port[1] = Utils::loadBigEndian(data + p); p += 2; break; case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: if ((p + 8) > len) return -1; rules[ruleCount].v.characteristics = Utils::loadBigEndian(data + p); p += 8; break; case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: if ((p + 4) > len) return -1; rules[ruleCount].v.frameSize[0] = Utils::loadBigEndian(data + p); p += 2; rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian(data + p); p += 2; break; case ZT_NETWORK_RULE_MATCH_RANDOM: if ((p + 4) > len) return -1; rules[ruleCount].v.randomProbability = Utils::loadBigEndian(data + p); p += 4; break; 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: case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: case ZT_NETWORK_RULE_MATCH_TAG_SENDER: case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: if ((p + 4) > len) return -1; rules[ruleCount].v.tag.id = Utils::loadBigEndian(data + p); p += 4; rules[ruleCount].v.tag.value = Utils::loadBigEndian(data + p); p += 4; break; case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: if ((p + 19) > len) return -1; rules[ruleCount].v.intRange.start = Utils::loadBigEndian(data + p); p += 8; rules[ruleCount].v.intRange.end = (uint32_t)(Utils::loadBigEndian(data + p) - rules[ruleCount].v.intRange.start); p += 8; rules[ruleCount].v.intRange.idx = Utils::loadBigEndian(data + p); p += 2; rules[ruleCount].v.intRange.format = data[p++]; break; } p += fieldLen; ++rc; } ruleCount = rc; return p; } } // namespace ZeroTier