From c2187c87599c60b9c47dd9d01244ce1ffd105fea Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 14 Aug 2014 19:52:22 -0400 Subject: (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 --- node/Defaults.cpp | 85 ++++++++++------------------ node/Defaults.hpp | 14 ++++- node/Dictionary.cpp | 8 +++ node/Dictionary.hpp | 12 ++++ node/Node.cpp | 16 +++++- node/Peer.hpp | 2 +- node/SoftwareUpdater.cpp | 2 +- node/Topology.cpp | 20 +++++++ node/Topology.hpp | 12 +++- root-topology/root-topology-authority.public | 1 - 10 files changed, 109 insertions(+), 63 deletions(-) delete mode 100644 root-topology/root-topology-authority.public diff --git a/node/Defaults.cpp b/node/Defaults.cpp index 9176a414..8144034c 100644 --- a/node/Defaults.cpp +++ b/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 #include @@ -43,58 +46,6 @@ namespace ZeroTier { const Defaults ZT_DEFAULTS; -static inline std::map< Identity,std::vector< std::pair > > _mkSupernodeMap() -{ - std::map< Identity,std::vector< std::pair > > sn; - Identity id; - std::vector< std::pair > 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("162.243.77.111",ZT_DEFAULT_UDP_PORT),false)); - addrs.push_back(std::pair(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("198.199.97.220",ZT_DEFAULT_UDP_PORT),false)); - addrs.push_back(std::pair(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("198.211.127.172",ZT_DEFAULT_UDP_PORT),false)); - addrs.push_back(std::pair(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("108.61.212.61",ZT_DEFAULT_UDP_PORT),false)); - addrs.push_back(std::pair(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("108.61.200.101",ZT_DEFAULT_UDP_PORT),false)); - addrs.push_back(std::pair(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) { } diff --git a/node/Defaults.hpp b/node/Defaults.hpp index 98110ac7..869707b4 100644 --- a/node/Defaults.hpp +++ b/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 > > 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 */ diff --git a/node/Dictionary.cpp b/node/Dictionary.cpp index 50440e5b..6c47b0ea 100644 --- a/node/Dictionary.cpp +++ b/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; diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index 22eb8a7e..35e93e43 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -28,6 +28,8 @@ #ifndef ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP +#include + #include #include #include @@ -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 */ diff --git a/node/Node.cpp b/node/Node.cpp index 7500e736..e031dbdb 100644 --- a/node/Node.cpp +++ b/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) { diff --git a/node/Peer.hpp b/node/Peer.hpp index ce0b79a6..d3c3669b 100644 --- a/node/Peer.hpp +++ b/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 { diff --git a/node/SoftwareUpdater.cpp b/node/SoftwareUpdater.cpp index 8a9714fc..e34fd3ca 100644 --- a/node/SoftwareUpdater.cpp +++ b/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; } diff --git a/node/Topology.cpp b/node/Topology.cpp index 4fae1372..6fcb17af 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -27,6 +27,8 @@ #include +#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 buf; diff --git a/node/Topology.hpp b/node/Topology.hpp index 37511208..478b4fc3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -37,18 +37,20 @@ #include #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 > &_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; diff --git a/root-topology/root-topology-authority.public b/root-topology/root-topology-authority.public deleted file mode 100644 index 7897b616..00000000 --- a/root-topology/root-topology-authority.public +++ /dev/null @@ -1 +0,0 @@ -77792b1c02:0:b5c361e8e9c2154e82c3e902fdfc337468b092a7c4d8dc685c37eb10ee4f3c17cc0bb1d024167e8cb0824d12263428373582da3d0a9a14b36e4546c317e811e6 \ No newline at end of file -- cgit v1.2.3