Browse Source

Safety upgrades to code

Adam Ierymenko 6 years ago
parent
commit
59ee0cfe88
9 changed files with 196 additions and 191 deletions
  1. 1 0
      node/CMakeLists.txt
  2. 2 2
      node/Credential.cpp
  3. 5 15
      node/Locator.hpp
  4. 28 46
      node/Network.cpp
  5. 73 86
      node/NetworkConfig.cpp
  6. 1 1
      node/NetworkConfig.hpp
  7. 34 39
      node/Node.cpp
  8. 2 2
      node/Peer.cpp
  9. 50 0
      node/ScopedPtr.hpp

+ 1 - 0
node/CMakeLists.txt

@@ -38,6 +38,7 @@ set(core_headers
 	RingBuffer.hpp
 	RuntimeEnvironment.hpp
 	Salsa20.hpp
+	ScopedPtr.hpp
 	SelfAwareness.hpp
 	SHA512.hpp
 	SharedPtr.hpp

+ 2 - 2
node/Credential.cpp

@@ -21,6 +21,7 @@
 #include "Revocation.hpp"
 #include "Switch.hpp"
 #include "Network.hpp"
+#include "ScopedPtr.hpp"
 
 namespace ZeroTier {
 
@@ -37,10 +38,9 @@ static inline Credential::VerifyResult _credVerify(const RuntimeEnvironment *con
 		return Credential::VERIFY_NEED_IDENTITY;
 	}
 	try {
-		Buffer<(sizeof(CRED) + 64)> *const tmp = new Buffer<(sizeof(CRED) + 64)>();
+		ScopedPtr< Buffer<(sizeof(CRED) + 64)> > tmp(new Buffer<(sizeof(CRED) + 64)>());
 		credential.serialize(*tmp,true);
 		const Credential::VerifyResult result = (id.verify(tmp->data(),tmp->size(),credential.signature(),credential.signatureLength()) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE);
-		delete tmp;
 		return result;
 	} catch ( ... ) {}
 	return Credential::VERIFY_BAD_SIGNATURE;

+ 5 - 15
node/Locator.hpp

@@ -21,6 +21,7 @@
 #include "Buffer.hpp"
 #include "SHA512.hpp"
 #include "Str.hpp"
+#include "ScopedPtr.hpp"
 
 #include <algorithm>
 #include <vector>
@@ -101,14 +102,12 @@ public:
 		} else {
 			_signedBy = signingId;
 		}
-		Buffer<65536> *tmp = new Buffer<65536>();
 		try {
+			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			serialize(*tmp,true);
 			_signatureLength = signingId.sign(tmp->data(),tmp->size(),_signature,ZT_SIGNATURE_BUFFER_SIZE);
-			delete tmp;
 			return (_signatureLength > 0);
 		} catch ( ... ) {
-			delete tmp;
 			return false;
 		}
 	}
@@ -120,15 +119,12 @@ public:
 	{
 		if ((_signatureLength == 0)||(_signatureLength > sizeof(_signature)))
 			return false;
-		Buffer<65536> *tmp = nullptr;
 		try {
-			tmp = new Buffer<65536>();
+			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			serialize(*tmp,true);
 			const bool ok = (_signedBy) ? _signedBy.verify(tmp->data(),tmp->size(),_signature,_signatureLength) : _id.verify(tmp->data(),tmp->size(),_signature,_signatureLength);
-			delete tmp;
 			return ok;
 		} catch ( ... ) {
-			if (tmp) delete tmp;
 			return false;
 		}
 	}
@@ -150,7 +146,7 @@ public:
 		uint8_t s384[48];
 		char enc[256];
 
-		Buffer<65536> *const tmp = new Buffer<65536>();
+		ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 		serialize(*tmp,false);
 		SHA384(s384,tmp->data(),tmp->size());
 		ECC384ECDSASign(p384SigningKeyPrivate,s384,((uint8_t *)tmp->unsafeData()) + tmp->size());
@@ -172,7 +168,6 @@ public:
 			++txtRecNo;
 		}
 
