Browse Source

A bunch of boring formattings stuff, etc.

Adam Ierymenko 5 years ago
parent
commit
d3777b3eb4

+ 0 - 2
node/Address.hpp

@@ -21,8 +21,6 @@
 
 #define ZT_ADDRESS_STRING_SIZE_MAX (ZT_ADDRESS_LENGTH_HEX + 1)
 
-static_assert(ZT_ADDRESS_LENGTH == 5,"parts of Address will need modification for any change in ZT_ADDRESS_LENGTH");
-
 namespace ZeroTier {
 
 /**

+ 5 - 2
node/Buf.hpp

@@ -394,9 +394,12 @@ public:
 	{
 		const char *const s = (const char *)(unsafeData + ii);
 		const int sii = ii;
-		while (likely(ii < ZT_BUF_MEM_SIZE)) {
+		while (ii < ZT_BUF_MEM_SIZE) {
 			if (unsafeData[ii++] == 0) {
-				Utils::copy(buf,s,ii - sii);
+				const int l = ii - sii;
+				if (unlikely((unsigned int)l > bufSize))
+					return nullptr;
+				Utils::copy(buf,s,l);
 				return buf;
 			}
 		}

+ 0 - 1
node/CMakeLists.txt

@@ -41,7 +41,6 @@ set(core_headers
 	SelfAwareness.hpp
 	SHA512.hpp
 	SharedPtr.hpp
-	Speck128.hpp
 	SymmetricKey.hpp
 	Tag.hpp
 	Topology.hpp

+ 120 - 69
node/Capability.cpp

@@ -18,44 +18,52 @@
 
 namespace ZeroTier {
 
-bool Capability::sign(const Identity &from,const Address &to) noexcept
+bool Capability::sign(const Identity &from, const Address &to) noexcept
 {
 	uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16];
 	m_issuedTo = to;
 	m_signedBy = from.address();
-	m_signatureLength = from.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature));
+	m_signatureLength = from.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature));
 	return m_signatureLength > 0;
 }
 
-int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],const bool forSign) const noexcept
+int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], const bool forSign) const noexcept
 {
 	int p = 0;
 
 	if (forSign) {
-		for(int k=0;k<8;++k)
+		for (int k = 0;k < 8;++k)
 			data[p++] = 0x7f;
 	}
 
-	Utils::storeBigEndian<uint64_t>(data + p, m_nwid); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)m_ts); p += 8;
-	Utils::storeBigEndian<uint32_t>(data + p, m_id); p += 4;
+	Utils::storeBigEndian<uint64_t>(data + p, m_nwid);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) m_ts);
+	p += 8;
+	Utils::storeBigEndian<uint32_t>(data + p, m_id);
+	p += 4;
 
-	Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)m_ruleCount); p += 2;
+	Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_ruleCount);
+	p += 2;
 	p += Capability::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount);
 
 	// LEGACY: older versions supported multiple records with this being a maximum custody
 	// chain length. This is deprecated so set the max chain length to one.
-	data[p++] = (uint8_t)1;
+	data[p++] = (uint8_t) 1;
 
 	if (!forSign) {
-		m_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
-		m_signedBy.copyTo(data + 0); p += ZT_ADDRESS_LENGTH;
+		m_issuedTo.copyTo(data + p);
+		p += ZT_ADDRESS_LENGTH;
+		m_signedBy.copyTo(data + 0);
+		p += ZT_ADDRESS_LENGTH;
 		data[p++] = 1; // LEGACY: old versions require a reserved byte here
-		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)m_signatureLength); p += 2;
-		Utils::copy(data + p, m_signature, m_signatureLength); p += (int)m_signatureLength;
+		Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength);
+		p += 2;
+		Utils::copy(data + p, m_signature, m_signatureLength);
+		p += (int) m_signatureLength;
 
 		// LEGACY: older versions supported more than one record terminated by a zero address.
-		for(int k=0;k<ZT_ADDRESS_LENGTH;++k)
+		for (int k = 0;k < ZT_ADDRESS_LENGTH;++k)
 			data[p++] = 0;
 	}
 
@@ -63,26 +71,26 @@ int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],const bool
 	data[p++] = 0; // uint16_t size of additional fields, currently 0
 
 	if (forSign) {
-		for(int k=0;k<8;++k)
+		for (int k = 0;k < 8;++k)
 			data[p++] = 0x7f;
 	}
 
 	return p;
 }
 
-int Capability::unmarshal(const uint8_t *data,int len) noexcept
+int Capability::unmarshal(const uint8_t *data, int len) noexcept
 {
 	if (len < 22)
 		return -1;
 
 	m_nwid = Utils::loadBigEndian<uint64_t>(data);
-	m_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
+	m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data + 8);
 	m_id = Utils::loadBigEndian<uint32_t>(data + 16);
 
 	const unsigned int rc = Utils::loadBigEndian<uint16_t>(data + 20);
 	if (rc > ZT_MAX_CAPABILITY_RULES)
 		return -1;
-	const int rulesLen = unmarshalVirtualNetworkRules(data + 22,len - 22, m_rules, m_ruleCount, rc);
+	const int rulesLen = unmarshalVirtualNetworkRules(data + 22, len - 22, m_rules, m_ruleCount, rc);
 	if (rulesLen < 0)
 		return rulesLen;
 	int p = 22 + rulesLen;
@@ -95,10 +103,11 @@ int Capability::unmarshal(const uint8_t *data,int len) noexcept
 	// this feature was never used, just set the signature and issued to and other related
 	// fields each time and we should only ever see one. If there's more than one and the
 	// last is not the controller, this credential will just fail validity check.
-	for(unsigned int i=0;;++i) {
+	for (unsigned int i = 0;;++i) {
 		if ((p + ZT_ADDRESS_LENGTH) > len)
 			return -1;
-		const Address to(data + p); p += ZT_ADDRESS_LENGTH;
+		const Address to(data + p);
+		p += ZT_ADDRESS_LENGTH;
 
 		if (!to)
 			break;
@@ -106,14 +115,17 @@ int Capability::unmarshal(const uint8_t *data,int len) noexcept
 		m_issuedTo = to;
 		if ((p + ZT_ADDRESS_LENGTH) > len)
 			return -1;
-		m_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1; // LEGACY: +1 to skip reserved field
+		m_signedBy.setTo(data + p);
+		p += ZT_ADDRESS_LENGTH + 1; // LEGACY: +1 to skip reserved field
 
 		if ((p + 2) > len)
 			return -1;
-		m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
-		if ((m_signatureLength > sizeof(m_signature)) || ((p + (int)m_signatureLength) > len))
+		m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p);
+		p += 2;
+		if ((m_signatureLength > sizeof(m_signature)) || ((p + (int) m_signatureLength) > len))
 			return -1;
-		Utils::copy(m_signature, data + p, m_signatureLength); p += (int)m_signatureLength;
+		Utils::copy(m_signature, data + p, m_signatureLength);
+		p += (int) m_signatureLength;
 	}
 
 	if ((p + 2) > len)
@@ -126,12 +138,12 @@ int Capability::unmarshal(const uint8_t *data,int len) noexcept
 	return p;
 }
 
-int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) noexcept
+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<ruleCount;++i) {
+	for (unsigned int i = 0;i < ruleCount;++i) {
 		data[p++] = rules[i].t;
-		switch((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3fU)) {
+		switch ((ZT_VirtualNetworkRuleType) (rules[i].t & 0x3fU)) {
 			default:
 				data[p++] = 0;
 				break;
@@ -139,18 +151,23 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 			case ZT_NETWORK_RULE_ACTION_WATCH:
 			case ZT_NETWORK_RULE_ACTION_REDIRECT:
 				data[p++] = 14;
-				Utils::storeBigEndian<uint64_t>(data + p,rules[i].v.fwd.address); p += 8;
-				Utils::storeBigEndian<uint32_t>(data + p,rules[i].v.fwd.flags); p += 4;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.fwd.length); p += 2;
+				Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.fwd.address);
+				p += 8;
+				Utils::storeBigEndian<uint32_t>(data + p, rules[i].v.fwd.flags);
+				p += 4;
+				Utils::storeBigEndian<uint16_t>(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;
+				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<uint16_t>(data + p,rules[i].v.vlanId); p += 2;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.vlanId);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
 				data[p++] = 1;
@@ -163,7 +180,8 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 			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;
+				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:
@@ -177,7 +195,8 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 			case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
 			case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
 				data[p++] = 17;
-				Utils::copy<16>(data + p,rules[i].v.ipv6.ip); p += 16;
+				Utils::copy<16>(data + p, rules[i].v.ipv6.ip);
+				p += 16;
 				data[p++] = rules[i].v.ipv6.mask;
 				break;
 			case ZT_NETWORK_RULE_MATCH_IP_TOS:
@@ -192,7 +211,8 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 				break;
 			case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
 				data[p++] = 2;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.etherType); p += 2;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.etherType);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_ICMP:
 				data[p++] = 3;
@@ -203,21 +223,27 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 			case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
 			case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
 				data[p++] = 4;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.port[0]); p += 2;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.port[1]); p += 2;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.port[0]);
+				p += 2;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.port[1]);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
 				data[p++] = 8;
-				Utils::storeBigEndian<uint64_t>(data + p,rules[i].v.characteristics); p += 8;
+				Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.characteristics);
+				p += 8;
 				break;
 			case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
 				data[p++] = 4;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.frameSize[0]); p += 2;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.frameSize[1]); p += 2;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.frameSize[0]);
+				p += 2;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.frameSize[1]);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_RANDOM:
 				data[p++] = 4;
-				Utils::storeBigEndian<uint32_t>(data + p,rules[i].v.randomProbability); p += 4;
+				Utils::storeBigEndian<uint32_t>(data + p, rules[i].v.randomProbability);
+				p += 4;
 				break;
 			case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE:
 			case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
@@ -227,14 +253,19 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 			case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
 			case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
 				data[p++] = 8;
-				Utils::storeBigEndian<uint32_t>(data + p,rules[i].v.tag.id); p += 4;
-				Utils::storeBigEndian<uint32_t>(data + p,rules[i].v.tag.value); p += 4;
+				Utils::storeBigEndian<uint32_t>(data + p, rules[i].v.tag.id);
+				p += 4;
+				Utils::storeBigEndian<uint32_t>(data + p, rules[i].v.tag.value);
+				p += 4;
 				break;
 			case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE:
 				data[p++] = 19;
-				Utils::storeBigEndian<uint64_t>(data + p,rules[i].v.intRange.start); p += 8;
-				Utils::storeBigEndian<uint64_t>(data + p,rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end); p += 8;
-				Utils::storeBigEndian<uint16_t>(data + p,rules[i].v.intRange.idx); p += 2;
+				Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.intRange.start);
+				p += 8;
+				Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.intRange.start + (uint64_t) rules[i].v.intRange.end);
+				p += 8;
+				Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.intRange.idx);
+				p += 2;
 				data[p++] = rules[i].v.intRange.format;
 				break;
 		}
@@ -242,7 +273,7 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
 	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 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;
@@ -250,28 +281,33 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
 		if (p >= len)
 			return -1;
 		rules[ruleCount].t = data[p++];
-		const int fieldLen = (int)data[p++];
+		const int fieldLen = (int) data[p++];
 		if ((p + fieldLen) > len)
 			return -1;
-		switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3fU)) {
+		switch ((ZT_VirtualNetworkRuleType) (rules[ruleCount].t & 0x3fU)) {
 			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<uint64_t>(data + p); p += 8;
-				rules[ruleCount].v.fwd.flags = Utils::loadBigEndian<uint32_t>(data + p); p += 4;
-				rules[ruleCount].v.fwd.length = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
+				rules[ruleCount].v.fwd.address = Utils::loadBigEndian<uint64_t>(data + p);
+				p += 8;
+				rules[ruleCount].v.fwd.flags = Utils::loadBigEndian<uint32_t>(data + p);
+				p += 4;
+				rules[ruleCount].v.fwd.length = Utils::loadBigEndian<uint16_t>(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;
+				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<uint16_t>(data + p); p += 2;
+				rules[ruleCount].v.vlanId = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
 				if ((p + 1) > len) return -1;
@@ -284,18 +320,21 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
 			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;
+				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;
+				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;
+				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:
@@ -310,7 +349,8 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
 				break;
 			case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
 				if ((p + 2) > len) return -1;
-				rules[ruleCount].v.etherType = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
+				rules[ruleCount].v.etherType = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_ICMP:
 				if ((p + 3) > len) return -1;
@@ -321,21 +361,27 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
 			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<uint16_t>(data + p); p += 2;
-				rules[ruleCount].v.port[1] = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
+				rules[ruleCount].v.port[0] = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
+				rules[ruleCount].v.port[1] = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
 				if ((p + 8) > len) return -1;
-				rules[ruleCount].v.characteristics = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
+				rules[ruleCount].v.characteristics = Utils::loadBigEndian<uint64_t>(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<uint16_t>(data + p); p += 2;
-				rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
+				rules[ruleCount].v.frameSize[0] = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
+				rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
 				break;
 			case ZT_NETWORK_RULE_MATCH_RANDOM:
 				if ((p + 4) > len) return -1;
-				rules[ruleCount].v.randomProbability = Utils::loadBigEndian<uint32_t>(data + p); p += 4;
+				rules[ruleCount].v.randomProbability = Utils::loadBigEndian<uint32_t>(data + p);
+				p += 4;
 				break;
 			case ZT_NETWORK_RULE_MATCH_TAGS_DIFFERENCE:
 			case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_AND:
@@ -345,14 +391,19 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
 			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<uint32_t>(data + p); p += 4;
-				rules[ruleCount].v.tag.value = Utils::loadBigEndian<uint32_t>(data + p); p += 4;
+				rules[ruleCount].v.tag.id = Utils::loadBigEndian<uint32_t>(data + p);
+				p += 4;
+				rules[ruleCount].v.tag.value = Utils::loadBigEndian<uint32_t>(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<uint64_t>(data + p); p += 8;
-				rules[ruleCount].v.intRange.end = (uint32_t)(Utils::loadBigEndian<uint64_t>(data + p) - rules[ruleCount].v.intRange.start); p += 8;
-				rules[ruleCount].v.intRange.idx = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
+				rules[ruleCount].v.intRange.start = Utils::loadBigEndian<uint64_t>(data + p);
+				p += 8;
+				rules[ruleCount].v.intRange.end = (uint32_t) (Utils::loadBigEndian<uint64_t>(data + p) - rules[ruleCount].v.intRange.start);
+				p += 8;
+				rules[ruleCount].v.intRange.idx = Utils::loadBigEndian<uint16_t>(data + p);
+				p += 2;
 				rules[ruleCount].v.intRange.format = data[p++];
 				break;
 		}

+ 57 - 39
node/CertificateOfMembership.cpp

@@ -15,12 +15,13 @@
 
 namespace ZeroTier {
 
-CertificateOfMembership::CertificateOfMembership(const int64_t timestamp,const int64_t timestampMaxDelta,const uint64_t nwid,const Identity &issuedTo) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
+CertificateOfMembership::CertificateOfMembership(const int64_t timestamp, const int64_t timestampMaxDelta, const uint64_t nwid, const Identity &issuedTo) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
 	m_timestamp(timestamp),
 	m_timestampMaxDelta(timestampMaxDelta),
 	m_networkId(nwid),
 	m_issuedTo(issuedTo.fingerprint()),
-	m_signatureLength(0) {}
+	m_signatureLength(0)
+{}
 
 bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const noexcept
 {
@@ -36,10 +37,10 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c
 	}
 
 	// us <> them
-	for(FCV<p_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(m_additionalQualifiers.begin());i != m_additionalQualifiers.end();++i) {
+	for (FCV<p_Qualifier, ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(m_additionalQualifiers.begin());i != m_additionalQualifiers.end();++i) {
 		if (i->delta != 0xffffffffffffffffULL) {
 			const uint64_t *v2 = nullptr;
-			for(FCV<p_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(other.m_additionalQualifiers.begin());j != other.m_additionalQualifiers.end();++i) {
+			for (FCV<p_Qualifier, ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(other.m_additionalQualifiers.begin());j != other.m_additionalQualifiers.end();++i) {
 				if (j->id == i->id) {
 					v2 = &(j->value);
 					break;
@@ -58,10 +59,10 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c
 	}
 
 	// them <> us (we need a second pass in case they have qualifiers we don't or vice versa)
-	for(FCV<p_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(other.m_additionalQualifiers.begin());i != other.m_additionalQualifiers.end();++i) {
+	for (FCV<p_Qualifier, ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(other.m_additionalQualifiers.begin());i != other.m_additionalQualifiers.end();++i) {
 		if (i->delta != 0xffffffffffffffffULL) {
 			const uint64_t *v2 = nullptr;
-			for(FCV<p_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(m_additionalQualifiers.begin());j != m_additionalQualifiers.end();++i) {
+			for (FCV<p_Qualifier, ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(m_additionalQualifiers.begin());j != m_additionalQualifiers.end();++i) {
 				if (j->id == i->id) {
 					v2 = &(j->value);
 					break;
@@ -93,45 +94,59 @@ bool CertificateOfMembership::sign(const Identity &with) noexcept
 	return m_signatureLength > 0;
 }
 
-int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX],const bool v2) const noexcept
+int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX], const bool v2) const noexcept
 {
 	data[0] = v2 ? 2 : 1;
 
 	// All formats start with the standard three qualifiers: timestamp with delta, network ID as a strict
 	// equality compare, and the address of the issued-to node as an informational tuple.
 	int p = 3;
-	Utils::storeBigEndian<uint64_t>(data + p,0); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)m_timestamp); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)m_timestampMaxDelta); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,1); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p, m_networkId); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,0); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,2); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p, m_issuedTo.address().toInt()); p += 8;
-	Utils::storeAsIsEndian<uint64_t>(data + p,0xffffffffffffffffULL); p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, 0);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) m_timestamp);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) m_timestampMaxDelta);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, 1);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, m_networkId);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, 0);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, 2);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, m_issuedTo.address().toInt());
+	p += 8;
+	Utils::storeAsIsEndian<uint64_t>(data + p, 0xffffffffffffffffULL);
+	p += 8;
 
 	if (v2) {
 		// V2 marshal format will have three tuples followed by the fingerprint hash.
-		Utils::storeBigEndian<uint16_t>(data + 1,3);
+		Utils::storeBigEndian<uint16_t>(data + 1, 3);
 		Utils::copy<48>(data + p, m_issuedTo.hash());
 		p += 48;
 	} else {
 		// V1 marshal format must shove everything into tuples, resulting in nine.
-		Utils::storeBigEndian<uint16_t>(data + 1,9);
-		for(int k=0;k<6;++k) {
-			Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)k + 3); p += 8;
-			Utils::storeAsIsEndian<uint64_t>(data + p,Utils::loadAsIsEndian<uint64_t>(m_issuedTo.hash() + (k * 8))); p += 8;
-			Utils::storeAsIsEndian<uint64_t>(data + p,0xffffffffffffffffULL); p += 8;
+		Utils::storeBigEndian<uint16_t>(data + 1, 9);
+		for (int k = 0;k < 6;++k) {
+			Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) k + 3);
+			p += 8;
+			Utils::storeAsIsEndian<uint64_t>(data + p, Utils::loadAsIsEndian<uint64_t>(m_issuedTo.hash() + (k * 8)));
+			p += 8;
+			Utils::storeAsIsEndian<uint64_t>(data + p, 0xffffffffffffffffULL);
+			p += 8;
 		}
 	}
 
-	m_signedBy.copyTo(data + p); p += 5;
+	m_signedBy.copyTo(data + p);
+	p += 5;
 
 	if (v2) {
 		// V2 marshal format prefixes signatures with a 16-bit length to support future signature types.
-		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)m_signatureLength); p += 2;
+		Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength);
+		p += 2;
 		Utils::copy(data + p, m_signature, m_signatureLength);
-		p += (int)m_signatureLength;
+		p += (int) m_signatureLength;
 	} else {
 		// V1 only supports 96-byte signature fields.
 		Utils::copy<96>(data + p, m_signature);
@@ -141,7 +156,7 @@ int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MAR
 	return p;
 }
 
-int CertificateOfMembership::unmarshal(const uint8_t *data,int len) noexcept
+int CertificateOfMembership::unmarshal(const uint8_t *data, int len) noexcept
 {
 	if (len < (1 + 2 + 72))
 		return -1;
@@ -149,19 +164,22 @@ int CertificateOfMembership::unmarshal(const uint8_t *data,int len) noexcept
 	TriviallyCopyable::memoryZero(this);
 
 	const unsigned int numq = Utils::loadBigEndian<uint16_t>(data + 1);
-	if ((numq < 3)||(numq > (ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS + 3)))
+	if ((numq < 3) || (numq > (ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS + 3)))
 		return -1;
 	int p = 3;
-	for(unsigned int q=0;q<numq;++q) {
+	for (unsigned int q = 0;q < numq;++q) {
 		if ((p + 24) > len)
 			return -1;
-		const uint64_t id = Utils::loadBigEndian<uint64_t>(data + p); p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
-		const uint64_t value = Utils::loadBigEndian<uint64_t>(data + p); p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
-		const uint64_t delta = Utils::loadBigEndian<uint64_t>(data + p); p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
-		switch(id) {
+		const uint64_t id = Utils::loadBigEndian<uint64_t>(data + p);
+		p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
+		const uint64_t value = Utils::loadBigEndian<uint64_t>(data + p);
+		p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
+		const uint64_t delta = Utils::loadBigEndian<uint64_t>(data + p);
+		p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
+		switch (id) {
 			case 0:
-				m_timestamp = (int64_t)value;
-				m_timestampMaxDelta = (int64_t)delta;
+				m_timestamp = (int64_t) value;
+				m_timestampMaxDelta = (int64_t) delta;
 				break;
 			case 1:
 				m_networkId = value;
@@ -214,10 +232,10 @@ int CertificateOfMembership::unmarshal(const uint8_t *data,int len) noexcept
 		if ((p + 2) > len)
 			return -1;
 		m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p);
-		if ((m_signatureLength > (unsigned int)sizeof(m_signature)) || ((p + (int)m_signatureLength) > len))
+		if ((m_signatureLength > (unsigned int) sizeof(m_signature)) || ((p + (int) m_signatureLength) > len))
 			return -1;
 		Utils::copy(m_signature, data + p, m_signatureLength);
-		return p + (int)m_signatureLength;
+		return p + (int) m_signatureLength;
 	}
 
 	return -1;
@@ -235,8 +253,8 @@ unsigned int CertificateOfMembership::m_fillSigningBuf(uint64_t *buf) const noex
 
 	// The standard three tuples that must begin every COM.
 	buf[0] = 0;
-	buf[1] = Utils::hton((uint64_t)m_timestamp);
-	buf[2] = Utils::hton((uint64_t)m_timestampMaxDelta);
+	buf[1] = Utils::hton((uint64_t) m_timestamp);
+	buf[2] = Utils::hton((uint64_t) m_timestampMaxDelta);
 	buf[3] = ZT_CONST_TO_BE_UINT64(1);
 	buf[4] = Utils::hton(m_networkId);
 	buf[5] = 0;
@@ -269,7 +287,7 @@ unsigned int CertificateOfMembership::m_fillSigningBuf(uint64_t *buf) const noex
 		buf[p++] = informational;
 	}
 
-	for(FCV<p_Qualifier,ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(m_additionalQualifiers.begin());i != m_additionalQualifiers.end();++i) { // NOLINT(modernize-loop-convert)
+	for (FCV<p_Qualifier, ZT_CERTIFICATEOFMEMBERSHIP_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(m_additionalQualifiers.begin());i != m_additionalQualifiers.end();++i) { // NOLINT(modernize-loop-convert)
 		buf[p++] = Utils::hton(i->id);
 		buf[p++] = Utils::hton(i->value);
 		buf[p++] = Utils::hton(i->delta);

+ 22 - 16
node/CertificateOfOwnership.cpp

@@ -44,53 +44,57 @@ bool CertificateOfOwnership::sign(const Identity &signer)
 	uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16];
 	if (signer.hasPrivate()) {
 		m_signedBy = signer.address();
-		m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature));
+		m_signatureLength = signer.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature));
 		return true;
 	}
 	return false;
 }
 
-int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX],bool forSign) const noexcept
+int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign) const noexcept
 {
 	int p = 0;
 	if (forSign) {
-		for(int k=0;k<16;++k)
+		for (int k = 0;k < 16;++k)
 			data[p++] = 0x7f;
 	}
 	Utils::storeBigEndian<uint64_t>(data + p, m_networkId);
-	Utils::storeBigEndian<uint64_t>(data + p + 8,(uint64_t)m_ts);
+	Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t) m_ts);
 	Utils::storeBigEndian<uint64_t>(data + p + 16, m_flags);
 	Utils::storeBigEndian<uint32_t>(data + p + 24, m_id);
-	Utils::storeBigEndian<uint16_t>(data + p + 28,(uint16_t)m_thingCount);
+	Utils::storeBigEndian<uint16_t>(data + p + 28, (uint16_t) m_thingCount);
 	p += 30;
-	for(unsigned int i=0,j=m_thingCount;i < j;++i) {
+	for (unsigned int i = 0, j = m_thingCount;i < j;++i) {
 		data[p++] = m_thingTypes[i];
 		Utils::copy<ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE>(data + p, m_thingValues[i]);
 		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
 	}
-	m_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
-	m_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
+	m_issuedTo.copyTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
+	m_signedBy.copyTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
 	if (!forSign) {
 		data[p++] = 1;
-		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)m_signatureLength); p += 2;
-		Utils::copy(data + p, m_signature, m_signatureLength); p += (int)m_signatureLength;
+		Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength);
+		p += 2;
+		Utils::copy(data + p, m_signature, m_signatureLength);
+		p += (int) m_signatureLength;
 	}
 	data[p++] = 0;
 	data[p++] = 0;
 	if (forSign) {
-		for(int k=0;k<16;++k)
+		for (int k = 0;k < 16;++k)
 			data[p++] = 0x7f;
 	}
 	return p;
 }
 
-int CertificateOfOwnership::unmarshal(const uint8_t *data,int len) noexcept
+int CertificateOfOwnership::unmarshal(const uint8_t *data, int len) noexcept
 {
 	if (len < 30)
 		return -1;
 
 	m_networkId = Utils::loadBigEndian<uint64_t>(data);
-	m_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
+	m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data + 8);
 	m_flags = Utils::loadBigEndian<uint64_t>(data + 16);
 	m_id = Utils::loadBigEndian<uint32_t>(data + 24);
 	m_thingCount = Utils::loadBigEndian<uint16_t>(data + 28);
@@ -98,7 +102,7 @@ int CertificateOfOwnership::unmarshal(const uint8_t *data,int len) noexcept
 		return -1;
 	int p = 30;
 
-	for(unsigned int i=0,j=m_thingCount;i < j;++i) {
+	for (unsigned int i = 0, j = m_thingCount;i < j;++i) {
 		if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len)
 			return -1;
 		m_thingTypes[i] = data[p++];
@@ -108,8 +112,10 @@ int CertificateOfOwnership::unmarshal(const uint8_t *data,int len) noexcept
 
 	if ((p + ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH + 1 + 2) > len)
 		return -1;
-	m_issuedTo.setTo(data + p); p += ZT_ADDRESS_LENGTH;
-	m_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1;
+	m_issuedTo.setTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
+	m_signedBy.setTo(data + p);
+	p += ZT_ADDRESS_LENGTH + 1;
 
 	p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
 	if (p > len)

+ 26 - 65
node/Identity.cpp

@@ -16,10 +16,8 @@
 #include "SHA512.hpp"
 #include "Salsa20.hpp"
 #include "Utils.hpp"
-#include "Speck128.hpp"
+#include "AES.hpp"
 
-#include <cstring>
-#include <cstdint>
 #include <algorithm>
 
 namespace ZeroTier {
@@ -78,74 +76,34 @@ struct identityV0ProofOfWorkCriteria
 // It's not quite as heavy as the V0 frankenhash, is a little more orderly in
 // its design, but remains relatively resistant to GPU acceleration due to memory
 // requirements for efficient computation.
-#define ZT_IDENTITY_V1_POW_MEMORY_SIZE 98304
+#define ZT_IDENTITY_V1_POW_MEMORY_SIZE 1048576
+#define ZT_IDENTITY_V1_POW_MEMORY_SIZE_U64 131072
 bool identityV1ProofOfWorkCriteria(const void *in,const unsigned int len,uint64_t *const b)
 {
 	SHA512(b,in,len);
 
-	// This treats hash output as little-endian, so swap on BE machines.
-#if __BYTE_ORDER == __BIG_ENDIAN
-	b[0] = Utils::swapBytes(b[0]);
-	b[1] = Utils::swapBytes(b[1]);
-	b[2] = Utils::swapBytes(b[2]);
-	b[3] = Utils::swapBytes(b[3]);
-	b[4] = Utils::swapBytes(b[4]);
-	b[5] = Utils::swapBytes(b[5]);
-	b[6] = Utils::swapBytes(b[6]);
-	b[7] = Utils::swapBytes(b[7]);
-#endif
-
-	// Memory-intensive work: fill 'b' with pseudo-random bits generated from
-	// a reduced-round instance of Speck128 using a CBC-like construction.
-	// Then sort the resulting integer array in ascending numerical order.
-	// The sort requires that we compute and cache the whole data set, or at
-	// least that this is the most efficient implementation.
-	Speck128<24> s16;
-	s16.initXY(b[4],b[5]);
-	for(unsigned long i=0;i<(ZT_IDENTITY_V1_POW_MEMORY_SIZE-8);) {
-		// Load four 128-bit blocks.
-		uint64_t x0 = b[i];
-		uint64_t y0 = b[i + 1];
-		uint64_t x1 = b[i + 2];
-		uint64_t y1 = b[i + 3];
-		uint64_t x2 = b[i + 4];
-		uint64_t y2 = b[i + 5];
-		uint64_t x3 = b[i + 6];
-		uint64_t y3 = b[i + 7];
-
-		// Advance by 512 bits / 64 bytes (its a uint64_t array).
-		i += 8;
-
-		// Ensure that mixing happens across blocks.
-		x0 += x1;
-		x1 += x2;
-		x2 += x3;
-		x3 += y0;
-
-		// Encrypt 4X blocks. Speck is used for this PoW function because
-		// its performance is similar on all architectures while AES is much
-		// faster on some than others.
-		s16.encryptXYXYXYXY(x0,y0,x1,y1,x2,y2,x3,y3);
-
-		// Store four 128-bit blocks at new position.
-		b[i] = x0;
-		b[i + 1] = y0;
-		b[i + 2] = x1;
-		b[i + 3] = y1;
-		b[i + 4] = x2;
-		b[i + 5] = y2;
-		b[i + 6] = x3;
-		b[i + 7] = y3;
+	AES c(b);
+	for(unsigned int i=8;i<ZT_IDENTITY_V1_POW_MEMORY_SIZE_U64;i+=8) {
+		SHA512(b + i,b + (i - 8),64);
+		if (unlikely((b[i] % 31337ULL) == (b[i] >> 49U)))
+			c.encrypt(b + i,b + i);
 	}
 
-	// Sort array, something that can't efficiently be done unless we have
-	// computed the whole array and have it in memory. This also involves
-	// branching which is less efficient on GPUs.
-	std::sort(b,b + ZT_IDENTITY_V1_POW_MEMORY_SIZE);
-
-	// Swap byte order back on BE machines.
 #if __BYTE_ORDER == __BIG_ENDIAN
-	for(unsigned int i=0;i<98304;i+=8) {
+	for(unsigned int i=0;i<ZT_IDENTITY_V1_POW_MEMORY_SIZE_U64;i+=8) {
+		b[i] = Utils::swapBytes(b[i]);
+		b[i + 1] = Utils::swapBytes(b[i + 1]);
+		b[i + 2] = Utils::swapBytes(b[i + 2]);
+		b[i + 3] = Utils::swapBytes(b[i + 3]);
+		b[i + 4] = Utils::swapBytes(b[i + 4]);
+		b[i + 5] = Utils::swapBytes(b[i + 5]);
+		b[i + 6] = Utils::swapBytes(b[i + 6]);
+		b[i + 7] = Utils::swapBytes(b[i + 7]);
+	}
+#endif
+	std::sort(b,b + ZT_IDENTITY_V1_POW_MEMORY_SIZE_U64);
+#if __BYTE_ORDER == __BIG_ENDIAN
+	for(unsigned int i=0;i<ZT_IDENTITY_V1_POW_MEMORY_SIZE_U64;i+=8) {
 		b[i] = Utils::swapBytes(b[i]);
 		b[i + 1] = Utils::swapBytes(b[i + 1]);
 		b[i + 2] = Utils::swapBytes(b[i + 2]);
@@ -158,6 +116,9 @@ bool identityV1ProofOfWorkCriteria(const void *in,const unsigned int len,uint64_
 #endif
 
 	// Hash resulting sorted array to get final result for PoW criteria test.
+	// We also include the original input after so that cryptographically this
+	// is exactly like SHA384(in). This should make any FIPS types happy as
+	// this means the identity hash is SHA384 and not some weird construction.
 	SHA384(b,b,sizeof(b),in,len);
 
 	// PoW passes if sum of first two 64-bit integers (treated as little-endian) mod 180 is 0.
@@ -197,7 +158,7 @@ bool Identity::generate(const Type t)
 		} break;
 
 		case P384: {
-			uint64_t *const b = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE * 8); // NOLINT(hicpp-use-auto,modernize-use-auto)
+			uint64_t *const b = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE); // NOLINT(hicpp-use-auto,modernize-use-auto)
 			if (!b)
 				return false;
 			for(;;) {

+ 2 - 2
node/NetworkConfig.cpp

@@ -43,7 +43,7 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
 			d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,tmp,this->com.marshal(tmp));
 		}
 
-		std::vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]);
+		Vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]);
 		for (unsigned int i = 0; i < this->capabilityCount; ++i) {
 			int l = this->capabilities[i].marshal(tmp);
 			if (l < 0)
@@ -121,7 +121,7 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
 		this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0);
 		this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0);
 		this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
-		const std::vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]);
+		const Vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]);
 		if (blob->size() == ZT_FINGERPRINT_HASH_SIZE) {
 			Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(this->issuedToFingerprintHash,blob->data());
 		} else {

+ 15 - 10
node/PeerList.hpp

@@ -33,7 +33,7 @@ namespace ZeroTier {
 class PeerList
 {
 public:
-	ZT_INLINE PeerList() noexcept :
+	ZT_INLINE PeerList() noexcept:
 		m_onePeer(),
 		m_peers(&m_onePeer),
 		m_peerCount(0)
@@ -47,7 +47,7 @@ public:
 			m_peers = &m_onePeer;
 		} else {
 			m_peers = new SharedPtr<Peer>[pc];
-			for (unsigned int i=0;i<pc;++i)
+			for (unsigned int i = 0;i < pc;++i)
 				m_peers[i] = pl.m_peers[i];
 		}
 		m_peerCount = pc;
@@ -56,14 +56,14 @@ public:
 	ZT_INLINE ~PeerList()
 	{
 		if (unlikely(m_peers != &m_onePeer))
-			delete [] m_peers;
+			delete[] m_peers;
 	}
 
 	ZT_INLINE PeerList &operator=(const PeerList &pl)
 	{
 		if (&pl != this) {
 			if (unlikely(m_peers != &m_onePeer))
-				delete [] m_peers;
+				delete[] m_peers;
 			if (likely(pl.m_peerCount <= 1)) {
 				m_onePeer = pl.m_onePeer;
 				m_peers = &m_onePeer;
@@ -90,7 +90,7 @@ public:
 	ZT_INLINE void resize(const unsigned int s)
 	{
 		if (unlikely(m_peers != &m_onePeer))
-			delete [] m_peers;
+			delete[] m_peers;
 		m_peerCount = s;
 		if (likely(s <= 1)) {
 			m_peers = &m_onePeer;
@@ -99,13 +99,18 @@ public:
 		}
 	}
 
-	ZT_INLINE SharedPtr<Peer> &operator[](const unsigned int i) noexcept { return m_peers[i]; }
-	ZT_INLINE const SharedPtr<Peer> &operator[](const unsigned int i) const noexcept { return m_peers[i]; }
-	ZT_INLINE unsigned int size() const noexcept { return m_peerCount; }
+	ZT_INLINE SharedPtr <Peer> &operator[](const unsigned int i) noexcept
+	{ return m_peers[i]; }
+
+	ZT_INLINE const SharedPtr <Peer> &operator[](const unsigned int i) const noexcept
+	{ return m_peers[i]; }
+
+	ZT_INLINE unsigned int size() const noexcept
+	{ return m_peerCount; }
 
 private:
-	SharedPtr<Peer> m_onePeer;
-	SharedPtr<Peer> *m_peers;
+	SharedPtr <Peer> m_onePeer;
+	SharedPtr <Peer> *m_peers;
 	unsigned int m_peerCount;
 };
 

+ 30 - 21
node/Revocation.cpp

@@ -17,48 +17,57 @@ namespace ZeroTier {
 
 bool Revocation::sign(const Identity &signer) noexcept
 {
-	uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX+32];
+	uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32];
 	if (signer.hasPrivate()) {
 		m_signedBy = signer.address();
-		m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature));
+		m_signatureLength = signer.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature));
 		return true;
 	}
 	return false;
 }
 
-int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],bool forSign) const noexcept
+int Revocation::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign) const noexcept
 {
 	int p = 0;
 	if (forSign) {
-		for(int k=0;k<8;++k)
+		for (int k = 0;k < 8;++k)
 			data[p++] = 0x7f;
 	}
-	Utils::storeBigEndian<uint32_t>(data + p,0); p += 4;
-	Utils::storeBigEndian<uint32_t>(data + p, m_id); p += 4;
-	Utils::storeBigEndian<uint64_t>(data + p, m_networkId); p += 8;
-	Utils::storeBigEndian<uint32_t>(data + p,0); p += 4;
-	Utils::storeBigEndian<uint32_t>(data + p, m_credentialId); p += 4;
-	Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)m_threshold); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p, m_flags); p += 8;
-	m_target.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
-	m_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
-	data[p++] = (uint8_t)m_type;
+	Utils::storeBigEndian<uint32_t>(data + p, 0);
+	p += 4;
+	Utils::storeBigEndian<uint32_t>(data + p, m_id);
+	p += 4;
+	Utils::storeBigEndian<uint64_t>(data + p, m_networkId);
+	p += 8;
+	Utils::storeBigEndian<uint32_t>(data + p, 0);
+	p += 4;
+	Utils::storeBigEndian<uint32_t>(data + p, m_credentialId);
+	p += 4;
+	Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) m_threshold);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, m_flags);
+	p += 8;
+	m_target.copyTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
+	m_signedBy.copyTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
+	data[p++] = (uint8_t) m_type;
 	if (!forSign) {
 		data[p++] = 1;
-		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)m_signatureLength);
+		Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength);
 		Utils::copy(data + p, m_signature, m_signatureLength);
-		p += (int)m_signatureLength;
+		p += (int) m_signatureLength;
 	}
 	data[p++] = 0;
 	data[p++] = 0;
 	if (forSign) {
-		for(int k=0;k<8;++k)
+		for (int k = 0;k < 8;++k)
 			data[p++] = 0x7f;
 	}
 	return p;
 }
 
-int Revocation::unmarshal(const uint8_t *restrict data,const int len) noexcept
+int Revocation::unmarshal(const uint8_t *restrict data, const int len) noexcept
 {
 	if (len < 54)
 		return -1;
@@ -67,14 +76,14 @@ int Revocation::unmarshal(const uint8_t *restrict data,const int len) noexcept
 	m_networkId = Utils::loadBigEndian<uint64_t>(data + 8);
 	// 4 bytes reserved
 	m_credentialId = Utils::loadBigEndian<uint32_t>(data + 20);
-	m_threshold = (int64_t)Utils::loadBigEndian<uint64_t>(data + 24);
+	m_threshold = (int64_t) Utils::loadBigEndian<uint64_t>(data + 24);
 	m_flags = Utils::loadBigEndian<uint64_t>(data + 32);
 	m_target.setTo(data + 40);
 	m_signedBy.setTo(data + 45);
-	m_type = (ZT_CredentialType)data[50];
+	m_type = (ZT_CredentialType) data[50];
 	// 1 byte reserved
 	m_signatureLength = Utils::loadBigEndian<uint16_t>(data + 52);
-	int p = 54 + (int)m_signatureLength;
+	int p = 54 + (int) m_signatureLength;
 	if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len))
 		return -1;
 	Utils::copy(m_signature, data + 54, m_signatureLength);

+ 0 - 4
node/SHA512.cpp

@@ -3,10 +3,6 @@
 #include "SHA512.hpp"
 #include "Utils.hpp"
 
-#include <cstdint>
-#include <cstring>
-#include <algorithm>
-
 namespace ZeroTier {
 
 #ifndef ZT_HAVE_NATIVE_SHA512

+ 0 - 7
node/Salsa20.hpp

@@ -14,18 +14,11 @@
 #ifndef ZT_SALSA20_HPP
 #define ZT_SALSA20_HPP
 
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
-
 #include "Constants.hpp"
 #include "Utils.hpp"
 #include "TriviallyCopyable.hpp"
 
 #ifdef ZT_ARCH_X64
-#include <xmmintrin.h>
-#include <emmintrin.h>
-#include <immintrin.h>
 #define ZT_SALSA20_SSE 1
 #endif
 

+ 0 - 195
node/Speck128.hpp

@@ -1,195 +0,0 @@
-/*
- * 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.
- */
-/****/
-
-#ifndef ZT_SPECK128_HPP
-#define ZT_SPECK128_HPP
-
-#include "Constants.hpp"
-#include "Utils.hpp"
-
-#define ZT_SPECK128_KEY_SIZE 16
-
-namespace ZeroTier {
-
-/**
- * Tiny and simple 128-bit ARX block cipher
- *
- * Speck does not specify a mandatory endian-ness. This implementation is
- * little-endian for higher performance on the majority of platforms.
- *
- * Right now this is only used as part of the PoW function for V1 identity
- * generation. It's used because it's faster than SHA for filling a buffer
- * with randomness and unlike AES its relative performance advantage
- * across CPU architectures is pretty much identical.
- *
- * @tparam R Number of rounds (default: 32)
- */
-template<int R = 32>
-class Speck128
-{
-public:
-	/**
-	 * Create an uninitialized instance, init() must be called to set up.
-	 */
-	ZT_INLINE Speck128() noexcept {}
-
-	/**
-	 * Initialize Speck from a 128-bit key
-	 *
-	 * @param k 128-bit / 16 byte key
-	 */
-	ZT_INLINE Speck128(const void *k) noexcept { this->init(k); }
-
-	ZT_INLINE ~Speck128() { Utils::burn(m_expandedKey, sizeof(m_expandedKey)); }
-
-	/**
-	 * Initialize Speck from a 128-bit key
-	 *
-	 * @param k 128-bit / 16 byte key
-	 */
-	ZT_INLINE void init(const void *k) noexcept
-	{
-		initXY(Utils::loadLittleEndian<uint64_t>(k),Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(k) + 8));
-	}
-
-	/**
-	 * Initialize Speck from a 128-bit key in two 64-bit words
-	 *
-	 * @param x Least significant 64 bits
-	 * @param y Most significant 64 bits
-	 */
-	ZT_INLINE void initXY(uint64_t x,uint64_t y) noexcept
-	{
-		m_expandedKey[0] = x;
-		for(uint64_t i=0;i<(R-1);++i) {
-			x = x >> 8U | x << 56U;
-			x += y;
-			x ^= i;
-			y = y << 3U | y >> 61U;
-			y ^= x;
-			m_expandedKey[i + 1] = y;
-		}
-	}
-
-	/**
-	 * Encrypt a 128-bit block as two 64-bit words
-	 *
-	 * These should be in host byte order. If read or written to/from data
-	 * they should be stored in little-endian byte order.
-	 *
-	 * @param x Least significant 64 bits
-	 * @param y Most significant 64 bits
-	 */
-	ZT_INLINE void encryptXY(uint64_t &x,uint64_t &y) const noexcept
-	{
-		for (int i=0;i<R;++i) {
-			const uint64_t kk = m_expandedKey[i];
-			x = x >> 8U | x << 56U;
-			x += y;
-			x ^= kk;
-			y = y << 3U | y >> 61U;
-			y ^= x;
-		}
-	}
-
-	/**
-	 * Encrypt 512 bits in parallel with the same key.
-	 *
-	 * Parallel in this case assumes instruction level parallelism, but even without that
-	 * it may be faster due to cache/memory effects.
-	 */
-	ZT_INLINE void encryptXYXYXYXY(uint64_t &x0,uint64_t &y0,uint64_t &x1,uint64_t &y1,uint64_t &x2,uint64_t &y2,uint64_t &x3,uint64_t &y3) const noexcept
-	{
-		for (int i=0;i<R;++i) {
-			const uint64_t kk = m_expandedKey[i];
-			x0 = x0 >> 8U | x0 << 56U;
-			x1 = x1 >> 8U | x1 << 56U;
-			x2 = x2 >> 8U | x2 << 56U;
-			x3 = x3 >> 8U | x3 << 56U;
-			x0 += y0;
-			x1 += y1;
-			x2 += y2;
-			x3 += y3;
-			x0 ^= kk;
-			x1 ^= kk;
-			x2 ^= kk;
-			x3 ^= kk;
-			y0 = y0 << 3U | y0 >> 61U;
-			y1 = y1 << 3U | y1 >> 61U;
-			y2 = y2 << 3U | y2 >> 61U;
-			y3 = y3 << 3U | y3 >> 61U;
-			y0 ^= x0;
-			y1 ^= x1;
-			y2 ^= x2;
-			y3 ^= x3;
-		}
-	}
-
-	/**
-	 * Decrypt a 128-bit block as two 64-bit words
-	 *
-	 * These should be in host byte order. If read or written to/from data
-	 * they should be stored in little-endian byte order.
-	 *
-	 * @param x Least significant 64 bits
-	 * @param y Most significant 64 bits
-	 */
-	ZT_INLINE void decryptXY(uint64_t &x,uint64_t &y) const noexcept
-	{
-		for (int i=(R-1);i>=0;--i) {
-			const uint64_t kk = m_expandedKey[i];
-			y ^= x;
-			y = y >> 3U | y << 61U;
-			x ^= kk;
-			x -= y;
-			x = x << 8U | x >> 56U;
-		}
-	}
-
-	/**
-	 * Encrypt a block
-	 *
-	 * @param in 128-bit / 16 byte input
-	 * @param out 128-bit / 16 byte output
-	 */
-	ZT_INLINE void encrypt(const void *const in,void *const out) const noexcept
-	{
-		uint64_t x = Utils::loadLittleEndian<uint64_t>(in);
-		uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(in) + 8);
-		encryptXY(x,y);
-		Utils::storeLittleEndian<uint64_t>(out,x);
-		Utils::storeLittleEndian<uint64_t>(reinterpret_cast<uint8_t *>(out) + 8,y);
-	}
-
-	/**
-	 * Decrypt a block
-	 *
-	 * @param in 128-bit / 16 byte input
-	 * @param out 128-bit / 16 byte output
-	 */
-	ZT_INLINE void decrypt(const void *const in,void *const out) const noexcept
-	{
-		uint64_t x = Utils::loadLittleEndian<uint64_t>(in);
-		uint64_t y = Utils::loadLittleEndian<uint64_t>(reinterpret_cast<const uint8_t *>(in) + 8);
-		decryptXY(x,y);
-		Utils::storeLittleEndian<uint64_t>(out,x);
-		Utils::storeLittleEndian<uint64_t>(reinterpret_cast<uint8_t *>(out) + 8,y);
-	}
-
-private:
-	uint64_t m_expandedKey[R];
-};
-
-} // namespace ZeroTier
-
-#endif

