Bladeren bron

(1) distribute default root-topology in new dictionary format, (2) bump peer serialization version to force obsolescence of old supernodes, (3) stop outputting a log message every time we poll for software updates

Adam Ierymenko 11 jaren geleden
bovenliggende
commit
c2187c8759
10 gewijzigde bestanden met toevoegingen van 109 en 63 verwijderingen
  1. 31 54
      node/Defaults.cpp
  2. 12 2
      node/Defaults.hpp
  3. 8 0
      node/Dictionary.cpp
  4. 12 0
      node/Dictionary.hpp
  5. 13 3
      node/Node.cpp
  6. 1 1
      node/Peer.hpp
  7. 1 1
      node/SoftwareUpdater.cpp
  8. 20 0
      node/Topology.cpp
  9. 11 1
      node/Topology.hpp
  10. 0 1
      root-topology/root-topology-authority.public

+ 31 - 54
node/Defaults.cpp

@@ -33,6 +33,9 @@
 #include "Defaults.hpp"
 #include "Utils.hpp"
 
+// bin2c'd signed default root topology dictionary
+#include "../root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c"
+
 #ifdef __WINDOWS__
 #include <WinSock2.h>
 #include <Windows.h>
@@ -43,58 +46,6 @@ namespace ZeroTier {
 
 const Defaults ZT_DEFAULTS;
 
-static inline std::map< Identity,std::vector< std::pair<InetAddress,bool> > > _mkSupernodeMap()
-{
-	std::map< Identity,std::vector< std::pair<InetAddress,bool> > > sn;
-	Identity id;
-	std::vector< std::pair<InetAddress,bool> > addrs;
-
-	// Nothing special about a supernode... except that they are
-	// designated as such and trusted to provide WHOIS lookup.
-
-	// cthulhu.zerotier.com - New York, New York, USA
-	addrs.clear();
-	if (!id.fromString("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"))
-		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("162.243.77.111",ZT_DEFAULT_UDP_PORT),false));
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("162.243.77.111",443),true));
-	sn[id] = addrs;
-
-	// nyarlathotep.zerotier.com - San Francisco, California, USA
-	addrs.clear();
-	if (!id.fromString("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"))
-		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("198.199.97.220",ZT_DEFAULT_UDP_PORT),false));
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("198.199.97.220",443),true));
-	sn[id] = addrs;
-
-	// shub-niggurath.zerotier.com - Amsterdam, Netherlands
-	addrs.clear();
-	if (!id.fromString("36f63d6574:0:67a776487a1a99b32f413329f2b67c43fbf6152e42c6b66e89043e69d93e48314c7d709b58a83016bd2612dd89400b856e18c553da94892f7d3ca16bf2c92c24"))
-		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("198.211.127.172",ZT_DEFAULT_UDP_PORT),false));
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("198.211.127.172",443),true));
-	sn[id] = addrs;
-
-	// yig.zerotier.com - Sydney, Australia
-	addrs.clear();
-	if (!id.fromString("275f0151f6:0:58716258283f7e14a2f999875d9cc681c1f0ca8403dce38ec354ceaf284a555f36402e79a32d03b8c0963245b7f1af61a1ad3519d90e05bc3ce591034f6a1c9c"))
-		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("108.61.212.61",ZT_DEFAULT_UDP_PORT),false));
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("108.61.212.61",443),true));
-	sn[id] = addrs;
-
-	// shoggoth.zerotier.com - Tokyo, Japan
-	addrs.clear();
-	if (!id.fromString("48e8f875cb:0:5ca54f55e1094f65589f3e6d74158b6964d418ddac3570757128f1c6a2498322d92fcdcd47de459f4d1f9b38df2afd0c7b3fc247ba3d773c38ba35288f24988e"))
-		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("108.61.200.101",ZT_DEFAULT_UDP_PORT),false));
-	addrs.push_back(std::pair<InetAddress,bool>(InetAddress("108.61.200.101",443),true));
-	sn[id] = addrs;
-
-	return sn;
-}
-
 static inline std::string _mkDefaultHomePath()
 {
 #ifdef __UNIX_LIKE__
@@ -113,12 +64,36 @@ static inline std::string _mkDefaultHomePath()
 		return (std::string(buf) + "\\ZeroTier\\One");
 	else return std::string("C:\\ZeroTier\\One");
 #else
-	// unknown platform
+#error Unknown platform, please define a default home path!
 #endif
 
 #endif // __UNIX_LIKE__ or not...
 }
 