-		delete tmp;
 		return txtRecords;
 	}
 
@@ -192,7 +187,6 @@ public:
 	inline bool decodeTxtRecords(I start,I end,const uint8_t p384SigningKeyPublic[ZT_ECC384_PUBLIC_KEY_SIZE])
 	{
 		uint8_t dec[256],s384[48];
-		Buffer<65536> *tmp = nullptr;
 		try {
 			std::vector<Str> txtRecords;
 			while (start != end) {
@@ -206,26 +200,22 @@ public:
 				return false;
 			std::sort(txtRecords.begin(),txtRecords.end());
 
-			tmp = new Buffer<65536>();
+			ScopedPtr< Buffer<65536> > tmp(new Buffer<65536>());
 			for(std::vector<Str>::const_iterator i(txtRecords.begin());i!=txtRecords.end();++i)
 				tmp->append(dec,Utils::b64d(i->c_str() + 2,dec,sizeof(dec)));
 
 			if (tmp->size() <= ZT_ECC384_SIGNATURE_SIZE) {
-				delete tmp;
 				return false;
 			}
 			SHA384(s384,tmp->data(),tmp->size() - ZT_ECC384_SIGNATURE_SIZE);
 			if (!ECC384ECDSAVerify(p384SigningKeyPublic,s384,((const uint8_t *)tmp->data()) + (tmp->size() - ZT_ECC384_SIGNATURE_SIZE))) {
-				delete tmp;
 				return false;
 			}
 
 			deserialize(*tmp,0);
-			delete tmp;
 
 			return verify();
 		} catch ( ... ) {
-			if (tmp) delete tmp;
 			return false;
 		}
 	}

+ 28 - 46
node/Network.cpp

@@ -31,6 +31,7 @@
 #include "Node.hpp"
 #include "Peer.hpp"
 #include "Trace.hpp"
+#include "ScopedPtr.hpp"
 
 #include <set>
 
@@ -561,22 +562,20 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,void *u
 		tmp[0] = nwid; tmp[1] = 0;
 
 		bool got = false;
-		Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dict = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
+		ScopedPtr< Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> > dict(new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>());
 		try {
 			int n = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,dict->unsafeData(),ZT_NETWORKCONFIG_DICT_CAPACITY - 1);
 			if (n > 1) {
-				NetworkConfig *nconf = new NetworkConfig();
 				try {
+					ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
 					if (nconf->fromDictionary(*dict)) {
 						this->setConfiguration(tPtr,*nconf,false);
 						_lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated
 						got = true;
 					}
 				} catch ( ... ) {}
-				delete nconf;
 			}
 		} catch ( ... ) {}
-		delete dict;
 
 		if (!got)
 			RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1);
@@ -856,7 +855,6 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
 	const unsigned int chunkLen = chunk.at<uint16_t>(ptr); ptr += 2;
 	const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen;
 
-	NetworkConfig *nc = (NetworkConfig *)0;
 	uint64_t configUpdateId;
 	{
 		Mutex::Lock l1(_config_l);
@@ -953,27 +951,16 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
 		if (c->haveBytes == totalLength) {
 			c->data.unsafeData()[c->haveBytes] = (char)0; // ensure null terminated
 
-			nc = new NetworkConfig();
+			ScopedPtr<NetworkConfig> nc(new NetworkConfig());
 			try {
-				if (!nc->fromDictionary(c->data)) {
-					delete nc;
-					nc = (NetworkConfig *)0;
+				if (nc->fromDictionary(c->data)) {
+					this->setConfiguration(tPtr,*nc,true);
+					return configUpdateId;
 				}
-			} catch ( ... ) {
-				delete nc;
-				nc = (NetworkConfig *)0;
-			}
+			} catch ( ... ) {}
 		}
 	}
 
-	if (nc) {
-		this->setConfiguration(tPtr,*nc,true);
-		delete nc;
-		return configUpdateId;
-	} else {
-		return 0;
-	}
-
 	return 0;
 }
 
