Browse Source

Yet more work on VL1/VL2

Adam Ierymenko 5 years ago
parent
commit
df4b1e9b12
13 changed files with 422 additions and 250 deletions
  1. 0 0
      attic/RingBuffer.hpp
  2. 5 4
      include/ZeroTierCore.h
  3. 1 1
      node/CMakeLists.txt
  4. 7 0
      node/OS.hpp
  5. 46 28
      node/Protocol.cpp
  6. 35 5
      node/Protocol.hpp
  7. 0 7
      node/Trace.cpp
  8. 1 0
      node/Utils.cpp
  9. 5 0
      node/Utils.hpp
  10. 233 185
      node/VL1.cpp
  11. 9 9
      node/VL1.hpp
  12. 67 0
      node/VL2.cpp
  13. 13 11
      node/VL2.hpp

+ 0 - 0
node/RingBuffer.hpp → attic/RingBuffer.hpp


+ 5 - 4
include/ZeroTierCore.h

@@ -350,10 +350,11 @@ enum ZT_TracePacketDropReason
 	ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD = 1,
 	ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET = 2,
 	ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED = 3,
-	ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 4,
-	ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 5,
-	ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 6,
-	ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 7
+	ZT_TRACE_PACKET_DROP_REASON_NOT_TRUSTED_PATH = 4,
+	ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED = 5,
+	ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT = 6,
+	ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA = 7,
+	ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB = 8
 };
 
 /**

+ 1 - 1
node/CMakeLists.txt

@@ -33,7 +33,6 @@ set(core_headers
 	Peer.hpp
 	Poly1305.hpp
 	Protocol.hpp
-	RingBuffer.hpp
 	RuntimeEnvironment.hpp
 	Salsa20.hpp
 	ScopedPtr.hpp
@@ -81,6 +80,7 @@ set(core_src
 	Trace.cpp
 	Utils.cpp
 	VL1.cpp
+	VL2.cpp
 )
 
 add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers})

+ 7 - 0
node/OS.hpp

@@ -172,4 +172,11 @@
 #define ZT_ALWAYS_INLINE inline
 #endif
 
+// Macro to avoid calling hton() on values known at compile time.
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
+#else
+#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x))
+#endif
+
 #endif

+ 46 - 28
node/Protocol.cpp

@@ -66,53 +66,71 @@ uint64_t getPacketId()
 #endif
 }
 
-#if 0
-void _armor(Buf< Header > &packet,const unsigned int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],const uint8_t cipherSuite)
+void armor(Buf &pkt,unsigned int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],uint8_t cipherSuite)
 {
-	packet.data.fields.flags = (packet.data.fields.flags & 0xc7U) | ((cipherSuite << 3U) & 0x38U); // FFCCCHHH
-	if (cipherSuite == ZT_PROTO_CIPHER_SUITE__AES_GCM) {
-		// TODO
-	} else if (cipherSuite != ZT_PROTO_CIPHER_SUITE__NONE) {
-		uint8_t mangledKey[ZT_PEER_SECRET_KEY_LENGTH],macKey[ZT_POLY1305_KEY_LEN];
-		uint64_t mac[2];
+	Protocol::Header &ph = pkt.as<Protocol::Header>();
+	ph.flags = (ph.flags & 0xc7U) | ((cipherSuite << 3U) & 0x38U); // flags: FFCCCHHH where CCC is cipher
 
-		_salsa20MangleKey(key,mangledKey,packet,packetSize);
-		Salsa20 s20(mangledKey,&(packet.data.fields.packetId));
-		s20.crypt12(ZEROES32,macKey,sizeof(macKey));
+	switch(cipherSuite) {
+		case ZT_PROTO_CIPHER_SUITE__POLY1305_NONE: {
+			uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH];
+			salsa2012DeriveKey(key,perPacketKey,pkt,packetSize);
+			Salsa20 s20(perPacketKey,&ph.packetId);
 
-		uint8_t *payload = packet.data.bytes + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START;
-		const unsigned int payloadLen = packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START;
+			uint8_t macKey[ZT_POLY1305_KEY_LEN];
+			s20.crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
 
-		if (cipherSuite == ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012)
-			s20.crypt12(payload,payload,payloadLen);
+			// only difference here is that we don't encrypt the payload
 
-		poly1305(mac,payload,payloadLen,macKey);
-		packet.data.fields.mac = mac[0];
+			uint64_t mac[2];
+			poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
+			ph.mac = mac[0];
+		} break;
+
+		case ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012: {
+			uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH];
+			salsa2012DeriveKey(key,perPacketKey,pkt,packetSize);
+			Salsa20 s20(perPacketKey,&ph.packetId);
+
+			uint8_t macKey[ZT_POLY1305_KEY_LEN];
+			s20.crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
+
+			const unsigned int encLen = packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START;
+			s20.crypt12(pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,encLen);
+
+			uint64_t mac[2];
+			poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,encLen,macKey);
+			ph.mac = mac[0];
+		} break;
+
+		case ZT_PROTO_CIPHER_SUITE__AES_GCM_NRH: {
+		} break;
 	}
 }
 
-unsigned int _compress(Buf< Header > &packet,const unsigned int packetSize)
+unsigned int compress(SharedPtr<Buf> &pkt,unsigned int packetSize)
 {
-	uint8_t tmp[ZT_BUF_MEM_SIZE + 32];
-
-	if ((packet.data.fields.verb & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) // sanity check for multiple calls to compress()
+	if (packetSize <= 128)
 		return packetSize;
 
+	SharedPtr<Buf> pkt2(Buf::get());
+	if (!pkt2) return packetSize;
+
 	const unsigned int uncompressedLen = packetSize - ZT_PROTO_PACKET_PAYLOAD_START;
 	const int compressedLen = LZ4_compress_fast(
-		reinterpret_cast<const char *>(packet.data.bytes + ZT_PROTO_PACKET_PAYLOAD_START),
-	  reinterpret_cast<char *>(tmp),
+		reinterpret_cast<const char *>(pkt->b + ZT_PROTO_PACKET_PAYLOAD_START),
+		reinterpret_cast<char *>(pkt2->b + ZT_PROTO_PACKET_PAYLOAD_START),
 		(int)uncompressedLen,
-		sizeof(tmp) - ZT_PROTO_PACKET_PAYLOAD_START);
-	if ((compressedLen > 0)&&(compressedLen < uncompressedLen)) {
-		packet.data.fields.verb |= ZT_PROTO_VERB_FLAG_COMPRESSED;
-		memcpy(packet.data.bytes + ZT_PROTO_PACKET_PAYLOAD_START,tmp,compressedLen);
+		ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
+	if ((compressedLen > 0)&&(compressedLen < (int)uncompressedLen)) {
+		memcpy(pkt2->b,pkt->b,ZT_PROTO_PACKET_PAYLOAD_START);
+		pkt.swap(pkt2);
+		pkt->as<Protocol::Header>().verb |= ZT_PROTO_VERB_FLAG_COMPRESSED;
 		return (unsigned int)compressedLen + ZT_PROTO_PACKET_PAYLOAD_START;
 	}
 
 	return packetSize;
 }
-#endif
 
 } // namespace Protocol
 } // namespace ZeroTier

+ 35 - 5
node/Protocol.hpp

@@ -146,6 +146,16 @@
  */
 #define ZT_PROTO_VERB_FLAG_COMPRESSED 0x80U
 
