Browse Source

More porting to new Buf system.

Adam Ierymenko 5 years ago
parent
commit
59da359b06

+ 3 - 0
node/CMakeLists.txt

@@ -51,7 +51,10 @@ set(core_src
 	Buf.cpp
 	Buf.cpp
 	C25519.cpp
 	C25519.cpp
 	Capability.cpp
 	Capability.cpp
+	CertificateOfMembership.cpp
+	CertificateOfOwnership.cpp
 	Credential.cpp
 	Credential.cpp
+	Dictionary.cpp
 	ECC384.cpp
 	ECC384.cpp
 	Endpoint.cpp
 	Endpoint.cpp
 	Identity.cpp
 	Identity.cpp

+ 139 - 0
node/CertificateOfMembership.cpp

@@ -0,0 +1,139 @@
+/*
+ * Copyright (c)2013-2020 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2024-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+#include "CertificateOfMembership.hpp"
+
+namespace ZeroTier {
+
+CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
+{
+	_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
+	_qualifiers[0].value = timestamp;
+	_qualifiers[0].maxDelta = timestampMaxDelta;
+	_qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
+	_qualifiers[1].value = nwid;
+	_qualifiers[1].maxDelta = 0;
+	_qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO;
+	_qualifiers[2].value = issuedTo.toInt();
+	_qualifiers[2].maxDelta = 0xffffffffffffffffULL;
+	_qualifierCount = 3;
+	_signatureLength = 0;
+}
+
+void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
+{
+	_signedBy.zero();
+	for(unsigned int i=0;i<_qualifierCount;++i) {
+		if (_qualifiers[i].id == id) {
+			_qualifiers[i].value = value;
+			_qualifiers[i].maxDelta = maxDelta;
+			return;
+		}
+	}
+	if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
+		_qualifiers[_qualifierCount].id = id;
+		_qualifiers[_qualifierCount].value = value;
+		_qualifiers[_qualifierCount].maxDelta = maxDelta;
+		++_qualifierCount;
+		std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
+	}
+}
+
+bool CertificateOfMembership::sign(const Identity &with)
+{
+	uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
+	unsigned int ptr = 0;
+	for(unsigned int i=0;i<_qualifierCount;++i) {
+		buf[ptr++] = Utils::hton(_qualifiers[i].id);
+		buf[ptr++] = Utils::hton(_qualifiers[i].value);
+		buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
+	}
+
+	try {
+		_signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature));
+		_signedBy = with.address();
+		return true;
+	} catch ( ... ) {
+		_signedBy.zero();
+		return false;
+	}
+}
+
+int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX]) const
+{
+	data[0] = 1;
+	Utils::storeBigEndian<uint16_t>(data + 1,(uint16_t)_qualifierCount);
+	int p = 3;
+	for(unsigned int i=0;i<_qualifierCount;++i) {
+		Utils::storeBigEndian<uint64_t>(data + p,_qualifiers[i].id); p += 8;
+		Utils::storeBigEndian<uint64_t>(data + p,_qualifiers[i].value); p += 8;
+		Utils::storeBigEndian<uint64_t>(data + p,_qualifiers[i].maxDelta); p += 8;
+	}
+	_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
+	if ((_signedBy)&&(_signatureLength == 96)) {
+		// UGLY: Ed25519 signatures in ZT are 96 bytes (64 + 32 bytes of hash).
+		// P-384 signatures are also 96 bytes, praise the horned one. That means
+		// we don't need to include a length. If we ever do we will need a new
+		// serialized object version, but only for those with length != 96.
+		memcpy(data + p,_signature,96); p += 96;
+	}
+	return p;
+}
+
+int CertificateOfMembership::unmarshal(const uint8_t *data,int len)
+{
+	if ((len < 3)||(data[0] != 1))
+		return -1;
+	unsigned int numq = Utils::loadBigEndian<uint16_t>(data + 1);
+	if (numq > ZT_NETWORK_COM_MAX_QUALIFIERS)
+		return -1;
+	_qualifierCount = numq;
+	int p = 3;
+	for(unsigned int i=0;i<numq;++i) {
+		if ((p + 24) > len)
+			return -1;
+		_qualifiers[i].id = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
+		_qualifiers[i].value = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
+		_qualifiers[i].maxDelta = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
+	}
+	if ((p + ZT_ADDRESS_LENGTH) > len)
+		return -1;
+	_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH;
+	if (_signedBy) {
+		if ((p + 96) > len)
+			return -1;
+		_signatureLength = 96;
+		memcpy(_signature,data + p,96);
+		p += 96;
+	}
+	return p;
+}
+
+bool CertificateOfMembership::operator==(const CertificateOfMembership &c) const
+{
+	if (_signedBy != c._signedBy)
+		return false;
+	if (_qualifierCount != c._qualifierCount)
+		return false;
+	if (_signatureLength != c._signatureLength)
+		return false;
+	for(unsigned int i=0;i<_qualifierCount;++i) {
+		const _Qualifier &a = _qualifiers[i];
+		const _Qualifier &b = c._qualifiers[i];
+		if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
+			return false;
+	}
+	return (memcmp(_signature,c._signature,_signatureLength) == 0);
+}
+
+} // namespace ZeroTier

+ 11 - 141
node/CertificateOfMembership.hpp

@@ -23,7 +23,6 @@
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Credential.hpp"
 #include "Credential.hpp"
-#include "Buffer.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
 #include "C25519.hpp"
 #include "C25519.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
@@ -34,6 +33,8 @@
  */
  */
 #define ZT_NETWORK_COM_MAX_QUALIFIERS 8
 #define ZT_NETWORK_COM_MAX_QUALIFIERS 8
 
 
+#define ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX (1 + 2 + (24 * ZT_NETWORK_COM_MAX_QUALIFIERS) + 5 + ZT_SIGNATURE_BUFFER_SIZE)
+
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 class RuntimeEnvironment;
 class RuntimeEnvironment;
@@ -113,29 +114,7 @@ public:
 	 * @param nwid Network ID
 	 * @param nwid Network ID
 	 * @param issuedTo Certificate recipient
 	 * @param issuedTo Certificate recipient
 	 */
 	 */
-	ZT_ALWAYS_INLINE CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
-	{
-		_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
-		_qualifiers[0].value = timestamp;
-		_qualifiers[0].maxDelta = timestampMaxDelta;
-		_qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
-		_qualifiers[1].value = nwid;
-		_qualifiers[1].maxDelta = 0;
-		_qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO;
-		_qualifiers[2].value = issuedTo.toInt();
-		_qualifiers[2].maxDelta = 0xffffffffffffffffULL;
-		_qualifierCount = 3;
-		_signatureLength = 0;
-	}
-
-	/**
-	 * Create from binary-serialized COM in buffer
-	 *
-	 * @param b Buffer to deserialize from
-	 * @param startAt Position to start in buffer
-	 */
-	template<unsigned int C>
-	ZT_ALWAYS_INLINE CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
+	CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo);
 
 
 	/**
 	/**
 	 * @return True if there's something here
 	 * @return True if there's something here
@@ -192,24 +171,7 @@ public:
 	 * @param value Qualifier value
 	 * @param value Qualifier value
 	 * @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
 	 * @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
 	 */
 	 */
-	ZT_ALWAYS_INLINE void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
-	{
-		_signedBy.zero();
-		for(unsigned int i=0;i<_qualifierCount;++i) {
-			if (_qualifiers[i].id == id) {
-				_qualifiers[i].value = value;
-				_qualifiers[i].maxDelta = maxDelta;
-				return;
-			}
-		}
-		if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
-			_qualifiers[_qualifierCount].id = id;
-			_qualifiers[_qualifierCount].value = value;
-			_qualifiers[_qualifierCount].maxDelta = maxDelta;
-			++_qualifierCount;
-			std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
-		}
-	}
+	void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta);
 
 
 	ZT_ALWAYS_INLINE void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
 	ZT_ALWAYS_INLINE void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
 
 
