Browse Source

Add persistent identity caching for use on supernodes. Activate by just making an iddb.d directory in the ZeroTier home folder. Also clean up some obsolete cruft from makefiles.

Adam Ierymenko 11 years ago
parent
commit
5e71e07f59
8 changed files with 82 additions and 29 deletions
  1. 1 2
      Makefile.linux
  2. 1 1
      Makefile.mac
  3. 0 18
      node/Constants.hpp
  4. 1 1
      node/Node.cpp
  5. 2 0
      node/NodeConfig.cpp
  6. 24 5
      node/PacketDecoder.cpp
  7. 31 1
      node/Topology.cpp
  8. 22 1
      node/Topology.hpp

+ 1 - 2
Makefile.linux

@@ -2,8 +2,7 @@ CC=gcc
 CXX=g++
 CXX=g++
 
 
 INCLUDES=
 INCLUDES=
-ARCH=$(shell uname -m)
-DEFS=-DZT_ARCH="$(ARCH)" -DZT_OSNAME="linux"
+DEFS=
 LIBS=
 LIBS=
 
 
 # Uncomment for a release optimized build
 # Uncomment for a release optimized build

+ 1 - 1
Makefile.mac

@@ -2,7 +2,7 @@ CC=gcc
 CXX=g++
 CXX=g++
 
 
 INCLUDES=
 INCLUDES=
-DEFS=-DZT_ARCH="x86_combined" -DZT_OSNAME="mac" -DZT_TRACE
+DEFS=
 LIBS=-lm
 LIBS=-lm
 
 
 # Uncomment for a release optimized universal binary build
 # Uncomment for a release optimized universal binary build

+ 0 - 18
node/Constants.hpp

@@ -99,24 +99,6 @@
 #ifndef __BYTE_ORDER
 #ifndef __BYTE_ORDER
 error_no_byte_order_defined;
 error_no_byte_order_defined;
 #endif
 #endif