+static inline std::map< Address,Identity > _mkRootTopologyAuth()
+{
+	std::map< Address,Identity > ua;
+
+	{ // 0001
+		Identity id("77792b1c02:0:b5c361e8e9c2154e82c3e902fdfc337468b092a7c4d8dc685c37eb10ee4f3c17cc0bb1d024167e8cb0824d12263428373582da3d0a9a14b36e4546c317e811e6");
+		ua[id.address()] = id;
+	}
+	{ // 0002
+		Identity id("86921e6de1:0:9ba04f9f12ed54ef567f548cb69d31e404537d7b0ee000c63f3d7c8d490a1a47a5a5b2af0cbe12d23f9194270593f298d936d7c872612ea509ef1c67ce2c7fc1");
+		ua[id.address()] = id;
+	}
+	{ // 0003
+		Identity id("90302b7025:0:358154a57af1b7afa07d0d91b69b92eaad2f11ade7f02343861f0c1b757d15626e8cb7f08fc52993d2202a39cbf5128c5647ee8c63d27d92db5a1d0fbe1eba19");
+		ua[id.address()] = id;
+	}
+	{ // 0004
+		Identity id("e5174078ee:0:c3f90daa834a74ee47105f5726ae2e29fc8ae0e939c9326788b52b16d847354de8de3b13a81896bbb509b91e1da21763073a30bbfb2b8e994550798d30a2d709");
+		ua[id.address()] = id;
+	}
+
+	return ua;
+}
+
 static inline std::map< Address,Identity > _mkUpdateAuth()
 {
 	std::map< Address,Identity > ua;
@@ -172,9 +147,11 @@ Defaults::Defaults() :
 	multicastTraceWatcher(ZT_TRACE_MULTICAST),
 #endif
 	defaultHomePath(_mkDefaultHomePath()),
-	supernodes(_mkSupernodeMap()),
+	defaultRootTopology((const char *)ZT_DEFAULT_ROOT_TOPOLOGY,ZT_DEFAULT_ROOT_TOPOLOGY_LEN),
+	rootTopologyAuthorities(_mkRootTopologyAuth()),
 	updateAuthorities(_mkUpdateAuth()),
 	updateLatestNfoURL(_mkUpdateUrl()),
+	rootTopologyUpdateURL("http://download.zerotier.com/net/topology/ROOT"),
 	v4Broadcast(((uint32_t)0xffffffff),ZT_DEFAULT_UDP_PORT)
 {
 }

+ 12 - 2
node/Defaults.hpp

@@ -64,9 +64,14 @@ public:
 	const std::string defaultHomePath;
 
 	/**
-	 * Supernodes on the ZeroTier network (identity, address/tcp?)
+	 * Default root topology dictionary
 	 */
-	const std::map< Identity,std::vector< std::pair<InetAddress,bool> > > supernodes;
+	const std::string defaultRootTopology;
+
+	/**
+	 * Identities permitted to sign root topology dictionaries
+	 */
+	const std::map< Address,Identity > rootTopologyAuthorities;
 
 	/**
 	 * Identities permitted to sign software updates
@@ -84,6 +89,11 @@ public:
 	 */
 	const std::string updateLatestNfoURL;
 
+	/**
+	 * URL to check for updates to root topology
+	 */
+	const std::string rootTopologyUpdateURL;
+
 	/**
 	 * Address for IPv4 LAN auto-location broadcasts: 255.255.255.255:9993
 	 */

+ 8 - 0
node/Dictionary.cpp

@@ -116,6 +116,14 @@ bool Dictionary::verify(const Identity &id) const
 	}
 }
 
+uint64_t Dictionary::signatureTimestamp() const
+{
+	const_iterator ts(find(ZT_DICTIONARY_SIGNATURE_TIMESTAMP));
+	if (ts == end())
+		return 0;
+	return Utils::hexStrToU64(ts->second.c_str());
+}
+
 void Dictionary::_mkSigBuf(std::string &buf) const
 {
 	unsigned long pairs = 0;

+ 12 - 0
node/Dictionary.hpp

@@ -28,6 +28,8 @@
 #ifndef ZT_DICTIONARY_HPP
 #define ZT_DICTIONARY_HPP
 
+#include <stdint.h>
+
 #include <string>
 #include <map>
 #include <stdexcept>
@@ -140,6 +142,16 @@ public:
 	 */
 	inline bool hasSignature() const { return (find(ZT_DICTIONARY_SIGNATURE) != end()); }
 
+	/**
+	 * @return Signing identity in string-serialized format or empty string if none
+	 */
+	inline std::string signingIdentity() const { return get(ZT_DICTIONARY_SIGNATURE_IDENTITY,std::string()); }
+
+	/**
+	 * @return Signature timestamp in milliseconds since epoch or 0 if none
+	 */
+	uint64_t signatureTimestamp() const;
+
 	/**
 	 * Remove any signature from this dictionary
 	 */

+ 13 - 3
node/Node.cpp

@@ -466,7 +466,6 @@ Node::ReasonForTermination Node::run()
 #endif
 		}
 