@@ -268,25 +230,7 @@ public:
 	 * @param with Identity to sign with, must include private key
 	 * @param with Identity to sign with, must include private key
 	 * @return True if signature was successful
 	 * @return True if signature was successful
 	 */
 	 */
-	ZT_ALWAYS_INLINE bool sign(const Identity &with)
-	{
-		uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
-		unsigned int ptr = 0;
-		for(unsigned int i=0;i<_qualifierCount;++i) {
-			buf[ptr++] = Utils::hton(_qualifiers[i].id);
-			buf[ptr++] = Utils::hton(_qualifiers[i].value);
-			buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
-		}
-
-		try {
-			_signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature));
-			_signedBy = with.address();
-			return true;
-		} catch ( ... ) {
-			_signedBy.zero();
-			return false;
-		}
-	}
+	bool sign(const Identity &with);
 
 
 	/**
 	/**
 	 * Verify this COM and its signature
 	 * Verify this COM and its signature
@@ -301,95 +245,21 @@ public:
 	 */
 	 */
 	ZT_ALWAYS_INLINE const Address &signedBy() const { return _signedBy; }
 	ZT_ALWAYS_INLINE const Address &signedBy() const { return _signedBy; }
 
 
-	template<unsigned int C>
-	inline void serialize(Buffer<C> &b) const
-	{
-		b.append((uint8_t)1);
-		b.append((uint16_t)_qualifierCount);
-		for(unsigned int i=0;i<_qualifierCount;++i) {
-			b.append(_qualifiers[i].id);
-			b.append(_qualifiers[i].value);
-			b.append(_qualifiers[i].maxDelta);
-		}
-		_signedBy.appendTo(b);
-		if ((_signedBy)&&(_signatureLength == 96)) {
-			// UGLY: Ed25519 signatures in ZT are 96 bytes (64 + 32 bytes of hash).
-			// P-384 signatures are also 96 bytes, praise the horned one. That means
-			// we don't need to include a length. If we ever do we will need a new
-			// serialized object version, but only for those with length != 96.
-			b.append(_signature,96);
-		}
-	}
-
-	template<unsigned int C>
-	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-	{
-		unsigned int p = startAt;
-
-		_signedBy.zero();
-		_qualifierCount = 0;
-		_signatureLength = 0;
-
-		if (b[p++] != 1)
-			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
-
-		unsigned int numq = b.template at<uint16_t>(p); p += sizeof(uint16_t);
-		uint64_t lastId = 0;
-		for(unsigned int i=0;i<numq;++i) {
-			const uint64_t qid = b.template at<uint64_t>(p);
-			if (qid < lastId)
-				throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
-			else lastId = qid;
-			if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
-				_qualifiers[_qualifierCount].id = qid;
-				_qualifiers[_qualifierCount].value = b.template at<uint64_t>(p + 8);
-				_qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
-				p += 24;
-				++_qualifierCount;
-			} else {
-				throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
-			}
-		}
-
-		_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
-		p += ZT_ADDRESS_LENGTH;
-
-		if (_signedBy) {
-			// See "UGLY" comment in serialize()...
-			_signatureLength = 96;
-			memcpy(_signature,b.field(p,96),96);
-			p += 96;
-		}
+	static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX; }
+	int marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX]) const;
+	int unmarshal(const uint8_t *data,int len);
 
 
-		return (p - startAt);
-	}
-
-	ZT_ALWAYS_INLINE bool operator==(const CertificateOfMembership &c) const
-	{
-		if (_signedBy != c._signedBy)
-			return false;
-		if (_qualifierCount != c._qualifierCount)
-			return false;
-		if (_signatureLength != c._signatureLength)
-			return false;
-		for(unsigned int i=0;i<_qualifierCount;++i) {
-			const _Qualifier &a = _qualifiers[i];
-			const _Qualifier &b = c._qualifiers[i];
-			if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
-				return false;
-		}
-		return (memcmp(_signature,c._signature,_signatureLength) == 0);
-	}
+	bool operator==(const CertificateOfMembership &c) const;
 	ZT_ALWAYS_INLINE bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
 	ZT_ALWAYS_INLINE bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
 
 
 private:
 private:
 	struct _Qualifier
 	struct _Qualifier
 	{
 	{
-		_Qualifier() : id(0),value(0),maxDelta(0) {}
+		ZT_ALWAYS_INLINE _Qualifier() : id(0),value(0),maxDelta(0) {}
 		uint64_t id;
 		uint64_t id;
 		uint64_t value;
 		uint64_t value;
 		uint64_t maxDelta;
 		uint64_t maxDelta;
-		inline bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order
+		ZT_ALWAYS_INLINE bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order
 	};
 	};
 
 
 	Address _signedBy;
 	Address _signedBy;

+ 118 - 0
node/CertificateOfOwnership.cpp

@@ -0,0 +1,118 @@
+/*
+ * Copyright (c)2013-2020 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2024-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+#include "CertificateOfOwnership.hpp"
+
+namespace ZeroTier {
+
+void CertificateOfOwnership::addThing(const InetAddress &ip)
+{
+	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
+	if (ip.ss_family == AF_INET) {
+		_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
+		memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
+		++_thingCount;
+	} else if (ip.ss_family == AF_INET6) {
+		_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
+		memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
+		++_thingCount;
+	}
+}
+
+void CertificateOfOwnership::addThing(const MAC &mac)
+{
+	if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
+	_thingTypes[_thingCount] = THING_MAC_ADDRESS;
+	mac.copyTo(_thingValues[_thingCount],6);
+	++_thingCount;
+}
+
+bool CertificateOfOwnership::sign(const Identity &signer)
+{
+	uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16];
+	if (signer.hasPrivate()) {
+		_signedBy = signer.address();
+		_signatureLength = signer.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature));
+		return true;
+	}
+	return false;
+}
+
+int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX],bool forSign) const
+{
+	int p = 0;
+	if (forSign) {
+		for(int k=0;k<16;++k)
+			data[p++] = 0x7f;
+	}
+	Utils::storeBigEndian<uint64_t>(data + p,_networkId);
+	Utils::storeBigEndian<uint64_t>(data + p + 8,(uint64_t)_ts);
+	Utils::storeBigEndian<uint64_t>(data + p + 16,_flags);
+	Utils::storeBigEndian<uint32_t>(data + p + 24,_id);
+	Utils::storeBigEndian<uint16_t>(data + p + 28,(uint16_t)_thingCount);
+	p += 30;
+	for(unsigned int i=0,j=_thingCount;i<j;++i) {
+		data[p++] = _thingTypes[i];
+		memcpy(data + p,_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
+		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
+	}
+	_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
+	_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
+	if (!forSign) {
+		data[p++] = 1;
+		Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
+		memcpy(data + p,_signature,_signatureLength); p += (int)_signatureLength;
+	}
+	data[p++] = 0;
+	data[p++] = 0;
+	if (forSign) {
+		for(int k=0;k<16;++k)
+			data[p++] = 0x7f;
+	}
+	return p;
+}
+
+int CertificateOfOwnership::unmarshal(const uint8_t *data,int len)
+{
+	if (len < 30)
+		return -1;
+
+	_networkId = Utils::loadBigEndian<uint64_t>(data);
+	_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
+	_flags = Utils::loadBigEndian<uint64_t>(data + 16);
+	_id = Utils::loadBigEndian<uint32_t>(data + 24);
+	_thingCount = Utils::loadBigEndian<uint16_t>(data + 28);
+	if (_thingCount > ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
+		return -1;
+	int p = 30;
+
+	for(unsigned int i=0,j=_thingCount;i<j;++i) {
+		if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len)
+			return -1;
+		_thingTypes[i] = data[p++];
+		memcpy(_thingValues[i],data + p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
+		p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
+	}
+
+	if ((p + ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH + 1 + 2) > len)
+		return -1;
+	_issuedTo.setTo(data + p); p += ZT_ADDRESS_LENGTH;
+	_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1;
+
+	p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
+	if (p > len)
+		return -1;
+	return p;
+}
+
+} // namespace ZeroTier

+ 8 - 99
node/CertificateOfOwnership.hpp

@@ -24,7 +24,6 @@
 #include "C25519.hpp"
 #include "C25519.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
-#include "Buffer.hpp"
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
 #include "MAC.hpp"
 #include "MAC.hpp"
 
 
@@ -34,6 +33,8 @@
 // Maximum size of a thing's value field in bytes
 // Maximum size of a thing's value field in bytes
 #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16
 #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16
 
 
+#define ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX (8 + 8 + 8 + 4 + 2 + ((1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) * ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2)
+
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 class RuntimeEnvironment;
 class RuntimeEnvironment;
@@ -98,112 +99,20 @@ public:
 		return this->_owns(THING_MAC_ADDRESS,tmp,6);
 		return this->_owns(THING_MAC_ADDRESS,tmp,6);
 	}
 	}
 
 
-	ZT_ALWAYS_INLINE void addThing(const InetAddress &ip)
-	{
-		if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
-		if (ip.ss_family == AF_INET) {
-			_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
-			memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
-			++_thingCount;
-		} else if (ip.ss_family == AF_INET6) {
-			_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
-			memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
-			++_thingCount;
-		}
-	}
-
-	ZT_ALWAYS_INLINE void addThing(const MAC &mac)
-	{
-		if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
-		_thingTypes[_thingCount] = THING_MAC_ADDRESS;
-		mac.copyTo(_thingValues[_thingCount],6);
-		++_thingCount;
-	}
+	void addThing(const InetAddress &ip);
+	void addThing(const MAC &mac);
 
 
 	/**
 	/**
 	 * @param signer Signing identity, must have private key
 	 * @param signer Signing identity, must have private key
 	 * @return True if signature was successful
 	 * @return True if signature was successful
 	 */
 	 */
