summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-01-12 09:49:11 -0800
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-01-12 09:49:11 -0800
commitfbc6ca28b7ee0b5d9917cdf6f7251e65dbb0d3ee (patch)
tree56787fd56d1fdafeabeb2e82e9bb3d8174f57468
parent72f926dc41bed699f6510a273f5ebbe30d84f755 (diff)
parenteab3ca1401b083b3d91d30d2c6f571dcb5c8a2a6 (diff)
downloadinfinitytier-fbc6ca28b7ee0b5d9917cdf6f7251e65dbb0d3ee.tar.gz
infinitytier-fbc6ca28b7ee0b5d9917cdf6f7251e65dbb0d3ee.zip
Merge branch 'adamierymenko-dev' of ssh://earth.zerotier.net:55522/git/ZeroTierOne into adamierymenko-dev
-rw-r--r--node/IncomingPacket.cpp39
-rw-r--r--node/Network.cpp2
-rw-r--r--node/NetworkConfigMaster.cpp15
-rw-r--r--node/NetworkConfigMaster.hpp7
-rw-r--r--node/Node.cpp15
-rw-r--r--node/Peer.hpp26
-rw-r--r--testnet/MTQ.hpp2
-rw-r--r--version.h2
8 files changed, 98 insertions, 10 deletions
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index f5379458..8e6de0e9 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -123,6 +123,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
}
break;
+ case Packet::ERROR_UNSUPPORTED_OPERATION:
+ if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
+ SharedPtr<Network> network(RR->nc->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
+ if ((network)&&(network->controller() == source()))
+ network->setNotFound();
+ }
+ break;
+
case Packet::ERROR_IDENTITY_COLLISION:
// TODO: if it comes from a supernode, regenerate a new identity
// if (RR->topology->isSupernode(source())) {}
@@ -286,9 +294,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
// If a supernode has a version higher than ours, this causes a software
- // update check to run now. This might bum-rush download.zerotier.com, but
- // it's hosted on S3 so hopefully it can take it. This should cause updates
- // to propagate out very quickly.
+ // update check to run now.
if ((RR->updater)&&(RR->topology->isSupernode(peer->address())))
RR->updater->sawRemoteVersion(vMajor,vMinor,vRevision);
} break;
@@ -307,12 +313,33 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
case Packet::VERB_NETWORK_CONFIG_REQUEST: {
SharedPtr<Network> nw(RR->nc->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
if ((nw)&&(nw->controller() == source())) {
- // OK(NETWORK_CONFIG_REQUEST) is only accepted from a network's
- // controller.
unsigned int dictlen = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT_LEN);
std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen);
if (dict.length()) {
- nw->setConfiguration(Dictionary(dict));
+ if (nw->setConfiguration(Dictionary(dict)) == 2) { // 2 == accepted and actually new
+ /* If this configuration was indeed new, we do another
+ * netconf request with its timestamp. We do this in
+ * order to (a) tell the netconf server we got it (it
+ * won't send a duplicate if ts == current), and (b)
+ * get another one if the netconf is changing rapidly
+ * until we finally have the final version.
+ *
+ * Note that we don't do this for netconf masters with
+ * versions <= 1.0.3, since those regenerate a new netconf
+ * with a new timestamp every time. In that case this double
+ * confirmation would create a race condition. */
+ if (peer->atLeastVersion(1,0,3)) {
+ SharedPtr<NetworkConfig> nc(nw->config2());
+ if ((nc)&&(nc->timestamp() > 0)) { // sanity check
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append((uint64_t)nw->id());
+ outp.append((uint16_t)0); // no meta-data
+ outp.append((uint64_t)nc->timestamp());
+ outp.armor(peer->key(),true);
+ _fromSock->send(_remoteAddress,outp.data(),outp.size());
+ }
+ }
+ }
TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str());
}
}
diff --git a/node/Network.cpp b/node/Network.cpp
index df741026..aac8d5d6 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -274,7 +274,7 @@ int Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
{
Mutex::Lock _l(_lock);
if ((_config)&&(*_config == *newConfig))
- return 1; // OK but duplicate
+ return 1; // OK config, but duplicate of what we already have
}
if (applyConfiguration(newConfig)) {
if (saveToDisk) {
diff --git a/node/NetworkConfigMaster.cpp b/node/NetworkConfigMaster.cpp
index cbf7252c..3be2ad8c 100644
--- a/node/NetworkConfigMaster.cpp
+++ b/node/NetworkConfigMaster.cpp
@@ -94,8 +94,9 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
Utils::snprintf(nwKey,sizeof(nwKey),"zt1:network:%s:~",nwids);
Utils::snprintf(revKey,sizeof(revKey),"zt1:network:%s:revision",nwids);
- TRACE("netconf: request from %s for %s (if newer than %llu)",addrs,nwids,(unsigned long long)haveTimestamp);
+ TRACE("netconf: %s : %s if > %llu",nwids,addrs,(unsigned long long)haveTimestamp);
+ // Check to make sure network itself exists and is valid
if (!_hget(nwKey,"id",tmps2)) {
LOG("netconf: Redis error retrieving %s/id",nwKey);
return;
@@ -111,6 +112,7 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
return;
}
+ // Get network revision
if (!_get(revKey,revision)) {
LOG("netconf: Redis error retrieving %s",revKey);
return;
@@ -118,20 +120,26 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
if (!revision.length())
revision = "0";
+ // Get network member record for this peer
if (!_hgetall(memberKey,memberRecord)) {
LOG("netconf: Redis error retrieving %s",memberKey);
return;
}
+ // If there is no member record, init a new one -- for public networks this
+ // auto-authorizes, and for private nets it makes the peer show up in the UI
+ // so the admin can authorize or delete/hide it.
if ((memberRecord.size() == 0)||(memberRecord.get("id","") != addrs)||(memberRecord.get("nwid","") != nwids)) {
if (!_initNewMember(nwid,member,metaData,memberRecord))
return;
}
if (memberRecord.getBoolean("authorized")) {
+ // Get current netconf and netconf timestamp
uint64_t ts = memberRecord.getHexUInt("netconfTimestamp",0);
std::string netconf(memberRecord.get("netconf",""));
+ // Update statistics for this node
Dictionary upd;
upd.setHex("netconfClientTimestamp",haveTimestamp);
if (fromAddr)
@@ -139,11 +147,16 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
upd.setHex("lastSeen",Utils::now());
_hmset(memberKey,upd);
+ // Attempt to generate netconf for this node if there isn't
+ // one or it's not in step with the network's revision.
if (((ts == 0)||(netconf.length() == 0))||(memberRecord.get("netconfRevision","") != revision)) {
if (!_generateNetconf(nwid,member,metaData,netconf,ts))
return;
}
+ // If the netconf we have (or just generated) is newer than what
+ // the client reports that it has, send it. Otherwise we just
+ // ignore the message since the client is up to date.
if (ts > haveTimestamp) {
TRACE("netconf: sending %u bytes of netconf data to %s",netconf.length(),addrs);
Packet outp(member,RR->identity.address(),Packet::VERB_OK);
diff --git a/node/NetworkConfigMaster.hpp b/node/NetworkConfigMaster.hpp
index 25d5bb1c..c6993c56 100644
--- a/node/NetworkConfigMaster.hpp
+++ b/node/NetworkConfigMaster.hpp
@@ -30,6 +30,13 @@
#include "Constants.hpp"
+#define ZT_LOCAL_CONFIG_NETCONF_REDIS_HOST "netconf.redisHost"
+#define ZT_LOCAL_CONFIG_NETCONF_REDIS_PORT "netconf.redisPort"
+#define ZT_LOCAL_CONFIG_NETCONF_REDIS_PORT_DEFAULT 6379
+#define ZT_LOCAL_CONFIG_NETCONF_REDIS_AUTH "netconf.redisAuth"
+#define ZT_LOCAL_CONFIG_NETCONF_REDIS_DBNUM "netconf.redisDatabaseNumber"
+#define ZT_LOCAL_CONFIG_NETCONF_REDIS_DBNUM_DEFAULT 0
+
#ifdef ZT_ENABLE_NETCONF_MASTER
#include <stdint.h>
diff --git a/node/Node.cpp b/node/Node.cpp
index d65e4e39..b9f027e3 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -310,6 +310,21 @@ Node::ReasonForTermination Node::run()
}
RR->node = this;
+#ifdef ZT_ENABLE_NETCONF_MASTER
+ {
+ std::string redisHost(RR->nc->getLocalConfig(ZT_LOCAL_CONFIG_NETCONF_REDIS_HOST));
+ if (redisHost.length() > 0) {
+ unsigned int redisPort = Utils::strToUInt(RR->nc->getLocalConfig(ZT_LOCAL_CONFIG_NETCONF_REDIS_PORT).c_str());
+ if ((redisPort == 0)||(redisPort > 0xffff))
+ redisPort = ZT_LOCAL_CONFIG_NETCONF_REDIS_PORT_DEFAULT;
+ std::string redisAuth(RR->nc->getLocalConfig(ZT_LOCAL_CONFIG_NETCONF_REDIS_AUTH));
+ std::string redisDatabaseNumberStr(RR->nc->getLocalConfig(ZT_LOCAL_CONFIG_NETCONF_REDIS_DBNUM));
+ unsigned int redisDatabaseNumber = (redisDatabaseNumberStr.length() > 0) ? Utils::strToUInt(redisDatabaseNumberStr.c_str()) : (unsigned int)ZT_LOCAL_CONFIG_NETCONF_REDIS_DBNUM_DEFAULT;
+ RR->netconfMaster = new NetworkConfigMaster(RR,redisHost.c_str(),redisPort,redisAuth.c_str(),redisDatabaseNumber);
+ }
+ }
+#endif
+
#ifdef ZT_AUTO_UPDATE
if (ZT_DEFAULTS.updateLatestNfoURL.length()) {
RR->updater = new SoftwareUpdater(RR);
diff --git a/node/Peer.hpp b/node/Peer.hpp
index 142002a8..09bf0e04 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -341,6 +341,32 @@ public:
inline unsigned int remoteVersionMinor() const throw() { return _vMinor; }
inline unsigned int remoteVersionRevision() const throw() { return _vRevision; }
+ /**
+ * Check whether this peer's version is both known and is at least what is specified
+ *
+ * @param major Major version to check against
+ * @param minor Minor version
+ * @param rev Revision
+ * @return True if peer's version is at least supplied tuple
+ */
+ inline bool atLeastVersion(unsigned int major,unsigned int minor,unsigned int rev)
+ throw()
+ {
+ if ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)) {
+ if (_vMajor > major)
+ return true;
+ else if (_vMajor == major) {
+ if (_vMinor > minor)
+ return true;
+ else if (_vMinor == minor) {
+ if (_vRevision >= rev)
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
/**
diff --git a/testnet/MTQ.hpp b/testnet/MTQ.hpp
index 2a2fe1cd..c2f53e21 100644
--- a/testnet/MTQ.hpp
+++ b/testnet/MTQ.hpp
@@ -1,6 +1,6 @@
/*
* ZeroTier One - Global Peer to Peer Ethernet
- * Copyright (C) 2012-2014 ZeroTier Networks LLC
+ * Copyright (C) 2011-2015 ZeroTier Networks LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/version.h b/version.h
index 60e058df..fabfa384 100644
--- a/version.h
+++ b/version.h
@@ -41,6 +41,6 @@
/**
* Revision
*/
-#define ZEROTIER_ONE_VERSION_REVISION 2
+#define ZEROTIER_ONE_VERSION_REVISION 3
#endif