+ 22 - 15
node/Tag.cpp

@@ -20,53 +20,60 @@ bool Tag::sign(const Identity &signer) noexcept
 	uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX];
 	if (signer.hasPrivate()) {
 		m_signedBy = signer.address();
-		m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature));
+		m_signatureLength = signer.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature));
 		return true;
 	}
 	return false;
 }
 
-int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX],bool forSign) const noexcept
+int Tag::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign) const noexcept
 {
 	int p = 0;
 	if (forSign) {
-		for(int k=0;k<8;++k)
+		for (int k = 0;k < 8;++k)
 			data[p++] = 0x7f;
 	}
-	Utils::storeBigEndian<uint64_t>(data + p, m_networkId); p += 8;
-	Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)m_ts); p += 8;
-	Utils::storeBigEndian<uint32_t>(data + p, m_id); p += 4;
-	Utils::storeBigEndian<uint32_t>(data + p, m_value); p += 4;
-	m_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
-	m_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
+	Utils::storeBigEndian<uint64_t>(data + p, m_networkId);
+	p += 8;
+	Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) m_ts);
+	p += 8;
+	Utils::storeBigEndian<uint32_t>(data + p, m_id);
+	p += 4;
+	Utils::storeBigEndian<uint32_t>(data + p, m_value);
+	p += 4;
+	m_issuedTo.copyTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
+	m_signedBy.copyTo(data + p);
+	p += ZT_ADDRESS_LENGTH;
 	if (!forSign) {
 		data[p++] = 1;
-		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)m_signatureLength); p += 2;
+		Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength);
+		p += 2;
 		Utils::copy(data + p, m_signature, m_signatureLength);