-	ZT_ALWAYS_INLINE bool sign(const Identity &signer)
-	{
-		if (signer.hasPrivate()) {
-			Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
-			_signedBy = signer.address();
-			this->serialize(tmp,true);
-			_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
-			return true;
-		}
-		return false;
-	}
+	bool sign(const Identity &signer);
 
 
 	ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
 	ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
 
 
-	template<unsigned int C>
-	inline void serialize(Buffer<C> &b,const bool forSign = false) const
-	{
-		if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
-
-		b.append(_networkId);
-		b.append(_ts);
-		b.append(_flags);
-		b.append(_id);
-		b.append((uint16_t)_thingCount);
-		for(unsigned int i=0,j=_thingCount;i<j;++i) {
-			b.append((uint8_t)_thingTypes[i]);
-			b.append(_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
-		}
-
-		_issuedTo.appendTo(b);
-		_signedBy.appendTo(b);
-		if (!forSign) {
-			b.append((uint8_t)1);
-			b.append((uint16_t)_signatureLength); // length of signature
-			b.append(_signature,_signatureLength);
-		}
-
-		b.append((uint16_t)0); // length of additional fields, currently 0
-
-		if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
-	}
-
-	template<unsigned int C>
-	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-	{
-		unsigned int p = startAt;
-
-		*this = CertificateOfOwnership();
-
-		_networkId = b.template at<uint64_t>(p); p += 8;
-		_ts = b.template at<uint64_t>(p); p += 8;
-		_flags = b.template at<uint64_t>(p); p += 8;
-		_id = b.template at<uint32_t>(p); p += 4;
-		_thingCount = b.template at<uint16_t>(p); p += 2;
-		for(unsigned int i=0,j=_thingCount;i<j;++i) {
-			if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
-				_thingTypes[i] = (uint8_t)b[p++];
-				memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
-				p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
-			}
-		}
-
-		_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
-		_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
-		if (b[p++] == 1) {
-			_signatureLength = b.template at<uint16_t>(p);
-			if (_signatureLength > sizeof(_signature))
-				throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
-			p += 2;
-			memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
-		} else {
-			p += 2 + b.template at<uint16_t>(p);
-		}
-
-		p += 2 + b.template at<uint16_t>(p);
-		if (p > b.size())
-			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
-
-		return (p - startAt);
-	}
+	static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX; }
+	int marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX],bool forSign = false) const;
+	int unmarshal(const uint8_t *data,int len);
 
 
 	// Provides natural sort order by ID
 	// Provides natural sort order by ID
 	ZT_ALWAYS_INLINE bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }
 	ZT_ALWAYS_INLINE bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }

+ 224 - 0
node/Dictionary.cpp

