From ab0228f626573381db93173cd5849cb934481ca5 Mon Sep 17 00:00:00 2001
From: Adam Ierymenko <adam.ierymenko@gmail.com>
Date: Wed, 7 Oct 2015 10:30:47 -0700
Subject: [PATCH] More cleanup and simple refactoring, consolidate InetAddres
 serialize/deserialize into the class.

---
 node/IncomingPacket.cpp | 102 ++++++++++++++--------------------------
 node/InetAddress.hpp    |   5 +-
 node/Packet.hpp         |  15 ++----
 node/Peer.cpp           |  19 +-------
 4 files changed, 43 insertions(+), 98 deletions(-)

diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 26d4bda8b..6186affdf 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -46,6 +46,7 @@ namespace ZeroTier {
 
 bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
 {
+	const Address sourceAddress(source());
 	try {
 		if ((cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
 			// Unencrypted HELLOs are handled here since they are used to
@@ -54,23 +55,24 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
 			return _doHELLO(RR);
 		}
 
-		SharedPtr<Peer> peer = RR->topology->getPeer(source());
+		SharedPtr<Peer> peer = RR->topology->getPeer(sourceAddress);
 		if (peer) {
 			if (!dearmor(peer->key())) {
-				TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),size());
+				TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),size());
 				return true;
 			}
 			if (!uncompress()) {
-				TRACE("dropped packet from %s(%s), compressed data invalid",source().toString().c_str(),_remoteAddress.toString().c_str());
+				TRACE("dropped packet from %s(%s), compressed data invalid",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
 				return true;
 			}
 
-			//TRACE("<< %s from %s(%s)",Packet::verbString(verb()),source().toString().c_str(),_remoteAddress.toString().c_str());
+			//TRACE("<< %s from %s(%s)",Packet::verbString(v),sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
 
-			switch(verb()) {
+			const Packet::Verb v = verb();
+			switch(v) {
 				//case Packet::VERB_NOP:
 				default: // ignore unknown verbs, but if they pass auth check they are "received"
-					peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP);
+					peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),v,0,Packet::VERB_NOP);
 					return true;
 				case Packet::VERB_HELLO:                          return _doHELLO(RR);
 				case Packet::VERB_ERROR:                          return _doERROR(RR,peer);
@@ -90,13 +92,13 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
 				case Packet::VERB_CIRCUIT_TEST_REPORT:            return _doCIRCUIT_TEST_REPORT(RR,peer);
 			}
 		} else {
-			RR->sw->requestWhois(source());
+			RR->sw->requestWhois(sourceAddress);
 			return false;
 		}
 	} catch ( ... ) {
 		// Exceptions are more informatively caught in _do...() handlers but
 		// this outer try/catch will catch anything else odd.
-		TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",source().toString().c_str(),_remoteAddress.toString().c_str());
+		TRACE("dropped ??? from %s(%s): unexpected exception in tryDecode()",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
 		return true;
 	}
 }
@@ -108,7 +110,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 		const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_IN_RE_PACKET_ID);
 		const Packet::ErrorCode errorCode = (Packet::ErrorCode)(*this)[ZT_PROTO_VERB_ERROR_IDX_ERROR_CODE];
 
-		//TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
+		//TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb));
 
 		switch(errorCode) {
 
@@ -118,7 +120,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 						RR->sw->cancelWhoisRequest(Address(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH));
 				} else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
 					SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
-					if ((network)&&(network->controller() == source()))
+					if ((network)&&(network->controller() == peer->address()))
 						network->setNotFound();
 				}
 				break;
@@ -126,7 +128,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 			case Packet::ERROR_UNSUPPORTED_OPERATION:
 				if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
 					SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
-					if ((network)&&(network->controller() == source()))
+					if ((network)&&(network->controller() == peer->address()))
 						network->setNotFound();
 				}
 				break;
@@ -154,7 +156,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 
 			case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
 				SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
-				if ((network)&&(network->controller() == source()))
+				if ((network)&&(network->controller() == peer->address()))
 					network->setAccessDenied();
 			}	break;
 