-		p += (int)m_signatureLength;
+		p += (int) m_signatureLength;
 	}
 	data[p++] = 0;
 	data[p++] = 0;
 	if (forSign) {
-		for(int k=0;k<8;++k)
+		for (int k = 0;k < 8;++k)
 			data[p++] = 0x7f;
 	}
 	return p;
 }
 
-int Tag::unmarshal(const uint8_t *data,int len) noexcept
+int Tag::unmarshal(const uint8_t *data, int len) noexcept
 {
 	if (len < 37)
 		return -1;
 	m_networkId = Utils::loadBigEndian<uint64_t>(data);
-	m_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
+	m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data + 8);
 	m_id = Utils::loadBigEndian<uint32_t>(data + 16);
 	m_value = Utils::loadBigEndian<uint32_t>(data + 20);
 	m_issuedTo.setTo(data + 24);
 	m_signedBy.setTo(data + 29);
 	// 1 byte reserved
 	m_signatureLength = Utils::loadBigEndian<uint16_t>(data + 35);
-	int p = 37 + (int)m_signatureLength;
+	int p = 37 + (int) m_signatureLength;
 	if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len))
 		return -1;
 	Utils::copy(m_signature, data + p, m_signatureLength);

+ 5 - 5
node/Tests.cpp

@@ -403,29 +403,29 @@ extern "C" const char *ZTT_general()
 			FCV<LifeCycleTracker,1024> test,test2;
 			for(unsigned int i=0;i<512;++i)
 				test.push_back(LifeCycleTracker(cnt));
