summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.linux3
-rw-r--r--Makefile.mac2
-rw-r--r--node/Constants.hpp18
-rw-r--r--node/Node.cpp2
-rw-r--r--node/NodeConfig.cpp2
-rw-r--r--node/PacketDecoder.cpp29
-rw-r--r--node/Topology.cpp32
-rw-r--r--node/Topology.hpp23
8 files changed, 82 insertions, 29 deletions
diff --git a/Makefile.linux b/Makefile.linux
index 7bacec73..8035a881 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 e195f088..33535798 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 23dd5e48..4fe7fd34 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 8b2815e2..593e63bc 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 85aca6d2..027f65ce 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 2efa7cf9..f65e4167 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> 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<Peer>(new Peer(_r->identity,id)));
}
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 18432f25..6efde33e 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<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
Mutex::Lock _l(_activePeers_m);
SharedPtr<Peer> p(_activePeers.insert(std::pair< Address,SharedPtr<Peer> >(peer->address(),peer)).first->second);
p->setLastUsed(now);
+ saveIdentity(p->identity());
return p;
}
@@ -102,6 +105,32 @@ SharedPtr<Peer> Topology::getPeer(const Address &zta)
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> bestSupernode;
@@ -244,6 +273,7 @@ void Topology::_loadPeers()
SharedPtr<Peer> 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 efb03dbe..09dec86e 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();
/**
@@ -83,6 +83,25 @@ public:
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
*/
inline std::map< Identity,std::vector<InetAddress> > supernodes() const
@@ -274,6 +293,8 @@ private:
void _dumpPeers();
void _loadPeers();
+ std::string _idCacheBase; // empty if identity caching disabled
+
std::map< Address,SharedPtr<Peer> > _activePeers;
Mutex _activePeers_m;