@@ -170,9 +172,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 
 		peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb);
 	} catch (std::exception &ex) {
-		TRACE("dropped ERROR from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
+		TRACE("dropped ERROR from %s(%s): unexpected exception: %s",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
 	} catch ( ... ) {
-		TRACE("dropped ERROR from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str());
+		TRACE("dropped ERROR from %s(%s): unexpected exception: (unknown)",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
 	}
 	return true;
 }
@@ -187,36 +189,29 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
 	 * in the first place. */
 
 	try {
+		const uint64_t pid = packetId();
+		const Address fromAddress(source());
 		const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
 		const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
 		const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION];
 		const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION);
 		const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
+
 		Identity id;
-		unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY;
+		const unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
+		InetAddress destAddr;
+		if (destAddrPtr < size()) // ZeroTier One < 1.0.3 did not include this field
+			destAddr.deserialize(*this,destAddrPtr);
 
 		if (protoVersion < ZT_PROTO_VERSION_MIN) {
 			TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
 		}
-		if (source() != id.address()) {
-			TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str());
+		if (fromAddress != id.address()) {
+			TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
 		}
 
-		InetAddress destAddr;
-		if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field
-			const unsigned int destAddrType = (*this)[destAddrPtr++];
-			switch(destAddrType) {
-				case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4:
-					destAddr.set(field(destAddrPtr,4),4,at<uint16_t>(destAddrPtr + 4));
-					break;
-				case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6:
-					destAddr.set(field(destAddrPtr,16),16,at<uint16_t>(destAddrPtr + 16));
-					break;
-			}
-		}
-
 		SharedPtr<Peer> peer(RR->topology->getPeer(id.address()));
 		if (peer) {
 			// We already have an identity with this address -- check for collisions
@@ -230,7 +225,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
 						TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str());
 						Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR);
 						outp.append((unsigned char)Packet::VERB_HELLO);
-						outp.append(packetId());
+						outp.append((uint64_t)pid);
 						outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
 						outp.armor(key,true);
 						RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
@@ -273,41 +268,23 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
 			// Continue at // VALID
 		}
 
-		// VALID -- continues here
+		// VALID -- if we made it here, packet passed identity and authenticity checks!
 
-		peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP);
+		peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP);
 		peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision);
 
-		bool trusted = RR->topology->isRoot(id);
 		if (destAddr)
-			RR->sa->iam(id.address(),_remoteAddress,destAddr,trusted,RR->node->now());
+			RR->sa->iam(id.address(),_remoteAddress,destAddr,RR->topology->isRoot(id),RR->node->now());
 
 		Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
-
 		outp.append((unsigned char)Packet::VERB_HELLO);
-		outp.append(packetId());
-		outp.append(timestamp);
+		outp.append((uint64_t)pid);
+		outp.append((uint64_t)timestamp);
 		outp.append((unsigned char)ZT_PROTO_VERSION);
 		outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
 		outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
 		outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
-
-		switch(_remoteAddress.ss_family) {
-			case AF_INET:
-				outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV4);
-				outp.append(_remoteAddress.rawIpData(),4);
-				outp.append((uint16_t)_remoteAddress.port());
-				break;
-			case AF_INET6:
-				outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV6);
-				outp.append(_remoteAddress.rawIpData(),16);
-				outp.append((uint16_t)_remoteAddress.port());
-				break;
-			default:
-				outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_NONE);
-				break;
-		}
-
+		_remoteAddress.serialize(outp);
 		outp.armor(peer->key(),true);
 		RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
 	} catch (std::exception &ex) {
@@ -336,18 +313,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
 				const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO__OK__IDX_REVISION);
 
 				InetAddress destAddr;