-			if (cnt != 512) {
+			if (cnt != (long)test.size()) {
 				ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (1))" ZT_EOL_S,cnt);
 				return "FCV object life cycle test failed (1)";
 			}
 			test2 = test;
-			if (cnt != 1024) {
+			if (cnt != (long)(test.size() + test2.size())) {
 				ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (2))" ZT_EOL_S,cnt);
 				return "FCV object life cycle test failed (2)";
 			}
 			test.clear();
-			if (cnt != 512) {
+			if (cnt != (long)test.size()) {
 				ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (3))" ZT_EOL_S,cnt);
 				return "FCV object life cycle test failed (3)";
 			}
 			for(unsigned int i=0;i<512;++i)
 				test.push_back(LifeCycleTracker(cnt));
-			if (cnt != 1024) {
+			if (cnt != (long)(test.size() + test2.size())) {
 				ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (4))" ZT_EOL_S,cnt);
 				return "FCV object life cycle test failed (4)";
 			}
 			test.clear();
 			test2.clear();
-			if (cnt != 0) {
+			if (cnt != (long)test.size()) {
 				ZT_T_PRINTF("FAILED (expected 0 objects, got %lu (5))" ZT_EOL_S,cnt);
 				return "FCV object life cycle test failed (5)";
 			}

+ 38 - 36
node/Topology.cpp

@@ -15,31 +15,33 @@
 
 namespace ZeroTier {
 
-Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
+Topology::Topology(const RuntimeEnvironment *renv, void *tPtr) :
 	RR(renv),
 	m_numConfiguredPhysicalPaths(0)
 {
-	uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
-	Vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_ROOTS,idtmp));
+	uint64_t idtmp[2];
+	idtmp[0] = 0;
+	idtmp[1] = 0;
+	Vector<uint8_t> data(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_ROOTS, idtmp));
 	if (!data.empty()) {
 		uint8_t *dptr = data.data();
-		int drem = (int)data.size();
+		int drem = (int) data.size();
 		while (drem > 0) {
 			Identity id;
-			int l = id.unmarshal(dptr,drem);
+			int l = id.unmarshal(dptr, drem);
 			if (l > 0) {
 				m_roots.insert(id);
 				dptr += l;
 				drem -= l;
-				ZT_SPEW("loaded root %s",id.address().toString().c_str());
+				ZT_SPEW("loaded root %s", id.address().toString().c_str());
 			}
 		}
 	}
 