@@ -1007,15 +994,14 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
 		_portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
 
 		if (saveToDisk) {
-			Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *const d = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
 			try {
+				ScopedPtr< Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> > d(new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>());
 				if (nconf.toDictionary(*d,false)) {
 					uint64_t tmp[2];
 					tmp[0] = _id; tmp[1] = 0;
 					RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d->data(),d->sizeBytes());
 				}
 			} catch ( ... ) {}
-			delete d;
 		}
 
 		return 2; // OK and configuration has changed
@@ -1120,7 +1106,7 @@ void Network::_requestConfiguration(void *tPtr)
 			const uint16_t startPortRange = (uint16_t)((_id >> 40) & 0xffff);
 			const uint16_t endPortRange = (uint16_t)((_id >> 24) & 0xffff);
 			if (endPortRange >= startPortRange) {
-				NetworkConfig *const nconf = new NetworkConfig();
+				ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
 
 				nconf->networkId = _id;
 				nconf->timestamp = RR->node->now();
@@ -1182,7 +1168,6 @@ void Network::_requestConfiguration(void *tPtr)
 				nconf->name[15] = (char)0;
 
 				this->setConfiguration(tPtr,*nconf,false);
-				delete nconf;
 			} else {
 				this->setNotFound();
 			}
@@ -1200,7 +1185,7 @@ void Network::_requestConfiguration(void *tPtr)
 			char v4ascii[24];
 			Utils::decimal(ipv4[0],v4ascii);
 
-			NetworkConfig *const nconf = new NetworkConfig();
+			ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
 
 			nconf->networkId = _id;
 			nconf->timestamp = RR->node->now();
@@ -1241,32 +1226,31 @@ void Network::_requestConfiguration(void *tPtr)
 			nconf->name[nn++] = (char)0;
 
 			this->setConfiguration(tPtr,*nconf,false);
-			delete nconf;
 		}
 		return;
 	}
 
 	const Address ctrl(controller());
 
-	Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> rmd;
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)ZT_VENDOR_ZEROTIER);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_ONE_VERSION_REVISION);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES,(uint64_t)ZT_MAX_NETWORK_CAPABILITIES);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS,(uint64_t)ZT_MAX_NETWORK_TAGS);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
-	rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
+	ScopedPtr< Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> > rmd(new Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>());
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)ZT_VENDOR_ZEROTIER);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_ONE_VERSION_REVISION);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES,(uint64_t)ZT_MAX_NETWORK_CAPABILITIES);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS,(uint64_t)ZT_MAX_NETWORK_TAGS);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
+	rmd->add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
 
 	RR->t->networkConfigRequestSent(tPtr,*this,ctrl);
 
 	if (ctrl == RR->identity.address()) {
 		if (RR->localNetworkController) {
-			RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd);
+			RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,*rmd);
 		} else {
 			this->setNotFound();
 		}