-		// Load or generate config authentication secret
 		std::string configAuthTokenPath(_r->homePath + ZT_PATH_SEPARATOR_S + "authtoken.secret");
 		std::string configAuthToken;
 		if (!Utils::readFile(configAuthTokenPath.c_str(),configAuthToken)) {
@@ -501,8 +500,19 @@ Node::ReasonForTermination Node::run()
 		}
 #endif
 
-		// Set initial supernode list
-		_r->topology->setSupernodes(ZT_DEFAULTS.supernodes);
+		std::string rootTopologyPath(_r->homePath + ZT_PATH_SEPARATOR_S + "root-topology");
+		std::string rootTopology;
+		if (!Utils::readFile(rootTopologyPath.c_str(),rootTopology))
+			rootTopology = ZT_DEFAULTS.defaultRootTopology;
+		try {
+			Dictionary rt(rootTopology);
+			if (!Topology::authenticateRootTopology(rt))
+				return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"root-topology failed signature verification check");
+			Dictionary supernodes(rt.get("supernodes"));
+			_r->topology->setSupernodes(supernodes);
+		} catch ( ... ) {
+			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"invalid root-topology format");
+		}
 	} catch (std::bad_alloc &exc) {
 		return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure");
 	} catch (std::runtime_error &exc) {

+ 1 - 1
node/Peer.hpp

@@ -50,7 +50,7 @@
 #include "NonCopyable.hpp"
 #include "Mutex.hpp"
 
-#define ZT_PEER_SERIALIZATION_VERSION 9
+#define ZT_PEER_SERIALIZATION_VERSION 10
 
 namespace ZeroTier {
 

+ 1 - 1
node/SoftwareUpdater.cpp

@@ -165,7 +165,7 @@ void SoftwareUpdater::_cbHandleGetLatestVersionInfo(void *arg,int code,const std
 
 #ifndef ZT_ALWAYS_UPDATE /* for testing */
 		if (packVersion(vMajor,vMinor,vRevision) <= upd->_myVersion) {
-			LOG("software update check complete: version on update site is not newer than my version, no update necessary");
+			TRACE("software update check complete: version on update site is not newer than my version, no update necessary");
 			upd->_status = UPDATE_STATUS_IDLE;
 			return;
 		}

+ 20 - 0
node/Topology.cpp

@@ -27,6 +27,8 @@
 
 #include <algorithm>
 
+#include "Constants.hpp"
+#include "Defaults.hpp"
 #include "Topology.hpp"
 #include "NodeConfig.hpp"
 #include "CMWC4096.hpp"
@@ -239,6 +241,24 @@ void Topology::clean()
 	}
 }
 
+bool Topology::authenticateRootTopology(const Dictionary &rt)
+{
+	try {
+		std::string signer(rt.signingIdentity());
+		if (!signer.length())
+			return false;
+		Identity signerId(signer);
+		std::map< Address,Identity >::const_iterator authority(ZT_DEFAULTS.rootTopologyAuthorities.find(signerId.address()));
+		if (authority == ZT_DEFAULTS.rootTopologyAuthorities.end())
+			return false;
+		if (signerId != authority->second)
+			return false;
+		return rt.verify(authority->second);
+	} catch ( ... ) {
+		return false;
+	}
+}
+
 void Topology::_dumpPeers()
 {
 	Buffer<ZT_PEER_WRITE_BUF_SIZE> buf;

+ 11 - 1
node/Topology.hpp

@@ -37,18 +37,20 @@
 #include <stdexcept>
 
 #include "Constants.hpp"
+
 #include "Address.hpp"
+#include "Identity.hpp"
 #include "Peer.hpp"
 #include "Mutex.hpp"
 #include "InetAddress.hpp"
 #include "Utils.hpp"
 #include "Packet.hpp"
 #include "Logger.hpp"
+#include "Dictionary.hpp"
 
 namespace ZeroTier {
 
 class RuntimeEnvironment;
-class Dictionary;
 
 /**
  * Database of network topology
@@ -370,6 +372,14 @@ public:
 		std::vector< SharedPtr<Peer> > &_v;
 	};
 
+	/**
+	 * Validate a root topology dictionary against the identities specified in Defaults
+	 *
+	 * @param rt Root topology dictionary
+	 * @return True if dictionary signature is valid
+	 */
+	static bool authenticateRootTopology(const Dictionary &rt);
+
 private:
 	const RuntimeEnvironment *const _r;
 

+ 0 - 1
root-topology/root-topology-authority.public

@@ -1 +0,0 @@
-77792b1c02:0:b5c361e8e9c2154e82c3e902fdfc337468b092a7c4d8dc685c37eb10ee4f3c17cc0bb1d024167e8cb0824d12263428373582da3d0a9a14b36e4546c317e811e6