-	for(Set<Identity>::const_iterator r(m_roots.begin());r != m_roots.end();++r) {
+	for (Set<Identity>::const_iterator r(m_roots.begin());r != m_roots.end();++r) {
 		SharedPtr<Peer> p;
-		m_loadCached(tPtr,r->address(),p);
-		if ((!p)||(p->identity() != *r)) {
+		m_loadCached(tPtr, r->address(), p);
+		if ((!p) || (p->identity() != *r)) {
 			p.set(new Peer(RR));
 			p->init(*r);
 		}
@@ -48,26 +50,26 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
 	}
 }
 
-SharedPtr<Peer> Topology::add(void *tPtr,const SharedPtr<Peer> &peer)
+SharedPtr<Peer> Topology::add(void *tPtr, const SharedPtr<Peer> &peer)
 {
 	RWMutex::Lock _l(m_peers_l);
 	SharedPtr<Peer> &hp = m_peers[peer->address()];
 	if (hp)
 		return hp;
-	m_loadCached(tPtr,peer->address(),hp);
+	m_loadCached(tPtr, peer->address(), hp);
 	if (hp)
 		return hp;
 	hp = peer;
 	return peer;
 }
 
-void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
+void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig)
 {
 	if (!pathNetwork) {
 		m_numConfiguredPhysicalPaths = 0;
 	} else {
-		std::map<InetAddress,ZT_PhysicalPathConfiguration> cpaths;
-		for(unsigned int i=0,j=m_numConfiguredPhysicalPaths;i < j;++i)
+		std::map<InetAddress, ZT_PhysicalPathConfiguration> cpaths;
+		for (unsigned int i = 0, j = m_numConfiguredPhysicalPaths;i < j;++i)
 			cpaths[m_physicalPathConfig[i].first] = m_physicalPathConfig[i].second;
 
 		if (pathConfig) {
@@ -86,7 +88,7 @@ void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathN
 		}
 
 		unsigned int cnt = 0;
-		for(std::map<InetAddress,ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cnt<ZT_MAX_CONFIGURABLE_PATHS));++i) {
+		for (std::map<InetAddress, ZT_PhysicalPathConfiguration>::const_iterator i(cpaths.begin());((i != cpaths.end()) && (cnt < ZT_MAX_CONFIGURABLE_PATHS));++i) {
 			m_physicalPathConfig[cnt].first = i->first;
 			m_physicalPathConfig[cnt].second = i->second;
 			++cnt;
@@ -97,7 +99,7 @@ void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathN
 
 struct p_RootSortComparisonOperator
 {
-	ZT_INLINE bool operator()(const SharedPtr<Peer> &a,const SharedPtr<Peer> &b) const noexcept
+	ZT_INLINE bool operator()(const SharedPtr<Peer> &a, const SharedPtr<Peer> &b) const noexcept
 	{
 		// Sort in inverse order of latency with lowest latency first (and -1 last).
 		const int bb = b->latency();
@@ -107,13 +109,13 @@ struct p_RootSortComparisonOperator
 	}
 };
 
-void Topology::addRoot(void *const tPtr,const Identity &id,const InetAddress &bootstrap)
+void Topology::addRoot(void *const tPtr, const Identity &id, const InetAddress &bootstrap)
 {
 	if (id == RR->identity)
 		return;
 
 	RWMutex::Lock l1(m_peers_l);
-	std::pair< Set<Identity>::iterator,bool > ir(m_roots.insert(id));
+	std::pair<Set<Identity>::iterator, bool> ir(m_roots.insert(id));
 	if (ir.second) {
 		SharedPtr<Peer> &p = m_peers[id.address()];
 		if (!p) {
@@ -123,17 +125,17 @@ void Topology::addRoot(void *const tPtr,const Identity &id,const InetAddress &bo
 				p->setBootstrap(Endpoint(bootstrap));
 		}
 		m_rootPeers.push_back(p);
-		std::sort(m_rootPeers.begin(),m_rootPeers.end(),p_RootSortComparisonOperator());
+		std::sort(m_rootPeers.begin(), m_rootPeers.end(), p_RootSortComparisonOperator());
 		m_writeRootList(tPtr);
 	}
 }
 
-bool Topology::removeRoot(void *const tPtr,const Identity &id)
+bool Topology::removeRoot(void *const tPtr, const Identity &id)
 {
 	RWMutex::Lock l1(m_peers_l);
 	Set<Identity>::iterator r(m_roots.find(id));
 	if (r != m_roots.end()) {
-		for(Vector< SharedPtr<Peer> >::iterator p(m_rootPeers.begin());p != m_rootPeers.end();++p) {
+		for (Vector<SharedPtr<Peer> >::iterator p(m_rootPeers.begin());p != m_rootPeers.end();++p) {
 			if ((*p)->identity() == id) {
 				m_rootPeers.erase(p);
 				break;
@@ -149,16 +151,16 @@ bool Topology::removeRoot(void *const tPtr,const Identity &id)
 void Topology::rankRoots()
 {
 	RWMutex::Lock l1(m_peers_l);
-	std::sort(m_rootPeers.begin(),m_rootPeers.end(),p_RootSortComparisonOperator());
+	std::sort(m_rootPeers.begin(), m_rootPeers.end(), p_RootSortComparisonOperator());
 }
 
-void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
+void Topology::doPeriodicTasks(void *tPtr, const int64_t now)
 {
 	// Delete peers that haven't said anything in ZT_PEER_ALIVE_TIMEOUT.
 	{
 		RWMutex::Lock l1(m_peers_l);
-		for(Map< Address,SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();) {
-			if ( ((now - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (m_roots.count(i->second->identity()) == 0) ) {
+		for (Map<Address, SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();) {
+			if (((now - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (m_roots.count(i->second->identity()) == 0)) {
 				i->second->save(tPtr);
 				m_peers.erase(i++);
 			} else ++i;
@@ -168,7 +170,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
 	// Delete paths that are no longer held by anyone else ("weak reference" type behavior).
 	{
 		RWMutex::Lock l1(m_paths_l);
-		for(Map< uint64_t,SharedPtr<Path> >::iterator i(m_paths.begin());i != m_paths.end();) {
+		for (Map<uint64_t, SharedPtr<Path> >::iterator i(m_paths.begin());i != m_paths.end();) {
 			if (i->second.weakGC())
 				m_paths.erase(i++);
 			else ++i;
@@ -179,7 +181,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
 void Topology::saveAll(void *tPtr)
 {
 	RWMutex::RLock l(m_peers_l);
-	for(Map< Address,SharedPtr<Peer> >::iterator i(m_peers.begin());i!=m_peers.end();++i)
+	for (Map<Address, SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();++i)
 		i->second->save(tPtr);
 }
 
@@ -189,14 +191,14 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &pee
 		uint64_t id[2];
 		id[0] = zta.toInt();
 		id[1] = 0;
-		Vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,id));
+		Vector<uint8_t> data(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_PEER, id));
 		if (data.size() > 8) {
 			const uint8_t *d = data.data();
-			int dl = (int)data.size();
+			int dl = (int) data.size();
 
-			const int64_t ts = (int64_t)Utils::loadBigEndian<uint64_t>(d);
+			const int64_t ts = (int64_t) Utils::loadBigEndian<uint64_t>(d);
 			Peer *const p = new Peer(RR);
-			int n = p->unmarshal(d + 8,dl - 8);
+			int n = p->unmarshal(d + 8, dl - 8);
 			if (n < 0) {
 				delete p;
 				return;
@@ -207,7 +209,7 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &pee
 				return;
 			}
 		}
-	} catch ( ... ) {
+	} catch (...) {
 		peer.zero();
 	}
 }
@@ -215,18 +217,18 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &pee
 void Topology::m_writeRootList(void *tPtr)
 {
 	// assumes m_peers_l is locked
-	uint8_t *const roots = (uint8_t *)malloc(ZT_IDENTITY_MARSHAL_SIZE_MAX * m_roots.size());
+	uint8_t *const roots = (uint8_t *) malloc(ZT_IDENTITY_MARSHAL_SIZE_MAX * m_roots.size());
 	if (roots) { // sanity check
 		int p = 0;
-		for(Set<Identity>::const_iterator i(m_roots.begin());i != m_roots.end();++i) {
-			const int pp = i->marshal(roots + p,false);
+		for (Set<Identity>::const_iterator i(m_roots.begin());i != m_roots.end();++i) {
+			const int pp = i->marshal(roots + p, false);
 			if (pp > 0)
 				p += pp;
 		}
 		uint64_t id[2];
 		id[0] = 0;
 		id[1] = 0;
-		RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_ROOTS,id,roots,(unsigned int)p);
+		RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_ROOTS, id, roots, (unsigned int) p);
 		free(roots);
 	}
 }

+ 6 - 58
node/Topology.hpp

@@ -63,7 +63,7 @@ public:
 		{
 			RWMutex::RLock l(m_peers_l);
 			const SharedPtr<Peer> *const ap = m_peers.get(zta);
-			if (ap)
+			if (likely(ap != nullptr))
 				return *ap;
 		}
 		{
@@ -95,7 +95,7 @@ public:
 		{
 			RWMutex::RLock lck(m_paths_l);
 			SharedPtr<Path> *const p = m_paths.get(k);
-			if (p)
+			if (likely(p != nullptr))
 				return *p;
 		}
 		{
@@ -115,7 +115,7 @@ public:
 	ZT_INLINE SharedPtr<Peer> root() const
 	{
 		RWMutex::RLock l(m_peers_l);
-		if (m_rootPeers.empty())
+		if (unlikely(m_rootPeers.empty()))
 			return SharedPtr<Peer>();
 		return m_rootPeers.front();
 	}
@@ -167,10 +167,8 @@ public:
 			rootPeerPtrs.push_back((uintptr_t)rp->ptr());
 		std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
 
-		try {
-			for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
-				f(i->second,std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)i->second.ptr()));
-		} catch ( ... ) {} // should not throw
+		for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
+			f(i->second,std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)i->second.ptr()));
 	}
 
 	/**
@@ -185,56 +183,6 @@ public:
 			allPeers.push_back(i->second);
 	}
 
-	/**
-	 * Get info about a path
-	 *
-	 * The supplied result variables are not modified if no special config info is found.
-	 *
-	 * @param physicalAddress Physical endpoint address
-	 * @param mtu Variable set to MTU
-	 * @param trustedPathId Variable set to trusted path ID
-	 */
-	ZT_INLINE void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId)
-	{
-		for(unsigned int i=0,j=m_numConfiguredPhysicalPaths;i < j;++i) {
-			if (m_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
-				trustedPathId = m_physicalPathConfig[i].second.trustedPathId;
-				mtu = m_physicalPathConfig[i].second.mtu;
-				return;
-			}
-		}
-	}
-
-	/**
-	 * Get the outbound trusted path ID for a physical address, or 0 if none
-	 *
-	 * @param physicalAddress Physical address to which we are sending the packet
-	 * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
-	 */
-	ZT_INLINE uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
-	{
-		for(unsigned int i=0,j=m_numConfiguredPhysicalPaths;i < j;++i) {
-			if (m_physicalPathConfig[i].first.containsAddress(physicalAddress))
-				return m_physicalPathConfig[i].second.trustedPathId;
-		}
-		return 0;
-	}
-
-	/**
-	 * Check whether in incoming trusted path marked packet is valid
-	 *
-	 * @param physicalAddress Originating physical address
-	 * @param trustedPathId Trusted path ID from packet (from MAC field)
-	 */
-	ZT_INLINE bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
-	{
-		for(unsigned int i=0,j=m_numConfiguredPhysicalPaths;i < j;++i) {
-			if ((m_physicalPathConfig[i].second.trustedPathId == trustedPathId) && (m_physicalPathConfig[i].first.containsAddress(physicalAddress)))
-				return true;
-		}
-		return false;
-	}
-
 	/**
 	 * Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
 	 */
@@ -259,7 +207,7 @@ public:
 	bool removeRoot(void *tPtr,const Identity &id);
 
 	/**
-	 * Sort roots in asecnding order of apparent latency
+	 * Sort roots in ascending order of apparent latency
 	 *
 	 * @param now Current time
 	 */

+ 0 - 1
node/Trace.cpp

@@ -15,7 +15,6 @@
 #include "RuntimeEnvironment.hpp"
 #include "Node.hpp"
 #include "Peer.hpp"
-#include "Path.hpp"
 #include "InetAddress.hpp"
 #include "FCV.hpp"
 

+ 65 - 81
node/Utils.cpp

@@ -11,15 +11,10 @@
  */
 /****/
 
-#include <cstdio>
-#include <cstdlib>
-#include <ctime>
-
 #include "Utils.hpp"
 #include "Mutex.hpp"
 #include "AES.hpp"
 #include "SHA512.hpp"
-#include "Speck128.hpp"
 
 #ifdef __UNIX_LIKE__
 #include <unistd.h>
@@ -27,6 +22,8 @@
 #include <sys/uio.h>
 #endif
 
+#include <time.h>
+
 #ifdef __WINDOWS__
 #include <wincrypt.h>
 #endif
@@ -189,41 +186,31 @@ unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen
 }
 
 #define ZT_GETSECURERANDOM_STATE_SIZE 64
-#define ZT_GETSECURERANDOM_BUF_SIZE 4096
+#define ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR 1048576
 
-void getSecureRandom(void *const buf,const unsigned int bytes) noexcept
+void getSecureRandom(void *const buf,unsigned int bytes) noexcept
 {
 	static Mutex globalLock;
 	static bool initialized = false;
-	static uint64_t randomState[ZT_GETSECURERANDOM_STATE_SIZE]; // secret state
-	static uint64_t randomBuf[ZT_GETSECURERANDOM_BUF_SIZE]; // next batch of random bytes
-	static unsigned long randomPtr = sizeof(randomBuf); // refresh on first iteration
+	static uint64_t randomState[ZT_GETSECURERANDOM_STATE_SIZE];
+	static unsigned int randomByteCounter = ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR; // init on first run
+	static AES randomGen;
 
 	Mutex::Lock gl(globalLock);
 
-	// This could be a lot faster if we're not going to need a new block.
-	if ((randomPtr + (unsigned long)bytes) <= sizeof(randomBuf)) {
-		Utils::copy(buf,reinterpret_cast<uint8_t *>(randomBuf) + randomPtr,bytes);
-		randomPtr += bytes;
-		return;
-	}
-
-	for(unsigned int i=0;i<bytes;++i) {
-		// Generate a new block of random data if we're at the end of the current block.
-		// Note that randomPtr is a byte pointer not a word pointer so we compare with sizeof.
-		if (randomPtr >= (unsigned long)sizeof(randomBuf)) {
-			randomPtr = 0;
-
-			if (!initialized) {
-				initialized = true;
+	// Re-initialize the generator every ITERATIONS_PER_GENERATOR bytes.
+	if (unlikely((randomByteCounter += bytes) >= ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR)) {
+		// On first run fill randomState with random bits from the system.
+		if (unlikely(!initialized)) {
+			initialized = true;
 
-				Utils::memoryLock(randomState,sizeof(randomState));
-				Utils::memoryLock(randomBuf,sizeof(randomBuf));
+			// Don't let randomState be swapped to disk (if supported by OS).
+			Utils::memoryLock(randomState,sizeof(randomState));
 
-				// Fill randomState with entropy from the system. If this doesn't work this is a hard fail.
-				Utils::zero<sizeof(randomState)>(randomState);
+			// Fill randomState with entropy from the system. Failure equals hard exit.
+			Utils::zero<sizeof(randomState)>(randomState);
 #ifdef __WINDOWS__
-				HCRYPTPROV cryptProvider = NULL;
+			HCRYPTPROV cryptProvider = NULL;
 				if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
 					fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
 					exit(1);
@@ -234,66 +221,63 @@ void getSecureRandom(void *const buf,const unsigned int bytes) noexcept
 				}
 				CryptReleaseContext(cryptProvider,0);
 #else
-				int devURandomFd = ::open("/dev/urandom",O_RDONLY);
-				if (devURandomFd < 0) {
-					fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to open /dev/urandom\n");
-					exit(1);
-				}
-				if ((long)::read(devURandomFd,randomState,sizeof(randomState)) != (long)sizeof(randomState)) {
-					::close(devURandomFd);
-					fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
-					exit(1);
-				}
-				close(devURandomFd);
+			int devURandomFd = ::open("/dev/urandom",O_RDONLY);
+			if (devURandomFd < 0) {
+				fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to open /dev/urandom\n");
+				exit(1);
+			}
+			if ((long)::read(devURandomFd,randomState,sizeof(randomState)) != (long)sizeof(randomState)) {
+				::close(devURandomFd);
+				fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
+				exit(1);
+			}
+			close(devURandomFd);
 #endif
 
-				// Mix in additional entropy from time, the address of 'buf', CPU RDRAND if present, etc.
-				randomState[0] += (uint64_t)time(nullptr);
-				randomState[1] += (uint64_t)((uintptr_t)buf);
+			// Mix in additional entropy from time, the address of 'buf', CPU RDRAND if present, etc.
+			randomState[0] += (uint64_t)time(nullptr);
+			randomState[1] += (uint64_t)((uintptr_t)buf);
 #ifdef __UNIX_LIKE__
-				randomState[2] += (uint64_t)getpid();
-				randomState[3] += (uint64_t)getppid();
+			randomState[2] += (uint64_t)getpid();
+			randomState[3] += (uint64_t)getppid();
 #endif
 #ifdef ZT_ARCH_X64
-				if (CPUID.rdrand) {
-					uint64_t tmp = 0;
-					for(int k=0;k<ZT_GETSECURERANDOM_STATE_SIZE;++k) {
-						_rdrand64_step((unsigned long long *)&tmp);
-						randomState[k] ^= tmp;
-					}
-				}
-#endif
-			}
-
-			// Perturb state, hash, and overwrite the first 64 bytes with this hash.
-			++randomState[ZT_GETSECURERANDOM_STATE_SIZE-1];
-			SHA512(randomState,randomState,sizeof(randomState));
-
-			// Use the part of the state that was overwritten with new state to key a
-			// stream cipher and re-fill the buffer. Use AES if we're HW accel or use
-			// Speck if not since it's way faster on tiny chips without AES units.
-			if (AES::accelerated()) {
-				AES aes(randomState);
-				uint64_t ctr[2];
-				ctr[0] = randomState[4];
-				ctr[1] = randomState[5];
-				for (int k = 0;k < ZT_GETSECURERANDOM_BUF_SIZE;k += 2) {
-					++ctr[0];
-					aes.encrypt(ctr,randomBuf + k);
-				}
-			} else {
-				Speck128<> speck(randomState);
-				uint64_t ctr[2];
-				ctr[0] = randomState[4];
-				ctr[1] = randomState[5];
-				for (int k = 0;k < ZT_GETSECURERANDOM_BUF_SIZE;k += 2) {
-					++ctr[0];
-					speck.encrypt(ctr,randomBuf + k);
+			if (CPUID.rdrand) {
+				uint64_t tmp = 0;
+				for(int k=0;k<ZT_GETSECURERANDOM_STATE_SIZE;++k) {
+					_rdrand64_step((unsigned long long *)&tmp);
+					randomState[k] ^= tmp;
 				}
 			}
+#endif
 		}
 
-		reinterpret_cast<uint8_t *>(buf)[i] = reinterpret_cast<uint8_t *>(randomBuf)[randomPtr++];
+		// Initialize or re-initialize generator by hashing the full state,
+		// replacing the first 64 bytes with this hash, and then re-initializing
+		// AES with the first 32 bytes.
+		randomByteCounter = 0;
+		SHA512(randomState,randomState,sizeof(randomState));
+		randomGen.init(randomState);
+	}
+
+	// Generate random bytes using AES and bytes 32-48 of randomState as an in-place
+	// AES-CTR counter. Counter can be machine endian; we don't care about portability
+	// for a random generator.
+	uint64_t *const ctr = randomState + 4;
+	uint8_t *out = reinterpret_cast<uint8_t *>(buf);
+	while (bytes >= 16) {
+		++*ctr;
+		randomGen.encrypt(ctr,out);
+		out += 16;
+		bytes -= 16;
+	}
+	if (bytes > 0) {
+		uint8_t tmp[16];
+		++*ctr;
+		randomGen.encrypt(ctr,tmp);
+		for(unsigned int i=0;i<bytes;++i)
+			out[i] = tmp[i];
+		Utils::burn(tmp,sizeof(tmp)); // don't leave used cryptographic randomness lying around!
 	}
 }
 

+ 197 - 158
node/VL1.cpp

@@ -40,27 +40,28 @@ struct p_SalsaPolyCopyFunction
 	Salsa20 s20;
 	Poly1305 poly1305;
 	unsigned int hdrRemaining;
-	ZT_INLINE p_SalsaPolyCopyFunction(const void *salsaKey,const void *salsaIv) :
-		s20(salsaKey,salsaIv),
+	ZT_INLINE p_SalsaPolyCopyFunction(const void *salsaKey, const void *salsaIv) :
+		s20(salsaKey, salsaIv),
 		poly1305(),
 		hdrRemaining(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START)
 	{
 		uint8_t macKey[ZT_POLY1305_KEY_SIZE];
-		s20.crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_SIZE);
+		s20.crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE);
 		poly1305.init(macKey);
 	}
-	ZT_INLINE void operator()(void *dest,const void *src,unsigned int len) noexcept
+
+	ZT_INLINE void operator()(void *dest, const void *src, unsigned int len) noexcept
 	{
 		if (hdrRemaining != 0) {
 			unsigned int hdrBytes = (len > hdrRemaining) ? hdrRemaining : len;
-			Utils::copy(dest,src,hdrBytes);
+			Utils::copy(dest, src, hdrBytes);
 			hdrRemaining -= hdrBytes;
 			dest = reinterpret_cast<uint8_t *>(dest) + hdrBytes;
 			src = reinterpret_cast<const uint8_t *>(src) + hdrBytes;
 			len -= hdrBytes;
 		}
-		poly1305.update(src,len);
-		s20.crypt12(src,dest,len);
+		poly1305.update(src, len);
+		s20.crypt12(src, dest, len);
 	}
 };
 
@@ -68,26 +69,27 @@ struct p_PolyCopyFunction
 {
 	Poly1305 poly1305;
 	unsigned int hdrRemaining;
-	ZT_INLINE p_PolyCopyFunction(const void *salsaKey,const void *salsaIv) :
+	ZT_INLINE p_PolyCopyFunction(const void *salsaKey, const void *salsaIv) :
 		poly1305(),
 		hdrRemaining(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START)
 	{
 		uint8_t macKey[ZT_POLY1305_KEY_SIZE];
-		Salsa20(salsaKey,salsaIv).crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_SIZE);
+		Salsa20(salsaKey, salsaIv).crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE);
 		poly1305.init(macKey);
 	}
-	ZT_INLINE void operator()(void *dest,const void *src,unsigned int len) noexcept
+
+	ZT_INLINE void operator()(void *dest, const void *src, unsigned int len) noexcept
 	{
 		if (hdrRemaining != 0) {
 			unsigned int hdrBytes = (len > hdrRemaining) ? hdrRemaining : len;
-			Utils::copy(dest,src,hdrBytes);
+			Utils::copy(dest, src, hdrBytes);
 			hdrRemaining -= hdrBytes;
 			dest = reinterpret_cast<uint8_t *>(dest) + hdrBytes;
 			src = reinterpret_cast<const uint8_t *>(src) + hdrBytes;
 			len -= hdrBytes;
 		}
-		poly1305.update(src,len);
-		Utils::copy(dest,src,len);
+		poly1305.update(src, len);
+		Utils::copy(dest, src, len);
 	}
 };
 
@@ -98,13 +100,13 @@ VL1::VL1(const RuntimeEnvironment *renv) :
 {
 }
 
-void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAddress &fromAddr,SharedPtr<Buf> &data,const unsigned int len)
+void VL1::onRemotePacket(void *const tPtr, const int64_t localSocket, const InetAddress &fromAddr, SharedPtr<Buf> &data, const unsigned int len)
 {
-	const SharedPtr<Path> path(RR->topology->path(localSocket,fromAddr));
+	const SharedPtr<Path> path(RR->topology->path(localSocket, fromAddr));
 	const int64_t now = RR->node->now();
 
-	ZT_SPEW("%u bytes from %s (local socket %lld)",len,fromAddr.toString().c_str(),localSocket);
-	path->received(now,len);
+	ZT_SPEW("%u bytes from %s (local socket %lld)", len, fromAddr.toString().c_str(), localSocket);
+	path->received(now, len);
 
 	// NOTE: likely/unlikely are used here to highlight the most common code path
 	// for valid data packets. This may allow the compiler to generate very slightly
@@ -126,13 +128,13 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 		if (unlikely(len < ZT_PROTO_MIN_FRAGMENT_LENGTH))
 			return;
 
-		static_assert((ZT_PROTO_PACKET_ID_INDEX + sizeof(uint64_t)) < ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow");
+		static_assert((ZT_PROTO_PACKET_ID_INDEX + sizeof(uint64_t)) < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow");
 		const uint64_t packetId = Utils::loadAsIsEndian<uint64_t>(data->unsafeData + ZT_PROTO_PACKET_ID_INDEX);
 
-		static_assert((ZT_PROTO_PACKET_DESTINATION_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow");
+		static_assert((ZT_PROTO_PACKET_DESTINATION_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow");
 		Address destination(data->unsafeData + ZT_PROTO_PACKET_DESTINATION_INDEX);
 		if (destination != RR->identity.address()) {
-			m_relay(tPtr,path,destination,data,len);
+			m_relay(tPtr, path, destination, data, len);
 			return;
 		}
 
@@ -142,10 +144,10 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 
 		Buf::PacketVector pktv;
 
-		static_assert(ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX <= ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow");
+		static_assert(ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX <= ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow");
 		if (data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX] == ZT_PROTO_PACKET_FRAGMENT_INDICATOR) {
 			// This looks like a fragment (excluding the head) of a larger packet.
-			static_assert(ZT_PROTO_PACKET_FRAGMENT_COUNTS < ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow");
+			static_assert(ZT_PROTO_PACKET_FRAGMENT_COUNTS < ZT_PROTO_MIN_FRAGMENT_LENGTH, "overflow");
 			const unsigned int totalFragments = (data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_COUNTS] >> 4U) & 0x0fU;
 			const unsigned int fragmentNo = data->unsafeData[ZT_PROTO_PACKET_FRAGMENT_COUNTS] & 0x0fU;
 			switch (m_inputPacketAssembler.assemble(
@@ -171,7 +173,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 		} else {
 			if (unlikely(len < ZT_PROTO_MIN_PACKET_LENGTH))
 				return;
-			static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
+			static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
 			if ((data->unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
 				// This is the head of a series of fragments that we may or may not already have.
 				switch (m_inputPacketAssembler.assemble(
@@ -208,26 +210,26 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 		// ----------------------------------------------------------------------------------------------------------------
 
 		const uint8_t *const hdr = pktv[0].b->unsafeData + pktv[0].s;
-		static_assert((ZT_PROTO_PACKET_SOURCE_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
+		static_assert((ZT_PROTO_PACKET_SOURCE_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
 		const Address source(hdr + ZT_PROTO_PACKET_SOURCE_INDEX);
-		static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
+		static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
 		const uint8_t hops = hdr[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK;
 		const uint8_t cipher = (hdr[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 3U;
 
 		SharedPtr<Buf> pkt(new Buf());
 		int pktSize = 0;
 
-		static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
-		if (unlikely( ((cipher == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)||(cipher == ZT_PROTO_CIPHER_SUITE__NONE)) && ((hdr[ZT_PROTO_PACKET_VERB_INDEX] & ZT_PROTO_VERB_MASK) == Protocol::VERB_HELLO) )) {
+		static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
+		if (unlikely(((cipher == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE) || (cipher == ZT_PROTO_CIPHER_SUITE__NONE)) && ((hdr[ZT_PROTO_PACKET_VERB_INDEX] & ZT_PROTO_VERB_MASK) == Protocol::VERB_HELLO))) {
 			// Handle unencrypted HELLO packets.
 			pktSize = pktv.mergeCopy(*pkt);
 			if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
-				ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
+				ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize);
 				return;
 			}
 			const SharedPtr<Peer> peer(m_HELLO(tPtr, path, *pkt, pktSize));
-			if (peer)
-				peer->received(tPtr,path,hops,packetId,pktSize - ZT_PROTO_PACKET_PAYLOAD_START,Protocol::VERB_HELLO,Protocol::VERB_NOP);
+			if (likely(peer))
+				peer->received(tPtr, path, hops, packetId, pktSize - ZT_PROTO_PACKET_PAYLOAD_START, Protocol::VERB_HELLO, Protocol::VERB_NOP);
 			return;
 		}
 
@@ -236,55 +238,55 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 		// secrecy status.
 		unsigned int auth = 0;
 
-		SharedPtr<Peer> peer(RR->topology->peer(tPtr,source));
-		if (peer) {
-			switch(cipher) {
+		SharedPtr<Peer> peer(RR->topology->peer(tPtr, source));
+		if (likely(peer)) {
+			switch (cipher) {
 
 				case ZT_PROTO_CIPHER_SUITE__POLY1305_NONE: {
 					uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE];
-					Protocol::salsa2012DeriveKey(peer->rawIdentityKey(),perPacketKey,*pktv[0].b,pktv.totalSize());
-					p_PolyCopyFunction s20cf(perPacketKey,&packetId);
+					Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, *pktv[0].b, pktv.totalSize());
+					p_PolyCopyFunction s20cf(perPacketKey, &packetId);
 
-					pktSize = pktv.mergeMap<p_PolyCopyFunction &>(*pkt,ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,s20cf);
+					pktSize = pktv.mergeMap<p_PolyCopyFunction &>(*pkt, ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, s20cf);
 					if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
-						ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
+						ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize);
 						return;
 					}
 
 					uint64_t mac[2];
 					s20cf.poly1305.finish(mac);
-					static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
+					static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
 					if (unlikely(Utils::loadAsIsEndian<uint64_t>(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) {
-						ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (none/poly1305)",packetId,source.toString().c_str(),fromAddr.toString().c_str());
-						RR->t->incomingPacketDropped(tPtr,0xcc89c812,packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+						ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (none/poly1305)", packetId, source.toString().c_str(), fromAddr.toString().c_str());
+						RR->t->incomingPacketDropped(tPtr, 0xcc89c812, packetId, 0, peer->identity(), path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 						return;
 					}
 
 					auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED;
-				}	break;
+				} break;
 
 				case ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012: {
 					uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE];
-					Protocol::salsa2012DeriveKey(peer->rawIdentityKey(),perPacketKey,*pktv[0].b,pktv.totalSize());
-					p_SalsaPolyCopyFunction s20cf(perPacketKey,&packetId);
+					Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, *pktv[0].b, pktv.totalSize());
+					p_SalsaPolyCopyFunction s20cf(perPacketKey, &packetId);
 
-					pktSize = pktv.mergeMap<p_SalsaPolyCopyFunction &>(*pkt,ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,s20cf);
+					pktSize = pktv.mergeMap<p_SalsaPolyCopyFunction &>(*pkt, ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, s20cf);
 					if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
-						ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
+						ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize);
 						return;
 					}
 
 					uint64_t mac[2];
 					s20cf.poly1305.finish(mac);
-					static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
+					static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
 					if (unlikely(Utils::loadAsIsEndian<uint64_t>(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) {
-						ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (salsa/poly1305)",packetId,source.toString().c_str(),fromAddr.toString().c_str());
-						RR->t->incomingPacketDropped(tPtr,0xcc89c812,packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+						ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (salsa/poly1305)", packetId, source.toString().c_str(), fromAddr.toString().c_str());
+						RR->t->incomingPacketDropped(tPtr, 0xcc89c812, packetId, 0, peer->identity(), path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 						return;
 					}
 
 					auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED | ZT_VL1_AUTH_RESULT_FLAG_ENCRYPTED;
-				}	break;
+				} break;
 
 				case ZT_PROTO_CIPHER_SUITE__NONE: {
 					// TODO
@@ -292,10 +294,10 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 
 				case ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV: {
 					// TODO
-				}	break;
+				} break;
 
 				default:
-					RR->t->incomingPacketDropped(tPtr,0x5b001099,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+					RR->t->incomingPacketDropped(tPtr, 0x5b001099, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
 					return;
 			}
 		}
@@ -304,99 +306,136 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 			// If authentication was successful go on and process the packet.
 
 			if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
-				ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size %d is smaller than minimum packet length",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
+				ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size %d is smaller than minimum packet length", packetId, source.toString().c_str(), fromAddr.toString().c_str(), pktSize);
 				return;
 			}
 
 			// TODO: should take instance ID into account here once that is fully implemented.
 			if (unlikely(peer->deduplicateIncomingPacket(packetId))) {
-				ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!",packetId,source.toString().c_str(),fromAddr.toString().c_str());
+				ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!", packetId, source.toString().c_str(), fromAddr.toString().c_str());
 				return;
 			}
 
-			static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
+			static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH, "overflow");
 			const uint8_t verbFlags = pkt->unsafeData[ZT_PROTO_PACKET_VERB_INDEX];
-			const Protocol::Verb verb = (Protocol::Verb)(verbFlags & ZT_PROTO_VERB_MASK);
+			const Protocol::Verb verb = (Protocol::Verb) (verbFlags & ZT_PROTO_VERB_MASK);
 
 			// Decompress packet payload if compressed. For additional safety decompression is
 			// only performed on packets whose MACs have already been validated. (Only HELLO is
 			// sent without this, and HELLO doesn't benefit from compression.)
-			if (((verbFlags & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0)&&(pktSize > ZT_PROTO_PACKET_PAYLOAD_START)) {
+			if (((verbFlags & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) && (pktSize > ZT_PROTO_PACKET_PAYLOAD_START)) {
 				SharedPtr<Buf> dec(new Buf());
-				Utils::copy<ZT_PROTO_PACKET_PAYLOAD_START>(dec->unsafeData,pkt->unsafeData);
+				Utils::copy<ZT_PROTO_PACKET_PAYLOAD_START>(dec->unsafeData, pkt->unsafeData);
 				const int uncompressedLen = LZ4_decompress_safe(
 					reinterpret_cast<const char *>(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),
 					reinterpret_cast<char *>(dec->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),
 					pktSize - ZT_PROTO_PACKET_PAYLOAD_START,
 					ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
-				if (likely((uncompressedLen >= 0)&&(uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START)))) {
+				if (likely((uncompressedLen >= 0) && (uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START)))) {
 					pkt.swap(dec);
-					ZT_SPEW("decompressed packet: %d -> %d",pktSize,ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen);
+					ZT_SPEW("decompressed packet: %d -> %d", pktSize, ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen);
 					pktSize = ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen;
 				} else {
-					RR->t->incomingPacketDropped(tPtr,0xee9e4392,packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
+					RR->t->incomingPacketDropped(tPtr, 0xee9e4392, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, verb, ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
 					return;
 				}
 			}
 
-			ZT_SPEW("%s from %s(%s) (%d bytes)",Protocol::verbName(verb),source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
+			ZT_SPEW("%s from %s(%s) (%d bytes)", Protocol::verbName(verb), source.toString().c_str(), fromAddr.toString().c_str(), pktSize);
 
 			// NOTE: HELLO is normally sent in the clear (in terms of our usual AEAD modes) and is handled
 			// above. We will try to process it here, but if so it'll still get re-authenticated via HELLO's
 			// own internal authentication logic as usual. It would be abnormal to make it here with HELLO
 			// but not invalid.
 
-			bool ok = true;
 			Protocol::Verb inReVerb = Protocol::VERB_NOP;
-			switch(verb) {
-				case Protocol::VERB_NOP:                        break;
-				case Protocol::VERB_HELLO:                      ok = (bool)(m_HELLO(tPtr, path, *pkt, pktSize)); break;
-				case Protocol::VERB_ERROR:                      ok = m_ERROR(tPtr, packetId, auth, path, peer, *pkt, pktSize, inReVerb); break;
-				case Protocol::VERB_OK:                         ok = m_OK(tPtr, packetId, auth, path, peer, *pkt, pktSize, inReVerb); break;
-				case Protocol::VERB_WHOIS:                      ok = m_WHOIS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_RENDEZVOUS:                 ok = m_RENDEZVOUS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_FRAME:                      ok = RR->vl2->m_FRAME(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_EXT_FRAME:                  ok = RR->vl2->m_EXT_FRAME(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_ECHO:                       ok = m_ECHO(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_MULTICAST_LIKE:             ok = RR->vl2->m_MULTICAST_LIKE(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_NETWORK_CREDENTIALS:        ok = RR->vl2->m_NETWORK_CREDENTIALS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_NETWORK_CONFIG_REQUEST:     ok = RR->vl2->m_NETWORK_CONFIG_REQUEST(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_NETWORK_CONFIG:             ok = RR->vl2->m_NETWORK_CONFIG(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_MULTICAST_GATHER:           ok = RR->vl2->m_MULTICAST_GATHER(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_MULTICAST_FRAME_deprecated: ok = RR->vl2->m_MULTICAST_FRAME_deprecated(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_PUSH_DIRECT_PATHS:          ok = m_PUSH_DIRECT_PATHS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_USER_MESSAGE:               ok = m_USER_MESSAGE(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_MULTICAST:                  ok = RR->vl2->m_MULTICAST(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
-				case Protocol::VERB_ENCAP:                      ok = m_ENCAP(tPtr, packetId, auth, path, peer, *pkt, pktSize); break;
+			bool ok = true;
+			switch (verb) {
+				case Protocol::VERB_NOP:
+					break;
+				case Protocol::VERB_HELLO:
+					ok = (bool) (m_HELLO(tPtr, path, *pkt, pktSize));
+					break;
+				case Protocol::VERB_ERROR:
+					ok = m_ERROR(tPtr, packetId, auth, path, peer, *pkt, pktSize, inReVerb);
+					break;
+				case Protocol::VERB_OK:
+					ok = m_OK(tPtr, packetId, auth, path, peer, *pkt, pktSize, inReVerb);
+					break;
+				case Protocol::VERB_WHOIS:
+					ok = m_WHOIS(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_RENDEZVOUS:
+					ok = m_RENDEZVOUS(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_FRAME:
+					ok = RR->vl2->m_FRAME(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_EXT_FRAME:
+					ok = RR->vl2->m_EXT_FRAME(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_ECHO:
+					ok = m_ECHO(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_MULTICAST_LIKE:
+					ok = RR->vl2->m_MULTICAST_LIKE(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_NETWORK_CREDENTIALS:
+					ok = RR->vl2->m_NETWORK_CREDENTIALS(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_NETWORK_CONFIG_REQUEST:
+					ok = RR->vl2->m_NETWORK_CONFIG_REQUEST(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_NETWORK_CONFIG:
+					ok = RR->vl2->m_NETWORK_CONFIG(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_MULTICAST_GATHER:
+					ok = RR->vl2->m_MULTICAST_GATHER(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_MULTICAST_FRAME_deprecated:
+					ok = RR->vl2->m_MULTICAST_FRAME_deprecated(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_PUSH_DIRECT_PATHS:
+					ok = m_PUSH_DIRECT_PATHS(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_USER_MESSAGE:
+					ok = m_USER_MESSAGE(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_MULTICAST:
+					ok = RR->vl2->m_MULTICAST(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
+				case Protocol::VERB_ENCAP:
+					ok = m_ENCAP(tPtr, packetId, auth, path, peer, *pkt, pktSize);
+					break;
 
 				default:
-					RR->t->incomingPacketDropped(tPtr,0xeeeeeff0,packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
+					RR->t->incomingPacketDropped(tPtr, 0xeeeeeff0, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, verb, ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
 					break;
 			}
 			if (likely(ok))
-				peer->received(tPtr,path,hops,packetId,pktSize - ZT_PROTO_PACKET_PAYLOAD_START,verb,inReVerb);
+				peer->received(tPtr, path, hops, packetId, pktSize - ZT_PROTO_PACKET_PAYLOAD_START, verb, inReVerb);
 		} else {
 			// If decryption and authentication were not successful, try to look up identities.
 			// This is rate limited by virtue of the retry rate limit timer.
 			if (pktSize <= 0)
 				pktSize = pktv.mergeCopy(*pkt);
 			if (pktSize >= ZT_PROTO_MIN_PACKET_LENGTH) {
-				ZT_SPEW("authentication failed or no peers match, queueing WHOIS for %s",source.toString().c_str());
+				ZT_SPEW("authentication failed or no peers match, queueing WHOIS for %s", source.toString().c_str());
 				bool sendPending;
 				{
 					Mutex::Lock wl(m_whoisQueue_l);
 					p_WhoisQueueItem &wq = m_whoisQueue[source];
 					const unsigned int wpidx = wq.waitingPacketCount++ % ZT_VL1_MAX_WHOIS_WAITING_PACKETS;
-					wq.waitingPacketSize[wpidx] = (unsigned int)pktSize;
+					wq.waitingPacketSize[wpidx] = (unsigned int) pktSize;
 					wq.waitingPacket[wpidx] = pkt;
 					sendPending = (now - wq.lastRetry) >= ZT_WHOIS_RETRY_DELAY;
 				}
 				if (sendPending)
-					m_sendPendingWhois(tPtr,now);
+					m_sendPendingWhois(tPtr, now);
 			}
 		}
-	} catch ( ... ) {
-		RR->t->unexpectedError(tPtr,0xea1b6dea,"unexpected exception in onRemotePacket() parsing packet from %s",path->address().toString().c_str());
+	} catch (...) {
+		RR->t->unexpectedError(tPtr, 0xea1b6dea, "unexpected exception in onRemotePacket() parsing packet from %s", path->address().toString().c_str());
 	}
 }
 
@@ -413,10 +452,10 @@ void VL1::m_sendPendingWhois(void *tPtr, int64_t now)
 	if (unlikely(!rootPath))
 		return;
 
-	std::vector<Address> toSend;
+	Vector<Address> toSend;
 	{
 		Mutex::Lock wl(m_whoisQueue_l);
-		for(Map<Address,p_WhoisQueueItem>::iterator wi(m_whoisQueue.begin());wi!=m_whoisQueue.end();++wi) {
+		for (Map<Address, p_WhoisQueueItem>::iterator wi(m_whoisQueue.begin());wi != m_whoisQueue.end();++wi) {
 			if ((now - wi->second.lastRetry) >= ZT_WHOIS_RETRY_DELAY) {
 				wi->second.lastRetry = now;
 				++wi->second.retries;
@@ -430,18 +469,18 @@ void VL1::m_sendPendingWhois(void *tPtr, int64_t now)
 
 	const SharedPtr<SymmetricKey> key(root->key());
 	uint8_t outp[ZT_DEFAULT_UDP_MTU - ZT_PROTO_MIN_PACKET_LENGTH];
-	std::vector<Address>::iterator a(toSend.begin());
+	Vector<Address>::iterator a(toSend.begin());
 	while (a != toSend.end()) {
-		const uint64_t packetId = key->nextMessage(RR->identity.address(),root->address());
-		int p = Protocol::newPacket(outp,packetId,root->address(),RR->identity.address(),Protocol::VERB_WHOIS);
-		while ((a != toSend.end())&&(p < (sizeof(outp) - ZT_ADDRESS_LENGTH))) {
+		const uint64_t packetId = key->nextMessage(RR->identity.address(), root->address());
+		int p = Protocol::newPacket(outp, packetId, root->address(), RR->identity.address(), Protocol::VERB_WHOIS);
+		while ((a != toSend.end()) && (p < (sizeof(outp) - ZT_ADDRESS_LENGTH))) {
 			a->copyTo(outp + p);
 			++a;
 			p += ZT_ADDRESS_LENGTH;
 		}
-		Protocol::armor(outp,p,key,root->cipher());
-		RR->expect->sending(packetId,now);
-		root->send(tPtr,now,outp,p,rootPath);
+		Protocol::armor(outp, p, key, root->cipher());
+		RR->expect->sending(packetId, now);
+		root->send(tPtr, now, outp, p, rootPath);
 	}
 }
 
@@ -453,7 +492,7 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
 
 	const uint8_t protoVersion = pkt.lI8<ZT_PROTO_PACKET_PAYLOAD_START>();
 	if (unlikely(protoVersion < ZT_PROTO_VERSION_MIN)) {
-		RR->t->incomingPacketDropped(tPtr,0x907a9891,packetId,0,Identity::NIL,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
+		RR->t->incomingPacketDropped(tPtr, 0x907a9891, packetId, 0, Identity::NIL, path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
 		return SharedPtr<Peer>();
 	}
 	const unsigned int versionMajor = pkt.lI8<ZT_PROTO_PACKET_PAYLOAD_START + 1>();
@@ -465,37 +504,37 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
 
 	// Get identity and verify that it matches the sending address in the packet.
 	Identity id;
-	if (unlikely(pkt.rO(ii,id) < 0)) {
-		RR->t->incomingPacketDropped(tPtr,0x707a9810,packetId,0,Identity::NIL,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+	if (unlikely(pkt.rO(ii, id) < 0)) {
+		RR->t->incomingPacketDropped(tPtr, 0x707a9810, packetId, 0, Identity::NIL, path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
 		return SharedPtr<Peer>();
 	}
 	if (unlikely(id.address() != Address(pkt.unsafeData + ZT_PROTO_PACKET_SOURCE_INDEX))) {
-		RR->t->incomingPacketDropped(tPtr,0x707a9010,packetId,0,Identity::NIL,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+		RR->t->incomingPacketDropped(tPtr, 0x707a9010, packetId, 0, Identity::NIL, path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 		return SharedPtr<Peer>();
 	}
 
 	// Get the peer that matches this identity, or learn a new one if we don't know it.
-	SharedPtr<Peer> peer(RR->topology->peer(tPtr,id.address(),true));
+	SharedPtr<Peer> peer(RR->topology->peer(tPtr, id.address(), true));
 	if (peer) {
-		if (peer->identity() != id) {
-			RR->t->incomingPacketDropped(tPtr,0x707a9891,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+		if (unlikely(peer->identity() != id)) {
+			RR->t->incomingPacketDropped(tPtr, 0x707a9891, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 			return SharedPtr<Peer>();
 		}
-		if (peer->deduplicateIncomingPacket(packetId)) {
-			ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!",packetId,id.address().toString().c_str(),path->address().toString().c_str());
+		if (unlikely(peer->deduplicateIncomingPacket(packetId))) {
+			ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!", packetId, id.address().toString().c_str(), path->address().toString().c_str());
 			return SharedPtr<Peer>();
 		}
 	} else {
 		if (unlikely(!id.locallyValidate())) {
-			RR->t->incomingPacketDropped(tPtr,0x707a9892,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+			RR->t->incomingPacketDropped(tPtr, 0x707a9892, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
 			return SharedPtr<Peer>();
 		}
 		peer.set(new Peer(RR));
 		if (unlikely(!peer->init(id))) {
-			RR->t->incomingPacketDropped(tPtr,0x707a9893,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
+			RR->t->incomingPacketDropped(tPtr, 0x707a9893, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
 			return SharedPtr<Peer>();
 		}
-		peer = RR->topology->add(tPtr,peer);
+		peer = RR->topology->add(tPtr, peer);
 	}
 
 	// ------------------------------------------------------------------------------------------------------------------
@@ -508,34 +547,34 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
 		// field is ignored, and eventually it'll be undefined.
 		uint8_t hmac[ZT_HMACSHA384_LEN];
 		if (unlikely(packetSize < ZT_HMACSHA384_LEN)) {
-			RR->t->incomingPacketDropped(tPtr,0xab9c9891,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+			RR->t->incomingPacketDropped(tPtr, 0xab9c9891, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 			return SharedPtr<Peer>();
 		}
 		packetSize -= ZT_HMACSHA384_LEN;
 		pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] &= ~ZT_PROTO_FLAG_FIELD_HOPS_MASK; // mask hops to 0
-		Utils::storeAsIsEndian<uint64_t>(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX,0); // set MAC field to 0
-		HMACSHA384(peer->identityHelloHmacKey(),pkt.unsafeData,packetSize,hmac);
-		if (unlikely(!Utils::secureEq(hmac,pkt.unsafeData + packetSize,ZT_HMACSHA384_LEN))) {
-			RR->t->incomingPacketDropped(tPtr,0x707a9891,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+		Utils::storeAsIsEndian<uint64_t>(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, 0); // set MAC field to 0
+		HMACSHA384(peer->identityHelloHmacKey(), pkt.unsafeData, packetSize, hmac);
+		if (unlikely(!Utils::secureEq(hmac, pkt.unsafeData + packetSize, ZT_HMACSHA384_LEN))) {
+			RR->t->incomingPacketDropped(tPtr, 0x707a9891, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 			return SharedPtr<Peer>();
 		}
 	} else {
 		// Older versions use Poly1305 MAC (but no whole packet encryption) for HELLO.
 		if (likely(packetSize > ZT_PROTO_PACKET_ENCRYPTED_SECTION_START)) {
 			uint8_t perPacketKey[ZT_SALSA20_KEY_SIZE];
-			Protocol::salsa2012DeriveKey(peer->rawIdentityKey(),perPacketKey,pkt,packetSize);
+			Protocol::salsa2012DeriveKey(peer->rawIdentityKey(), perPacketKey, pkt, packetSize);
 			uint8_t macKey[ZT_POLY1305_KEY_SIZE];
-			Salsa20(perPacketKey,&packetId).crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_SIZE);
+			Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, macKey, ZT_POLY1305_KEY_SIZE);
 			Poly1305 poly1305(macKey);
-			poly1305.update(pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START);
+			poly1305.update(pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START);
 			uint64_t polyMac[2];
 			poly1305.finish(polyMac);
 			if (unlikely(mac != polyMac[0])) {
-				RR->t->incomingPacketDropped(tPtr,0x11bfff82,packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+				RR->t->incomingPacketDropped(tPtr, 0x11bfff82, packetId, 0, id, path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 				return SharedPtr<Peer>();
 			}
 		} else {
-			RR->t->incomingPacketDropped(tPtr,0x11bfff81,packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+			RR->t->incomingPacketDropped(tPtr, 0x11bfff81, packetId, 0, id, path->address(), hops, Protocol::VERB_NOP, ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 			return SharedPtr<Peer>();
 		}
 	}
@@ -545,8 +584,8 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
 	// ------------------------------------------------------------------------------------------------------------------
 
 	InetAddress sentTo;
-	if (unlikely(pkt.rO(ii,sentTo) < 0)) {
-		RR->t->incomingPacketDropped(tPtr,0x707a9811,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+	if (unlikely(pkt.rO(ii, sentTo) < 0)) {
+		RR->t->incomingPacketDropped(tPtr, 0x707a9811, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
 		return SharedPtr<Peer>();
 	}
 
@@ -559,19 +598,19 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
 			AES::CTR ctr(peer->identityHelloDictionaryEncryptionCipher());
 			const uint8_t *const ctrNonce = pkt.unsafeData + ii;
 			ii += 12;
-			ctr.init(ctrNonce,0,pkt.unsafeData + ii);
-			ctr.crypt(pkt.unsafeData + ii,packetSize - ii);
+			ctr.init(ctrNonce, 0, pkt.unsafeData + ii);
+			ctr.crypt(pkt.unsafeData + ii, packetSize - ii);
 			ctr.finish();
 
 			ii += 2; // skip reserved field
 			const unsigned int dictSize = pkt.rI16(ii);
 			if (unlikely((ii + dictSize) > packetSize)) {
-				RR->t->incomingPacketDropped(tPtr,0x707a9815,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+				RR->t->incomingPacketDropped(tPtr, 0x707a9815, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
 				return peer;
 			}
 			Dictionary md;
-			if (!md.decode(pkt.unsafeData + ii,dictSize)) {
-				RR->t->incomingPacketDropped(tPtr,0x707a9816,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+			if (!md.decode(pkt.unsafeData + ii, dictSize)) {
+				RR->t->incomingPacketDropped(tPtr, 0x707a9816, packetId, 0, identityFromPeerPtr(peer), path->address(), hops, Protocol::VERB_HELLO, ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
 				return peer;
 			}
 
@@ -581,36 +620,36 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
 		}
 	}
 
-	Protocol::newPacket(pkt,key->nextMessage(RR->identity.address(),peer->address()),peer->address(),RR->identity.address(),Protocol::VERB_OK);
+	Protocol::newPacket(pkt, key->nextMessage(RR->identity.address(), peer->address()), peer->address(), RR->identity.address(), Protocol::VERB_OK);
 	ii = ZT_PROTO_PACKET_PAYLOAD_START;
-	pkt.wI8(ii,Protocol::VERB_HELLO);
-	pkt.wI64(ii,packetId);
-	pkt.wI64(ii,timestamp);
-	pkt.wI8(ii,ZT_PROTO_VERSION);
-	pkt.wI8(ii,ZEROTIER_VERSION_MAJOR);
-	pkt.wI8(ii,ZEROTIER_VERSION_MINOR);
-	pkt.wI16(ii,ZEROTIER_VERSION_REVISION);
-	pkt.wO(ii,path->address());
-	pkt.wI16(ii,0); // reserved, specifies no "moons" for older versions
+	pkt.wI8(ii, Protocol::VERB_HELLO);
+	pkt.wI64(ii, packetId);
+	pkt.wI64(ii, timestamp);
+	pkt.wI8(ii, ZT_PROTO_VERSION);
+	pkt.wI8(ii, ZEROTIER_VERSION_MAJOR);
+	pkt.wI8(ii, ZEROTIER_VERSION_MINOR);
+	pkt.wI16(ii, ZEROTIER_VERSION_REVISION);
+	pkt.wO(ii, path->address());
+	pkt.wI16(ii, 0); // reserved, specifies no "moons" for older versions
 
 	if (protoVersion >= 11) {
-		FCV<uint8_t,1024> okmd;
-		pkt.wI16(ii,(uint16_t)okmd.size());
-		pkt.wB(ii,okmd.data(),okmd.size());
+		FCV<uint8_t, 1024> okmd;
+		pkt.wI16(ii, (uint16_t) okmd.size());
+		pkt.wB(ii, okmd.data(), okmd.size());
 
 		if (unlikely((ii + ZT_HMACSHA384_LEN) > ZT_BUF_MEM_SIZE)) // sanity check, should be impossible
 			return SharedPtr<Peer>();
 
-		HMACSHA384(peer->identityHelloHmacKey(),pkt.unsafeData,ii,pkt.unsafeData + ii);
+		HMACSHA384(peer->identityHelloHmacKey(), pkt.unsafeData, ii, pkt.unsafeData + ii);
 		ii += ZT_HMACSHA384_LEN;
 	}
 
-	peer->setRemoteVersion(protoVersion,versionMajor,versionMinor,versionRev);
-	peer->send(tPtr,RR->node->now(),pkt.unsafeData,ii,path);
+	peer->setRemoteVersion(protoVersion, versionMajor, versionMinor, versionRev);
+	peer->send(tPtr, RR->node->now(), pkt.unsafeData, ii, path);
 	return peer;
 }
 
-bool VL1::m_ERROR(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
+bool VL1::m_ERROR(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
 {
 #if 0
 	if (packetSize < (int)sizeof(Protocol::ERROR::Header)) {
@@ -657,26 +696,26 @@ bool VL1::m_ERROR(void *tPtr,const uint64_t packetId,const unsigned int auth, co
 #endif
 }
 
-bool VL1::m_OK(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
+bool VL1::m_OK(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
 {
 	int ii = ZT_PROTO_PACKET_PAYLOAD_START + 13;
 
-	inReVerb = (Protocol::Verb)pkt.rI8(ii);
+	inReVerb = (Protocol::Verb) pkt.rI8(ii);
 	const uint64_t inRePacketId = pkt.rI64(ii);
-	if (unlikely(Buf::readOverflow(ii,packetSize))) {
-		RR->t->incomingPacketDropped(tPtr,0x4c1f1ff7,packetId,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
+	if (unlikely(Buf::readOverflow(ii, packetSize))) {
+		RR->t->incomingPacketDropped(tPtr, 0x4c1f1ff7, packetId, 0, identityFromPeerPtr(peer), path->address(), 0, Protocol::VERB_OK, ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
 		return false;
 	}
 
 	const int64_t now = RR->node->now();
-	if (!RR->expect->expecting(inRePacketId,now)) {
-		RR->t->incomingPacketDropped(tPtr,0x4c1f1ff8,packetId,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED);
+	if (!RR->expect->expecting(inRePacketId, now)) {
+		RR->t->incomingPacketDropped(tPtr, 0x4c1f1ff8, packetId, 0, identityFromPeerPtr(peer), path->address(), 0, Protocol::VERB_OK, ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED);
 		return false;
 	}
 
-	ZT_SPEW("got OK in-re %s (packet ID %.16llx) from %s(%s)",Protocol::verbName(inReVerb),inRePacketId,peer->address().toString().c_str(),path->address().toString().c_str());
+	ZT_SPEW("got OK in-re %s (packet ID %.16llx) from %s(%s)", Protocol::verbName(inReVerb), inRePacketId, peer->address().toString().c_str(), path->address().toString().c_str());
 
-	switch(inReVerb) {
+	switch (inReVerb) {
 
 		case Protocol::VERB_HELLO:
 			break;
@@ -695,7 +734,7 @@ bool VL1::m_OK(void *tPtr,const uint64_t packetId,const unsigned int auth, const
 	return true;
 }
 
-bool VL1::m_WHOIS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
+bool VL1::m_WHOIS(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
 {
 #if 0
 	if (packetSize < (int)sizeof(Protocol::OK::Header)) {
@@ -749,7 +788,7 @@ bool VL1::m_WHOIS(void *tPtr,const uint64_t packetId,const unsigned int auth, co
 #endif
 }
 
-bool VL1::m_RENDEZVOUS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
+bool VL1::m_RENDEZVOUS(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
 {
 #if 0
 	if (RR->topology->isRoot(peer->identity())) {
@@ -797,7 +836,7 @@ bool VL1::m_RENDEZVOUS(void *tPtr,const uint64_t packetId,const unsigned int aut
 #endif
 }
 
-bool VL1::m_ECHO(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
+bool VL1::m_ECHO(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
 {
 #if 0
 	const uint64_t packetId = Protocol::packetId(pkt,packetSize);
@@ -835,7 +874,7 @@ bool VL1::m_ECHO(void *tPtr,const uint64_t packetId,const unsigned int auth, con
 #endif
 }
 
-bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
+bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
 {
 #if 0
 	if (packetSize < (int)sizeof(Protocol::PUSH_DIRECT_PATHS)) {
@@ -926,13 +965,13 @@ bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr,const uint64_t packetId,const unsigned
 #endif
 }
 
-bool VL1::m_USER_MESSAGE(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
+bool VL1::m_USER_MESSAGE(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
 {
 	// TODO
 	return true;
 }
 
-bool VL1::m_ENCAP(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
+bool VL1::m_ENCAP(void *tPtr, const uint64_t packetId, const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
 {
 	// TODO: not implemented yet
 	return true;

+ 1 - 1
node/VL2.cpp

@@ -27,7 +27,7 @@ VL2::VL2(const RuntimeEnvironment *renv)
 {
 }
 
-void VL2::onLocalEthernet(void *const tPtr,const uint64_t packetId,const unsigned int auth,const SharedPtr<Network> &network,const MAC &from,const MAC &to,const unsigned int etherType,unsigned int vlanId,SharedPtr<Buf> &data,unsigned int len)
+void VL2::onLocalEthernet(void *const tPtr,const SharedPtr<Network> &network,const MAC &from,const MAC &to,const unsigned int etherType,unsigned int vlanId,SharedPtr<Buf> &data,unsigned int len)
 {
 }