+/**
+ * Mask to extract just the verb from the verb field, which also includes flags
+ */
+#define ZT_PROTO_VERB_MASK 0x1fU
+
+/**
+ * Key derivation function label for the key used with HMAC-384 in HELLO
+ */
+#define ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC 'H'
+
 /**
  * HELLO exchange meta-data: signed locator for this node
  */
@@ -240,6 +250,7 @@ enum Verb
 
 	/**
 	 * Announcement of a node's existence and vitals:
+	 *   [... HMAC-384 starts here ...]
 	 *   <[1] protocol version>
 	 *   <[1] software major version>
 	 *   <[1] software minor version>
@@ -251,8 +262,9 @@ enum Verb
 	 *   <[2] 16-bit reserved (legacy) field, always 0>
 	 *   <[2] 16-bit length of meta-data dictionary>
 	 *   <[...] meta-data dictionary>
+	 *   <[2] 16-bit length of any additional fields>
+	 *   <[48] HMAC-SHA384 of full plaintext payload>
 	 *   [... end encrypted region ...]
-	 *   <[48] HMAC-SHA384 of all fields to this point (as plaintext)>
 	 *
 	 * HELLO is sent with authentication but without the usual encryption so
 	 * that peers can exchange identities.
@@ -967,11 +979,29 @@ ZT_ALWAYS_INLINE void salsa2012DeriveKey(const uint8_t *const in,uint8_t *const
  */
 uint64_t getPacketId();
 
