Updater.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2012-2013 ZeroTier Networks LLC
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #include "Updater.hpp"
  28. #include "RuntimeEnvironment.hpp"
  29. #include "Logger.hpp"
  30. #include "Defaults.hpp"
  31. #include "Utils.hpp"
  32. #include "Topology.hpp"
  33. #include "Switch.hpp"
  34. #include "SHA512.hpp"
  35. #include "../version.h"
  36. namespace ZeroTier {
  37. Updater::Updater(const RuntimeEnvironment *renv) :
  38. _r(renv),
  39. _download((_Download *)0)
  40. {
  41. refreshShared();
  42. }
  43. Updater::~Updater()
  44. {
  45. Mutex::Lock _l(_lock);
  46. delete _download;
  47. }
  48. void Updater::refreshShared()
  49. {
  50. std::string updatesPath(_r->homePath + ZT_PATH_SEPARATOR_S + "updates.d");
  51. std::map<std::string,bool> ud(Utils::listDirectory(updatesPath.c_str()));
  52. Mutex::Lock _l(_lock);
  53. _sharedUpdates.clear();
  54. for(std::map<std::string,bool>::iterator u(ud.begin());u!=ud.end();++u) {
  55. if (u->second)
  56. continue; // skip directories
  57. if ((u->first.length() >= 4)&&(!strcasecmp(u->first.substr(u->first.length() - 4).c_str(),".sig")))
  58. continue; // skip .sig companion files
  59. std::string fullPath(updatesPath + ZT_PATH_SEPARATOR_S + u->first);
  60. std::string sigPath(fullPath + ".sig");
  61. std::string buf;
  62. if (Utils::readFile(sigPath.c_str(),buf)) {
  63. Dictionary sig(buf);
  64. SharedUpdate shared;
  65. shared.fullPath = fullPath;
  66. shared.filename = u->first;
  67. std::string sha512(Utils::unhex(sig.get("sha512",std::string())));
  68. std::string signature(Utils::unhex(sig.get("sha512_ed25519",std::string())));
  69. Address signedBy(sig.get("signedBy",std::string()));
  70. if ((sha512.length() < sizeof(shared.sha512))||(signature.length() < shared.sig.size())||(!signedBy)) {
  71. TRACE("skipped shareable update due to missing fields in companion .sig: %s",fullPath.c_str());
  72. continue;
  73. }
  74. memcpy(shared.sha512,sha512.data(),sizeof(shared.sha512));
  75. memcpy(shared.sig.data,signature.data(),shared.sig.size());
  76. shared.signedBy = signedBy;
  77. int64_t fs = Utils::getFileSize(fullPath.c_str());
  78. if (fs <= 0) {
  79. TRACE("skipped shareable update due to unreadable, invalid, or 0-byte file: %s",fullPath.c_str());
  80. continue;
  81. }
  82. shared.size = (unsigned long)fs;
  83. LOG("sharing software update %s to other peers",shared.filename.c_str());
  84. _sharedUpdates.push_back(shared);
  85. } else {
  86. TRACE("skipped shareable update due to missing companion .sig: %s",fullPath.c_str());
  87. continue;
  88. }
  89. }
  90. }
  91. void Updater::getUpdateIfThisIsNewer(unsigned int vMajor,unsigned int vMinor,unsigned int revision)
  92. {
  93. if (!compareVersions(vMajor,vMinor,revision,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION))
  94. return;
  95. std::string updateFilename(generateUpdateFilename(vMajor,vMinor,revision));
  96. if (!updateFilename.length()) {
  97. TRACE("an update to %u.%u.%u is available, but this platform or build doesn't support auto-update",vMajor,vMinor,revision);
  98. return;
  99. }
  100. std::vector< SharedPtr<Peer> > peers;
  101. _r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(peers,Utils::now()));
  102. TRACE("new update available to %u.%u.%u, looking for %s from %u peers",vMajor,vMinor,revision,updateFilename.c_str(),(unsigned int)peers.size());
  103. for(std::vector< SharedPtr<Peer> >::iterator p(peers.begin());p!=peers.end();++p) {
  104. Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST);
  105. outp.append((unsigned char)0);
  106. outp.append((uint16_t)updateFilename.length());
  107. outp.append(updateFilename.data(),updateFilename.length());
  108. _r->sw->send(outp,true);
  109. }
  110. }
  111. void Updater::retryIfNeeded()
  112. {
  113. Mutex::Lock _l(_lock);
  114. if (_download) {
  115. uint64_t elapsed = Utils::now() - _download->lastChunkReceivedAt;
  116. if ((elapsed >= ZT_UPDATER_PEER_TIMEOUT)||(!_download->currentlyReceivingFrom)) {
  117. if (_download->peersThatHave.empty()) {
  118. // Search for more sources if we have no more possibilities queued
  119. TRACE("all sources for %s timed out, searching for more...",_download->filename.c_str());
  120. _download->currentlyReceivingFrom.zero();
  121. std::vector< SharedPtr<Peer> > peers;
  122. _r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(peers,Utils::now()));
  123. for(std::vector< SharedPtr<Peer> >::iterator p(peers.begin());p!=peers.end();++p) {
  124. Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST);
  125. outp.append((unsigned char)0);
  126. outp.append((uint16_t)_download->filename.length());
  127. outp.append(_download->filename.data(),_download->filename.length());
  128. _r->sw->send(outp,true);
  129. }
  130. } else {
  131. // If that peer isn't answering, try the next queued source
  132. _download->currentlyReceivingFrom = _download->peersThatHave.front();
  133. _download->peersThatHave.pop_front();
  134. _requestNextChunk();
  135. }
  136. } else if (elapsed >= ZT_UPDATER_RETRY_TIMEOUT) {
  137. // Re-request next chunk we don't have from current source
  138. _requestNextChunk();
  139. }
  140. }
  141. }
  142. void Updater::handleChunk(const Address &from,const void *sha512,unsigned int shalen,unsigned long at,const void *chunk,unsigned long len)
  143. {
  144. Mutex::Lock _l(_lock);
  145. if (!_download) {
  146. TRACE("got chunk from %s while no download is in progress, ignored",from.toString().c_str());
  147. return;
  148. }
  149. if (memcmp(_download->sha512,sha512,(shalen > 64) ? 64 : shalen)) {
  150. TRACE("got chunk from %s for wrong download (SHA mismatch), ignored",from.toString().c_str());
  151. return;
  152. }
  153. unsigned long whichChunk = at / ZT_UPDATER_CHUNK_SIZE;
  154. if (
  155. (at != (ZT_UPDATER_CHUNK_SIZE * whichChunk))||
  156. (whichChunk >= _download->haveChunks.size())||
  157. ((whichChunk == (_download->haveChunks.size() - 1))&&(len != _download->lastChunkSize))||
  158. (len != ZT_UPDATER_CHUNK_SIZE)
  159. ) {
  160. TRACE("got chunk from %s at invalid position or invalid size, ignored",from.toString().c_str());
  161. return;
  162. }
  163. for(unsigned long i=0;i<len;++i)
  164. _download->data[at + i] = ((const char *)chunk)[i];
  165. _download->haveChunks[whichChunk] = true;
  166. _download->lastChunkReceivedAt = Utils::now();
  167. _requestNextChunk();
  168. }
  169. void Updater::handlePeerHasFile(const Address &from,const char *filename,const void *sha512,unsigned long filesize,const Address &signedBy,const void *signature,unsigned int siglen)
  170. {
  171. unsigned int vMajor = 0,vMinor = 0,revision = 0;
  172. if (!parseUpdateFilename(filename,vMajor,vMinor,revision)) {
  173. TRACE("rejected offer of %s from %s: could not extract version information from filename",filename,from.toString().c_str());
  174. return;
  175. }
  176. if (filesize > ZT_UPDATER_MAX_SUPPORTED_SIZE) {
  177. TRACE("rejected offer of %s from %s: file too large (%u > %u)",filename,from.toString().c_str(),(unsigned int)filesize,(unsigned int)ZT_UPDATER_MAX_SUPPORTED_SIZE);
  178. return;
  179. }
  180. if (!compareVersions(vMajor,vMinor,revision,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION)) {
  181. TRACE("rejected offer of %s from %s: version older than mine",filename,from.toString().c_str());
  182. return;
  183. }
  184. Mutex::Lock _l(_lock);
  185. if (_download) {
  186. if ((_download->filename == filename)&&(_download->data.length() == filesize)&&(!memcmp(sha512,_download->sha512,64))) {
  187. // Learn another source for the current download if this is the
  188. // same file.
  189. LOG("learned new source for %s: %s",filename,from.toString().c_str());
  190. if (!_download->currentlyReceivingFrom) {
  191. _download->currentlyReceivingFrom = from;
  192. _requestNextChunk();
  193. } else _download->peersThatHave.push_back(from);
  194. return;
  195. } else {
  196. // If there's a download, compare versions... only proceed if this
  197. // file being offered is newer.
  198. if (!compareVersions(vMajor,vMinor,revision,_download->versionMajor,_download->versionMinor,_download->revision)) {
  199. TRACE("rejected offer of %s from %s: already downloading newer version %s",filename,from.toString().c_str(),_download->filename.c_str());
  200. return;
  201. }
  202. }
  203. }
  204. // If we have no download OR if this was a different file, check its
  205. // validity via signature and then see if it's newer. If so start a new
  206. // download for it.
  207. {
  208. std::string nameAndSha(filename);
  209. nameAndSha.append((const char *)sha512,64);
  210. std::map< Address,Identity >::const_iterator uauth(ZT_DEFAULTS.updateAuthorities.find(signedBy));
  211. if (uauth == ZT_DEFAULTS.updateAuthorities.end()) {
  212. LOG("rejected offer of %s from %s: failed authentication: unknown signer %s",filename,from.toString().c_str(),signedBy.toString().c_str());
  213. return;
  214. }
  215. if (!uauth->second.verify(nameAndSha.data(),nameAndSha.length(),signature,siglen)) {
  216. LOG("rejected offer of %s from %s: failed authentication: signature from %s invalid",filename,from.toString().c_str(),signedBy.toString().c_str());
  217. return;
  218. }
  219. }
  220. // Replace existing download if any.
  221. delete _download;
  222. _download = (_Download *)0;
  223. // Create and initiate new download
  224. _download = new _Download;
  225. try {
  226. LOG("beginning download of software update %s from %s (%u bytes, signed by authorized identity %s)",filename,from.toString().c_str(),(unsigned int)filesize,signedBy.toString().c_str());
  227. _download->data.assign(filesize,(char)0);
  228. _download->haveChunks.resize((filesize / ZT_UPDATER_CHUNK_SIZE) + 1,false);
  229. _download->filename = filename;
  230. memcpy(_download->sha512,sha512,64);
  231. _download->currentlyReceivingFrom = from;
  232. _download->lastChunkReceivedAt = 0;
  233. _download->lastChunkSize = filesize % ZT_UPDATER_CHUNK_SIZE;
  234. _download->versionMajor = vMajor;
  235. _download->versionMinor = vMinor;
  236. _download->revision = revision;
  237. _requestNextChunk();
  238. } catch (std::exception &exc) {
  239. delete _download;
  240. _download = (_Download *)0;
  241. LOG("unable to begin download of %s from %s: %s",filename,from.toString().c_str(),exc.what());
  242. } catch ( ... ) {
  243. delete _download;
  244. _download = (_Download *)0;
  245. LOG("unable to begin download of %s from %s: unknown exception",filename,from.toString().c_str());
  246. }
  247. }
  248. bool Updater::findSharedUpdate(const char *filename,SharedUpdate &update) const
  249. {
  250. Mutex::Lock _l(_lock);
  251. for(std::list<SharedUpdate>::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) {
  252. if (u->filename == filename) {
  253. update = *u;
  254. return true;
  255. }
  256. }
  257. return false;
  258. }
  259. bool Updater::findSharedUpdate(const void *sha512,unsigned int shalen,SharedUpdate &update) const
  260. {
  261. if (!shalen)
  262. return false;
  263. Mutex::Lock _l(_lock);
  264. for(std::list<SharedUpdate>::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) {
  265. if (!memcmp(u->sha512,sha512,(shalen > 64) ? 64 : shalen)) {
  266. update = *u;
  267. return true;
  268. }
  269. }
  270. return false;
  271. }
  272. bool Updater::getSharedChunk(const void *sha512,unsigned int shalen,unsigned long at,void *chunk,unsigned long chunklen) const
  273. {
  274. if (!chunklen)
  275. return true;
  276. if (!shalen)
  277. return false;
  278. Mutex::Lock _l(_lock);
  279. for(std::list<SharedUpdate>::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) {
  280. if (!memcmp(u->sha512,sha512,(shalen > 64) ? 64 : shalen)) {
  281. FILE *f = fopen(u->fullPath.c_str(),"rb");
  282. if (!f)
  283. return false;
  284. if (!fseek(f,(long)at,SEEK_SET)) {
  285. fclose(f);
  286. return false;
  287. }
  288. if (fread(chunk,chunklen,1,f) != 1) {
  289. fclose(f);
  290. return false;
  291. }
  292. fclose(f);
  293. return true;
  294. }
  295. }
  296. return false;
  297. }
  298. std::string Updater::generateUpdateFilename(unsigned int vMajor,unsigned int vMinor,unsigned int revision)
  299. {
  300. // Defining ZT_OFFICIAL_BUILD enables this cascade of macros, which will
  301. // make your build auto-update itself if it's for an officially supported
  302. // architecture. The signing identity for auto-updates is in Defaults.
  303. #ifdef ZT_OFFICIAL_BUILD
  304. // Not supported... yet? Get it first cause it might identify as Linux too.
  305. #ifdef __ANDROID__
  306. #define _updSupported 1
  307. return std::string();
  308. #endif
  309. // Linux on x86 and possibly in the future ARM
  310. #ifdef __LINUX__
  311. #if defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__amd64) || defined(__x86_64) || defined(i386)
  312. #define _updSupported 1
  313. char buf[128];
  314. Utils::snprintf(buf,sizeof(buf),"zt1-%u_%u_%u-linux-%s-install",vMajor,vMinor,revision,(sizeof(void *) == 8) ? "x64" : "x86");
  315. return std::string(buf);
  316. #endif
  317. /*
  318. #if defined(__arm__) || defined(__arm) || defined(__aarch64__)
  319. #define _updSupported 1
  320. char buf[128];
  321. Utils::snprintf(buf,sizeof(buf),"zt1-%u_%u_%u-linux-%s-install",vMajor,vMinor,revision,(sizeof(void *) == 8) ? "arm64" : "arm32");
  322. return std::string(buf);
  323. #endif
  324. */
  325. #endif
  326. // Apple stuff... only Macs so far...
  327. #ifdef __APPLE__
  328. #define _updSupported 1
  329. #if defined(__powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64) || defined(__ppc64__) || defined(__powerpc64__)
  330. return std::string();
  331. #endif
  332. #if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
  333. return std::string();
  334. #endif
  335. char buf[128];
  336. Utils::snprintf(buf,sizeof(buf),"zt1-%u_%u_%u-mac-x86combined-install",vMajor,vMinor,revision);
  337. return std::string(buf);
  338. #endif
  339. // ???
  340. #ifndef _updSupported
  341. return std::string();
  342. #endif
  343. #else
  344. return std::string();
  345. #endif // ZT_OFFICIAL_BUILD
  346. }
  347. bool Updater::parseUpdateFilename(const char *filename,unsigned int &vMajor,unsigned int &vMinor,unsigned int &revision)
  348. {
  349. std::vector<std::string> byDash(Utils::split(filename,"-","",""));
  350. if (byDash.size() < 2)
  351. return false;
  352. std::vector<std::string> byUnderscore(Utils::split(byDash[1].c_str(),"_","",""));
  353. if (byUnderscore.size() < 3)
  354. return false;
  355. vMajor = Utils::strToUInt(byUnderscore[0].c_str());
  356. vMinor = Utils::strToUInt(byUnderscore[1].c_str());
  357. revision = Utils::strToUInt(byUnderscore[2].c_str());
  358. return true;
  359. }
  360. void Updater::_requestNextChunk()
  361. {
  362. // assumes _lock is locked
  363. if (!_download)
  364. return;
  365. unsigned long whichChunk = 0;
  366. std::vector<bool>::iterator ptr(std::find(_download->haveChunks.begin(),_download->haveChunks.end(),false));
  367. if (ptr == _download->haveChunks.end()) {
  368. unsigned char digest[64];
  369. SHA512::hash(digest,_download->data.data(),_download->data.length());
  370. if (memcmp(digest,_download->sha512,64)) {
  371. LOG("retrying download of %s -- SHA-512 mismatch, file corrupt!",_download->filename.c_str());
  372. std::fill(_download->haveChunks.begin(),_download->haveChunks.end(),false);
  373. whichChunk = 0;
  374. } else {
  375. LOG("successfully downloaded and authenticated %s, launching update...",_download->filename.c_str());
  376. delete _download;
  377. _download = (_Download *)0;
  378. return;
  379. }
  380. } else {
  381. whichChunk = std::distance(_download->haveChunks.begin(),ptr);
  382. }
  383. 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());
  384. Packet outp(_download->currentlyReceivingFrom,_r->identity.address(),Packet::VERB_FILE_BLOCK_REQUEST);
  385. outp.append(_download->sha512,16);
  386. outp.append((uint32_t)(whichChunk * ZT_UPDATER_CHUNK_SIZE));
  387. if (whichChunk == (_download->haveChunks.size() - 1))
  388. outp.append((uint16_t)_download->lastChunkSize);
  389. else outp.append((uint16_t)ZT_UPDATER_CHUNK_SIZE);
  390. _r->sw->send(outp,true);
  391. }
  392. } // namespace ZeroTier