@@ -1275,9 +1259,9 @@ void Network::_requestConfiguration(void *tPtr)
 
 	Packet outp(ctrl,RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
 	outp.append((uint64_t)_id);
-	const unsigned int rmdSize = rmd.sizeBytes();
+	const unsigned int rmdSize = rmd->sizeBytes();
 	outp.append((uint16_t)rmdSize);
-	outp.append((const void *)rmd.data(),rmdSize);
+	outp.append((const void *)rmd->data(),rmdSize);
 	if (_config) {
 		outp.append((uint64_t)_config.revision);
 		outp.append((uint64_t)_config.timestamp);
@@ -1373,7 +1357,7 @@ void Network::_announceMulticastGroups(void *tPtr,bool force)
 void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups)
 {
 	// Assumes _myMulticastGroups_l and _memberships_l are locked
-	Packet *const outp = new Packet(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
+	ScopedPtr<Packet> outp(new Packet(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE));
 
 	for(std::vector<MulticastGroup>::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) {
 		if ((outp->size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) {
@@ -1392,8 +1376,6 @@ void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const st
 		outp->compress();
 		RR->sw->send(tPtr,*outp,true);
 	}
-
-	delete outp;
 }
 
 std::vector<MulticastGroup> Network::_allMulticastGroups() const

+ 73 - 86
node/NetworkConfig.cpp

@@ -16,99 +16,93 @@
 #include <algorithm>
 
 #include "NetworkConfig.hpp"
+#include "ScopedPtr.hpp"
 
 namespace ZeroTier {
 
 bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const
 {
-	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];
 
-	try {
-		d.clear();
-
-		// Try to put the more human-readable fields first
-
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false;
-		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) return false;
-
-		// Then add binary blobs
-
-		if (this->com) {
-			tmp->clear();
-			this->com.serialize(*tmp);
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false;
-		}
+	d.clear();
 
-		tmp->clear();
-		for(unsigned int i=0;i<this->capabilityCount;++i)
-			this->capabilities[i].serialize(*tmp);
-		if (tmp->size()) {
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false;
-		}
+	// Try to put the more human-readable fields first
 
-		tmp->clear();
-		for(unsigned int i=0;i<this->tagCount;++i)
-			this->tags[i].serialize(*tmp);
-		if (tmp->size()) {
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false;
-		}
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL,(uint64_t)this->remoteTraceLevel)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false;
+	if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) return false;
 
-		tmp->clear();
-		for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i)
-			this->certificatesOfOwnership[i].serialize(*tmp);
-		if (tmp->size()) {
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false;
-		}
+	// Then add binary blobs
 
+	if (this->com) {
 		tmp->clear();
-		for(unsigned int i=0;i<this->specialistCount;++i)
-			tmp->append((uint64_t)this->specialists[i]);
-		if (tmp->size()) {
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false;
-		}
+		this->com.serialize(*tmp);
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,*tmp)) return false;
+	}
 
-		tmp->clear();
-		for(unsigned int i=0;i<this->routeCount;++i) {
-			reinterpret_cast<const InetAddress *>(&(this->routes[i].target))->serialize(*tmp);
-			reinterpret_cast<const InetAddress *>(&(this->routes[i].via))->serialize(*tmp);
-			tmp->append((uint16_t)this->routes[i].flags);
-			tmp->append((uint16_t)this->routes[i].metric);
-		}
-		if (tmp->size()) {
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false;
-		}
+	tmp->clear();
+	for(unsigned int i=0;i<this->capabilityCount;++i)
+		this->capabilities[i].serialize(*tmp);
+	if (tmp->size()) {
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES,*tmp)) return false;
+	}
 
+	tmp->clear();
+	for(unsigned int i=0;i<this->tagCount;++i)
+		this->tags[i].serialize(*tmp);
+	if (tmp->size()) {
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TAGS,*tmp)) return false;
+	}
+
+	tmp->clear();
+	for(unsigned int i=0;i<this->certificateOfOwnershipCount;++i)
+		this->certificatesOfOwnership[i].serialize(*tmp);
+	if (tmp->size()) {
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP,*tmp)) return false;
+	}
+
+	tmp->clear();
+	for(unsigned int i=0;i<this->specialistCount;++i)
+		tmp->append((uint64_t)this->specialists[i]);
+	if (tmp->size()) {
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS,*tmp)) return false;
+	}
+
+	tmp->clear();
+	for(unsigned int i=0;i<this->routeCount;++i) {
+		reinterpret_cast<const InetAddress *>(&(this->routes[i].target))->serialize(*tmp);
+		reinterpret_cast<const InetAddress *>(&(this->routes[i].via))->serialize(*tmp);
+		tmp->append((uint16_t)this->routes[i].flags);
+		tmp->append((uint16_t)this->routes[i].metric);
+	}
+	if (tmp->size()) {
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ROUTES,*tmp)) return false;
+	}
+
+	tmp->clear();
+	for(unsigned int i=0;i<this->staticIpCount;++i)
+		this->staticIps[i].serialize(*tmp);
+	if (tmp->size()) {
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false;
+	}
+
+	if (this->ruleCount) {
 		tmp->clear();
-		for(unsigned int i=0;i<this->staticIpCount;++i)
-			this->staticIps[i].serialize(*tmp);
+		Capability::serializeRules(*tmp,rules,ruleCount);
 		if (tmp->size()) {
-			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS,*tmp)) return false;
-		}
-
-		if (this->ruleCount) {
-			tmp->clear();
-			Capability::serializeRules(*tmp,rules,ruleCount);
-			if (tmp->size()) {
-				if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false;
-			}
+			if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_RULES,*tmp)) return false;
 		}