-void armor(Buf &packet,unsigned int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],uint8_t cipherSuite);
-
-unsigned int compress(Buf &packet,unsigned int packetSize);
+/**
+ * Encrypt and compute packet MAC
+ *
+ * @param pkt Packet data to encrypt (in place)
+ * @param packetSize Packet size, must be at least ZT_PROTO_MIN_PACKET_LENGTH or crash will occur
+ * @param key Key to use for encryption (not per-packet key)
+ * @param cipherSuite Cipher suite to use for AEAD encryption or just MAC
+ */
+void armor(Buf &pkt,unsigned int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],uint8_t cipherSuite);
 
-int uncompress(Buf &packet,unsigned int packetSize);
+/**
+ * Attempt to compress packet payload
+ *
+ * This attempts compression and swaps the pointer in 'pkt' for a buffer holding
+ * compressed data on success. If compression did not shrink the packet, the original
+ * packet size is returned and 'pkt' remains unchanged. If compression is successful
+ * the compressed verb flag is also set.
+ *
+ * @param pkt Packet buffer value/result parameter: pointer may be swapped if compression is successful
+ * @param packetSize Total size of packet in bytes (including headers)
+ * @return New size of packet after compression or original size of compression wasn't helpful
+ */
+unsigned int compress(SharedPtr<Buf> &pkt,unsigned int packetSize);
 
 } // namespace Protocol
 } // namespace ZeroTier

+ 0 - 7
node/Trace.cpp

@@ -16,13 +16,6 @@
 #include "Node.hpp"
 #include "Peer.hpp"
 
