Browse Source

Merge branch 'adamierymenko-dev' of ssh://earth.zerotier.net:55522/git/ZeroTierOne into adamierymenko-dev

Adam Ierymenko 10 years ago
parent
commit
fbc6ca28b7
8 changed files with 98 additions and 10 deletions
  1. 33 6
      node/IncomingPacket.cpp
  2. 1 1
      node/Network.cpp
  3. 14 1
      node/NetworkConfigMaster.cpp
  4. 7 0
      node/NetworkConfigMaster.hpp
  5. 15 0
      node/Node.cpp
  6. 26 0
      node/Peer.hpp
  7. 1 1
      testnet/MTQ.hpp
  8. 1 1
      version.h

+ 33 - 6
node/IncomingPacket.cpp

@@ -123,6 +123,14 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 				}
 				}
 				break;
 				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:
 			case Packet::ERROR_IDENTITY_COLLISION:
 				// TODO: if it comes from a supernode, regenerate a new identity
 				// TODO: if it comes from a supernode, regenerate a new identity
 				// if (RR->topology->isSupernode(source())) {}
 				// 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);
 				peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
 
 
 				// If a supernode has a version higher than ours, this causes a software
 				// 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())))
 				if ((RR->updater)&&(RR->topology->isSupernode(peer->address())))
 					RR->updater->sawRemoteVersion(vMajor,vMinor,vRevision);
 					RR->updater->sawRemoteVersion(vMajor,vMinor,vRevision);
 			}	break;
 			}	break;
@@ -307,12 +313,33 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
 			case Packet::VERB_NETWORK_CONFIG_REQUEST: {
 			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)));
 				SharedPtr<Network> nw(RR->nc->network(at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_NETWORK_ID)));
 				if ((nw)&&(nw->controller() == source())) {
 				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);
 					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);
 					std::string dict((const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST__OK__IDX_DICT,dictlen),dictlen);
 					if (dict.length()) {
 					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());
 						TRACE("got network configuration for network %.16llx from %s",(unsigned long long)nw->id(),source().toString().c_str());
 					}
 					}
 				}
 				}

+ 1 - 1
node/Network.cpp

