From ae138566a94ed407c71dbc7a155c810b2389cc4b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Nov 2013 12:38:38 -0400 Subject: Updater code, work in progress... --- node/Defaults.hpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'node/Defaults.hpp') diff --git a/node/Defaults.hpp b/node/Defaults.hpp index 5f870194..b0eb40e5 100644 --- a/node/Defaults.hpp +++ b/node/Defaults.hpp @@ -67,6 +67,11 @@ public: * Supernodes on the ZeroTier network */ const std::map< Identity,std::vector > supernodes; + + /** + * Identities permitted to sign software updates + */ + const std::map< Address,Identity > updateAuthorities; }; extern const Defaults ZT_DEFAULTS; -- cgit v1.2.3 From 6c63bfce69f0b0087526879f49d36071ddc4b9d9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 4 Nov 2013 17:31:00 -0500 Subject: File transfer work, add identities for validation of updates. --- node/Defaults.cpp | 27 ++++++- node/Defaults.hpp | 6 ++ node/Packet.hpp | 12 ++- node/Updater.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++--- node/Updater.hpp | 138 ++++++++++++++++++++-------------- node/Utils.cpp | 2 +- 6 files changed, 329 insertions(+), 72 deletions(-) (limited to 'node/Defaults.hpp') diff --git a/node/Defaults.cpp b/node/Defaults.cpp index 35a677f2..cfc901b5 100644 --- a/node/Defaults.cpp +++ b/node/Defaults.cpp @@ -98,12 +98,37 @@ static inline std::string _mkDefaultHomePath() #endif } +static inline std::map< Address,Identity > _mkUpdateAuth() +{ + std::map< Address,Identity > ua; + + { // 0001 + Identity id("e9bc3707b5:0:c4cef17bde99eadf9748c4fd11b9b06dc5cd8eb429227811d2c336e6b96a8d329e8abd0a4f45e47fe1bcebf878c004c822d952ff77fc2833af4c74e65985c435"); + ua[id.address()] = id; + } + { // 0002 + Identity id("56520eaf93:0:7d858b47988b34399a9a31136de07b46104d7edb4a98fa1d6da3e583d3a33e48be531532b886f0b12cd16794a66ab9220749ec5112cbe96296b18fe0cc79ca05"); + ua[id.address()] = id; + } + { // 0003 + Identity id("7c195de2e0:0:9f659071c960f9b0f0b96f9f9ecdaa27c7295feed9c79b7db6eedcc11feb705e6dd85c70fa21655204d24c897865b99eb946b753a2bbcf2be5f5e006ae618c54"); + ua[id.address()] = id; + } + { // 0004 + Identity id("415f4cfde7:0:54118e87777b0ea5d922c10b337c4f4bd1db7141845bd54004b3255551a6e356ba6b9e1e85357dbfafc45630b8faa2ebf992f31479e9005f0472685f2d8cbd6e"); + ua[id.address()] = id; + } + + return ua; +} + Defaults::Defaults() : #ifdef ZT_TRACE_MULTICAST multicastTraceWatcher(ZT_TRACE_MULTICAST), #endif defaultHomePath(_mkDefaultHomePath()), - supernodes(_mkSupernodeMap()) + supernodes(_mkSupernodeMap()), + updateAuthorities(_mkUpdateAuth()) { } diff --git a/node/Defaults.hpp b/node/Defaults.hpp index b0eb40e5..dac59ae6 100644 --- a/node/Defaults.hpp +++ b/node/Defaults.hpp @@ -70,6 +70,12 @@ public: /** * Identities permitted to sign software updates + * + * ZTN can keep multiple signing identities and rotate them, keeping some in + * "cold storage" and obsoleting others gradually. + * + * If you don't build with ZT_OFFICIAL_BUILD, this isn't used since your + * build will not auto-update. */ const std::map< Address,Identity > updateAuthorities; }; diff --git a/node/Packet.hpp b/node/Packet.hpp index 05c6f3a4..d476e89e 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -619,12 +619,12 @@ public: /* Request information about a shared file (for software updates): * <[1] flags, currently unused and must be 0> - * <[2] 16-bit length of filename> + * <[1] 8-bit length of filename> * <[...] name of file being requested> * * OK response payload (indicates that we have and will share): * <[1] flags, currently unused and must be 0> - * <[2] 16-bit length of filename> + * <[1] 8-bit length of filename> * <[...] name of file being requested> * <[64] full length SHA-512 hash of file contents> * <[4] 32-bit length of file in bytes> @@ -636,6 +636,10 @@ public: * <[2] 16-bit length of filename> * <[...] name of file being requested> * + * This is used for distribution of software updates and in the future may + * be used for anything else that needs to be globally distributed. It + * is not designed for end-user use for other purposes. + * * Support is optional. Nodes should return UNSUPPORTED_OPERATION if * not supported or enabled. */ @@ -657,6 +661,10 @@ public: * <[4] 32-bit index of desired chunk> * <[2] 16-bit length of desired chunk> * + * This is used for distribution of software updates and in the future may + * be used for anything else that needs to be globally distributed. It + * is not designed for end-user use for other purposes. + * * Support is optional. Nodes should return UNSUPPORTED_OPERATION if * not supported or enabled. */ diff --git a/node/Updater.cpp b/node/Updater.cpp index 10ac6096..1eefa7a4 100644 --- a/node/Updater.cpp +++ b/node/Updater.cpp @@ -31,6 +31,8 @@ #include "Defaults.hpp" #include "Utils.hpp" #include "Topology.hpp" +#include "Switch.hpp" +#include "SHA512.hpp" #include "../version.h" @@ -69,8 +71,9 @@ void Updater::refreshShared() if (Utils::readFile(nfoPath.c_str(),buf)) { Dictionary nfo(buf); - _Shared shared; - shared.filename = fullPath; + SharedUpdate shared; + shared.fullPath = fullPath; + shared.filename = u->first; std::string sha512(Utils::unhex(nfo.get("sha512",std::string()))); if (sha512.length() < sizeof(shared.sha512)) { @@ -104,9 +107,7 @@ void Updater::refreshShared() } shared.size = (unsigned long)fs; - Array first16Bytes; - memcpy(first16Bytes.data,sha512.data(),16); - _sharedUpdates[first16Bytes] = shared; + _sharedUpdates.push_back(shared); } else { TRACE("skipped shareable update due to missing companion .nfo: %s",fullPath.c_str()); continue; @@ -127,9 +128,9 @@ void Updater::getUpdateIfThisIsNewer(unsigned int vMajor,unsigned int vMinor,uns } } - std::string updateFilename(generateUpdateFilename()); + std::string updateFilename(generateUpdateFilename(vMajor,vMinor,revision)); if (!updateFilename.length()) { - TRACE("a new update to %u.%u.%u is available, but this platform doesn't support auto updates",vMajor,vMinor,revision); + TRACE("an update to %u.%u.%u is available, but this platform or build doesn't support auto-update",vMajor,vMinor,revision); return; } @@ -138,11 +139,8 @@ void Updater::getUpdateIfThisIsNewer(unsigned int vMajor,unsigned int vMinor,uns TRACE("new update available to %u.%u.%u, looking for %s from %u peers",vMajor,vMinor,revision,updateFilename.c_str(),(unsigned int)peers.size()); - if (!peers.size()) - return; - for(std::vector< SharedPtr >::iterator p(peers.begin());p!=peers.end();++p) { - Packet outp(p->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST); + Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST); outp.append((unsigned char)0); outp.append((uint16_t)updateFilename.length()); outp.append(updateFilename.data(),updateFilename.length()); @@ -152,14 +150,167 @@ void Updater::getUpdateIfThisIsNewer(unsigned int vMajor,unsigned int vMinor,uns void Updater::retryIfNeeded() { + Mutex::Lock _l(_lock); + + if (_download) { + uint64_t elapsed = Utils::now() - _download->lastChunkReceivedAt; + if ((elapsed >= ZT_UPDATER_PEER_TIMEOUT)||(!_download->currentlyReceivingFrom)) { + if (_download->peersThatHave.empty()) { + // Search for more sources if we have no more possibilities queued + _download->currentlyReceivingFrom.zero(); + + std::vector< SharedPtr > peers; + _r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(peers,Utils::now())); + + for(std::vector< SharedPtr >::iterator p(peers.begin());p!=peers.end();++p) { + Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST); + outp.append((unsigned char)0); + outp.append((uint16_t)_download->filename.length()); + outp.append(_download->filename.data(),_download->filename.length()); + _r->sw->send(outp,true); + } + } else { + // If that peer isn't answering, try the next queued source + _download->currentlyReceivingFrom = _download->peersThatHave.front(); + _download->peersThatHave.pop_front(); + } + } else if (elapsed >= ZT_UPDATER_RETRY_TIMEOUT) { + // Re-request next chunk we don't have from current source + _requestNextChunk(); + } + } } -void Updater::handleChunk(const void *sha512First16,unsigned long at,const void *chunk,unsigned long len) +void Updater::handleChunk(const Address &from,const void *sha512,unsigned int shalen,unsigned long at,const void *chunk,unsigned long len) { + Mutex::Lock _l(_lock); + + if (!_download) { + TRACE("got chunk from %s while no download is in progress, ignored",from.toString().c_str()); + return; + } + + if (memcmp(_download->sha512,sha512,(shalen > 64) ? 64 : shalen)) { + TRACE("got chunk from %s for wrong download (SHA mismatch), ignored",from.toString().c_str()); + return; + } + + unsigned long whichChunk = at / ZT_UPDATER_CHUNK_SIZE; + + if (at != (ZT_UPDATER_CHUNK_SIZE * whichChunk)) + return; // not at chunk boundary + if (whichChunk >= _download->haveChunks.size()) + return; // overflow + if ((whichChunk == (_download->haveChunks.size() - 1))&&(len != _download->lastChunkSize)) + return; // last chunk, size wrong + else if (len != ZT_UPDATER_CHUNK_SIZE) + return; // chunk size wrong + + for(unsigned long i=0;idata[at + i] = ((const char *)chunk)[i]; + + _download->haveChunks[whichChunk] = true; + _download->lastChunkReceivedAt = Utils::now(); + + _requestNextChunk(); +} + +void Updater::handleAvailable(const Address &from,const char *filename,const void *sha512,unsigned long filesize,const Address &signedBy,const void *signature,unsigned int siglen) +{ + unsigned int vMajor = 0,vMinor = 0,revision = 0; + if (!parseUpdateFilename(filename,vMajor,vMinor,revision)) { + TRACE("rejected offer of %s from %s: could not parse version information",filename,from.toString().c_str()); + return; + } + + if (filesize > ZT_UPDATER_MAX_SUPPORTED_SIZE) { + TRACE("rejected offer of %s from %s: file too large (%u)",filename,from.toString().c_str(),(unsigned int)filesize); + return; + } + + if (vMajor < ZEROTIER_ONE_VERSION_MAJOR) + return; + else if (vMajor == ZEROTIER_ONE_VERSION_MAJOR) { + if (vMinor < ZEROTIER_ONE_VERSION_MINOR) + return; + else if (vMinor == ZEROTIER_ONE_VERSION_MINOR) { + if (revision <= ZEROTIER_ONE_VERSION_REVISION) + return; + } + } + + Mutex::Lock _l(_lock); + + if (_download) { + // If a download is in progress, only accept this as another source if + // it matches the size, hash, and version. Also check if this is a newer + // version and if so replace download with this. + } else { + // If there is no download in progress, create one provided the signature + // for the SHA-512 hash verifies as being from a valid signer. + } +} + +bool Updater::findSharedUpdate(const char *filename,SharedUpdate &update) const +{ + Mutex::Lock _l(_lock); + for(std::list::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) { + if (u->filename == filename) { + update = *u; + return true; + } + } + return false; +} + +bool Updater::findSharedUpdate(const void *sha512,unsigned int shalen,SharedUpdate &update) const +{ + if (!shalen) + return false; + Mutex::Lock _l(_lock); + for(std::list::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) { + if (!memcmp(u->sha512,sha512,(shalen > 64) ? 64 : shalen)) { + update = *u; + return true; + } + } + return false; +} + +bool Updater::getSharedChunk(const void *sha512,unsigned int shalen,unsigned long at,void *chunk,unsigned long chunklen) const +{ + if (!chunklen) + return true; + if (!shalen) + return false; + Mutex::Lock _l(_lock); + for(std::list::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) { + if (!memcmp(u->sha512,sha512,(shalen > 64) ? 64 : shalen)) { + FILE *f = fopen(u->fullPath.c_str(),"rb"); + if (!f) + return false; + if (!fseek(f,(long)at,SEEK_SET)) { + fclose(f); + return false; + } + if (fread(chunk,chunklen,1,f) != 1) { + fclose(f); + return false; + } + fclose(f); + return true; + } + } + return false; } std::string Updater::generateUpdateFilename(unsigned int vMajor,unsigned int vMinor,unsigned int revision) { + // Defining ZT_OFFICIAL_BUILD enables this cascade of macros, which will + // make your build auto-update itself if it's for an officially supported + // architecture. The signing identity for auto-updates is in Defaults. +#ifdef ZT_OFFICIAL_BUILD + // Not supported... yet? Get it first cause it might identify as Linux too. #ifdef __ANDROID__ #define _updSupported 1 @@ -202,6 +353,10 @@ std::string Updater::generateUpdateFilename(unsigned int vMajor,unsigned int vMi #ifndef _updSupported return std::string(); #endif + +#else + return std::string(); +#endif // ZT_OFFICIAL_BUILD } bool Updater::parseUpdateFilename(const char *filename,unsigned int &vMajor,unsigned int &vMinor,unsigned int &revision) @@ -218,5 +373,42 @@ bool Updater::parseUpdateFilename(const char *filename,unsigned int &vMajor,unsi return true; } +void Updater::_requestNextChunk() +{ + // assumes _lock is locked + + if (!_download) + return; + + unsigned long whichChunk = 0; + std::vector::iterator ptr(std::find(_download->haveChunks.begin(),_download->haveChunks.end(),false)); + if (ptr == _download->haveChunks.end()) { + unsigned char digest[64]; + SHA512::hash(digest,_download->data.data(),_download->data.length()); + if (memcmp(digest,_download->sha512,64)) { + LOG("retrying download of %s -- SHA-512 mismatch, file corrupt!",_download->filename.c_str()); + std::fill(_download->haveChunks.begin(),_download->haveChunks.end(),false); + whichChunk = 0; + } else { + LOG("successfully downloaded and authenticated %s, launching update...",_download->filename.c_str()); + delete _download; + _download = (_Download *)0; + return; + } + } else { + whichChunk = std::distance(_download->haveChunks.begin(),ptr); + } + + TRACE("requesting chunk %u/%u of %s from %s",(unsigned int)whichChunk,(unsigned int)_download->haveChunks.size(),_download->filename.c_str()_download->currentlyReceivingFrom.toString().c_str()); + + Packet outp(_download->currentlyReceivingFrom,_r->identity.address(),Packet::VERB_FILE_BLOCK_REQUEST); + outp.append(_download->sha512,16); + outp.append((uint32_t)(whichChunk * ZT_UPDATER_CHUNK_SIZE)); + if (whichChunk == (_download->haveChunks.size() - 1)) + outp.append((uint16_t)_download->lastChunkSize); + else outp.append((uint16_t)ZT_UPDATER_CHUNK_SIZE); + _r->sw->send(outp,true); +} + } // namespace ZeroTier diff --git a/node/Updater.hpp b/node/Updater.hpp index 6a1c266b..1fdfdbee 100644 --- a/node/Updater.hpp +++ b/node/Updater.hpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "Constants.hpp" #include "Packet.hpp" @@ -55,10 +56,10 @@ #define ZT_UPDATER_MAX_SUPPORTED_SIZE (1024 * 1024 * 16) // Retry timeout in ms. -#define ZT_UPDATER_RETRY_TIMEOUT 30000 +#define ZT_UPDATER_RETRY_TIMEOUT 15000 -// After this long, look for a new set of peers that have the download shared. -#define ZT_UPDATER_REPOLL_TIMEOUT 60000 +// After this long, look for a new peer to download from +#define ZT_UPDATER_PEER_TIMEOUT 65000 namespace ZeroTier { @@ -67,10 +68,12 @@ class RuntimeEnvironment; /** * Software update downloader and executer * - * FYI: downloads occur via the protocol rather than out of band via http so + * Downloads occur via the ZT1 protocol rather than out of band via http so * that ZeroTier One can be run in secure jailed environments where it is the - * only protocol permitted over the "real" Internet. This is required for a - * number of potentially popular use cases. + * only protocol permitted over the "real" Internet. This is wanted for a + * number of potentially popular use cases, like private LANs that connect + * nodes in hostile environments or playing attack/defend on the future CTF + * network. * * The protocol is a simple chunk-pulling "trivial FTP" like thing that should * be suitable for core engine software updates. Software updates themselves @@ -84,6 +87,19 @@ class RuntimeEnvironment; class Updater { public: + /** + * Contains information about a shared update available to other peers + */ + struct SharedUpdate + { + std::string fullPath; + std::string filename; + unsigned char sha512[64]; + C25519::Signature sig; + Address signedBy; + unsigned long size; + }; + Updater(const RuntimeEnvironment *renv); ~Updater(); @@ -108,18 +124,72 @@ public: /** * Called periodically from main loop + * + * This retries downloads if they're stalled and performs other cleanup. */ void retryIfNeeded(); /** * Called when a chunk is received * - * @param sha512First16 First 16 bytes of SHA-512 hash + * If the chunk is a final chunk and we now have an update, this may result + * in the commencement of the update process and the shutdown of ZT1. + * + * @param from Originating peer + * @param sha512 Up to 64 bytes of hash to match + * @param shalen Length of sha512[] * @param at Position of chunk * @param chunk Chunk data * @param len Length of chunk */ - void handleChunk(const void *sha512First16,unsigned long at,const void *chunk,unsigned long len); + void handleChunk(const Address &from,const void *sha512,unsigned int shalen,unsigned long at,const void *chunk,unsigned long len); + + /** + * Called when a reply to a search for an update is received + * + * This checks SHA-512 hash signature and version as parsed from filename + * before starting the transfer. + * + * @param from Node that sent reply saying it has the file + * @param filename Name of file (can be parsed for version info) + * @param sha512 64-byte SHA-512 hash of file's contents + * @param filesize Size of file in bytes + * @param signedBy Address of signer of hash + * @param signature Signature (currently must be Ed25519) + * @param siglen Length of signature in bytes + */ + void handleAvailable(const Address &from,const char *filename,const void *sha512,unsigned long filesize,const Address &signedBy,const void *signature,unsigned int siglen); + + /** + * Get data about a shared update if found + * + * @param filename File name + * @param update Empty structure to be filled with update info + * @return True if found (if false, 'update' is unmodified) + */ + bool findSharedUpdate(const char *filename,SharedUpdate &update) const; + + /** + * Get data about a shared update if found + * + * @param sha512 Up to 64 bytes of hash to match + * @param shalen Length of sha512[] + * @param update Empty structure to be filled with update info + * @return True if found (if false, 'update' is unmodified) + */ + bool findSharedUpdate(const void *sha512,unsigned int shalen,SharedUpdate &update) const; + + /** + * Get a chunk of a shared update + * + * @param sha512 Up to 64 bytes of hash to match + * @param shalen Length of sha512[] + * @param at Position in file + * @param chunk Buffer to store data + * @param chunklen Number of bytes to get + * @return True if chunk[] was successfully filled, false if not found or other error + */ + bool getSharedChunk(const void *sha512,unsigned int shalen,unsigned long at,void *chunk,unsigned long chunklen) const; /** * @return Canonical update filename for this platform or empty string if unsupported @@ -135,48 +205,13 @@ public: static bool parseUpdateFilename(const char *filename,unsigned int &vMajor,unsigned int &vMinor,unsigned int &revision); private: + void _requestNextChunk(); + struct _Download { - _Download(const void *s512,const std::string &fn,unsigned long len,unsigned int vMajor,unsigned int vMinor,unsigned int rev) - { - data.resize(len); - haveChunks.resize((len / ZT_UPDATER_CHUNK_SIZE) + 1,false); - filename = fn; - memcpy(sha512,s512,64); - lastChunkSize = len % ZT_UPDATER_CHUNK_SIZE; - versionMajor = vMajor; - versionMinor = vMinor; - revision = rev; - } - - long nextChunk() const - { - std::vector::const_iterator ptr(std::find(haveChunks.begin(),haveChunks.end(),false)); - if (ptr != haveChunks.end()) - return std::distance(haveChunks.begin(),ptr); - else return -1; - } - - bool gotChunk(unsigned long at,const void *chunk,unsigned long len) - { - unsigned long whichChunk = at / ZT_UPDATER_CHUNK_SIZE; - if (at != (ZT_UPDATER_CHUNK_SIZE * whichChunk)) - return false; // not at chunk boundary - if (whichChunk >= haveChunks.size()) - return false; // overflow - if ((whichChunk == (haveChunks.size() - 1))&&(len != lastChunkSize)) - return false; // last chunk, size wrong - else if (len != ZT_UPDATER_CHUNK_SIZE) - return false; // chunk size wrong - for(unsigned long i=0;i haveChunks; - std::vector
peersThatHave; + std::list
peersThatHave; // excluding current std::string filename; unsigned char sha512[64]; Address currentlyReceivingFrom; @@ -185,18 +220,9 @@ private: unsigned int versionMajor,versionMinor,revision; }; - struct _Shared - { - std::string filename; - unsigned char sha512[64]; - C25519::Signature sig; - Address signedBy; - unsigned long size; - }; - const RuntimeEnvironment *_r; _Download *_download; - std::map< Array,_Shared > _sharedUpdates; + std::list _sharedUpdates; // usually not more than 1 or 2 of these Mutex _lock; }; diff --git a/node/Utils.cpp b/node/Utils.cpp index 66bd27dd..661dbb8c 100644 --- a/node/Utils.cpp +++ b/node/Utils.cpp @@ -265,7 +265,7 @@ uint64_t Utils::getLastModified(const char *path) return (((uint64_t)s.st_mtime) * 1000ULL); } -static int64_t getFileSize(const char *path) +int64_t Utils::getFileSize(const char *path) { struct stat s; if (stat(path,&s)) -- cgit v1.2.3 From 612c17240af65243a1fa5d8cc17d3ebdb38a9bee Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 6 Dec 2013 16:49:20 -0800 Subject: Dead code removal, fix for cleanup GitHub issue #28 --- node/Address.hpp | 4 ++-- node/Array.hpp | 4 ++-- node/AtomicCounter.hpp | 4 ++-- node/BandwidthAccount.hpp | 4 ++-- node/Buffer.hpp | 4 ++-- node/C25519.hpp | 4 ++-- node/CMWC4096.hpp | 4 ++-- node/CertificateOfMembership.hpp | 4 ++-- node/Condition.hpp | 4 ++-- node/Constants.hpp | 4 ++-- node/Defaults.hpp | 4 ++-- node/Demarc.hpp | 4 ++-- node/Dictionary.hpp | 4 ++-- node/EthernetTap.hpp | 4 ++-- node/Identity.hpp | 4 ++-- node/InetAddress.hpp | 4 ++-- node/Logger.hpp | 4 ++-- node/MAC.hpp | 4 ++-- node/MulticastGroup.hpp | 4 ++-- node/Multicaster.hpp | 4 ++-- node/Mutex.hpp | 4 ++-- node/Network.hpp | 4 ++-- node/NetworkConfig.hpp | 4 ++-- node/Node.cpp | 9 --------- node/Node.hpp | 12 ++---------- node/NodeConfig.hpp | 4 ++-- node/NonCopyable.hpp | 4 ++-- node/Packet.hpp | 4 ++-- node/PacketDecoder.hpp | 4 ++-- node/Peer.hpp | 4 ++-- node/Poly1305.hpp | 4 ++-- node/RuntimeEnvironment.hpp | 4 ++-- node/SHA512.hpp | 4 ++-- node/Salsa20.hpp | 4 ++-- node/Service.hpp | 4 ++-- node/SharedPtr.hpp | 4 ++-- node/Switch.hpp | 4 ++-- node/SysEnv.hpp | 4 ++-- node/Thread.hpp | 4 ++-- node/Topology.hpp | 4 ++-- node/UdpSocket.hpp | 4 ++-- node/Utils.hpp | 4 ++-- 42 files changed, 82 insertions(+), 99 deletions(-) (limited to 'node/Defaults.hpp') diff --git a/node/Address.hpp b/node/Address.hpp index b28284b0..7247260c 100644 --- a/node/Address.hpp +++ b/node/Address.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_ADDRESS_HPP -#define _ZT_ADDRESS_HPP +#ifndef ZT_ADDRESS_HPP +#define ZT_ADDRESS_HPP #include #include diff --git a/node/Array.hpp b/node/Array.hpp index d48c2f52..c31626b2 100644 --- a/node/Array.hpp +++ b/node/Array.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_ARRAY_HPP -#define _ZT_ARRAY_HPP +#ifndef ZT_ARRAY_HPP +#define ZT_ARRAY_HPP #include #include diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index ebc70817..1aecaa65 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_ATOMICCOUNTER_HPP -#define _ZT_ATOMICCOUNTER_HPP +#ifndef ZT_ATOMICCOUNTER_HPP +#define ZT_ATOMICCOUNTER_HPP #include "Mutex.hpp" #include "NonCopyable.hpp" diff --git a/node/BandwidthAccount.hpp b/node/BandwidthAccount.hpp index be180cfc..98c7dd20 100644 --- a/node/BandwidthAccount.hpp +++ b/node/BandwidthAccount.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_BWACCOUNT_HPP -#define _ZT_BWACCOUNT_HPP +#ifndef ZT_BWACCOUNT_HPP +#define ZT_BWACCOUNT_HPP #include #include diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 1767ae04..e8308306 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_BUFFER_HPP -#define _ZT_BUFFER_HPP +#ifndef ZT_BUFFER_HPP +#define ZT_BUFFER_HPP #include #include diff --git a/node/C25519.hpp b/node/C25519.hpp index 79edfa06..2a594f72 100644 --- a/node/C25519.hpp +++ b/node/C25519.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_C25519_HPP -#define _ZT_C25519_HPP +#ifndef ZT_C25519_HPP +#define ZT_C25519_HPP #include "Array.hpp" #include "Utils.hpp" diff --git a/node/CMWC4096.hpp b/node/CMWC4096.hpp index 29351861..01c57e15 100644 --- a/node/CMWC4096.hpp +++ b/node/CMWC4096.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_CMWC4096_HPP -#define _ZT_CMWC4096_HPP +#ifndef ZT_CMWC4096_HPP +#define ZT_CMWC4096_HPP #include #include "Utils.hpp" diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 76e1cfbc..6f78734e 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_CERTIFICATEOFMEMBERSHIP_HPP -#define _ZT_CERTIFICATEOFMEMBERSHIP_HPP +#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP +#define ZT_CERTIFICATEOFMEMBERSHIP_HPP #include #include diff --git a/node/Condition.hpp b/node/Condition.hpp index 4b2d32ca..728799d9 100644 --- a/node/Condition.hpp +++ b/node/Condition.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_CONDITION_HPP -#define _ZT_CONDITION_HPP +#ifndef ZT_CONDITION_HPP +#define ZT_CONDITION_HPP #include "Constants.hpp" #include "NonCopyable.hpp" diff --git a/node/Constants.hpp b/node/Constants.hpp index dbdc4ec9..3f121cf4 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_CONSTANTS_HPP -#define _ZT_CONSTANTS_HPP +#ifndef ZT_CONSTANTS_HPP +#define ZT_CONSTANTS_HPP // // This include file also auto-detects and canonicalizes some environment diff --git a/node/Defaults.hpp b/node/Defaults.hpp index dac59ae6..d546d01f 100644 --- a/node/Defaults.hpp +++ b/node/Defaults.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_DEFAULTS_HPP -#define _ZT_DEFAULTS_HPP +#ifndef ZT_DEFAULTS_HPP +#define ZT_DEFAULTS_HPP #include #include diff --git a/node/Demarc.hpp b/node/Demarc.hpp index fc283fef..0bbdef44 100644 --- a/node/Demarc.hpp +++ b/node/Demarc.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_DEMARC_HPP -#define _ZT_DEMARC_HPP +#ifndef ZT_DEMARC_HPP +#define ZT_DEMARC_HPP #include #include diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp index a0a64cec..214c0094 100644 --- a/node/Dictionary.hpp +++ b/node/Dictionary.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_DICTIONARY_HPP -#define _ZT_DICTIONARY_HPP +#ifndef ZT_DICTIONARY_HPP +#define ZT_DICTIONARY_HPP #include #include diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp index 3db41392..68a365bf 100644 --- a/node/EthernetTap.hpp +++ b/node/EthernetTap.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_ETHERNETTAP_HPP -#define _ZT_ETHERNETTAP_HPP +#ifndef ZT_ETHERNETTAP_HPP +#define ZT_ETHERNETTAP_HPP #include #include diff --git a/node/Identity.hpp b/node/Identity.hpp index cb911b92..f6b1f876 100644 --- a/node/Identity.hpp +++ b/node/Identity.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_IDENTITY_HPP -#define _ZT_IDENTITY_HPP +#ifndef ZT_IDENTITY_HPP +#define ZT_IDENTITY_HPP #include #include diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index 54fbc395..d90574e5 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_INETADDRESS_HPP -#define _ZT_INETADDRESS_HPP +#ifndef ZT_INETADDRESS_HPP +#define ZT_INETADDRESS_HPP #include #include diff --git a/node/Logger.hpp b/node/Logger.hpp index de71ed39..b99df392 100644 --- a/node/Logger.hpp +++ b/node/Logger.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_LOGGER_HPP -#define _ZT_LOGGER_HPP +#ifndef ZT_LOGGER_HPP +#define ZT_LOGGER_HPP #include diff --git a/node/MAC.hpp b/node/MAC.hpp index 87363a44..f0bca937 100644 --- a/node/MAC.hpp +++ b/node/MAC.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_MAC_HPP -#define _ZT_MAC_HPP +#ifndef ZT_MAC_HPP +#define ZT_MAC_HPP #include #include diff --git a/node/MulticastGroup.hpp b/node/MulticastGroup.hpp index 426ef048..32f8c0ed 100644 --- a/node/MulticastGroup.hpp +++ b/node/MulticastGroup.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_MULTICASTGROUP_HPP -#define _ZT_MULTICASTGROUP_HPP +#ifndef ZT_MULTICASTGROUP_HPP +#define ZT_MULTICASTGROUP_HPP #include diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 16ae7218..164bfd79 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_MULTICASTER_HPP -#define _ZT_MULTICASTER_HPP +#ifndef ZT_MULTICASTER_HPP +#define ZT_MULTICASTER_HPP #include #include diff --git a/node/Mutex.hpp b/node/Mutex.hpp index b0130293..509b60be 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_MUTEX_HPP -#define _ZT_MUTEX_HPP +#ifndef ZT_MUTEX_HPP +#define ZT_MUTEX_HPP #include "Constants.hpp" #include "NonCopyable.hpp" diff --git a/node/Network.hpp b/node/Network.hpp index a219cdf2..f41e7502 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_NETWORK_HPP -#define _ZT_NETWORK_HPP +#ifndef ZT_NETWORK_HPP +#define ZT_NETWORK_HPP #include diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index a833006f..823363bd 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_NETWORKCONFIG_HPP -#define _ZT_NETWORKCONFIG_HPP +#ifndef ZT_NETWORKCONFIG_HPP +#define ZT_NETWORKCONFIG_HPP #include diff --git a/node/Node.cpp b/node/Node.cpp index f2668e4e..8c6ab49b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -623,15 +623,6 @@ unsigned int Node::versionMajor() throw() { return ZEROTIER_ONE_VERSION_MAJOR; } unsigned int Node::versionMinor() throw() { return ZEROTIER_ONE_VERSION_MINOR; } unsigned int Node::versionRevision() throw() { return ZEROTIER_ONE_VERSION_REVISION; } -// Scanned for by loader and/or updater to determine a binary's version -const unsigned char EMBEDDED_VERSION_STAMP[20] = { - 0x6d,0xfe,0xff,0x01,0x90,0xfa,0x89,0x57,0x88,0xa1,0xaa,0xdc,0xdd,0xde,0xb0,0x33, - ZEROTIER_ONE_VERSION_MAJOR, - ZEROTIER_ONE_VERSION_MINOR, - (unsigned char)(((unsigned int)ZEROTIER_ONE_VERSION_REVISION) & 0xff), /* little-endian */ - (unsigned char)((((unsigned int)ZEROTIER_ONE_VERSION_REVISION) >> 8) & 0xff) -}; - } // namespace ZeroTier extern "C" { diff --git a/node/Node.hpp b/node/Node.hpp index 476ec7cd..9d02c008 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_NODE_HPP -#define _ZT_NODE_HPP +#ifndef ZT_NODE_HPP +#define ZT_NODE_HPP #include #include @@ -171,14 +171,6 @@ private: void *const _impl; // private implementation }; -/** - * An embedded version code that can be searched for in the binary - * - * This shouldn't be used by users, but is exported to make certain that - * the linker actually includes it in the image. - */ -extern const unsigned char EMBEDDED_VERSION_STAMP[20]; - } // namespace ZeroTier extern "C" { diff --git a/node/NodeConfig.hpp b/node/NodeConfig.hpp index 0e7e4c98..2612cf6a 100644 --- a/node/NodeConfig.hpp +++ b/node/NodeConfig.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_NODECONFIG_HPP -#define _ZT_NODECONFIG_HPP +#ifndef ZT_NODECONFIG_HPP +#define ZT_NODECONFIG_HPP #include diff --git a/node/NonCopyable.hpp b/node/NonCopyable.hpp index 26536a36..e39deba8 100644 --- a/node/NonCopyable.hpp +++ b/node/NonCopyable.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _NONCOPYABLE_HPP__ -#define _NONCOPYABLE_HPP__ +#ifndef ZT_NONCOPYABLE_HPP__ +#define ZT_NONCOPYABLE_HPP__ namespace ZeroTier { diff --git a/node/Packet.hpp b/node/Packet.hpp index b7f52e3c..6f3f9117 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_N_PACKET_HPP -#define _ZT_N_PACKET_HPP +#ifndef ZT_N_PACKET_HPP +#define ZT_N_PACKET_HPP #include #include diff --git a/node/PacketDecoder.hpp b/node/PacketDecoder.hpp index cb3522ff..72b05290 100644 --- a/node/PacketDecoder.hpp +++ b/node/PacketDecoder.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_PACKETDECODER_HPP -#define _ZT_PACKETDECODER_HPP +#ifndef ZT_PACKETDECODER_HPP +#define ZT_PACKETDECODER_HPP #include diff --git a/node/Peer.hpp b/node/Peer.hpp index 0a8a7b57..de5df08f 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_PEER_HPP -#define _ZT_PEER_HPP +#ifndef ZT_PEER_HPP +#define ZT_PEER_HPP #include diff --git a/node/Poly1305.hpp b/node/Poly1305.hpp index 94e6078d..8baa448f 100644 --- a/node/Poly1305.hpp +++ b/node/Poly1305.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_POLY1305_HPP -#define _ZT_POLY1305_HPP +#ifndef ZT_POLY1305_HPP +#define ZT_POLY1305_HPP namespace ZeroTier { diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 75b171ff..48797b14 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_RUNTIMEENVIRONMENT_HPP -#define _ZT_RUNTIMEENVIRONMENT_HPP +#ifndef ZT_RUNTIMEENVIRONMENT_HPP +#define ZT_RUNTIMEENVIRONMENT_HPP #include diff --git a/node/SHA512.hpp b/node/SHA512.hpp index 565eb097..721933cb 100644 --- a/node/SHA512.hpp +++ b/node/SHA512.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_SHA512_HPP -#define _ZT_SHA512_HPP +#ifndef ZT_SHA512_HPP +#define ZT_SHA512_HPP #define ZT_SHA512_DIGEST_LEN 64 diff --git a/node/Salsa20.hpp b/node/Salsa20.hpp index 9f34ba78..e09e2aaa 100644 --- a/node/Salsa20.hpp +++ b/node/Salsa20.hpp @@ -4,8 +4,8 @@ * This therefore is public domain. */ -#ifndef _ZT_SALSA20_HPP -#define _ZT_SALSA20_HPP +#ifndef ZT_SALSA20_HPP +#define ZT_SALSA20_HPP #include diff --git a/node/Service.hpp b/node/Service.hpp index d8467cd1..22e53d62 100644 --- a/node/Service.hpp +++ b/node/Service.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_SERVICE_HPP -#define _ZT_SERVICE_HPP +#ifndef ZT_SERVICE_HPP +#define ZT_SERVICE_HPP #include #include diff --git a/node/SharedPtr.hpp b/node/SharedPtr.hpp index 834d0a2e..f7604c06 100644 --- a/node/SharedPtr.hpp +++ b/node/SharedPtr.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_SHAREDPTR_HPP -#define _ZT_SHAREDPTR_HPP +#ifndef ZT_SHAREDPTR_HPP +#define ZT_SHAREDPTR_HPP #include "Mutex.hpp" #include "AtomicCounter.hpp" diff --git a/node/Switch.hpp b/node/Switch.hpp index 68e3c6c4..6b3b8e6e 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_N_SWITCH_HPP -#define _ZT_N_SWITCH_HPP +#ifndef ZT_N_SWITCH_HPP +#define ZT_N_SWITCH_HPP #include #include diff --git a/node/SysEnv.hpp b/node/SysEnv.hpp index 21c25713..4f4a4f16 100644 --- a/node/SysEnv.hpp +++ b/node/SysEnv.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_SYSENV_HPP -#define _ZT_SYSENV_HPP +#ifndef ZT_SYSENV_HPP +#define ZT_SYSENV_HPP #include diff --git a/node/Thread.hpp b/node/Thread.hpp index d295fea3..8adf79d3 100644 --- a/node/Thread.hpp +++ b/node/Thread.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_THREAD_HPP -#define _ZT_THREAD_HPP +#ifndef ZT_THREAD_HPP +#define ZT_THREAD_HPP #include diff --git a/node/Topology.hpp b/node/Topology.hpp index 09dec86e..312377bc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_TOPOLOGY_HPP -#define _ZT_TOPOLOGY_HPP +#ifndef ZT_TOPOLOGY_HPP +#define ZT_TOPOLOGY_HPP #include #include diff --git a/node/UdpSocket.hpp b/node/UdpSocket.hpp index d8467f64..cbd9de86 100644 --- a/node/UdpSocket.hpp +++ b/node/UdpSocket.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_UDPSOCKET_HPP -#define _ZT_UDPSOCKET_HPP +#ifndef ZT_UDPSOCKET_HPP +#define ZT_UDPSOCKET_HPP #include diff --git a/node/Utils.hpp b/node/Utils.hpp index 2fea8b9b..dfead0d1 100644 --- a/node/Utils.hpp +++ b/node/Utils.hpp @@ -25,8 +25,8 @@ * LLC. Start here: http://www.zerotier.com/ */ -#ifndef _ZT_UTILS_HPP -#define _ZT_UTILS_HPP +#ifndef ZT_UTILS_HPP +#define ZT_UTILS_HPP #include #include -- cgit v1.2.3 From bf0da9f2f778aeb3eebe200a8cdeecbc6e1f9253 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 10 Dec 2013 15:30:53 -0800 Subject: Rest of software updater, ready to test... --- main.cpp | 17 +++- node/Constants.hpp | 10 +++ node/Defaults.cpp | 7 +- node/Defaults.hpp | 5 ++ node/HttpClient.cpp | 12 ++- node/Node.hpp | 17 +++- node/RuntimeEnvironment.hpp | 6 +- node/SoftwareUpdater.cpp | 187 ++++++++++++++++++++++++++++++++++++++++++++ node/SoftwareUpdater.hpp | 110 ++++++++++++++++++++++++++ objects.mk | 1 + 10 files changed, 361 insertions(+), 11 deletions(-) create mode 100644 node/SoftwareUpdater.cpp create mode 100644 node/SoftwareUpdater.hpp (limited to 'node/Defaults.hpp') diff --git a/main.cpp b/main.cpp index 872fd37c..37d82bc8 100644 --- a/main.cpp +++ b/main.cpp @@ -44,6 +44,7 @@ #else #include #include +#include #include #include #include @@ -473,13 +474,21 @@ int main(int argc,char **argv) try { node = new Node(homeDir,port,controlPort); - const char *termReason = (char *)0; switch(node->run()) { - case Node::NODE_UNRECOVERABLE_ERROR: + case Node::NODE_NODE_RESTART_FOR_UPGRADE: { +#ifdef __UNIX_LIKE__ + const char *upgPath = node->reasonForTermination(); + if (upgPath) + execl(upgPath,upgPath,"-s",(char *)0); // -s = (re)start after install/upgrade + exitCode = -1; + fprintf(stderr,"%s: abnormal termination: unable to execute update at %s",argv[0],(upgPath) ? upgPath : "(unknown path)"); +#endif + } break; + case Node::NODE_UNRECOVERABLE_ERROR: { exitCode = -1; - termReason = node->reasonForTermination(); + const char *termReason = node->reasonForTermination(); fprintf(stderr,"%s: abnormal termination: %s\n",argv[0],(termReason) ? termReason : "(unknown reason)"); - break; + } break; default: break; } diff --git a/node/Constants.hpp b/node/Constants.hpp index 3f121cf4..21c8a0ec 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -330,4 +330,14 @@ error_no_byte_order_defined; */ #define ZT_RENDEZVOUS_NAT_T_DELAY 500 +/** + * Minimum interval between attempts to do a software update + */ +#define ZT_UPDATE_MIN_INTERVAL 120000 + +/** + * Update HTTP timeout in seconds + */ +#define ZT_UPDATE_HTTP_TIMEOUT 30 + #endif diff --git a/node/Defaults.cpp b/node/Defaults.cpp index cfc901b5..566658fa 100644 --- a/node/Defaults.cpp +++ b/node/Defaults.cpp @@ -122,13 +122,18 @@ static inline std::map< Address,Identity > _mkUpdateAuth() return ua; } +static inline std::string _mkUpdateUrl() +{ +} + Defaults::Defaults() : #ifdef ZT_TRACE_MULTICAST multicastTraceWatcher(ZT_TRACE_MULTICAST), #endif defaultHomePath(_mkDefaultHomePath()), supernodes(_mkSupernodeMap()), - updateAuthorities(_mkUpdateAuth()) + updateAuthorities(_mkUpdateAuth()), + updateLatestNfoURL(_mkUpdateUrl()) { } diff --git a/node/Defaults.hpp b/node/Defaults.hpp index d546d01f..9d6d4bcf 100644 --- a/node/Defaults.hpp +++ b/node/Defaults.hpp @@ -78,6 +78,11 @@ public: * build will not auto-update. */ const std::map< Address,Identity > updateAuthorities; + + /** + * URL to latest .nfo for software updates + */ + const std::string updateLatestNfoURL; }; extern const Defaults ZT_DEFAULTS; diff --git a/node/HttpClient.cpp b/node/HttpClient.cpp index 1d1624db..15c01c44 100644 --- a/node/HttpClient.cpp +++ b/node/HttpClient.cpp @@ -112,6 +112,12 @@ public: return; } + if (!_url.length()) { + _handler(_arg,-1,_url,false,"cannot fetch empty URL"); + delete this; + return; + } + curlArgs[0] = const_cast (curlPath.c_str()); curlArgs[1] = const_cast ("-D"); curlArgs[2] = const_cast ("-"); // append headers before output @@ -171,9 +177,11 @@ public: if (FD_ISSET(curlStdout[0],&readfds)) { int n = (int)::read(curlStdout[0],buf,sizeof(buf)); - if (n > 0) + if (n > 0) { _body.append(buf,n); - else if (n < 0) + // Reset timeout when data is read... + timesOutAt = Utils::now() + ((unsigned long long)_timeout * 1000ULL); + } else if (n < 0) break; if (_body.length() > CURL_MAX_MESSAGE_LENGTH) { ::kill(pid,SIGKILL); diff --git a/node/Node.hpp b/node/Node.hpp index 9d02c008..2736713f 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -97,9 +97,24 @@ public: */ enum ReasonForTermination { + /** + * Node is currently in run() + */ NODE_RUNNING = 0, + + /** + * Node is shutting down for normal reasons, including a signal + */ NODE_NORMAL_TERMINATION = 1, - NODE_RESTART_FOR_RECONFIGURATION = 2, + + /** + * An upgrade is available. Its path is in reasonForTermination(). + */ + NODE_RESTART_FOR_UPGRADE = 2, + + /** + * A serious unrecoverable error has occurred. + */ NODE_UNRECOVERABLE_ERROR = 3 }; diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 48797b14..05e10676 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -46,7 +46,7 @@ class CMWC4096; class Service; class Node; class Multicaster; -class Updater; +class SoftwareUpdater; /** * Holds global state for an instance of ZeroTier::Node @@ -73,7 +73,7 @@ public: topology((Topology *)0), sysEnv((SysEnv *)0), nc((NodeConfig *)0), - updater((Updater *)0) + updater((SoftwareUpdater *)0) #ifndef __WINDOWS__ ,netconfService((Service *)0) #endif @@ -110,7 +110,7 @@ public: SysEnv *sysEnv; NodeConfig *nc; Node *node; - Updater *updater; // null if auto-updates are disabled + SoftwareUpdater *updater; // null if software updates are not enabled #ifndef __WINDOWS__ Service *netconfService; // null if no netconf service running #endif diff --git a/node/SoftwareUpdater.cpp b/node/SoftwareUpdater.cpp new file mode 100644 index 00000000..4cb2f7e4 --- /dev/null +++ b/node/SoftwareUpdater.cpp @@ -0,0 +1,187 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2012-2013 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#include +#include +#include + +#include "../version.h" + +#include "SoftwareUpdater.hpp" +#include "Dictionary.hpp" +#include "C25519.hpp" +#include "Identity.hpp" +#include "Logger.hpp" +#include "RuntimeEnvironment.hpp" +#include "Thread.hpp" +#include "Node.hpp" + +#ifdef __UNIX_LIKE__ +#include +#include +#include +#include +#endif + +namespace ZeroTier { + +SoftwareUpdater::SoftwareUpdater(const RuntimeEnvironment *renv) : + _r(renv), + _myVersion(packVersion(ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION)), + _lastUpdateAttempt(0), + _status(UPDATE_STATUS_IDLE), + _die(false), + _lock() +{ +} + +SoftwareUpdater::~SoftwareUpdater() +{ + _die = true; + for(;;) { + _lock.lock(); + bool ip = (_status != UPDATE_STATUS_IDLE); + _lock.unlock(); + if (ip) + Thread::sleep(500); + else break; + } +} + +void SoftwareUpdater::_cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,bool onDisk,const std::string &body) +{ + SoftwareUpdater *upd = (SoftwareUpdater *)arg; + const RuntimeEnvironment *_r = (const RuntimeEnvironment *)upd->_r; + Mutex::Lock _l(upd->_lock); + + if ((upd->_die)||(upd->_status != UPDATE_STATUS_GETTING_NFO)) { + upd->_status = UPDATE_STATUS_IDLE; + return; + } + + if (code != 200) { + LOG("unable to check for software updates, response code %d (%s)",code,body.c_str()); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + + try { + Dictionary nfo(body); + const unsigned int vMajor = Utils::strToUInt(nfo.get("vMajor").c_str()); + const unsigned int vMinor = Utils::strToUInt(nfo.get("vMinor").c_str()); + const unsigned int vRevision = Utils::strToUInt(nfo.get("vRevision").c_str()); + const Address signedBy(nfo.get("signedBy")); + const std::string signature(Utils::unhex(nfo.get("ed25519"))); + const std::string &url = nfo.get("url"); + + if (signature.length() != ZT_C25519_SIGNATURE_LEN) { + LOG("software update aborted: .nfo file invalid: bad Ed25519 signature"); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + if ((url.length() <= 7)||(url.substr(0,7) != "http://")) { + LOG("software update aborted: .nfo file invalid: update URL must begin with http://"); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + if (packVersion(vMajor,vMinor,vRevision) <= upd->_myVersion) { + LOG("software update aborted: .nfo file invalid: version on web site <= my version"); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + + if (!ZT_DEFAULTS.updateAuthorities.count(signedBy)) { + LOG("software update aborted: .nfo file specifies unknown signing authority"); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + + upd->_status = UPDATE_STATUS_GETTING_FILE; + upd->_signedBy = signedBy; + upd->_signature = signature; + + HttpClient::GET(url,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionBinary,arg); + } catch ( ... ) { + LOG("software update check failed: .nfo file invalid: fields missing or invalid dictionary format"); + upd->_status = UPDATE_STATUS_IDLE; + } +} + +void SoftwareUpdater::_cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,bool onDisk,const std::string &body) +{ + SoftwareUpdater *upd = (SoftwareUpdater *)arg; + const RuntimeEnvironment *_r = (const RuntimeEnvironment *)upd->_r; + Mutex::Lock _l(upd->_lock); + + std::map< Address,Identity >::const_iterator updateAuthority = ZT_DEFAULTS.updateAuthorities.find(upd->_signedBy); + if (updateAuthority == ZT_DEFAULTS.updateAuthorities.end()) { // sanity check, shouldn't happen + LOG("software update aborted: .nfo file specifies unknown signing authority"); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + + // The all-important authenticity check... :) + if (!updateAuthority->second.verify(body.data(),body.length(),upd->_signature.data(),upd->_signature.length())) { + LOG("software update aborted: update fetched from '%s' failed certificate check against signer %s",url.c_str(),updateAuthority->first.toString().c_str()); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + +#ifdef __UNIX_LIKE__ + size_t lastSlash = url.rfind('/'); + if (lastSlash == std::string::npos) { // sanity check, shouldn't happen + LOG("software update aborted: invalid URL"); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + std::string updatesDir(_r->homePath + ZT_PATH_SEPARATOR_S + "updates.d"); + std::string updatePath(updatesDir + ZT_PATH_SEPARATOR_S + url.substr(lastSlash + 1)); + mkdir(updatesDir.c_str(),0755); + + int fd = ::open(updatePath.c_str(),O_WRONLY|O_CREAT|O_TRUNC,0755); + if (fd <= 0) { + LOG("software update aborted: unable to open %s for writing",updatePath.c_str()); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + if ((long)::write(fd,body.data(),body.length()) != (long)body.length()) { + LOG("software update aborted: unable to write to %s",updatePath.c_str()); + upd->_status = UPDATE_STATUS_IDLE; + return; + } + ::close(fd); + ::chmod(updatePath.c_str(),0755); + + _r->node->terminate(Node::NODE_RESTART_FOR_UPGRADE,updatePath.c_str()); +#endif + +#ifdef __WINDOWS__ + todo; +#endif +} + +} // namespace ZeroTier diff --git a/node/SoftwareUpdater.hpp b/node/SoftwareUpdater.hpp new file mode 100644 index 00000000..bfcdf395 --- /dev/null +++ b/node/SoftwareUpdater.hpp @@ -0,0 +1,110 @@ +/* + * ZeroTier One - Global Peer to Peer Ethernet + * Copyright (C) 2012-2013 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * -- + * + * ZeroTier may be used and distributed under the terms of the GPLv3, which + * are available at: http://www.gnu.org/licenses/gpl-3.0.html + * + * If you would like to embed ZeroTier into a commercial application or + * redistribute it in a modified binary form, please contact ZeroTier Networks + * LLC. Start here: http://www.zerotier.com/ + */ + +#ifndef ZT_SOFTWAREUPDATER_HPP +#define ZT_SOFTWAREUPDATER_HPP + +#include + +#include "Constants.hpp" +#include "Mutex.hpp" +#include "Utils.hpp" +#include "HttpClient.hpp" +#include "Defaults.hpp" + +namespace ZeroTier { + +class RuntimeEnvironment; + +/** + * Software updater + */ +class SoftwareUpdater +{ +public: + SoftwareUpdater(const RuntimeEnvironment *renv); + ~SoftwareUpdater(); + + /** + * Called on each version message from a peer + * + * If a peer has a newer version, that causes an update to be started. + * + * @param vmaj Peer's major version + * @param vmin Peer's minor version + * @param rev Peer's revision + */ + inline void sawRemoteVersion(unsigned int vmaj,unsigned int vmin,unsigned int rev) + { + const uint64_t tmp = packVersion(vmaj,vmin,rev); + if (tmp > _myVersion) { + Mutex::Lock _l(_lock); + if ((_status == UPDATE_STATUS_IDLE)&&(!_die)&&(ZT_DEFAULTS.updateLatestNfoURL.length())) { + const uint64_t now = Utils::now(); + if ((now - _lastUpdateAttempt) >= ZT_UPDATE_MIN_INTERVAL) { + _lastUpdateAttempt = now; + _status = UPDATE_STATUS_GETTING_NFO; + HttpClient::GET(ZT_DEFAULTS.updateLatestNfoURL,HttpClient::NO_HEADERS,ZT_UPDATE_HTTP_TIMEOUT,&_cbHandleGetLatestVersionInfo,this); + } + } + } + } + + /** + * Pack three-component version into a 64-bit integer + * + * @param vmaj Major version (0..65535) + * @param vmin Minor version (0..65535) + * @param rev Revision (0..65535) + */ + static inline uint64_t packVersion(unsigned int vmaj,unsigned int vmin,unsigned int rev) + throw() + { + return ( ((uint64_t)(vmaj & 0xffff) << 32) | ((uint64_t)(vmin & 0xffff) << 16) | (uint64_t)(rev & 0xffff) ); + } + +private: + static void _cbHandleGetLatestVersionInfo(void *arg,int code,const std::string &url,bool onDisk,const std::string &body); + static void _cbHandleGetLatestVersionBinary(void *arg,int code,const std::string &url,bool onDisk,const std::string &body); + + const RuntimeEnvironment *_r; + const uint64_t _myVersion; + volatile uint64_t _lastUpdateAttempt; + volatile enum { + UPDATE_STATUS_IDLE, + UPDATE_STATUS_GETTING_NFO, + UPDATE_STATUS_GETTING_FILE + } _status; + volatile bool _die; + Address _signedBy; + std::string _signature; + Mutex _lock; +}; + +} // namespace ZeroTier + +#endif diff --git a/objects.mk b/objects.mk index 7eb97574..317e9e84 100644 --- a/objects.mk +++ b/objects.mk @@ -21,6 +21,7 @@ OBJS=\ node/Poly1305.o \ node/Salsa20.o \ node/Service.o \ + node/SoftwareUpdater.o \ node/SHA512.o \ node/Switch.o \ node/SysEnv.o \ -- cgit v1.2.3