@@ -0,0 +1,224 @@
+/*
+ * Copyright (c)2013-2020 ZeroTier, Inc.
+ *
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
+ *
+ * Change Date: 2024-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+#include "Dictionary.hpp"
+
+namespace ZeroTier {
+
+Dictionary::Dictionary(const char *s,unsigned int len)
+{
+	for(unsigned int i=0;i<ZT_DICTIONARY_MAX_CAPACITY;++i) {
+		if ((s)&&(i < len)) {
+			if (!(_d[i] = *s))
+				s = (const char *)0;
+			else ++s;
+		} else _d[i] = (char)0;
+	}
+	_d[ZT_DICTIONARY_MAX_CAPACITY-1] = (char)0;
+}
+
+bool Dictionary::load(const char *s)
+{
+	for(unsigned int i=0;i<ZT_DICTIONARY_MAX_CAPACITY;++i) {
+		if (s) {
+			if (!(_d[i] = *s))
+				s = (const char *)0;
+			else ++s;
+		} else _d[i] = (char)0;
+	}
+	_d[ZT_DICTIONARY_MAX_CAPACITY - 1] = (char)0;
+	return (!s);
+}
+
+int Dictionary::get(const char *key,char *dest,unsigned int destlen) const
+{
+	const char *p = _d;
+	const char *const eof = p + ZT_DICTIONARY_MAX_CAPACITY;
+	const char *k;
+	bool esc;
+	int j;
+
+	if (!destlen) // sanity check
+		return -1;
+
+	while (*p) {
+		k = key;
+		while ((*k)&&(*p)) {
+			if (*p != *k)
+				break;
+			++k;
+			if (++p == eof) {
+				dest[0] = (char)0;
+				return -1;
+			}
+		}
+
+		if ((!*k)&&(*p == '=')) {
+			j = 0;
+			esc = false;
+			++p;
+			while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
+				if (esc) {
+					esc = false;
+					switch(*p) {
+						case 'r': dest[j++] = 13; break;
+						case 'n': dest[j++] = 10; break;
+						case '0': dest[j++] = (char)0; break;
+						case 'e': dest[j++] = '='; break;
+						default: dest[j++] = *p; break;
+					}
+					if (j == (int)destlen) {
+						dest[j-1] = (char)0;
+						return j-1;
+					}
+				} else if (*p == '\\') {
+					esc = true;
+				} else {
+					dest[j++] = *p;
+					if (j == (int)destlen) {
+						dest[j-1] = (char)0;
+						return j-1;
+					}
+				}
+				if (++p == eof) {
+					dest[0] = (char)0;
+					return -1;
+				}
+			}
+			dest[j] = (char)0;
+			return j;
+		} else {
+			while ((*p)&&(*p != 13)&&(*p != 10)) {
+				if (++p == eof) {
+					dest[0] = (char)0;
+					return -1;
+				}
+			}
+			if (*p) {
+				if (++p == eof) {
+					dest[0] = (char)0;
+					return -1;
+				}
+			}
+			else break;
+		}
+	}
+
+	dest[0] = (char)0;
+	return -1;
+}
+
+bool Dictionary::add(const char *key,const char *value,int vlen)
+{
+	for(unsigned int i=0;i<ZT_DICTIONARY_MAX_CAPACITY;++i) {
+		if (!_d[i]) {
+			unsigned int j = i;
+
+			if (j > 0) {
+				_d[j++] = (char)10;
+				if (j == ZT_DICTIONARY_MAX_CAPACITY) {
+					_d[i] = (char)0;
+					return false;
+				}
+			}
+
+			const char *p = key;
+			while (*p) {
+				_d[j++] = *(p++);
+				if (j == ZT_DICTIONARY_MAX_CAPACITY) {
+					_d[i] = (char)0;
+					return false;
+				}
+			}
+
+			_d[j++] = '=';
+			if (j == ZT_DICTIONARY_MAX_CAPACITY) {
+				_d[i] = (char)0;
+				return false;
+			}
+
+			p = value;
+			int k = 0;
+			while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
+				switch(*p) {
+					case 0:
+					case 13:
+					case 10:
+					case '\\':
+					case '=':
+						_d[j++] = '\\';
+						if (j == ZT_DICTIONARY_MAX_CAPACITY) {
+							_d[i] = (char)0;
+							return false;
+						}
+						switch(*p) {
+							case 0: _d[j++] = '0'; break;
+							case 13: _d[j++] = 'r'; break;
+							case 10: _d[j++] = 'n'; break;
+							case '\\': _d[j++] = '\\'; break;
+							case '=': _d[j++] = 'e'; break;
+						}
+						if (j == ZT_DICTIONARY_MAX_CAPACITY) {
+							_d[i] = (char)0;
+							return false;
+						}
+						break;
+					default:
+						_d[j++] = *p;
+						if (j == ZT_DICTIONARY_MAX_CAPACITY) {
+							_d[i] = (char)0;
+							return false;
+						}
+						break;
+				}
+				++p;
+				++k;
+			}
+
+			_d[j] = (char)0;
+
+			return true;
+		}
+	}
+	return false;
+}
+
+bool Dictionary::add(const char *key,bool value)
+{
+	return this->add(key,(value) ? "1" : "0",1);
+}
+
+bool Dictionary::add(const char *key,uint64_t value)
+{
+	char tmp[32];
+	return this->add(key,Utils::hex(value,tmp),-1);
+}
+
+bool Dictionary::add(const char *key,int64_t value)
+{
+	char tmp[32];
+	if (value >= 0) {
+		return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
+	} else {
+		tmp[0] = '-';
+		return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
+	}
+}
+
+bool Dictionary::add(const char *key,const Address &a)
+{
+	char tmp[32];
+	return this->add(key,Utils::hex(a.toInt(),tmp),-1);
+}
+
+} // namespace ZeroTier

+ 22 - 263
node/Dictionary.hpp

@@ -16,11 +16,13 @@
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
-#include "Buffer.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
+#include "Buf.hpp"
 
 
 #include <cstdint>
 #include <cstdint>
 
 
+#define ZT_DICTIONARY_MAX_CAPACITY 65536
+
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 /**
 /**
@@ -45,32 +47,14 @@ namespace ZeroTier {
  *
  *
  * @tparam C Dictionary max capacity in bytes
  * @tparam C Dictionary max capacity in bytes
  */
  */
-template<unsigned int C>
 class Dictionary
 class Dictionary
 {
 {
 public:
 public:
-	inline Dictionary() { memset(_d,0,sizeof(_d)); }
-	inline Dictionary(const char *s) { this->load(s); }
-	inline Dictionary(const char *s,unsigned int len)
-	{
-		for(unsigned int i=0;i<C;++i) {
-			if ((s)&&(i < len)) {
-				if (!(_d[i] = *s))
-					s = (const char *)0;
-				else ++s;
-			} else _d[i] = (char)0;
-		}
-		_d[C - 1] = (char)0;
-	}
-	inline Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
-
-	inline Dictionary &operator=(const Dictionary &d)
-	{
-		memcpy(_d,d._d,C);
-		return *this;
-	}
+	ZT_ALWAYS_INLINE Dictionary() { _d[0] = 0; }
+	explicit ZT_ALWAYS_INLINE Dictionary(const char *s) { this->load(s); }
+	Dictionary(const char *s,unsigned int len);
 
 
-	inline operator bool() const { return (_d[0] != 0); }
+	ZT_ALWAYS_INLINE operator bool() const { return (_d[0] != 0); }
 
 
 	/**
 	/**
 	 * Load a dictionary from a C-string
 	 * Load a dictionary from a C-string
@@ -78,35 +62,12 @@ public:
 	 * @param s Dictionary in string form
 	 * @param s Dictionary in string form
 	 * @return False if 's' was longer than our capacity
 	 * @return False if 's' was longer than our capacity
 	 */
 	 */
-	inline bool load(const char *s)
-	{
-		for(unsigned int i=0;i<C;++i) {
-			if (s) {
-				if (!(_d[i] = *s))
-					s = (const char *)0;
-				else ++s;
-			} else _d[i] = (char)0;
-		}
-		_d[C - 1] = (char)0;
-		return (!s);
-	}
+	bool load(const char *s);
 
 
 	/**
 	/**
 	 * Delete all entries
 	 * Delete all entries
 	 */
 	 */
-	inline void clear() { memset(_d,0,sizeof(_d)); }
-
-	/**
-	 * @return Size of dictionary in bytes not including terminating NULL
-	 */
-	inline unsigned int sizeBytes() const
-	{
-		for(unsigned int i=0;i<C;++i) {
-			if (!_d[i])
-				return i;
-		}
-		return C-1;
-	}
+	ZT_ALWAYS_INLINE void clear() { memset(_d,0,sizeof(_d)); }
 
 
 	/**
 	/**
 	 * Get an entry
 	 * Get an entry
@@ -130,104 +91,7 @@ public:
 	 * @param destlen Size of destination buffer
 	 * @param destlen Size of destination buffer
 	 * @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
 	 * @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
 	 */
 	 */
-	inline int get(const char *key,char *dest,unsigned int destlen) const
-	{
-		const char *p = _d;
-		const char *const eof = p + C;
-		const char *k;
-		bool esc;
-		int j;
-
-		if (!destlen) // sanity check
-			return -1;
-
-		while (*p) {
-			k = key;
-			while ((*k)&&(*p)) {
-				if (*p != *k)
-					break;
-				++k;
-				if (++p == eof) {
-					dest[0] = (char)0;
-					return -1;
-				}
-			}
-
-			if ((!*k)&&(*p == '=')) {
-				j = 0;
-				esc = false;
-				++p;
-				while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
-					if (esc) {
-						esc = false;
-						switch(*p) {
-							case 'r': dest[j++] = 13; break;
-							case 'n': dest[j++] = 10; break;
-							case '0': dest[j++] = (char)0; break;
-							case 'e': dest[j++] = '='; break;
-							default: dest[j++] = *p; break;
-						}
-						if (j == (int)destlen) {
-							dest[j-1] = (char)0;
-							return j-1;
-						}
-					} else if (*p == '\\') {
-						esc = true;
-					} else {
-						dest[j++] = *p;
-						if (j == (int)destlen) {
-							dest[j-1] = (char)0;
-							return j-1;
-						}
-					}
-					if (++p == eof) {
-						dest[0] = (char)0;
-						return -1;
-					}
-				}
-				dest[j] = (char)0;
-				return j;
-			} else {
-				while ((*p)&&(*p != 13)&&(*p != 10)) {
-					if (++p == eof) {
-						dest[0] = (char)0;
-						return -1;
-					}
-				}
-				if (*p) {
-					if (++p == eof) {
-						dest[0] = (char)0;
-						return -1;
-					}
-				}
-				else break;
-			}
-		}
-
-		dest[0] = (char)0;
-		return -1;
-	}
-
-	/**
-	 * Get the contents of a key into a buffer
-	 *
-	 * @param key Key to get
-	 * @param dest Destination buffer
-	 * @return True if key was found (if false, dest will be empty)
-	 * @tparam BC Buffer capacity (usually inferred)
-	 */
-	template<unsigned int BC>
-	inline bool get(const char *key,Buffer<BC> &dest) const
-	{
-		const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),BC);
-		if (r >= 0) {
-			dest.setSize((unsigned int)r);
-			return true;
-		} else {
-			dest.clear();
-			return false;
-		}
-	}
+	int get(const char *key,char *dest,unsigned int destlen) const;
 
 
 	/**
 	/**
 	 * Get a boolean value
 	 * Get a boolean value
@@ -236,7 +100,7 @@ public:
 	 * @param dfl Default value if not found in dictionary
 	 * @param dfl Default value if not found in dictionary
 	 * @return Boolean value of key or 'dfl' if not found
 	 * @return Boolean value of key or 'dfl' if not found
 	 */
 	 */