@@ -274,7 +274,7 @@ int Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
 		{
 		{
 			Mutex::Lock _l(_lock);
 			Mutex::Lock _l(_lock);
 			if ((_config)&&(*_config == *newConfig))
 			if ((_config)&&(*_config == *newConfig))
-				return 1; // OK but duplicate
+				return 1; // OK config, but duplicate of what we already have
 		}
 		}
 		if (applyConfiguration(newConfig)) {
 		if (applyConfiguration(newConfig)) {
 			if (saveToDisk) {
 			if (saveToDisk) {

+ 14 - 1
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(nwKey,sizeof(nwKey),"zt1:network:%s:~",nwids);
 	Utils::snprintf(revKey,sizeof(revKey),"zt1:network:%s:revision",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)) {
 	if (!_hget(nwKey,"id",tmps2)) {
 		LOG("netconf: Redis error retrieving %s/id",nwKey);
 		LOG("netconf: Redis error retrieving %s/id",nwKey);
 		return;
 		return;
@@ -111,6 +112,7 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
 		return;
 		return;
 	}
 	}
 
 
+	// Get network revision
 	if (!_get(revKey,revision)) {
 	if (!_get(revKey,revision)) {
 		LOG("netconf: Redis error retrieving %s",revKey);
 		LOG("netconf: Redis error retrieving %s",revKey);
 		return;
 		return;
@@ -118,20 +120,26 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
 	if (!revision.length())
 	if (!revision.length())
 		revision = "0";
 		revision = "0";
 
 
+	// Get network member record for this peer
 	if (!_hgetall(memberKey,memberRecord)) {
 	if (!_hgetall(memberKey,memberRecord)) {
 		LOG("netconf: Redis error retrieving %s",memberKey);
 		LOG("netconf: Redis error retrieving %s",memberKey);
 		return;
 		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 ((memberRecord.size() == 0)||(memberRecord.get("id","") != addrs)||(memberRecord.get("nwid","") != nwids)) {
 		if (!_initNewMember(nwid,member,metaData,memberRecord))
 		if (!_initNewMember(nwid,member,metaData,memberRecord))
 			return;
 			return;
 	}
 	}
 
 
 	if (memberRecord.getBoolean("authorized")) {
 	if (memberRecord.getBoolean("authorized")) {
+		// Get current netconf and netconf timestamp
 		uint64_t ts = memberRecord.getHexUInt("netconfTimestamp",0);
 		uint64_t ts = memberRecord.getHexUInt("netconfTimestamp",0);
 		std::string netconf(memberRecord.get("netconf",""));
 		std::string netconf(memberRecord.get("netconf",""));
 
 
+		// Update statistics for this node
 		Dictionary upd;
 		Dictionary upd;
 		upd.setHex("netconfClientTimestamp",haveTimestamp);
 		upd.setHex("netconfClientTimestamp",haveTimestamp);
 		if (fromAddr)
 		if (fromAddr)
@@ -139,11 +147,16 @@ void NetworkConfigMaster::doNetworkConfigRequest(const InetAddress &fromAddr,uin
 		upd.setHex("lastSeen",Utils::now());
 		upd.setHex("lastSeen",Utils::now());
 		_hmset(memberKey,upd);
 		_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 (((ts == 0)||(netconf.length() == 0))||(memberRecord.get("netconfRevision","") != revision)) {
 			if (!_generateNetconf(nwid,member,metaData,netconf,ts))
 			if (!_generateNetconf(nwid,member,metaData,netconf,ts))
 				return;
 				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) {
 		if (ts > haveTimestamp) {
 			TRACE("netconf: sending %u bytes of netconf data to %s",netconf.length(),addrs);
 			TRACE("netconf: sending %u bytes of netconf data to %s",netconf.length(),addrs);
 			Packet outp(member,RR->identity.address(),Packet::VERB_OK);
 			Packet outp(member,RR->identity.address(),Packet::VERB_OK);

+ 7 - 0
node/NetworkConfigMaster.hpp

@@ -30,6 +30,13 @@
 
 
 #include "Constants.hpp"
 #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
 #ifdef ZT_ENABLE_NETCONF_MASTER
 
 
 #include <stdint.h>
 #include <stdint.h>

+ 15 - 0
node/Node.cpp

@@ -310,6 +310,21 @@ Node::ReasonForTermination Node::run()
 		}
 		}
 		RR->node = this;
 		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
 #ifdef ZT_AUTO_UPDATE
 		if (ZT_DEFAULTS.updateLatestNfoURL.length()) {
 		if (ZT_DEFAULTS.updateLatestNfoURL.length()) {
 			RR->updater = new SoftwareUpdater(RR);
 			RR->updater = new SoftwareUpdater(RR);

+ 26 - 0
node/Peer.hpp

@@ -341,6 +341,32 @@ public:
 	inline unsigned int remoteVersionMinor() const throw() { return _vMinor; }
 	inline unsigned int remoteVersionMinor() const throw() { return _vMinor; }
 	inline unsigned int remoteVersionRevision() const throw() { return _vRevision; }
 	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)); }
 	inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
 
 
 	/**
 	/**

+ 1 - 1
testnet/MTQ.hpp

@@ -1,6 +1,6 @@
 /*
 /*
  * ZeroTier One - Global Peer to Peer Ethernet
  * 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
  * 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
  * it under the terms of the GNU General Public License as published by

+ 1 - 1
version.h

@@ -41,6 +41,6 @@
 /**
 /**
  * Revision
  * Revision
  */
  */
-#define ZEROTIER_ONE_VERSION_REVISION 2
+#define ZEROTIER_ONE_VERSION_REVISION 3
 
 
 #endif
 #endif