diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2017-01-12 14:34:52 -0800 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2017-01-12 14:34:52 -0800 |
commit | e1727d6297033881c9a379480aeacff806df2f2a (patch) | |
tree | da2d9419b7948cb5877229a79a66edfa64a77ed6 /service | |
parent | e7bab66d291acdd627e3bcfe434792ce360483b0 (diff) | |
download | infinitytier-e1727d6297033881c9a379480aeacff806df2f2a.tar.gz infinitytier-e1727d6297033881c9a379480aeacff806df2f2a.zip |
Fix to software update repeat downloads.
Diffstat (limited to 'service')
-rw-r--r-- | service/SoftwareUpdater.cpp | 121 | ||||
-rw-r--r-- | service/SoftwareUpdater.hpp | 19 |
2 files changed, 81 insertions, 59 deletions
diff --git a/service/SoftwareUpdater.cpp b/service/SoftwareUpdater.cpp index 0f5b4fca..c47a5faf 100644 --- a/service/SoftwareUpdater.cpp +++ b/service/SoftwareUpdater.cpp @@ -258,9 +258,10 @@ SoftwareUpdater::SoftwareUpdater(Node &node,const std::string &homePath) : _lastCheckTime(0), _homePath(homePath), _channel(ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL), - _latestBinLength(0), - _latestBinValid(false) + _latestValid(false), + _downloadLength(0) { + // Check for a cached newer update. If there's a cached update that is not newer, delete. } SoftwareUpdater::~SoftwareUpdater() @@ -286,6 +287,7 @@ void SoftwareUpdater::setUpdateDistribution(bool distribute) uint8_t sha512[ZT_SHA512_DIGEST_LEN]; SHA512::hash(sha512,d.bin.data(),(unsigned int)d.bin.length()); if (!memcmp(sha512,metaHash.data(),ZT_SHA512_DIGEST_LEN)) { // double check that hash in JSON is correct + d.meta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIZE] = d.bin.length(); // override with correct value -- setting this in meta json is optional _dist[Array<uint8_t,16>(sha512)] = d; printf("update-dist.d: %s\n",u->c_str()); } @@ -351,19 +353,24 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void if ((len <= ZT_SOFTWARE_UPDATE_MAX_SIZE)&&(hash.length() >= 16)) { if (_latestMeta != req) { _latestMeta = req; - _latestBin = ""; - memcpy(_latestBinHashPrefix.data,hash.data(),16); - _latestBinLength = len; - _latestBinValid = false; - printf("<< LATEST\n%s\n",OSUtils::jsonDump(req).c_str()); + _latestValid = false; + + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_META_FILENAME).c_str()); + OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str()); + + _download = std::string(); + memcpy(_downloadHashPrefix.data,hash.data(),16); + _downloadLength = len; } - Buffer<128> gd; - gd.append((uint8_t)VERB_GET_DATA); - gd.append(_latestBinHashPrefix.data,16); - gd.append((uint32_t)_latestBin.length()); - _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_latestBin.length()); + if ((_downloadLength > 0)&&(_download.length() < _downloadLength)) { + Buffer<128> gd; + gd.append((uint8_t)VERB_GET_DATA); + gd.append(_downloadHashPrefix.data,16); + gd.append((uint32_t)_download.length()); + _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); + printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); + } } } @@ -379,7 +386,7 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 20); printf("<< GET_DATA @%u from %.10llx for %s\n",(unsigned int)idx,origin,Utils::hex(reinterpret_cast<const uint8_t *>(data) + 1,16).c_str()); std::map< Array<uint8_t,16>,_D >::iterator d(_dist.find(Array<uint8_t,16>(reinterpret_cast<const uint8_t *>(data) + 1))); - if ((d != _dist.end())&&(idx < d->second.bin.length())) { + if ((d != _dist.end())&&(idx < (unsigned long)d->second.bin.length())) { Buffer<ZT_SOFTWARE_UPDATE_CHUNK_SIZE + 128> buf; buf.append((uint8_t)VERB_DATA); buf.append(reinterpret_cast<const uint8_t *>(data) + 1,16); @@ -392,21 +399,21 @@ void SoftwareUpdater::handleSoftwareUpdateUserMessage(uint64_t origin,const void break; case VERB_DATA: - if ((len >= 21)&&(!memcmp(_latestBinHashPrefix.data,reinterpret_cast<const uint8_t *>(data) + 1,16))) { + if ((len >= 21)&&(_downloadLength > 0)&&(!memcmp(_downloadHashPrefix.data,reinterpret_cast<const uint8_t *>(data) + 1,16))) { unsigned long idx = (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 17) << 24; idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 18) << 16; idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 19) << 8; idx |= (unsigned long)*(reinterpret_cast<const uint8_t *>(data) + 20); - printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_latestBin.length()); - if (idx == _latestBin.length()) { - _latestBin.append(reinterpret_cast<const char *>(data) + 21,len - 21); - if (_latestBin.length() < _latestBinLength) { + printf("<< DATA @%u / %u bytes (we now have %u bytes)\n",(unsigned int)idx,(unsigned int)(len - 21),(unsigned int)_download.length()); + if (idx == (unsigned long)_download.length()) { + _download.append(reinterpret_cast<const char *>(data) + 21,len - 21); + if (_download.length() < _downloadLength) { Buffer<128> gd; gd.append((uint8_t)VERB_GET_DATA); - gd.append(_latestBinHashPrefix.data,16); - gd.append((uint32_t)_latestBin.length()); + gd.append(_downloadHashPrefix.data,16); + gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_latestBin.length()); + printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } } @@ -447,44 +454,50 @@ bool SoftwareUpdater::check(const uint64_t now) printf(">> GET_LATEST\n"); } - if (_latestBinLength > 0) { - if (_latestBin.length() >= _latestBinLength) { - if (_latestBinValid) { - return true; - } else { - // This is the very important security validation part that makes sure - // this software update doesn't have cooties. - - try { - // (1) Check the hash itself to make sure the image is basically okay - uint8_t sha512[ZT_SHA512_DIGEST_LEN]; - SHA512::hash(sha512,_latestBin.data(),(unsigned int)_latestBin.length()); - if (Utils::hex(sha512,ZT_SHA512_DIGEST_LEN) == OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"~")) { - // (2) Check signature by signing authority - std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); - if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_latestBin.data(),(unsigned int)_latestBin.length(),sig.data(),(unsigned int)sig.length())) { - // If we passed both of these, the update is good! - _latestBinValid = true; + if (_latestValid) + return true; + + if (_downloadLength > 0) { + if (_download.length() >= _downloadLength) { + // This is the very important security validation part that makes sure + // this software update doesn't have cooties. + + try { + // (1) Check the hash itself to make sure the image is basically okay + uint8_t sha512[ZT_SHA512_DIGEST_LEN]; + SHA512::hash(sha512,_download.data(),(unsigned int)_download.length()); + if (Utils::hex(sha512,ZT_SHA512_DIGEST_LEN) == OSUtils::jsonString(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_HASH],"~")) { + // (2) Check signature by signing authority + std::string sig(OSUtils::jsonBinFromHex(_latestMeta[ZT_SOFTWARE_UPDATE_JSON_UPDATE_SIGNATURE])); + if (Identity(ZT_SOFTWARE_UPDATE_SIGNING_AUTHORITY).verify(_download.data(),(unsigned int)_download.length(),sig.data(),(unsigned int)sig.length())) { + // If we passed both of these, the update is good! + if (OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_META_FILENAME).c_str(),OSUtils::jsonDump(_latestMeta)) && OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S + ZT_SOFTWARE_UPDATE_BIN_FILENAME).c_str(),_download)) { + _latestValid = true; printf("VALID UPDATE\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - return true; + } else { + _latestMeta = nlohmann::json(); + _latestValid = false; } + _download = std::string(); + _downloadLength = 0; + return _latestValid; } - } catch ( ... ) {} // any exception equals verification failure - printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); - - // If we get here, checks failed. - _latestMeta = nlohmann::json(); - _latestBin = ""; - _latestBinLength = 0; - _latestBinValid = false; - } + } + } catch ( ... ) {} // any exception equals verification failure + + // If we get here, checks failed. + printf("INVALID UPDATE (!!!)\n%s\n",OSUtils::jsonDump(_latestMeta).c_str()); + _latestMeta = nlohmann::json(); + _latestValid = false; + _download = std::string(); + _downloadLength = 0; } else { Buffer<128> gd; gd.append((uint8_t)VERB_GET_DATA); - gd.append(_latestBinHashPrefix.data,16); - gd.append((uint32_t)_latestBin.length()); + gd.append(_downloadHashPrefix.data,16); + gd.append((uint32_t)_download.length()); _node.sendUserMessage(ZT_SOFTWARE_UPDATE_SERVICE,ZT_SOFTWARE_UPDATE_USER_MESSAGE_TYPE,gd.data(),gd.size()); - printf(">> GET_DATA @%u\n",(unsigned int)_latestBin.length()); + printf(">> GET_DATA @%u\n",(unsigned int)_download.length()); } } @@ -493,8 +506,6 @@ bool SoftwareUpdater::check(const uint64_t now) void SoftwareUpdater::apply() { - if ((_latestBin.length() > 0)&&(_latestBinValid)) { - } } } // namespace ZeroTier diff --git a/service/SoftwareUpdater.hpp b/service/SoftwareUpdater.hpp index b9cabf23..26e44f86 100644 --- a/service/SoftwareUpdater.hpp +++ b/service/SoftwareUpdater.hpp @@ -69,6 +69,16 @@ */ #define ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL "release" +/** + * Filename for latest update's meta JSON + */ +#define ZT_SOFTWARE_UPDATE_META_FILENAME "latest-update.json" + +/** + * Filename for latest update's binary image + */ +#define ZT_SOFTWARE_UPDATE_BIN_FILENAME "latest-update.exe" + #define ZT_SOFTWARE_UPDATE_JSON_VERSION_MAJOR "versionMajor" #define ZT_SOFTWARE_UPDATE_JSON_VERSION_MINOR "versionMinor" #define ZT_SOFTWARE_UPDATE_JSON_VERSION_REVISION "versionRev" @@ -188,10 +198,11 @@ private: std::map< Array<uint8_t,16>,_D > _dist; // key is first 16 bytes of hash nlohmann::json _latestMeta; - std::string _latestBin; - Array<uint8_t,16> _latestBinHashPrefix; - unsigned long _latestBinLength; - bool _latestBinValid; + bool _latestValid; + + std::string _download; + Array<uint8_t,16> _downloadHashPrefix; + unsigned long _downloadLength; }; } // namespace ZeroTier |