-				unsigned int destAddrPtr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2; // dest address, if present, will start after 16-bit revision
-				if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field
-					const unsigned int destAddrType = (*this)[destAddrPtr++];
-					switch(destAddrType) {
-						case ZT_PROTO_DEST_ADDRESS_TYPE_IPV4:
-							destAddr.set(field(destAddrPtr,4),4,at<uint16_t>(destAddrPtr + 4));
-							break;
-						case ZT_PROTO_DEST_ADDRESS_TYPE_IPV6:
-							destAddr.set(field(destAddrPtr,16),16,at<uint16_t>(destAddrPtr + 16));
-							break;
-					}
-				}
+				if ((ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2) < size()) // ZeroTier One < 1.0.3 did not include this field
+					destAddr.deserialize(*this,ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2);
+				printf("OK(HELLO) %s\n",destAddr.toString().c_str());
 
 				if (vProto < ZT_PROTO_VERSION_MIN) {
 					TRACE("%s(%s): OK(HELLO) dropped, protocol version too old",source().toString().c_str(),_remoteAddress.toString().c_str());
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index c376a032e..6970e92d2 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -366,7 +366,8 @@ struct InetAddress : public sockaddr_storage
 	template<unsigned int C>
 	inline void serialize(Buffer<C> &b) const
 	{
-		// Format is the same as in VERB_HELLO in Packet.hpp
+		// 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);
@@ -387,8 +388,8 @@ struct InetAddress : public sockaddr_storage
 	template<unsigned int C>
 	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
 	{
-		unsigned int p = startAt;
 		memset(this,0,sizeof(InetAddress));
+		unsigned int p = startAt;
 		switch(b[p++]) {
 			case 0:
 				return 1;
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 409762c7e..1413db107 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -55,13 +55,15 @@
  * 3 - 0.5.0 ... 0.6.0
  *   * Yet another multicast redesign
  *   * New crypto completely changes key agreement cipher
- * 4 - 0.6.0 ... CURRENT
+ * 4 - 0.6.0 ... 1.0.6
  *   * New identity format based on hashcash design
+ * 5 - 1.0.6 ... CURRENT
+ *   * Supports CIRCUIT_TEST and friends, otherwise compatibie w/v4
  *
  * This isn't going to change again for a long time unless your
  * author wakes up again at 4am with another great idea. :P
  */
-#define ZT_PROTO_VERSION 4
+#define ZT_PROTO_VERSION 5
 
 /**
  * Minimum supported protocol version
@@ -233,15 +235,6 @@
  */
 #define ZT_PROTO_MIN_FRAGMENT_LENGTH ZT_PACKET_FRAGMENT_IDX_PAYLOAD
 
-// Destination address types from HELLO, OK(HELLO), and other message types
-#define ZT_PROTO_DEST_ADDRESS_TYPE_NONE 0
-#define ZT_PROTO_DEST_ADDRESS_TYPE_ZEROTIER 1   // reserved but unused
-#define ZT_PROTO_DEST_ADDRESS_TYPE_ETHERNET 2   // future use
-#define ZT_PROTO_DEST_ADDRESS_TYPE_BLUETOOTH 3  // future use
-#define ZT_PROTO_DEST_ADDRESS_TYPE_IPV4 4
-#define ZT_PROTO_DEST_ADDRESS_TYPE_LTE_DIRECT 5 // future use
-#define ZT_PROTO_DEST_ADDRESS_TYPE_IPV6 6
-
 // Ephemeral key record flags
 #define ZT_PROTO_EPHEMERAL_KEY_FLAG_FIPS 0x01   // future use
 
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 757f822c5..15648e0f0 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -170,25 +170,8 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo
 	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
 	outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
 	outp.append(now);
-
 	RR->identity.serialize(outp,false);
-
-	switch(atAddress.ss_family) {
-		case AF_INET:
-			outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV4);
-			outp.append(atAddress.rawIpData(),4);
-			outp.append((uint16_t)atAddress.port());
-			break;
-		case AF_INET6:
-			outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_IPV6);
-			outp.append(atAddress.rawIpData(),16);
-			outp.append((uint16_t)atAddress.port());
-			break;
-		default:
-			outp.append((unsigned char)ZT_PROTO_DEST_ADDRESS_TYPE_NONE);
-			break;
-	}
-
+	atAddress.serialize(outp);
 	outp.armor(_key,false); // HELLO is sent in the clear
 	RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
 }