From 5e71e07f5940056f1fb5124dcdfeb71a313b9854 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 21 Oct 2013 14:12:00 -0400 Subject: [PATCH] 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. --- Makefile.linux | 3 +-- Makefile.mac | 2 +- node/Constants.hpp | 18 ------------------ node/Node.cpp | 2 +- node/NodeConfig.cpp | 2 ++ node/PacketDecoder.cpp | 29 ++++++++++++++++++++++++----- node/Topology.cpp | 32 +++++++++++++++++++++++++++++++- node/Topology.hpp | 23 ++++++++++++++++++++++- 8 files changed, 82 insertions(+), 29 deletions(-) diff --git a/Makefile.linux b/Makefile.linux index 7bacec735..8035a8811 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -2,8 +2,7 @@ CC=gcc CXX=g++ INCLUDES= -ARCH=$(shell uname -m) -DEFS=-DZT_ARCH="$(ARCH)" -DZT_OSNAME="linux" +DEFS= LIBS= # Uncomment for a release optimized build diff --git a/Makefile.mac b/Makefile.mac index e195f0886..335357984 100644 --- a/Makefile.mac +++ b/Makefile.mac @@ -2,7 +2,7 @@ CC=gcc CXX=g++ INCLUDES= -DEFS=-DZT_ARCH="x86_combined" -DZT_OSNAME="mac" -DZT_TRACE +DEFS= LIBS=-lm # Uncomment for a release optimized universal binary build diff --git a/node/Constants.hpp b/node/Constants.hpp index 23dd5e480..4fe7fd348 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -99,24 +99,6 @@ #ifndef __BYTE_ORDER error_no_byte_order_defined; #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 diff --git a/node/Node.cpp b/node/Node.cpp index 8b2815e20..593e63bc3 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -408,7 +408,7 @@ Node::ReasonForTermination Node::run() _r->mc = new Multicaster(); _r->sw = new Switch(_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); try { _r->nc = new NodeConfig(_r,configAuthToken.c_str(),impl->controlPort); diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp index 85aca6d2b..027f65ce3 100644 --- a/node/NodeConfig.cpp +++ b/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) { NodeConfig *nc = (NodeConfig *)arg; +#ifdef ZT_TRACE const RuntimeEnvironment *_r = nc->_r; +#endif try { unsigned long convId = 0; diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 2efa7cf9c..f65e41675 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -189,16 +189,16 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r) return true; } + // Do we already have this peer? SharedPtr peer(_r->topology->getPeer(id.address())); 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) { - // 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]; 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()); @@ -209,7 +209,26 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r) return true; } // else continue and send OK since we already know thee... } 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(new Peer(_r->identity,id))); } diff --git a/node/Topology.cpp b/node/Topology.cpp index 18432f25d..6efde33ed 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -35,10 +35,12 @@ namespace ZeroTier { -Topology::Topology(const RuntimeEnvironment *renv) : +Topology::Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching) : _r(renv), _amSupernode(false) { + if (enablePermanentIdCaching) + _idCacheBase = (_r->homePath + ZT_PATH_SEPARATOR_S + "iddb.d"); _loadPeers(); } @@ -83,6 +85,7 @@ SharedPtr Topology::addPeer(const SharedPtr &peer) Mutex::Lock _l(_activePeers_m); SharedPtr p(_activePeers.insert(std::pair< Address,SharedPtr >(peer->address(),peer)).first->second); p->setLastUsed(now); + saveIdentity(p->identity()); return p; } @@ -102,6 +105,32 @@ SharedPtr Topology::getPeer(const Address &zta) return SharedPtr(); } +Identity Topology::getIdentity(const Address &zta) +{ + SharedPtr 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 Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid) const { SharedPtr bestSupernode; @@ -244,6 +273,7 @@ void Topology::_loadPeers() SharedPtr p(new Peer()); ptr += p->deserialize(buf,ptr); _activePeers[p->address()] = p; + saveIdentity(p->identity()); } if (ptr) { memmove(buf.data(),buf.data() + ptr,buf.size() - ptr); diff --git a/node/Topology.hpp b/node/Topology.hpp index efb03dbe1..09dec86e0 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -53,7 +53,7 @@ class RuntimeEnvironment; class Topology { public: - Topology(const RuntimeEnvironment *renv); + Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching); ~Topology(); /** @@ -82,6 +82,25 @@ public: */ SharedPtr 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 */ @@ -274,6 +293,8 @@ private: void _dumpPeers(); void _loadPeers(); + std::string _idCacheBase; // empty if identity caching disabled + std::map< Address,SharedPtr > _activePeers; Mutex _activePeers_m;