-
-		delete tmp;
-	} catch ( ... ) {
-		delete tmp;
-		throw;
 	}
 
 	return true;
@@ -117,25 +111,21 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
 bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
 {
 	static const NetworkConfig NIL_NC;
-	Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *const tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
+	ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
 
 	try {
 		*this = NIL_NC;
 
 		// Fields that are always present, new or old
 		this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0);
-		if (!this->networkId) {
-			delete tmp;
+		if (!this->networkId)
 			return false;
-		}
 		this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0);
 		this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0);
 		this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0);
 		this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
-		if (!this->issuedTo) {
-			delete tmp;
+		if (!this->issuedTo)
 			return false;
-		}
 		this->remoteTraceTarget = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET);
 		this->remoteTraceLevel = (Trace::Level)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_LEVEL);
 		this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0);
@@ -148,7 +138,6 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
 			this->mtu = ZT_MAX_MTU;
 
 		if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) {
-			delete tmp;
 			return false;
 		} else {
 			// Otherwise we can use the new fields
@@ -228,10 +217,8 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
 			}
 		}
 
-		delete tmp;
 		return true;
 	} catch ( ... ) {
-		delete tmp;
 		return false;
 	}
 }

+ 1 - 1
node/NetworkConfig.hpp

@@ -86,7 +86,7 @@ namespace ZeroTier {
 #define ZT_NETWORKCONFIG_DICT_CAPACITY (1024 + (sizeof(ZT_VirtualNetworkRule) * ZT_MAX_NETWORK_RULES) + (sizeof(Capability) * ZT_MAX_NETWORK_CAPABILITIES) + (sizeof(Tag) * ZT_MAX_NETWORK_TAGS) + (sizeof(CertificateOfOwnership) * ZT_MAX_CERTIFICATES_OF_OWNERSHIP))
 
 // Dictionary capacity needed for max size network meta-data
-#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 2048
+#define ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY 8192
 
 // Network config version
 #define ZT_NETWORKCONFIG_VERSION 7

+ 34 - 39
node/Node.cpp

@@ -32,6 +32,7 @@
 #include "SelfAwareness.hpp"
 #include "Network.hpp"
 #include "Trace.hpp"
+#include "ScopedPtr.hpp"
 
 namespace ZeroTier {
 
@@ -558,47 +559,41 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de
 		if (!n) return;
 		n->setConfiguration((void *)0,nc,true);
 	} else {
-		Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dconf = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
-		try {
-			if (nc.toDictionary(*dconf,sendLegacyFormatConfig)) {
-				uint64_t configUpdateId = Utils::random();
-				if (!configUpdateId) ++configUpdateId;
-
-				const unsigned int totalSize = dconf->sizeBytes();
-				unsigned int chunkIndex = 0;
-				while (chunkIndex < totalSize) {
-					const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256)));
-					Packet outp(destination,RR->identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG);
-					if (requestPacketId) {
-						outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
-						outp.append(requestPacketId);
-					}
-
-					const unsigned int sigStart = outp.size();
-					outp.append(nwid);
-					outp.append((uint16_t)chunkLen);
-					outp.append((const void *)(dconf->data() + chunkIndex),chunkLen);
-
-					outp.append((uint8_t)0); // no flags
-					outp.append((uint64_t)configUpdateId);
-					outp.append((uint32_t)totalSize);
-					outp.append((uint32_t)chunkIndex);
-
-					uint8_t sig[256];
-					const unsigned int siglen = RR->identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart,sig,sizeof(sig));
-					outp.append((uint8_t)1);
-					outp.append((uint16_t)siglen);
-					outp.append(sig,siglen);
-
-					outp.compress();
-					RR->sw->send((void *)0,outp,true);
-					chunkIndex += chunkLen;
+		ScopedPtr< Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> > dconf(new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>());
+		if (nc.toDictionary(*dconf,sendLegacyFormatConfig)) {
+			uint64_t configUpdateId = Utils::random();
+			if (!configUpdateId) ++configUpdateId;
+
+			const unsigned int totalSize = dconf->sizeBytes();
+			unsigned int chunkIndex = 0;
+			while (chunkIndex < totalSize) {
+				const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256)));
+				Packet outp(destination,RR->identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG);
+				if (requestPacketId) {
+					outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+					outp.append(requestPacketId);
 				}