-	inline bool getB(const char *key,bool dfl = false) const
+	ZT_ALWAYS_INLINE bool getB(const char *key,bool dfl = false) const
 	{
 	{
 		char tmp[4];
 		char tmp[4];
 		if (this->get(key,tmp,sizeof(tmp)) >= 0)
 		if (this->get(key,tmp,sizeof(tmp)) >= 0)
@@ -251,7 +115,7 @@ public:
 	 * @param dfl Default value or 0 if unspecified
 	 * @param dfl Default value or 0 if unspecified
 	 * @return Decoded hex UInt value or 'dfl' if not found
 	 * @return Decoded hex UInt value or 'dfl' if not found
 	 */
 	 */
-	inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
+	ZT_ALWAYS_INLINE uint64_t getUI(const char *key,uint64_t dfl = 0) const
 	{
 	{
 		char tmp[128];
 		char tmp[128];
 		if (this->get(key,tmp,sizeof(tmp)) >= 1)
 		if (this->get(key,tmp,sizeof(tmp)) >= 1)
@@ -266,7 +130,7 @@ public:
 	 * @param dfl Default value or 0 if unspecified
 	 * @param dfl Default value or 0 if unspecified
 	 * @return Decoded hex UInt value or 'dfl' if not found
 	 * @return Decoded hex UInt value or 'dfl' if not found
 	 */
 	 */
-	inline int64_t getI(const char *key,int64_t dfl = 0) const
+	ZT_ALWAYS_INLINE int64_t getI(const char *key,int64_t dfl = 0) const
 	{
 	{
 		char tmp[128];
 		char tmp[128];
 		if (this->get(key,tmp,sizeof(tmp)) >= 1)
 		if (this->get(key,tmp,sizeof(tmp)) >= 1)
@@ -288,137 +152,33 @@ public:
 	 * @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
 	 * @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
 	 * @return True if there was enough room to add this key=value pair
 	 * @return True if there was enough room to add this key=value pair
 	 */
 	 */
-	inline bool add(const char *key,const char *value,int vlen = -1)
-	{
-		for(unsigned int i=0;i<C;++i) {
-			if (!_d[i]) {
-				unsigned int j = i;
-
-				if (j > 0) {
-					_d[j++] = (char)10;
-					if (j == C) {
-						_d[i] = (char)0;
-						return false;
-					}
-				}
-
-				const char *p = key;
-				while (*p) {
-					_d[j++] = *(p++);
-					if (j == C) {
-						_d[i] = (char)0;
-						return false;
-					}
-				}
-
-				_d[j++] = '=';
-				if (j == C) {
-					_d[i] = (char)0;
-					return false;
-				}
-
-				p = value;
-				int k = 0;
-				while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
-					switch(*p) {
-						case 0:
-						case 13:
-						case 10:
-						case '\\':
-						case '=':
-							_d[j++] = '\\';
-							if (j == C) {
-								_d[i] = (char)0;
-								return false;
-							}
-							switch(*p) {
-								case 0: _d[j++] = '0'; break;
-								case 13: _d[j++] = 'r'; break;
-								case 10: _d[j++] = 'n'; break;
-								case '\\': _d[j++] = '\\'; break;
-								case '=': _d[j++] = 'e'; break;
-							}
-							if (j == C) {
-								_d[i] = (char)0;
-								return false;
-							}
-							break;
-						default:
-							_d[j++] = *p;
-							if (j == C) {
-								_d[i] = (char)0;
-								return false;
-							}
-							break;
-					}
-					++p;
-					++k;
-				}
-
-				_d[j] = (char)0;
-
-				return true;
-			}
-		}
-		return false;
-	}
+	bool add(const char *key,const char *value,int vlen = -1);
 
 
 	/**
 	/**
 	 * Add a boolean as a '1' or a '0'
 	 * Add a boolean as a '1' or a '0'
 	 */
 	 */
-	inline bool add(const char *key,bool value)
-	{
-		return this->add(key,(value) ? "1" : "0",1);
-	}
+	bool add(const char *key,bool value);
 
 
 	/**
 	/**
 	 * Add a 64-bit integer (unsigned) as a hex value
 	 * Add a 64-bit integer (unsigned) as a hex value
 	 */
 	 */
-	inline bool add(const char *key,uint64_t value)
-	{
-		char tmp[32];
-		return this->add(key,Utils::hex(value,tmp),-1);
-	}
+	bool add(const char *key,uint64_t value);
 
 
 	/**
 	/**
 	 * Add a 64-bit integer (unsigned) as a hex value
 	 * Add a 64-bit integer (unsigned) as a hex value
 	 */
 	 */
-	inline bool add(const char *key,int64_t value)
-	{
-		char tmp[32];
-		if (value >= 0) {
-			return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
-		} else {
-			tmp[0] = '-';
-			return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
-		}
-	}
+	bool add(const char *key,int64_t value);
 
 
 	/**
 	/**
 	 * Add a 64-bit integer (unsigned) as a hex value
 	 * Add a 64-bit integer (unsigned) as a hex value
 	 */
 	 */
-	inline bool add(const char *key,const Address &a)
-	{
-		char tmp[32];
-		return this->add(key,Utils::hex(a.toInt(),tmp),-1);
-	}
-
-	/**
-	 * Add a binary buffer's contents as a value
-	 *
-	 * @tparam BC Buffer capacity (usually inferred)
-	 */
-	template<unsigned int BC>
-	inline bool add(const char *key,const Buffer<BC> &value)
-	{
-		return this->add(key,(const char *)value.data(),(int)value.size());
-	}
+	bool add(const char *key,const Address &a);
 
 
 	/**
 	/**
 	 * @param key Key to check
 	 * @param key Key to check
 	 * @return True if key is present
 	 * @return True if key is present
 	 */
 	 */
-	inline bool contains(const char *key) const
+	ZT_ALWAYS_INLINE bool contains(const char *key) const
 	{
 	{
 		char tmp[2];
 		char tmp[2];
 		return (this->get(key,tmp,2) >= 0);
 		return (this->get(key,tmp,2) >= 0);
@@ -427,13 +187,12 @@ public:
 	/**
 	/**
 	 * @return Value of C template parameter
 	 * @return Value of C template parameter
 	 */
 	 */
-	inline unsigned int capacity() const { return C; }
+	ZT_ALWAYS_INLINE unsigned int capacity() const { return sizeof(_d); }
 
 
-	inline const char *data() const { return _d; }
-	inline char *unsafeData() { return _d; }
+	ZT_ALWAYS_INLINE const char *data() const { return _d; }
 
 
 private:
 private:
-	char _d[C];
+	char _d[ZT_DICTIONARY_MAX_CAPACITY];
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 0 - 103
node/Identity.hpp

@@ -21,7 +21,6 @@
 #include "Utils.hpp"
 #include "Utils.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
 #include "C25519.hpp"
 #include "C25519.hpp"
-#include "Buffer.hpp"
 #include "SHA512.hpp"
 #include "SHA512.hpp"
 #include "ECC384.hpp"
 #include "ECC384.hpp"
 
 
@@ -158,108 +157,6 @@ public:
 	 */
 	 */
 	ZT_ALWAYS_INLINE const Address &address() const { return _address; }
 	ZT_ALWAYS_INLINE const Address &address() const { return _address; }
 
 
-	/**
-	 * Serialize this identity (binary)
-	 *
-	 * @param b Destination buffer to append to
-	 * @param includePrivate If true, include private key component (if present) (default: false)
-	 */
-	template<unsigned int C>
-	inline void serialize(Buffer<C> &b,bool includePrivate = false) const
-	{
-		_address.appendTo(b);
-		switch(_type) {
-
-			case C25519:
-				b.append((uint8_t)C25519);
-				b.append(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
-				if ((_hasPrivate)&&(includePrivate)) {
-					b.append((uint8_t)ZT_C25519_PRIVATE_KEY_LEN);
-					b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
-				} else {
-					b.append((uint8_t)0);
-				}
-				break;
-
-			case P384:
-				b.append((uint8_t)P384);
-				b.append(&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
-				if ((_hasPrivate)&&(includePrivate)) {
-					b.append((uint8_t)(ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE));
-					b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
-					b.append(_priv.p384,ZT_ECC384_PRIVATE_KEY_SIZE);
-				} else {
-					b.append((uint8_t)0);
-				}
-				b.append((uint8_t)0); // size of additional fields (should have included such a thing in v0!)
-				break;
-
-		}
-	}
-
-	/**
-	 * Deserialize a binary serialized identity
-	 *
-	 * If an exception is thrown, the Identity object is left in an undefined
-	 * state and should not be used.
-	 *
-	 * @param b Buffer containing serialized data
-	 * @param startAt Index within buffer of serialized data (default: 0)
-	 * @return Length of serialized data read from buffer
-	 */
-	template<unsigned int C>
-	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-	{
-		_hasPrivate = false;
-		unsigned int p = startAt;
-		unsigned int pkl;
-
-		_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
-		p += ZT_ADDRESS_LENGTH;
-
-		switch((_type = (Type)b[p++])) {
-
-			case C25519:
-				memcpy(_pub.c25519,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
-				p += ZT_C25519_PUBLIC_KEY_LEN;
-				pkl = (unsigned int)b[p++];
-				if (pkl) {
-					if (pkl != ZT_C25519_PRIVATE_KEY_LEN)
-						throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
-					_hasPrivate = true;
-					memcpy(_priv.c25519,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
-					p += ZT_C25519_PRIVATE_KEY_LEN;
-				} else {
-					_hasPrivate = false;
-				}
-				break;
-
-			case P384:
-				memcpy(&_pub,b.field(p,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
-				p += ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE;
-				pkl = (unsigned int)b[p++];
-				if (pkl) {
-					if (pkl != (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE))
-						throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
-					_hasPrivate = true;
-					memcpy(_priv.c25519,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
-					p += ZT_C25519_PRIVATE_KEY_LEN;
-					memcpy(_priv.p384,b.field(p,ZT_ECC384_PRIVATE_KEY_SIZE),ZT_ECC384_PRIVATE_KEY_SIZE);
-					p += ZT_ECC384_PRIVATE_KEY_SIZE;
-				} else {
-					_hasPrivate = false;
-				}
-				p += b.template at<uint8_t>(p) + 2;
-				break;
-
-			default:
-				throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
-
-		}
-
-		return (p - startAt);
-	}
-
 	/**
 	/**
 	 * Serialize to a more human-friendly string
 	 * Serialize to a more human-friendly string
 	 *
 	 *

+ 0 - 57
node/InetAddress.hpp

@@ -21,7 +21,6 @@
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
 #include "MAC.hpp"
 #include "MAC.hpp"
-#include "Buffer.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
@@ -498,62 +497,6 @@ public:
 	int marshal(uint8_t data[19]) const;
 	int marshal(uint8_t data[19]) const;
 	int unmarshal(const uint8_t *restrict data,const int len);
 	int unmarshal(const uint8_t *restrict data,const int len);
 
 
-	template<unsigned int C>
-	inline void serialize(Buffer<C> &b) const
-	{
-		// This is used in the protocol and must be the same as describe in places
-		// like VERB_HELLO in Packet.hpp.
-		switch(ss_family) {
-			case AF_INET:
-				b.append((uint8_t)0x04);
-				b.append(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr),4);
-				b.append((uint16_t)port()); // just in case sin_port != uint16_t
-				return;
-			case AF_INET6:
-				b.append((uint8_t)0x06);
-				b.append(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
-				b.append((uint16_t)port()); // just in case sin_port != uint16_t
-				return;
-			default:
-				b.append((uint8_t)0);
-				return;
-		}
-	}
-
-	template<unsigned int C>
-	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-	{
-		memset(this,0,sizeof(InetAddress));
-		unsigned int p = startAt;
-		switch(b[p++]) {
-			case 0:
-				return 1;
-			case 0x01:
-				// TODO: Ethernet address (but accept for forward compatibility)
-				return 7;
-			case 0x02:
-				// TODO: Bluetooth address (but accept for forward compatibility)
-				return 7;
-			case 0x03:
-				// TODO: Other address types (but accept for forward compatibility)
-				// These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc.
-				return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
-			case 0x04:
-				ss_family = AF_INET;
-				memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
-				reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
-				break;
-			case 0x06:
-				ss_family = AF_INET6;
-				memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16;
-				reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
-				break;
-			default:
-				throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
-		}
-		return (p - startAt);
-	}
-
 	bool operator==(const InetAddress &a) const;
 	bool operator==(const InetAddress &a) const;
 	bool operator<(const InetAddress &a) const;
 	bool operator<(const InetAddress &a) const;
 	ZT_ALWAYS_INLINE bool operator!=(const InetAddress &a) const { return !(*this == a); }
 	ZT_ALWAYS_INLINE bool operator!=(const InetAddress &a) const { return !(*this == a); }

+ 2 - 3
node/MAC.hpp

@@ -21,7 +21,6 @@
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
-#include "Buffer.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
@@ -39,9 +38,9 @@ public:
 		    ((((uint64_t)d) & 0xffULL) << 16U) |
 		    ((((uint64_t)d) & 0xffULL) << 16U) |
 		    ((((uint64_t)e) & 0xffULL) << 8U) |
 		    ((((uint64_t)e) & 0xffULL) << 8U) |
 		    (((uint64_t)f) & 0xffULL) ) {}
 		    (((uint64_t)f) & 0xffULL) ) {}
-	ZT_ALWAYS_INLINE MAC(const uint8_t b[6]) { setTo(b); }
+	explicit ZT_ALWAYS_INLINE MAC(const uint8_t b[6]) { setTo(b); }
 	ZT_ALWAYS_INLINE MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
 	ZT_ALWAYS_INLINE MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
-	ZT_ALWAYS_INLINE MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
+	explicit ZT_ALWAYS_INLINE MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
 
 
 	/**
 	/**
 	 * @return MAC in 64-bit integer
 	 * @return MAC in 64-bit integer

+ 0 - 1
node/Membership.cpp

@@ -18,7 +18,6 @@
 #include "Peer.hpp"
 #include "Peer.hpp"
 #include "Topology.hpp"
 #include "Topology.hpp"
 #include "Switch.hpp"
 #include "Switch.hpp"
-#include "Packet.hpp"
 #include "Node.hpp"
 #include "Node.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {

+ 1 - 1
node/MulticastGroup.hpp

@@ -63,7 +63,7 @@ public:
 			// multicast address directly from the IP address, and it gives us
 			// multicast address directly from the IP address, and it gives us
 			// 24 bits of uniqueness. Collisions aren't likely to be common enough
 			// 24 bits of uniqueness. Collisions aren't likely to be common enough
 			// to care about.
 			// to care about.
-			const unsigned char *a = (const unsigned char *)ip.rawIpData();
+			const uint8_t *a = (const uint8_t *)ip.rawIpData();
 			return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
 			return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
 		}
 		}
 		return MulticastGroup();
 		return MulticastGroup();

+ 39 - 2
node/NetworkConfig.cpp

@@ -20,7 +20,28 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const
+NetworkConfig::NetworkConfig() :
+	networkId(0),
+	timestamp(0),
+	credentialTimeMaxDelta(0),
+	revision(0),
+	issuedTo(),
+	flags(0),
+	mtu(0),
+	multicastLimit(0),
+	specialistCount(0),
+	routeCount(0),
+	staticIpCount(0),
+	ruleCount(0),
+	capabilityCount(0),
+	tagCount(0),
+	certificateOfOwnershipCount(0),
+	type(ZT_NETWORK_TYPE_PRIVATE)
+{
+	name[0] = 0;
+}
+
+bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const
 {
 {
 	ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
 	ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
 	char tmp2[128];
 	char tmp2[128];
@@ -105,7 +126,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
 	return true;
 	return true;
 }
 }
 
 
-bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
+bool NetworkConfig::fromDictionary(const Dictionary &d)
 {
 {
 	static const NetworkConfig NIL_NC;
 	static const NetworkConfig NIL_NC;
 	ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
 	ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
@@ -218,4 +239,20 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
 	}
 	}
 }
 }
 
 
+bool NetworkConfig::addSpecialist(const Address &a,const uint64_t f)
+{
+	const uint64_t aint = a.toInt();
+	for(unsigned int i=0;i<specialistCount;++i) {
+		if ((specialists[i] & 0xffffffffffULL) == aint) {
+			specialists[i] |= f;
+			return true;
+		}
+	}
+	if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
+		specialists[specialistCount++] = f | aint;
+		return true;
+	}
+	return false;
+}
+
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 14 - 49
node/NetworkConfig.hpp

@@ -17,13 +17,11 @@
 #include <cstdint>
 #include <cstdint>
 #include <cstring>
 #include <cstring>
 #include <cstdlib>
 #include <cstdlib>
-
 #include <vector>
 #include <vector>
 #include <stdexcept>
 #include <stdexcept>
 #include <algorithm>
 #include <algorithm>
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
-#include "Buffer.hpp"
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
 #include "MulticastGroup.hpp"
 #include "MulticastGroup.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
@@ -168,26 +166,7 @@ namespace ZeroTier {
  */
  */
 struct NetworkConfig
 struct NetworkConfig
 {
 {
-	inline NetworkConfig() :
-		networkId(0),
-		timestamp(0),
-		credentialTimeMaxDelta(0),
-		revision(0),
-		issuedTo(),
-		flags(0),
-		mtu(0),
-		multicastLimit(0),
-		specialistCount(0),
-		routeCount(0),
-		staticIpCount(0),
-		ruleCount(0),
-		capabilityCount(0),
-		tagCount(0),
-		certificateOfOwnershipCount(0),
-		type(ZT_NETWORK_TYPE_PRIVATE)
-	{
-		name[0] = 0;
-	}
+	NetworkConfig();
 
 
 	/**
 	/**
 	 * Write this network config to a dictionary for transport
 	 * Write this network config to a dictionary for transport
@@ -196,7 +175,7 @@ struct NetworkConfig
 	 * @param includeLegacy If true, include legacy fields for old node versions
 	 * @param includeLegacy If true, include legacy fields for old node versions
 	 * @return True if dictionary was successfully created, false if e.g. overflow
 	 * @return True if dictionary was successfully created, false if e.g. overflow
 	 */
 	 */
-	bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const;
+	bool toDictionary(Dictionary &d,bool includeLegacy) const;
 
 
 	/**
 	/**
 	 * Read this network config from a dictionary
 	 * Read this network config from a dictionary
@@ -204,33 +183,33 @@ struct NetworkConfig
 	 * @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
 	 * @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
 	 * @return True if dictionary was valid and network config successfully initialized
 	 * @return True if dictionary was valid and network config successfully initialized
 	 */
 	 */
-	bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
+	bool fromDictionary(const Dictionary &d);
 
 
 	/**
 	/**
 	 * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
 	 * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
 	 */
 	 */
-	inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
+	ZT_ALWAYS_INLINE bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
 
 
 	/**
 	/**
 	 * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
 	 * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
 	 */
 	 */
-	inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
+	ZT_ALWAYS_INLINE bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
 
 
 	/**
 	/**
 	 * @return Network type is public (no access control)
 	 * @return Network type is public (no access control)
 	 */
 	 */
-	inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
+	ZT_ALWAYS_INLINE bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
 
 
 	/**
 	/**
 	 * @return Network type is private (certificate access control)
 	 * @return Network type is private (certificate access control)
 	 */
 	 */
-	inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
+	ZT_ALWAYS_INLINE bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
 
 
 	/**
 	/**
 	 * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
 	 * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
 	 * @return True if this network allows bridging
 	 * @return True if this network allows bridging
 	 */
 	 */
-	inline bool permitsBridging(const Address &fromPeer) const
+	ZT_ALWAYS_INLINE bool permitsBridging(const Address &fromPeer) const
 	{
 	{
 		for(unsigned int i=0;i<specialistCount;++i) {
 		for(unsigned int i=0;i<specialistCount;++i) {
 			if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
 			if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
@@ -239,9 +218,9 @@ struct NetworkConfig
 		return false;
 		return false;
 	}
 	}
 
 
-	inline operator bool() const { return (networkId != 0); }
-	inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
-	inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
+	ZT_ALWAYS_INLINE operator bool() const { return (networkId != 0); }
+	ZT_ALWAYS_INLINE bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
+	ZT_ALWAYS_INLINE bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
 
 
 	/**
 	/**
 	 * Add a specialist or mask flags if already present
 	 * Add a specialist or mask flags if already present
@@ -253,23 +232,9 @@ struct NetworkConfig
 	 * @param f Flags (OR of specialist role/type flags)
 	 * @param f Flags (OR of specialist role/type flags)
 	 * @return True if successfully masked or added
 	 * @return True if successfully masked or added
 	 */
 	 */
-	inline bool addSpecialist(const Address &a,const uint64_t f)
-	{
-		const uint64_t aint = a.toInt();
-		for(unsigned int i=0;i<specialistCount;++i) {
-			if ((specialists[i] & 0xffffffffffULL) == aint) {
-				specialists[i] |= f;
-				return true;
-			}
-		}
-		if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
-			specialists[specialistCount++] = f | aint;
-			return true;
-		}
-		return false;
-	}
+	bool addSpecialist(const Address &a,const uint64_t f);
 
 
-	inline const Capability *capability(const uint32_t id) const
+	ZT_ALWAYS_INLINE const Capability *capability(const uint32_t id) const
 	{
 	{
 		for(unsigned int i=0;i<capabilityCount;++i) {
 		for(unsigned int i=0;i<capabilityCount;++i) {
 			if (capabilities[i].id() == id)
 			if (capabilities[i].id() == id)
@@ -278,7 +243,7 @@ struct NetworkConfig
 		return (Capability *)0;
 		return (Capability *)0;
 	}
 	}
 
 
-	inline const Tag *tag(const uint32_t id) const
+	ZT_ALWAYS_INLINE const Tag *tag(const uint32_t id) const
 	{
 	{
 		for(unsigned int i=0;i<tagCount;++i) {
 		for(unsigned int i=0;i<tagCount;++i) {
 			if (tags[i].id() == id)
 			if (tags[i].id() == id)

+ 1 - 2
node/Node.cpp

@@ -21,8 +21,6 @@
 #include "NetworkController.hpp"
 #include "NetworkController.hpp"
 #include "Switch.hpp"
 #include "Switch.hpp"
 #include "Topology.hpp"
 #include "Topology.hpp"
-#include "Buffer.hpp"
-#include "Packet.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
 #include "SelfAwareness.hpp"
 #include "SelfAwareness.hpp"
@@ -30,6 +28,7 @@
 #include "Trace.hpp"
 #include "Trace.hpp"
 #include "ScopedPtr.hpp"
 #include "ScopedPtr.hpp"
 #include "Locator.hpp"
 #include "Locator.hpp"
+#include "Protocol.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 

+ 3 - 2
node/Peer.hpp

@@ -29,6 +29,7 @@
 #include "Mutex.hpp"
 #include "Mutex.hpp"
 #include "Endpoint.hpp"
 #include "Endpoint.hpp"
 #include "Locator.hpp"
 #include "Locator.hpp"
+#include "Protocol.hpp"
 
 
 #include <vector>
 #include <vector>
 
 
@@ -103,9 +104,9 @@ public:
 		unsigned int hops,
 		unsigned int hops,
 		uint64_t packetId,
 		uint64_t packetId,
 		unsigned int payloadLength,
 		unsigned int payloadLength,
-		Packet::Verb verb,
+		Protocol::Verb verb,
 		uint64_t inRePacketId,
 		uint64_t inRePacketId,
-		Packet::Verb inReVerb,
+		Protocol::Verb inReVerb,
 		uint64_t networkId);
 		uint64_t networkId);
 
 
 	/**
 	/**

+ 0 - 1
node/Revocation.hpp

@@ -24,7 +24,6 @@
 #include "Address.hpp"
 #include "Address.hpp"
 #include "C25519.hpp"
 #include "C25519.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
-#include "Buffer.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
 
 
 /**
 /**

+ 0 - 1
node/Switch.cpp

@@ -22,7 +22,6 @@
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
 #include "Peer.hpp"
 #include "Peer.hpp"
 #include "SelfAwareness.hpp"
 #include "SelfAwareness.hpp"
-#include "Packet.hpp"
 #include "Trace.hpp"
 #include "Trace.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {

+ 1 - 1
node/Switch.hpp

@@ -22,7 +22,6 @@
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Mutex.hpp"
 #include "Mutex.hpp"
 #include "MAC.hpp"
 #include "MAC.hpp"
-#include "Packet.hpp"
 #include "Utils.hpp"
 #include "Utils.hpp"
 #include "InetAddress.hpp"
 #include "InetAddress.hpp"
 #include "Topology.hpp"
 #include "Topology.hpp"
@@ -30,6 +29,7 @@
 #include "SharedPtr.hpp"
 #include "SharedPtr.hpp"
 #include "IncomingPacket.hpp"
 #include "IncomingPacket.hpp"
 #include "Hashtable.hpp"
 #include "Hashtable.hpp"
+#include "Protocol.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 

+ 0 - 1
node/Tag.hpp

@@ -24,7 +24,6 @@
 #include "C25519.hpp"
 #include "C25519.hpp"
 #include "Address.hpp"
 #include "Address.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
-#include "Buffer.hpp"
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 

+ 15 - 13
node/Utils.cpp

@@ -15,7 +15,10 @@
 #include <cstdlib>
 #include <cstdlib>
 #include <ctime>
 #include <ctime>
 
 
-#include "Constants.hpp"
+#include "Utils.hpp"
+#include "Mutex.hpp"
+#include "AES.hpp"
+#include "SHA512.hpp"
 
 
 #ifdef __UNIX_LIKE__
 #ifdef __UNIX_LIKE__
 #include <unistd.h>
 #include <unistd.h>
@@ -27,11 +30,6 @@
 #include <wincrypt.h>
 #include <wincrypt.h>
 #endif
 #endif
 
 
-#include "Utils.hpp"
-#include "Mutex.hpp"
-#include "AES.hpp"
-#include "SHA512.hpp"
-
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 namespace Utils {
 namespace Utils {
@@ -166,13 +164,13 @@ void getSecureRandom(void *buf,unsigned int bytes)
 	static Mutex globalLock;
 	static Mutex globalLock;
 	static bool initialized = false;
 	static bool initialized = false;
 	static uint64_t randomState[8];
 	static uint64_t randomState[8];
-	static uint8_t randomBuf[65536];
-	static unsigned long randomPtr = sizeof(randomBuf);
+	static uint64_t randomBuf[8192];
+	static unsigned int randomPtr = 65536;
 
 
 	Mutex::Lock gl(globalLock);
 	Mutex::Lock gl(globalLock);
 
 
 	for(unsigned int i=0;i<bytes;++i) {
 	for(unsigned int i=0;i<bytes;++i) {
-		if (randomPtr >= sizeof(randomBuf)) {
+		if (randomPtr >= 65536) {
 			randomPtr = 0;
 			randomPtr = 0;
 
 
 			if (!initialized) {
 			if (!initialized) {
@@ -225,18 +223,22 @@ void getSecureRandom(void *buf,unsigned int bytes)
 #endif
 #endif
 			}
 			}
 
 
+			++randomState[0];
 			SHA512(randomState,randomState,sizeof(randomState));
 			SHA512(randomState,randomState,sizeof(randomState));
 			AES aes(reinterpret_cast<const uint8_t *>(randomState));
 			AES aes(reinterpret_cast<const uint8_t *>(randomState));
-			uint64_t ctr[2];
+			uint64_t ctr[2],tmp[2];
 			ctr[0] = randomState[6];
 			ctr[0] = randomState[6];
 			ctr[1] = randomState[7];
 			ctr[1] = randomState[7];
-			for(unsigned long i=0;i<sizeof(randomBuf);i+=16) {
+			for(int k=0;k<8192;) {
 				++ctr[0];
 				++ctr[0];
-				aes.encrypt(reinterpret_cast<const uint8_t *>(ctr),randomBuf + i);
+				aes.encrypt(reinterpret_cast<const uint8_t *>(ctr),reinterpret_cast<uint8_t *>(tmp));
+				randomBuf[k] ^= tmp[0];
+				randomBuf[k+1] ^= tmp[1];
+				k += 2;
 			}
 			}
 		}
 		}
 
 
-		reinterpret_cast<uint8_t *>(buf)[i] = randomBuf[randomPtr++];
+		reinterpret_cast<uint8_t *>(buf)[i] = reinterpret_cast<uint8_t *>(randomBuf)[randomPtr++];
 	}
 	}
 }
 }
 
 

+ 6 - 7
node/Utils.hpp

@@ -19,6 +19,11 @@
 #include <cstdint>
 #include <cstdint>
 #include <cstring>
 #include <cstring>
 #include <ctime>
 #include <ctime>
+#include <stdexcept>
+#include <vector>
+#include <map>
+
+#include "Constants.hpp"
 
 
 #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
 #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
 #include <emmintrin.h>
 #include <emmintrin.h>
@@ -26,12 +31,6 @@
 #include <immintrin.h>
 #include <immintrin.h>
 #endif
 #endif
 
 
-#include <stdexcept>
-#include <vector>
-#include <map>
-
-#include "Constants.hpp"
-
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 namespace Utils {
 namespace Utils {
@@ -87,7 +86,7 @@ char *decimal(unsigned long n,char s[24]);
  * @return Pointer to s containing hex string with trailing zero byte
  * @return Pointer to s containing hex string with trailing zero byte
  */
  */
 template<typename I>
 template<typename I>
-static inline char *hex(I x,char *s)
+static ZT_ALWAYS_INLINE char *hex(I x,char *s)
 {
 {
 	char *const r = s;
 	char *const r = s;
 	for(unsigned int i=0,b=(sizeof(x)*8);i<sizeof(x);++i) {
 	for(unsigned int i=0,b=(sizeof(x)*8);i<sizeof(x);++i) {