-#ifndef ZT_OSNAME
-#ifdef __WINDOWS__
-#define ZT_OSNAME "windows"
-#else
-no ZT_OSNAME defined;
-#endif
-#endif
-#ifndef ZT_ARCH
-#ifdef __WINDOWS__
-#ifdef _WIN64
-#define ZT_ARCH "x64"
-#else
-#define ZT_ARCH "x86"
-#endif
-#else
-error_no_ZT_ARCH_defined;
-#endif
-#endif
 
 
 /**
 /**
  * Length of a ZeroTier address in bytes
  * Length of a ZeroTier address in bytes

+ 1 - 1
node/Node.cpp

@@ -408,7 +408,7 @@ Node::ReasonForTermination Node::run()
 		_r->mc = new Multicaster();
 		_r->mc = new Multicaster();
 		_r->sw = new Switch(_r);
 		_r->sw = new Switch(_r);
 		_r->demarc = new Demarc(_r);
 		_r->demarc = new Demarc(_r);
-		_r->topology = new Topology(_r);
+		_r->topology = new Topology(_r,Utils::fileExists((_r->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str()));
 		_r->sysEnv = new SysEnv(_r);
 		_r->sysEnv = new SysEnv(_r);
 		try {
 		try {
 			_r->nc = new NodeConfig(_r,configAuthToken.c_str(),impl->controlPort);
 			_r->nc = new NodeConfig(_r,configAuthToken.c_str(),impl->controlPort);

+ 2 - 0
node/NodeConfig.cpp

@@ -353,7 +353,9 @@ bool NodeConfig::decodeControlMessagePacket(const void *key,const void *data,uns
 void NodeConfig::_CBcontrolPacketHandler(UdpSocket *sock,void *arg,const InetAddress &remoteAddr,const void *data,unsigned int len)
 void NodeConfig::_CBcontrolPacketHandler(UdpSocket *sock,void *arg,const InetAddress &remoteAddr,const void *data,unsigned int len)
 {
 {
 	NodeConfig *nc = (NodeConfig *)arg;
 	NodeConfig *nc = (NodeConfig *)arg;
+#ifdef ZT_TRACE
 	const RuntimeEnvironment *_r = nc->_r;
 	const RuntimeEnvironment *_r = nc->_r;
+#endif
 
 
 	try {
 	try {
 		unsigned long convId = 0;
 		unsigned long convId = 0;

+ 24 - 5
node/PacketDecoder.cpp

@@ -189,16 +189,16 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 			return true;
 			return true;
 		}
 		}
 
 
+		// Do we already have this peer?
 		SharedPtr<Peer> peer(_r->topology->getPeer(id.address()));
 		SharedPtr<Peer> peer(_r->topology->getPeer(id.address()));
 		if (peer) {
 		if (peer) {
+			// Check to make sure this isn't a colliding identity (different key,
+			// but same address). The odds are spectacularly low but it could happen.
+			// Could also be a sign of someone doing something nasty.
 			if (peer->identity() != id) {
 			if (peer->identity() != id) {
-				// Sorry, someone beat you to that address. What are the odds?
-				// Well actually they're around two in 2^40. You should play
-				// the lottery.
 				unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
 				unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
 				if (_r->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
 				if (_r->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
 					TRACE("rejected HELLO from %s(%s): address already claimed",source().toString().c_str(),_remoteAddress.toString().c_str());
 					TRACE("rejected HELLO from %s(%s): address already claimed",source().toString().c_str(),_remoteAddress.toString().c_str());
-
 					Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
 					Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
 					outp.append((unsigned char)Packet::VERB_HELLO);
 					outp.append((unsigned char)Packet::VERB_HELLO);
 					outp.append(packetId());
 					outp.append(packetId());
@@ -209,7 +209,26 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 				return true;
 				return true;
 			} // else continue and send OK since we already know thee...
 			} // else continue and send OK since we already know thee...
 		} else {
 		} else {
-			// Learn a new peer
+			// If we don't have a peer record on file, check the identity cache (if
+			// we have one) to see if we have a cached identity. Then check that for
+			// collision before adding a new peer.
+			Identity alreadyHaveCachedId(_r->topology->getIdentity(id.address()));
+			if ((alreadyHaveCachedId)&&(id != alreadyHaveCachedId)) {
+				unsigned char key[ZT_PEER_SECRET_KEY_LENGTH];
+				if (_r->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) {
+					TRACE("rejected HELLO from %s(%s): address already claimed",source().toString().c_str(),_remoteAddress.toString().c_str());
+					Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
+					outp.append((unsigned char)Packet::VERB_HELLO);
+					outp.append(packetId());
+					outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
+					outp.armor(key,true);
+					_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+				}
+				return true;
+			}
+
+			// Learn a new peer if it's new. This also adds it to the identity
+			// cache if that's enabled.
 			peer = _r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,id)));
 			peer = _r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,id)));
 		}
 		}
 
 

+ 31 - 1
node/Topology.cpp

@@ -35,10 +35,12 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-Topology::Topology(const RuntimeEnvironment *renv) :
+Topology::Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching) :
 	_r(renv),
 	_r(renv),
 	_amSupernode(false)
 	_amSupernode(false)
 {
 {
+	if (enablePermanentIdCaching)
+		_idCacheBase = (_r->homePath + ZT_PATH_SEPARATOR_S + "iddb.d");
 	_loadPeers();
 	_loadPeers();
 }
 }
 
 
@@ -83,6 +85,7 @@ SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
 	Mutex::Lock _l(_activePeers_m);
 	Mutex::Lock _l(_activePeers_m);
 	SharedPtr<Peer> p(_activePeers.insert(std::pair< Address,SharedPtr<Peer> >(peer->address(),peer)).first->second);
 	SharedPtr<Peer> p(_activePeers.insert(std::pair< Address,SharedPtr<Peer> >(peer->address(),peer)).first->second);
 	p->setLastUsed(now);
 	p->setLastUsed(now);
+	saveIdentity(p->identity());
 	return p;
 	return p;
 }
 }
 
 
@@ -102,6 +105,32 @@ SharedPtr<Peer> Topology::getPeer(const Address &zta)
 	return SharedPtr<Peer>();
 	return SharedPtr<Peer>();
 }
 }
 
 
+Identity Topology::getIdentity(const Address &zta)
+{
+	SharedPtr<Peer> p(getPeer(zta));
+	if (p)
+		return p->identity();
+	if (_idCacheBase.length()) {
+		std::string idcPath(_idCacheBase + ZT_PATH_SEPARATOR_S + zta.toString());
+		std::string ids;
+		if (Utils::readFile(idcPath.c_str(),ids)) {
+			try {
+				return Identity(ids);
+			} catch ( ... ) {} // ignore invalid IDs
+		}
+	}
+	return Identity();
+}
+
+void Topology::saveIdentity(const Identity &id)
+{
+	if ((id)&&(_idCacheBase.length())) {
+		std::string idcPath(_idCacheBase + ZT_PATH_SEPARATOR_S + id.address().toString());
+		if (!Utils::fileExists(idcPath.c_str()))
+			Utils::writeFile(idcPath.c_str(),id.toString(false));
+	}
+}
+
 SharedPtr<Peer> Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid) const
 SharedPtr<Peer> Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid) const
 {
 {
 	SharedPtr<Peer> bestSupernode;
 	SharedPtr<Peer> bestSupernode;
@@ -244,6 +273,7 @@ void Topology::_loadPeers()
 					SharedPtr<Peer> p(new Peer());
 					SharedPtr<Peer> p(new Peer());
 					ptr += p->deserialize(buf,ptr);
 					ptr += p->deserialize(buf,ptr);
 					_activePeers[p->address()] = p;
 					_activePeers[p->address()] = p;
+					saveIdentity(p->identity());
 				}
 				}
 				if (ptr) {
 				if (ptr) {
 					memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);
 					memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);

+ 22 - 1
node/Topology.hpp

@@ -53,7 +53,7 @@ class RuntimeEnvironment;
 class Topology
 class Topology
 {
 {
 public:
 public:
-	Topology(const RuntimeEnvironment *renv);
+	Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching);
 	~Topology();
 	~Topology();
 
 
 	/**
 	/**
@@ -82,6 +82,25 @@ public:
 	 */
 	 */
 	SharedPtr<Peer> getPeer(const Address &zta);
 	SharedPtr<Peer> getPeer(const Address &zta);
 
 
+	/**
+	 * Get an identity if cached or available in a peer record
+	 *
+	 * @param zta ZeroTier address
+	 * @return Identity or NULL-identity if not found
+	 */
+	Identity getIdentity(const Address &zta);
+
+	/**
+	 * Save identity in permanent store, or do nothing if disabled
+	 *
+	 * This is called automatically by addPeer(), so it should not need to be
+	 * called manually anywhere else. The private part of the identity, if
+	 * present, is NOT cached by this.
+	 *
+	 * @param id Identity to save
+	 */
+	void saveIdentity(const Identity &id);
+
 	/**
 	/**
 	 * @return Current network supernodes
 	 * @return Current network supernodes
 	 */
 	 */
@@ -274,6 +293,8 @@ private:
 	void _dumpPeers();
 	void _dumpPeers();
 	void _loadPeers();
 	void _loadPeers();
 
 
+	std::string _idCacheBase; // empty if identity caching disabled
+
 	std::map< Address,SharedPtr<Peer> > _activePeers;
 	std::map< Address,SharedPtr<Peer> > _activePeers;
 	Mutex _activePeers_m;
 	Mutex _activePeers_m;