+
+				const unsigned int sigStart = outp.size();
+				outp.append(nwid);
+				outp.append((uint16_t)chunkLen);
+				outp.append((const void *)(dconf->data() + chunkIndex),chunkLen);
+
+				outp.append((uint8_t)0); // no flags
+				outp.append((uint64_t)configUpdateId);
+				outp.append((uint32_t)totalSize);
+				outp.append((uint32_t)chunkIndex);
+
+				uint8_t sig[256];
+				const unsigned int siglen = RR->identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart,sig,sizeof(sig));
+				outp.append((uint8_t)1);
+				outp.append((uint16_t)siglen);
+				outp.append(sig,siglen);
+
+				outp.compress();
+				RR->sw->send((void *)0,outp,true);
+				chunkIndex += chunkLen;
 			}
-			delete dconf;
-		} catch ( ... ) {
-			delete dconf;
-			throw;
 		}
 	}
 }

+ 2 - 2
node/Peer.cpp

@@ -22,6 +22,7 @@
 #include "InetAddress.hpp"
 #include "RingBuffer.hpp"
 #include "Utils.hpp"
+#include "ScopedPtr.hpp"
 
 namespace ZeroTier {
 
@@ -173,7 +174,7 @@ void Peer::received(
 		if (pathsToPush.size() > 0) {
 			std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
 			while (p != pathsToPush.end()) {
-				Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
+				ScopedPtr<Packet> outp(new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS));
 				outp->addSize(2); // leave room for count
 				unsigned int count = 0;
 				while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) {
@@ -205,7 +206,6 @@ void Peer::received(
 					outp->armor(_key,true);
 					path->send(RR,tPtr,outp->data(),outp->size(),now);
 				}
-				delete outp;
 			}
 		}
 	}

+ 50 - 0
node/ScopedPtr.hpp

@@ -0,0 +1,50 @@
+/*
+ * Copyright (c)2019 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: 2023-01-01
+ *
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
+ */
+/****/
+
+#ifndef ZT_SCOPEDPTR_HPP
+#define ZT_SCOPEDPTR_HPP
+
+#include "Constants.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Simple scoped pointer
+ *
+ * This is used in the core to avoid requiring C++11 and because auto_ptr is weird.
+ */
+template<typename T>
+class ScopedPtr
+{
+public:
+	ZT_ALWAYS_INLINE ScopedPtr(T *const p) : _p(p) {}
+	ZT_ALWAYS_INLINE ~ScopedPtr() { delete _p; }
+
+	ZT_ALWAYS_INLINE T *operator->() const { return _p; }
+	ZT_ALWAYS_INLINE T &operator*() const { return *_p; }
+	ZT_ALWAYS_INLINE operator bool() const { return (_p != (T *)0); }
+	ZT_ALWAYS_INLINE T *ptr() const { return _p; }
+
+	ZT_ALWAYS_INLINE bool operator==(const ScopedPtr &p) const { return (_p == p._p); }
+	ZT_ALWAYS_INLINE bool operator!=(const ScopedPtr &p) const { return (_p != p._p); }
+	ZT_ALWAYS_INLINE bool operator==(T *const p) const { return (_p == p); }
+	ZT_ALWAYS_INLINE bool operator!=(T *const p) const { return (_p != p); }
+
+private:
+	ZT_ALWAYS_INLINE ScopedPtr() {}
+	T *const _p;
+};
+
+} // namespace ZeroTier
+
+#endif