-// Macro to avoid calling hton() on values known at compile time.
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
-#else
-#define CONST_TO_BE_UINT16(x) ((uint16_t)(x))
-#endif
-
 // NOTE: packet IDs are always handled in network byte order, so no need to convert them.
 
 namespace ZeroTier {

+ 1 - 0
node/Utils.cpp

@@ -57,6 +57,7 @@ CPUIDRegisters::CPUIDRegisters()
 CPUIDRegisters CPUID;
 #endif
 
+const uint64_t ZERO256[4] = { 0,0,0,0 };
 const char HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
 
 bool secureEq(const void *a,const void *b,unsigned int len)

+ 5 - 0
node/Utils.hpp

@@ -46,6 +46,11 @@ struct CPUIDRegisters
 extern CPUIDRegisters CPUID;
 #endif
 
+/**
+ * 256 zero bits
+ */
+extern const uint64_t ZERO256[4];
+
 /**
  * Hexadecimal characters 0-f
  */

+ 233 - 185
node/VL1.cpp

@@ -18,160 +18,12 @@
 #include "Salsa20.hpp"
 #include "LZ4.hpp"
 #include "Poly1305.hpp"
+#include "Identity.hpp"
+#include "SelfAwareness.hpp"
+#include "SHA512.hpp"
 
 namespace ZeroTier {
 
-namespace {
-
-#if 0
-ZT_ALWAYS_INLINE bool _doHELLO(SharedPtr<Buf> &pkt,int len,const RuntimeEnvironment *const RR,void *const tPtr,const bool alreadyAuthenticated)
-{
-	if (p.size < sizeof(Protocol::HELLO)) {
-		RR->t->incomingPacketDropped(tPtr,p.idBE,0,Identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
-		return true;
-	}
-	Buf< Protocol::HELLO > &pkt = reinterpret_cast<Buf< Protocol::HELLO > &>(*p.pkt);
-
-	Identity id;
-	int ptr = sizeof(Protocol::HELLO);
-	if (pkt.rO(ptr,id) < 0) {
-		RR->t->incomingPacketDropped(tPtr,p.idBE,0,Identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
-		return true;
-	}
-
-	if (pkt.data.fields.versionProtocol < ZT_PROTO_VERSION_MIN) {
-		RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
-		return true;
-	}
-	if (Address(pkt.data.fields.h.source) != id.address()) {
-		RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
-		return true;
-	}
-
-	const int64_t now = RR->node->now();
-
-	SharedPtr<Peer> peer(RR->topology->get(tPtr,id.address()));
-	if (peer) {
-		// We already have an identity with this address -- check for collisions
-		if (!alreadyAuthenticated) {
-			if (peer->identity() != id) {
-				// Identity is different from the one we already have -- address collision
-
-				// Check rate limits
-				if (!RR->node->rateGateIdentityVerification(now,p.path->address()))
-					return true;
-
-				uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
-				if (RR->identity.agree(id,key)) {
-					if (Protocol::dearmor(pkt,p.size,key) < 0) { // ensure packet is authentic, otherwise drop
-						RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
-						return true;
-					} else {
-						// TODO: we handle identity collisions differently now
-					}
-				} else {
-					RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
-					return true;
-				}
-
-				return true;
-			} else {
-				// Identity is the same as the one we already have -- check packet integrity
-
-				if (Protocol::dearmor(pkt,p.size,peer->key()) < 0) {
-					RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
-					return true;
-				}
-
-				// Continue at // VALID
-			}
-		} // else if alreadyAuthenticated then continue at // VALID
-	} else {
-		// We don't already have an identity with this address -- validate and learn it
-
-		// Sanity check: this basically can't happen
-		if (alreadyAuthenticated) {
-			RR->t->incomingPacketDropped(tPtr,p.idBE,0,Identity(),p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_UNSPECIFIED);
-			return true;
-		}
-
-		// Check rate limits
-		if (!RR->node->rateGateIdentityVerification(now,p.path->address())) {
-			RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
-			return true;
-		}
-
-		// Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap)
-		SharedPtr<Peer> newPeer(new Peer(RR));
-		if (!newPeer->init(RR->identity,id)) {
-			RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
-			return true;
-		}
-		if (Protocol::dearmor(pkt,p.size,newPeer->key())) {
-			RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
-			return true;
-		}
-
-		// Check that identity's address is valid as per the derivation function
-		if (!id.locallyValidate()) {
-			RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
-			return true;
-		}
-
-		peer = RR->topology->add(tPtr,newPeer);
-
-		// Continue at // VALID
-	}
-
-	// VALID -- if we made it here, packet passed identity and authenticity checks!
-
-	// Get address to which this packet was sent to learn our external surface address if packet was direct.
-	InetAddress externalSurfaceAddress;
-	if (ptr < p.size) {
-		if (pkt.rO(ptr,externalSurfaceAddress) < 0) {
-			RR->t->incomingPacketDropped(tPtr,p.idBE,0,id,p.path->address(),p.hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
-			return true;
-		}
-		if ((p.hops == 0)&&(externalSurfaceAddress))
-			RR->sa->iam(tPtr,id,p.path->localSocket(),p.path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
-	}
-
-	// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
-	// information about us: version, sent-to address, etc.
-
-	ZT_GET_NEW_BUF(outp,Protocol::OK::HELLO);
-
-	outp->data.fields.h.packetId = Protocol::getPacketId();
-	peer->address().copyTo(outp->data.fields.h.destination);
-	RR->identity.address().copyTo(outp->data.fields.h.source);
-	outp->data.fields.h.flags = 0;
-	outp->data.fields.h.verb = Protocol::VERB_OK;
-
-	outp->data.fields.oh.inReVerb = Protocol::VERB_HELLO;
-	outp->data.fields.oh.inRePacketId = p.idBE;
-
-	outp->data.fields.timestampEcho = pkt.data.fields.timestamp;
-	outp->data.fields.versionProtocol = ZT_PROTO_VERSION;
-	outp->data.fields.versionMajor = ZEROTIER_ONE_VERSION_MAJOR;
-	outp->data.fields.versionMinor = ZEROTIER_ONE_VERSION_MINOR;
-	outp->data.fields.versionRev = CONST_TO_BE_UINT16(ZEROTIER_ONE_VERSION_REVISION);
-
-	int outl = sizeof(Protocol::OK::HELLO);
-	outp->wO(outl,p.path->address());
-	if (!Buf<>::writeOverflow(outl)) {
-		Protocol::armor(*outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
-		p.path->send(RR,tPtr,outp->data.bytes,outl,RR->node->now());
-	}
-
-	peer->setRemoteVersion(pkt.data.fields.versionProtocol,pkt.data.fields.versionMajor,pkt.data.fields.versionMinor,Utils::ntoh(pkt.data.fields.versionRev));
-	peer->received(tPtr,p.path,p.hops,p.idBE,p.size,Protocol::VERB_HELLO,0,Protocol::VERB_NOP,0);
-
-	return true;
-}
-#endif
-
-} // anonymous namespace
-
 VL1::VL1(const RuntimeEnvironment *renv) :
 	RR(renv),
 	_vl2(nullptr)
@@ -184,7 +36,6 @@ VL1::~VL1()
 
 void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAddress &fromAddr,SharedPtr<Buf> &data,const unsigned int len)
 {
-	static const uint64_t ZEROES32[4] = { 0,0,0,0 };
 	const int64_t now = RR->node->now();
 	const SharedPtr<Path> path(RR->topology->getPath(localSocket,fromAddr));
 	path->received(now);
@@ -339,11 +190,11 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 					uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH];
 					uint8_t macKey[ZT_POLY1305_KEY_LEN];
 					Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,*pktv[0].b,packetSize);
-					Salsa20(perPacketKey,&ph->packetId).crypt12(ZEROES32,macKey,ZT_POLY1305_KEY_LEN);
+					Salsa20(perPacketKey,&ph->packetId).crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
 
 					// Verify packet MAC.
 					uint64_t mac[2];
-					poly1305(mac,pkt.b->b,pkt.e,macKey);
+					poly1305(mac,pkt.b->b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
 					if (ph->mac != mac[0]) {
 						RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 						return;
@@ -361,7 +212,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 
 					// Do one Salsa20 block to generate the one-time-use Poly1305 key.
 					uint8_t macKey[ZT_POLY1305_KEY_LEN];
-					s20.crypt12(ZEROES32,macKey,ZT_POLY1305_KEY_LEN);
+					s20.crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
 
 					// Get a buffer to store the decrypted and fully contiguous packet.
 					pkt.b = Buf::get();
@@ -397,7 +248,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 
 					// Verify packet MAC.
 					uint64_t mac[2];
-					poly1305(mac,pkt.b->b,pkt.e,macKey);
+					poly1305(mac,pkt.b->b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
 					if (ph->mac != mac[0]) {
 						RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
 						return;
@@ -423,7 +274,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 					authenticated = true;
 				} else {
 					if (peer)
-						RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+						RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_NOT_TRUSTED_PATH);
 					return;
 				}
 			} break;
@@ -445,7 +296,12 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 		pktv.clear();
 
 		// Decompress packet payload if compressed.
-		if (((ph->verb & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0)&&(authenticated)) {
+		if ((ph->verb & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) {
+			if (!authenticated) {
+				RR->t->incomingPacketDropped(tPtr,ph->packetId,0,Identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
+				return;
+			}
+
 			SharedPtr<Buf> nb(Buf::get());
 			if (!nb) // can only happen if we're out of memory
 				return;
@@ -461,35 +317,35 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
 				pkt.e = packetSize = (unsigned int)uncompressedLen;
 			} else {
 				if (peer)
-					RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,(Protocol::Verb)(ph->verb & 0x1fU),ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
+					RR->t->incomingPacketDropped(tPtr,ph->packetId,0,peer->identity(),path->address(),hops,(Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK),ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
 				return;
 			}
 		}
 
-		const Protocol::Verb verb = (Protocol::Verb)(ph->verb & 0x1fU);
+		const Protocol::Verb verb = (Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK);
 		switch(verb) {
 			case Protocol::VERB_NOP:
 				peer->received(tPtr,path,hops,ph->packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,Protocol::VERB_NOP,0,Protocol::VERB_NOP,0);
 				break;
 
-			case Protocol::VERB_HELLO:                      _HELLO(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_ERROR:                      _ERROR(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_OK:                         _OK(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_WHOIS:                      _WHOIS(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_RENDEZVOUS:                 _RENDEZVOUS(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_FRAME:                      _vl2->_FRAME(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_EXT_FRAME:                  _vl2->_EXT_FRAME(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_ECHO:                       _ECHO(tPtr,path,peer,*pkt.b,packetSize,authenticated);
-			case Protocol::VERB_MULTICAST_LIKE:             _vl2->_MULTICAST_LIKE(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_NETWORK_CREDENTIALS:        _vl2->_NETWORK_CREDENTIALS(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_NETWORK_CONFIG_REQUEST:     _vl2->_NETWORK_CONFIG_REQUEST(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_NETWORK_CONFIG:             _vl2->_NETWORK_CONFIG(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_MULTICAST_GATHER:           _vl2->_MULTICAST_LIKE(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_MULTICAST_FRAME_deprecated: _vl2->_MULTICAST_FRAME_deprecated(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_PUSH_DIRECT_PATHS:          _PUSH_DIRECT_PATHS(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_USER_MESSAGE:               _USER_MESSAGE(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_MULTICAST:                  _vl2->_MULTICAST(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
-			case Protocol::VERB_ENCAP:                      _ENCAP(tPtr,path,peer,*pkt.b,packetSize,authenticated); break;
+			case Protocol::VERB_HELLO:                      _HELLO(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_ERROR:                      _ERROR(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_OK:                         _OK(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_WHOIS:                      _WHOIS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_RENDEZVOUS:                 _RENDEZVOUS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_FRAME:                      _vl2->_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_EXT_FRAME:                  _vl2->_EXT_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_ECHO:                       _ECHO(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated);
+			case Protocol::VERB_MULTICAST_LIKE:             _vl2->_MULTICAST_LIKE(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_NETWORK_CREDENTIALS:        _vl2->_NETWORK_CREDENTIALS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_NETWORK_CONFIG_REQUEST:     _vl2->_NETWORK_CONFIG_REQUEST(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_NETWORK_CONFIG:             _vl2->_NETWORK_CONFIG(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_MULTICAST_GATHER:           _vl2->_MULTICAST_GATHER(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_MULTICAST_FRAME_deprecated: _vl2->_MULTICAST_FRAME_deprecated(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_PUSH_DIRECT_PATHS:          _PUSH_DIRECT_PATHS(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_USER_MESSAGE:               _USER_MESSAGE(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_MULTICAST:                  _vl2->_MULTICAST(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
+			case Protocol::VERB_ENCAP:                      _ENCAP(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break;
 
 			default:
 				if (peer)
@@ -515,31 +371,223 @@ void VL1::_sendPendingWhois()
 	// assume _whoisQueue_l locked
 }
 
-void VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+	if (packetSize < sizeof(Protocol::HELLO)) {
+		RR->t->incomingPacketDropped(tPtr,0,0,Identity(),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
+		return;
+	}
+
+	Protocol::HELLO &p = pkt.as<Protocol::HELLO>();
+	const uint8_t hops = Protocol::packetHops(p.h);
+	int ptr = sizeof(Protocol::HELLO);
+
+	if (p.versionProtocol < ZT_PROTO_VERSION_MIN) {
+		RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,Identity(),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_PEER_TOO_OLD);
+		return;
+	}
+
+	Identity id;
+	if (pkt.rO(ptr,id) < 0) {
+		RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,Identity(),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+		return;
+	}
+	if (Address(p.h.source) != id.address()) {
+		RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+		return;
+	}
+
+	// Get long-term static key for this node.
+	uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
+	if ((peer)&&(id == peer->identity())) {
+		memcpy(key,peer->key(),ZT_PEER_SECRET_KEY_LENGTH);
+	} else {
+		peer.zero();
+		if (!RR->identity.agree(id,key)) {
+			RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+			return;
+		}
+	}
+
+	// Verify packet using Poly1305. For v2.x+ HELLOs this will be the first of two MACs for HELLO.
+	{
+		uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH];
+		uint8_t macKey[ZT_POLY1305_KEY_LEN];
+		Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,pkt,packetSize);
+		Salsa20(perPacketKey,&p.h.packetId).crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
+		uint64_t mac[2];
+		poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
+		if (p.h.mac != mac[0]) {
+			RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+			return;
+		}
+	}
+
+	InetAddress externalSurfaceAddress;
+	Dictionary nodeMetaData;
+
+	// Get external surface address if present.
+	if (ptr < packetSize) {
+		if (pkt.rO(ptr,externalSurfaceAddress) < 0) {
+			RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+			return;
+		}
+	}
+
+	if (ptr < packetSize) {
+		// NOTE to auditors:
+		// Anything after the external surface address is encrypted using Salsa20/12.
+		// The key for this is un-mangled static peer key. This is a bit of a legacy
+		// thing and isn't absolutely necessary, but does help conceal information
+		// that does not need to be in plaintext. This should not be considered
+		// a required part of the security/authentication model since leakage of
+		// this information would have no impact on either authentication or actual
+		// payload encryption.
+		uint8_t iv[8];
+		for(int i=0;i<8;++i) iv[i] = pkt.b[i];
+		iv[7] &= 0xf8U;
+		Salsa20 s20(key,iv);
+		s20.crypt12(pkt.b + ptr,pkt.b + ptr,packetSize - ptr);
+
+		ptr += pkt.rI16(ptr); // this field is zero in v2.0+ but can indicate data between this point and dictionary
+		if (ptr < packetSize) {
+			const unsigned int dictionarySize = pkt.rI16(ptr);
+			const void *const dictionaryBytes = pkt.b + ptr;
+			if ((ptr += (int)dictionarySize) > packetSize) {
+				RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+				return;
+			}
+
+			ptr += pkt.rI16(ptr); // skip any additional fields, currently always 0
+			if (ptr > packetSize) {
+				RR->t->incomingPacketDropped(tPtr,0,0,Identity(),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
+				return;
+			}
+
+			if ((ptr + ZT_SHA384_DIGEST_LEN) <= packetSize) {
+				uint8_t hmacKey[ZT_PEER_SECRET_KEY_LENGTH],mac[ZT_HMACSHA384_LEN];
+				KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,0,hmacKey);
+				HMACSHA384(hmacKey,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,mac);
+				if (!Utils::secureEq(pkt.b + ptr,mac,ZT_HMACSHA384_LEN)) {
+					RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
+					return;
+				}
+			}
+
+			if (dictionarySize) {
+				if (!nodeMetaData.decode(dictionaryBytes,dictionarySize)) {
+					RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+					return;
+				}
+			}
+		}
+	}
+
+	const int64_t now = RR->node->now();
+
+	if (!peer) {
+		if (!RR->node->rateGateIdentityVerification(now,path->address())) {
+			RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
+			return;
+		}
+		if (!id.locallyValidate()) {
+			RR->t->incomingPacketDropped(tPtr,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
+			return;
+		}
+		peer.set(new Peer(RR));
+		if (!peer)
+			return;
+		peer->init(RR->identity,id);
+		peer = RR->topology->add(tPtr,peer);
+	}
+
+	if ((hops == 0)&&(externalSurfaceAddress))
+		RR->sa->iam(tPtr,id,path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now);
+
+	// Send OK(HELLO) with an echo of the packet's timestamp and some of the same
+	// information about us: version, sent-to address, etc.
+
+	SharedPtr<Buf> outp(Buf::get());
+	if (!outp) return;
+	Protocol::OK::HELLO &ok = outp->as<Protocol::OK::HELLO>();
+
+	ok.h.packetId = Protocol::getPacketId();
+	id.address().copyTo(ok.h.destination);
+	RR->identity.address().copyTo(ok.h.source);
+	ok.h.flags = 0;
+	ok.h.verb = Protocol::VERB_OK;
+
+	ok.oh.inReVerb = Protocol::VERB_HELLO;
+	ok.oh.inRePacketId = p.h.packetId;
+
+	ok.timestampEcho = p.timestamp;
+	ok.versionProtocol = ZT_PROTO_VERSION;
+	ok.versionMajor = ZEROTIER_ONE_VERSION_MAJOR;
+	ok.versionMinor = ZEROTIER_ONE_VERSION_MINOR;
+	ok.versionRev = ZT_CONST_TO_BE_UINT16(ZEROTIER_ONE_VERSION_REVISION);
+
+	int outl = sizeof(Protocol::OK::HELLO);
+	outp->wO(outl,path->address());
+
+#if 0
+	ZT_GET_NEW_BUF(outp,Protocol::OK::HELLO);
+
+	outp->data.fields.h.packetId = Protocol::getPacketId();
+	peer->address().copyTo(outp->data.fields.h.destination);
+	RR->identity.address().copyTo(outp->data.fields.h.source);
+	outp->data.fields.h.flags = 0;
+	outp->data.fields.h.verb = Protocol::VERB_OK;
+
+	outp->data.fields.oh.inReVerb = Protocol::VERB_HELLO;
+	outp->data.fields.oh.inRePacketId = p.idBE;
+
+	outp->data.fields.timestampEcho = pkt.data.fields.timestamp;
+	outp->data.fields.versionProtocol = ZT_PROTO_VERSION;
+	outp->data.fields.versionMajor = ZEROTIER_ONE_VERSION_MAJOR;
+	outp->data.fields.versionMinor = ZEROTIER_ONE_VERSION_MINOR;
+	outp->data.fields.versionRev = CONST_TO_BE_UINT16(ZEROTIER_ONE_VERSION_REVISION);
+
+	int outl = sizeof(Protocol::OK::HELLO);
+	outp->wO(outl,p.path->address());
+	if (!Buf<>::writeOverflow(outl)) {
+		Protocol::armor(*outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012);
+		p.path->send(RR,tPtr,outp->data.bytes,outl,RR->node->now());
+	}
+#endif
+
+	peer->setRemoteVersion(p.versionProtocol,p.versionMajor,p.versionMinor,Utils::ntoh(p.versionRev));
+	peer->received(tPtr,path,hops,p.h.packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,Protocol::VERB_HELLO,0,Protocol::VERB_NOP,0);
+}
+
+void VL1::_ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL1::_OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 
-void VL1::_ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 
-void VL1::_OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 
-void VL1::_WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 
-void VL1::_PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 
-void VL1::_USER_MESSAGE(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_USER_MESSAGE(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 
-void VL1::_ENCAP(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated)
+void VL1::_ENCAP(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
 {
 }
 

+ 9 - 9
node/VL1.hpp

@@ -56,15 +56,15 @@ private:
 	void _sendPendingWhois();
 
 	// Handlers for VL1 verbs
-	void _HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _USER_MESSAGE(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _ENCAP(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
+	void _HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _USER_MESSAGE(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _ENCAP(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
 
 	const RuntimeEnvironment *RR;
 	VL2 *const _vl2;

+ 67 - 0
node/VL2.cpp

@@ -0,0 +1,67 @@
+/*
+ * 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 "VL2.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "VL1.hpp"
+#include "Topology.hpp"
+#include "Peer.hpp"
+#include "Path.hpp"
+
+namespace ZeroTier {
+
+VL2::VL2(const RuntimeEnvironment *renv)
+{
+}
+
+VL2::~VL2()
+{
+}
+
+void VL2::_FRAME(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_EXT_FRAME(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_MULTICAST_LIKE(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_NETWORK_CREDENTIALS(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_NETWORK_CONFIG_REQUEST(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_NETWORK_CONFIG(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_MULTICAST_GATHER(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_MULTICAST_FRAME_deprecated(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+void VL2::_MULTICAST(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated)
+{
+}
+
+} // namespace ZeroTier

+ 13 - 11
node/VL2.hpp

@@ -24,6 +24,8 @@
 
 namespace ZeroTier {
 
+class Path;
+class Peer;
 class RuntimeEnvironment;
 class VL1;
 
@@ -32,19 +34,19 @@ class VL2
 	friend class VL1;
 
 public:
-	VL1(const RuntimeEnvironment *renv);
-	~VL1();
+	VL2(const RuntimeEnvironment *renv);
+	~VL2();
 
 protected:
-	void _FRAME(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _EXT_FRAME(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _MULTICAST_LIKE(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _NETWORK_CREDENTIALS(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _NETWORK_CONFIG_REQUEST(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _NETWORK_CONFIG(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _MULTICAST_GATHER(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _MULTICAST_FRAME_deprecated(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
-	void _MULTICAST(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,unsigned int len,bool authenticated);
+	void _FRAME(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _EXT_FRAME(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _MULTICAST_LIKE(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _NETWORK_CREDENTIALS(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _NETWORK_CONFIG_REQUEST(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _NETWORK_CONFIG(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _MULTICAST_GATHER(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _MULTICAST_FRAME_deprecated(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
+	void _MULTICAST(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
 
 private:
 };