diff options
-rw-r--r-- | node/IncomingPacket.cpp | 44 | ||||
-rw-r--r-- | node/Node.cpp | 16 | ||||
-rw-r--r-- | node/Peer.cpp | 8 | ||||
-rw-r--r-- | node/Peer.hpp | 62 | ||||
-rw-r--r-- | node/Topology.cpp | 165 | ||||
-rw-r--r-- | node/Topology.hpp | 35 |
6 files changed, 72 insertions, 258 deletions
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 95091985..ad250d18 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -181,12 +181,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) return true; } - // Do we already have this peer? SharedPtr<Peer> peer(RR->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) { unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { @@ -208,33 +204,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) } else if (!dearmor(peer->key())) { LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str()); return true; - } // else continue and respond + } } else { - // 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(RR->topology->getIdentity(id.address())); - if ((alreadyHaveCachedId)&&(id != alreadyHaveCachedId)) { - unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; - if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { - if (dearmor(key)) { // ensure packet is authentic, otherwise drop - LOG("rejected HELLO from %s(%s): address already claimed",source().toString().c_str(),_remoteAddress.toString().c_str()); - Packet outp(source(),RR->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); - _fromSock->send(_remoteAddress,outp.data(),outp.size()); - } else { - LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str()); - } - } else { - LOG("rejected HELLO from %s(%s): key agreement failed",source().toString().c_str(),_remoteAddress.toString().c_str()); - } - return true; - } // else continue since identity is already known and matches - - // If this is a new peer, learn it SharedPtr<Peer> newPeer(new Peer(RR->identity,id)); if (!dearmor(newPeer->key())) { LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str()); @@ -376,29 +347,26 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> { try { if (payloadLength() == ZT_ADDRESS_LENGTH) { - Identity id(RR->topology->getIdentity(Address(payload(),ZT_ADDRESS_LENGTH))); - if (id) { - Packet outp(source(),RR->identity.address(),Packet::VERB_OK); + SharedPtr<Peer> queried(RR->topology->getPeer(Address(payload(),ZT_ADDRESS_LENGTH))); + if (queried) { + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_WHOIS); outp.append(packetId()); - id.serialize(outp,false); + queried->identity().serialize(outp,false); outp.armor(peer->key(),true); _fromSock->send(_remoteAddress,outp.data(),outp.size()); - //TRACE("sent WHOIS response to %s for %s",source().toString().c_str(),Address(payload(),ZT_ADDRESS_LENGTH).toString().c_str()); } else { - Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); + Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_WHOIS); outp.append(packetId()); outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(payload(),ZT_ADDRESS_LENGTH); outp.armor(peer->key(),true); _fromSock->send(_remoteAddress,outp.data(),outp.size()); - //TRACE("sent WHOIS ERROR to %s for %s (not found)",source().toString().c_str(),Address(payload(),ZT_ADDRESS_LENGTH).toString().c_str()); } } else { TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str()); } - peer->receive(RR,_fromSock,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,Utils::now()); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); diff --git a/node/Node.cpp b/node/Node.cpp index 2f97c999..4673312a 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -377,7 +377,7 @@ Node::ReasonForTermination Node::run() Utils::lockDownFile(identitySecretPath.c_str(),false); } - // Make sure networks.d exists + // Make sure networks.d exists (used by NodeConfig to remember networks) { std::string networksDotD(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d"); #ifdef __WINDOWS__ @@ -386,13 +386,22 @@ Node::ReasonForTermination Node::run() mkdir(networksDotD.c_str(),0700); #endif } + // Make sure iddb.d exists (used by Topology to remember identities) + { + std::string iddbDotD(RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d"); +#ifdef __WINDOWS__ + CreateDirectoryA(iddbDotD.c_str(),NULL); +#else + mkdir(iddbDotD.c_str(),0700); +#endif + } RR->http = new HttpClient(); RR->antiRec = new AntiRecursion(); RR->mc = new Multicaster(RR); RR->sw = new Switch(RR); RR->sm = new SocketManager(impl->udpPort,impl->tcpPort,&_CBztTraffic,RR); - RR->topology = new Topology(RR,Utils::fileExists((RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str())); + RR->topology = new Topology(RR); try { RR->nc = new NodeConfig(RR); } catch (std::exception &exc) { @@ -443,6 +452,9 @@ Node::ReasonForTermination Node::run() return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format"); } } + + // Delete peers.persist if it exists -- legacy file, just takes up space + Utils::rm(std::string(RR->homePath + ZT_PATH_SEPARATOR_S + "peers.persist").c_str()); } catch (std::bad_alloc &exc) { return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure"); } catch (std::runtime_error &exc) { diff --git a/node/Peer.cpp b/node/Peer.cpp index 94b8f29a..540a83a1 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -42,7 +42,7 @@ Peer::Peer() : _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), - __lastAnnouncedTo(0), + _lastAnnouncedTo(0), _vMajor(0), _vMinor(0), _vRevision(0), @@ -55,7 +55,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastReceive(0), _lastUnicastFrame(0), _lastMulticastFrame(0), - __lastAnnouncedTo(0), + _lastAnnouncedTo(0), _vMajor(0), _vMinor(0), _vRevision(0), @@ -118,8 +118,8 @@ void Peer::receive( * supernodes and network controllers. The other place this is done * is in rescanMulticastGroups() in Network, but that only sends something * if a network's multicast groups change. */ - if ((now - __lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { - __lastAnnouncedTo = now; + if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { + _lastAnnouncedTo = now; Packet outp(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); std::vector< SharedPtr<Network> > networks(RR->nc->networks()); diff --git a/node/Peer.hpp b/node/Peer.hpp index ead14311..3bb2a56e 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -50,9 +50,6 @@ #include "NonCopyable.hpp" #include "Mutex.hpp" -// Comment out to disable peers.persist -//#define ZT_PEER_SERIALIZATION_VERSION 13 - namespace ZeroTier { /** @@ -248,7 +245,7 @@ public: /** * @return Time we last announced state TO this peer, such as multicast LIKEs */ - inline uint64_t lastAnnouncedTo() const throw() { return __lastAnnouncedTo; } + inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; } /** * @param now Current time @@ -405,61 +402,6 @@ public: else return std::pair<InetAddress,InetAddress>(); } -#ifdef ZT_PEER_SERIALIZATION_VERSION - template<unsigned int C> - inline void serialize(Buffer<C> &b) const - { - Mutex::Lock _l(_lock); - - b.append((unsigned char)ZT_PEER_SERIALIZATION_VERSION); - _id.serialize(b,false); - b.append(_key,sizeof(_key)); - b.append(_lastUsed); - b.append(_lastReceive); - b.append(_lastUnicastFrame); - b.append(_lastMulticastFrame); - b.append((uint16_t)_vProto); - b.append((uint16_t)_vMajor); - b.append((uint16_t)_vMinor); - b.append((uint16_t)_vRevision); - b.append((uint16_t)_latency); - b.append((uint16_t)_paths.size()); - for(std::vector<Path>::const_iterator p(_paths.begin());p!=_paths.end();++p) - p->serialize(b); - } - template<unsigned int C> - inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0) - { - unsigned int p = startAt; - - if (b[p++] != ZT_PEER_SERIALIZATION_VERSION) - throw std::invalid_argument("Peer: deserialize(): version mismatch"); - - Mutex::Lock _l(_lock); - - p += _id.deserialize(b,p); - memcpy(_key,b.field(p,sizeof(_key)),sizeof(_key)); p += sizeof(_key); - _lastUsed = b.template at<uint64_t>(p); p += sizeof(uint64_t); - _lastReceive = b.template at<uint64_t>(p); p += sizeof(uint64_t); - _lastUnicastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t); - _lastMulticastFrame = b.template at<uint64_t>(p); p += sizeof(uint64_t); - __lastAnnouncedTo = 0; - _vProto = b.template at<uint16_t>(p); p += sizeof(uint16_t); - _vMajor = b.template at<uint16_t>(p); p += sizeof(uint16_t); - _vMinor = b.template at<uint16_t>(p); p += sizeof(uint16_t); - _vRevision = b.template at<uint16_t>(p); p += sizeof(uint16_t); - _latency = b.template at<uint16_t>(p); p += sizeof(uint16_t); - unsigned int npaths = (unsigned int)b.template at<uint16_t>(p); p += sizeof(uint16_t); - _paths.clear(); - for(unsigned int i=0;i<npaths;++i) { - _paths.push_back(Path()); - p += _paths.back().deserialize(b,p); - } - - return (p - startAt); - } -#endif // ZT_PEER_SERIALIZATION_VERSION - private: void _announceMulticastGroups(const RuntimeEnvironment *RR,uint64_t now); @@ -472,7 +414,7 @@ private: volatile uint64_t _lastReceive; // direct or indirect volatile uint64_t _lastUnicastFrame; volatile uint64_t _lastMulticastFrame; - volatile uint64_t __lastAnnouncedTo; // not persisted -- shouldn't be unless Multicaster state is also persisted + volatile uint64_t _lastAnnouncedTo; volatile uint16_t _vProto; volatile uint16_t _vMajor; volatile uint16_t _vMinor; diff --git a/node/Topology.cpp b/node/Topology.cpp index 10e5d9c7..c8f14a2c 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -38,19 +38,15 @@ namespace ZeroTier { -Topology::Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching) : +Topology::Topology(const RuntimeEnvironment *renv) : RR(renv), + _idCacheBase(renv->homePath + ZT_PATH_SEPARATOR_S + "iddb.d"), _amSupernode(false) { - if (enablePermanentIdCaching) - _idCacheBase = (RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d"); - _loadPeers(); } Topology::~Topology() { - clean(Utils::now()); - _dumpPeers(); } void Topology::setSupernodes(const std::map< Identity,std::vector< std::pair<InetAddress,bool> > > &sn) @@ -108,57 +104,49 @@ SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer) TRACE("BUG: addNewPeer() caught and ignored attempt to add peer for self"); throw std::logic_error("cannot add peer for self"); } + uint64_t now = Utils::now(); Mutex::Lock _l(_activePeers_m); + SharedPtr<Peer> p(_activePeers.insert(std::pair< Address,SharedPtr<Peer> >(peer->address(),peer)).first->second); p->use(now); - saveIdentity(p->identity()); + _saveIdentity(p->identity()); + return p; } -SharedPtr<Peer> Topology::getPeer(const Address &zta) const +SharedPtr<Peer> Topology::getPeer(const Address &zta) { if (zta == RR->identity.address()) { TRACE("BUG: ignored attempt to getPeer() for self, returned NULL"); return SharedPtr<Peer>(); } + uint64_t now = Utils::now(); Mutex::Lock _l(_activePeers_m); - std::map< Address,SharedPtr<Peer> >::const_iterator ap(_activePeers.find(zta)); - if ((ap != _activePeers.end())&&(ap->second)) { - ap->second->use(now); - return ap->second; - } - 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 - } + SharedPtr<Peer> &ap = _activePeers[zta]; + + if (ap) { + ap->use(now); + return ap; } - 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)); + Identity id(_getIdentity(zta)); + if (id) { + try { + ap = SharedPtr<Peer>(new Peer(RR->identity,id)); + ap->use(now); + return ap; + } catch ( ... ) {} // invalid identity? } + + _activePeers.erase(zta); + + return SharedPtr<Peer>(); } -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) { SharedPtr<Peer> bestSupernode; uint64_t now = Utils::now(); @@ -261,9 +249,9 @@ void Topology::clean(uint64_t now) Mutex::Lock _l(_activePeers_m); Mutex::Lock _l2(_supernodes_m); for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();) { - if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(!_supernodeAddresses.count(p->second->address()))) + if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(!_supernodeAddresses.count(p->second->address()))) { _activePeers.erase(p++); - else { + } else { p->second->clean(now); ++p; } @@ -288,101 +276,24 @@ bool Topology::authenticateRootTopology(const Dictionary &rt) } } -void Topology::_dumpPeers() +Identity Topology::_getIdentity(const Address &zta) { -#ifdef ZT_PEER_SERIALIZATION_VERSION - Buffer<ZT_PEER_WRITE_BUF_SIZE> buf; - std::string pdpath(RR->homePath + ZT_PATH_SEPARATOR_S + "peers.persist"); - Mutex::Lock _l(_activePeers_m); - - FILE *pd = fopen(pdpath.c_str(),"wb"); - if (!pd) - return; - if (fwrite("ZTPD0",5,1,pd) != 1) { - fclose(pd); - Utils::rm(pdpath); - return; - } - - for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();++p) { + std::string idcPath(_idCacheBase + ZT_PATH_SEPARATOR_S + zta.toString()); + std::string ids; + if (Utils::readFile(idcPath.c_str(),ids)) { try { - p->second->serialize(buf); - if (buf.size() >= (ZT_PEER_WRITE_BUF_SIZE / 2)) { - if (fwrite(buf.data(),buf.size(),1,pd) != 1) { - fclose(pd); - Utils::rm(pdpath); - buf.burn(); - return; - } - buf.clear(); - buf.burn(); - } - } catch ( ... ) { - fclose(pd); - Utils::rm(pdpath); - buf.burn(); - return; - } + return Identity(ids); + } catch ( ... ) {} // ignore invalid IDs } - - if (buf.size()) { - if (fwrite(buf.data(),buf.size(),1,pd) != 1) { - fclose(pd); - Utils::rm(pdpath); - buf.burn(); - return; - } - buf.burn(); - } - - fclose(pd); - buf.burn(); - - Utils::lockDownFile(pdpath.c_str(),false); -#endif // ZT_PEER_SERIALIZATION_VERSION + return Identity(); } -void Topology::_loadPeers() +void Topology::_saveIdentity(const Identity &id) { - std::string pdpath(RR->homePath + ZT_PATH_SEPARATOR_S + "peers.persist"); - -#ifdef ZT_PEER_SERIALIZATION_VERSION - Buffer<ZT_PEER_WRITE_BUF_SIZE> buf; - Mutex::Lock _l(_activePeers_m); - - _activePeers.clear(); - - FILE *pd = fopen(pdpath.c_str(),"rb"); - if (!pd) - return; - - try { - char magic[5]; - if ((fread(magic,5,1,pd) == 1)&&(!memcmp("ZTPD0",magic,5))) { - long rlen = 0; - do { - long rlen = (long)fread(const_cast<char *>(static_cast<const char *>(buf.data())) + buf.size(),1,ZT_PEER_WRITE_BUF_SIZE - buf.size(),pd); - if (rlen < 0) rlen = 0; - buf.setSize(buf.size() + (unsigned int)rlen); - unsigned int ptr = 0; - while ((ptr < (ZT_PEER_WRITE_BUF_SIZE / 2))&&(ptr < buf.size())) { - SharedPtr<Peer> p(new Peer()); - ptr += p->deserialize(buf,ptr); - _activePeers[p->address()] = p; - saveIdentity(p->identity()); - } - buf.behead(ptr); - } while (rlen > 0); - } - } catch ( ... ) { - _activePeers.clear(); + if (id) { + std::string idcPath(_idCacheBase + ZT_PATH_SEPARATOR_S + id.address().toString()); + Utils::writeFile(idcPath.c_str(),id.toString(false)); } - - fclose(pd); - buf.burn(); -#endif // ZT_PEER_SERIALIZATION_VERSION - - Utils::rm(pdpath); } } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 8ab10074..f58d7486 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -58,7 +58,7 @@ class RuntimeEnvironment; class Topology { public: - Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching); + Topology(const RuntimeEnvironment *renv); ~Topology(); /** @@ -95,26 +95,7 @@ public: * @param zta ZeroTier address of peer * @return Peer or NULL if not found */ - SharedPtr<Peer> getPeer(const Address &zta) const; - - /** - * 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); + SharedPtr<Peer> getPeer(const Address &zta); /** * @return Vector of peers that are supernodes @@ -139,7 +120,7 @@ public: * * @return Supernode with lowest latency or NULL if none */ - inline SharedPtr<Peer> getBestSupernode() const + inline SharedPtr<Peer> getBestSupernode() { return getBestSupernode((const Address *)0,0,false); } @@ -156,7 +137,7 @@ public: * @param strictAvoid If false, consider avoided supernodes anyway if no non-avoid supernodes are available * @return Supernode or NULL if none */ - SharedPtr<Peer> getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid) const; + SharedPtr<Peer> getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid); /** * @param zta ZeroTier address @@ -373,12 +354,12 @@ public: static bool authenticateRootTopology(const Dictionary &rt); private: - const RuntimeEnvironment *RR; + Identity _getIdentity(const Address &zta); + void _saveIdentity(const Identity &id); - void _dumpPeers(); - void _loadPeers(); + const RuntimeEnvironment *RR; - std::string _idCacheBase; // empty if identity caching disabled + std::string _idCacheBase; std::map< Address,SharedPtr<Peer> > _activePeers; Mutex _activePeers_m; |