Updater.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  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(),".nfo")))
  58. continue; // skip .nfo companion files
  59. std::string fullPath(updatesPath + ZT_PATH_SEPARATOR_S + u->first);
  60. std::string nfoPath(fullPath + ".nfo");
  61. std::string buf;
  62. if (Utils::readFile(nfoPath.c_str(),buf)) {
  63. Dictionary nfo(buf);
  64. SharedUpdate shared;
  65. shared.fullPath = fullPath;
  66. shared.filename = u->first;
  67. std::string sha512(Utils::unhex(nfo.get("sha512",std::string())));
  68. if (sha512.length() < sizeof(shared.sha512)) {
  69. TRACE("skipped shareable update due to missing fields in companion .nfo: %s",fullPath.c_str());
  70. continue;
  71. }
  72. memcpy(shared.sha512,sha512.data(),sizeof(shared.sha512));
  73. std::string sig(Utils::unhex(nfo.get("sha512sig_ed25519",std::string())));
  74. if (sig.length() < shared.sig.size()) {
  75. TRACE("skipped shareable update due to missing fields in companion .nfo: %s",fullPath.c_str());
  76. continue;
  77. }
  78. memcpy(shared.sig.data,sig.data(),shared.sig.size());
  79. // Check signature to guard against updates.d being used as a data
  80. // exfiltration mechanism. We will only share properly signed updates,
  81. // nothing else.
  82. Address signedBy(nfo.get("signedBy",std::string()));
  83. std::map< Address,Identity >::const_iterator authority(ZT_DEFAULTS.updateAuthorities.find(signedBy));
  84. if ((authority == ZT_DEFAULTS.updateAuthorities.end())||(!authority->second.verify(shared.sha512,64,shared.sig))) {
  85. TRACE("skipped shareable update: not signed by valid authority or signature invalid: %s",fullPath.c_str());
  86. continue;
  87. }
  88. shared.signedBy = signedBy;
  89. int64_t fs = Utils::getFileSize(fullPath.c_str());
  90. if (fs <= 0) {
  91. TRACE("skipped shareable update due to unreadable, invalid, or 0-byte file: %s",fullPath.c_str());
  92. continue;
  93. }
  94. shared.size = (unsigned long)fs;
  95. _sharedUpdates.push_back(shared);
  96. } else {
  97. TRACE("skipped shareable update due to missing companion .nfo: %s",fullPath.c_str());
  98. continue;
  99. }
  100. }
  101. }
  102. void Updater::getUpdateIfThisIsNewer(unsigned int vMajor,unsigned int vMinor,unsigned int revision)
  103. {
  104. if (vMajor < ZEROTIER_ONE_VERSION_MAJOR)
  105. return;
  106. else if (vMajor == ZEROTIER_ONE_VERSION_MAJOR) {
  107. if (vMinor < ZEROTIER_ONE_VERSION_MINOR)
  108. return;
  109. else if (vMinor == ZEROTIER_ONE_VERSION_MINOR) {
  110. if (revision <= ZEROTIER_ONE_VERSION_REVISION)
  111. return;
  112. }
  113. }
  114. std::string updateFilename(generateUpdateFilename(vMajor,vMinor,revision));
  115. if (!updateFilename.length()) {
  116. TRACE("an update to %u.%u.%u is available, but this platform or build doesn't support auto-update",vMajor,vMinor,revision);
  117. return;
  118. }
  119. std::vector< SharedPtr<Peer> > peers;
  120. _r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(peers,Utils::now()));
  121. TRACE("new update available to %u.%u.%u, looking for %s from %u peers",vMajor,vMinor,revision,updateFilename.c_str(),(unsigned int)peers.size());
  122. for(std::vector< SharedPtr<Peer> >::iterator p(peers.begin());p!=peers.end();++p) {
  123. Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST);
  124. outp.append((unsigned char)0);
  125. outp.append((uint16_t)updateFilename.length());
  126. outp.append(updateFilename.data(),updateFilename.length());
  127. _r->sw->send(outp,true);
  128. }
  129. }
  130. void Updater::retryIfNeeded()
  131. {
  132. Mutex::Lock _l(_lock);
  133. if (_download) {
  134. uint64_t elapsed = Utils::now() - _download->lastChunkReceivedAt;
  135. if ((elapsed >= ZT_UPDATER_PEER_TIMEOUT)||(!_download->currentlyReceivingFrom)) {
  136. if (_download->peersThatHave.empty()) {
  137. // Search for more sources if we have no more possibilities queued
  138. _download->currentlyReceivingFrom.zero();
  139. std::vector< SharedPtr<Peer> > peers;
  140. _r->topology->eachPeer(Topology::CollectPeersWithActiveDirectPath(peers,Utils::now()));
  141. for(std::vector< SharedPtr<Peer> >::iterator p(peers.begin());p!=peers.end();++p) {
  142. Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_FILE_INFO_REQUEST);
  143. outp.append((unsigned char)0);
  144. outp.append((uint16_t)_download->filename.length());
  145. outp.append(_download->filename.data(),_download->filename.length());
  146. _r->sw->send(outp,true);
  147. }
  148. } else {
  149. // If that peer isn't answering, try the next queued source
  150. _download->currentlyReceivingFrom = _download->peersThatHave.front();
  151. _download->peersThatHave.pop_front();
  152. }
  153. } else if (elapsed >= ZT_UPDATER_RETRY_TIMEOUT) {
  154. // Re-request next chunk we don't have from current source
  155. _requestNextChunk();
  156. }
  157. }
  158. }
  159. void Updater::handleChunk(const Address &from,const void *sha512,unsigned int shalen,unsigned long at,const void *chunk,unsigned long len)
  160. {
  161. Mutex::Lock _l(_lock);
  162. if (!_download) {
  163. TRACE("got chunk from %s while no download is in progress, ignored",from.toString().c_str());
  164. return;
  165. }
  166. if (memcmp(_download->sha512,sha512,(shalen > 64) ? 64 : shalen)) {
  167. TRACE("got chunk from %s for wrong download (SHA mismatch), ignored",from.toString().c_str());
  168. return;
  169. }
  170. unsigned long whichChunk = at / ZT_UPDATER_CHUNK_SIZE;
  171. if (at != (ZT_UPDATER_CHUNK_SIZE * whichChunk))
  172. return; // not at chunk boundary
  173. if (whichChunk >= _download->haveChunks.size())
  174. return; // overflow
  175. if ((whichChunk == (_download->haveChunks.size() - 1))&&(len != _download->lastChunkSize))
  176. return; // last chunk, size wrong
  177. else if (len != ZT_UPDATER_CHUNK_SIZE)
  178. return; // chunk size wrong
  179. for(unsigned long i=0;i<len;++i)
  180. _download->data[at + i] = ((const char *)chunk)[i];
  181. _download->haveChunks[whichChunk] = true;
  182. _download->lastChunkReceivedAt = Utils::now();
  183. _requestNextChunk();
  184. }
  185. void Updater::handleAvailable(const Address &from,const char *filename,const void *sha512,unsigned long filesize,const Address &signedBy,const void *signature,unsigned int siglen)
  186. {
  187. unsigned int vMajor = 0,vMinor = 0,revision = 0;
  188. if (!parseUpdateFilename(filename,vMajor,vMinor,revision)) {
  189. TRACE("rejected offer of %s from %s: could not parse version information",filename,from.toString().c_str());
  190. return;
  191. }
  192. if (filesize > ZT_UPDATER_MAX_SUPPORTED_SIZE) {
  193. TRACE("rejected offer of %s from %s: file too large (%u)",filename,from.toString().c_str(),(unsigned int)filesize);
  194. return;
  195. }
  196. if (vMajor < ZEROTIER_ONE_VERSION_MAJOR)
  197. return;
  198. else if (vMajor == ZEROTIER_ONE_VERSION_MAJOR) {
  199. if (vMinor < ZEROTIER_ONE_VERSION_MINOR)
  200. return;
  201. else if (vMinor == ZEROTIER_ONE_VERSION_MINOR) {
  202. if (revision <= ZEROTIER_ONE_VERSION_REVISION)
  203. return;
  204. }
  205. }
  206. Mutex::Lock _l(_lock);
  207. if (_download) {
  208. // If a download is in progress, only accept this as another source if
  209. // it matches the size, hash, and version. Also check if this is a newer
  210. // version and if so replace download with this.
  211. } else {
  212. // If there is no download in progress, create one provided the signature
  213. // for the SHA-512 hash verifies as being from a valid signer.
  214. }
  215. }
  216. bool Updater::findSharedUpdate(const char *filename,SharedUpdate &update) const
  217. {
  218. Mutex::Lock _l(_lock);
  219. for(std::list<SharedUpdate>::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) {
  220. if (u->filename == filename) {
  221. update = *u;
  222. return true;
  223. }
  224. }
  225. return false;
  226. }
  227. bool Updater::findSharedUpdate(const void *sha512,unsigned int shalen,SharedUpdate &update) const
  228. {
  229. if (!shalen)
  230. return false;
  231. Mutex::Lock _l(_lock);
  232. for(std::list<SharedUpdate>::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) {
  233. if (!memcmp(u->sha512,sha512,(shalen > 64) ? 64 : shalen)) {
  234. update = *u;
  235. return true;
  236. }
  237. }
  238. return false;
  239. }
  240. bool Updater::getSharedChunk(const void *sha512,unsigned int shalen,unsigned long at,void *chunk,unsigned long chunklen) const
  241. {
  242. if (!chunklen)
  243. return true;
  244. if (!shalen)
  245. return false;
  246. Mutex::Lock _l(_lock);
  247. for(std::list<SharedUpdate>::const_iterator u(_sharedUpdates.begin());u!=_sharedUpdates.end();++u) {
  248. if (!memcmp(u->sha512,sha512,(shalen > 64) ? 64 : shalen)) {
  249. FILE *f = fopen(u->fullPath.c_str(),"rb");
  250. if (!f)
  251. return false;
  252. if (!fseek(f,(long)at,SEEK_SET)) {
  253. fclose(f);
  254. return false;
  255. }
  256. if (fread(chunk,chunklen,1,f) != 1) {
  257. fclose(f);
  258. return false;
  259. }
  260. fclose(f);
  261. return true;
  262. }
  263. }
  264. return false;
  265. }
  266. std::string Updater::generateUpdateFilename(unsigned int vMajor,unsigned int vMinor,unsigned int revision)
  267. {
  268. // Defining ZT_OFFICIAL_BUILD enables this cascade of macros, which will
  269. // make your build auto-update itself if it's for an officially supported
  270. // architecture. The signing identity for auto-updates is in Defaults.
  271. #ifdef ZT_OFFICIAL_BUILD
  272. // Not supported... yet? Get it first cause it might identify as Linux too.
  273. #ifdef __ANDROID__
  274. #define _updSupported 1
  275. return std::string();
  276. #endif
  277. // Linux on x86 and possibly in the future ARM
  278. #ifdef __LINUX__
  279. #if defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) || defined(__amd64) || defined(__x86_64) || defined(i386)
  280. #define _updSupported 1
  281. char buf[128];
  282. Utils::snprintf(buf,sizeof(buf),"zt1-%u_%u_%u-linux-%s-update",vMajor,vMinor,revision,(sizeof(void *) == 8) ? "x64" : "x86");
  283. return std::string(buf);
  284. #endif
  285. /*
  286. #if defined(__arm__) || defined(__arm) || defined(__aarch64__)
  287. #define _updSupported 1
  288. char buf[128];
  289. Utils::snprintf(buf,sizeof(buf),"zt1-%u_%u_%u-linux-%s-update",vMajor,vMinor,revision,(sizeof(void *) == 8) ? "arm64" : "arm32");
  290. return std::string(buf);
  291. #endif
  292. */
  293. #endif
  294. // Apple stuff... only Macs so far...
  295. #ifdef __APPLE__
  296. #define _updSupported 1
  297. #if defined(__powerpc) || defined(__powerpc__) || defined(__ppc__) || defined(__ppc64) || defined(__ppc64__) || defined(__powerpc64__)
  298. return std::string();
  299. #endif
  300. #if defined(TARGET_IPHONE_SIMULATOR) || defined(TARGET_OS_IPHONE)
  301. return std::string();
  302. #endif
  303. char buf[128];
  304. Utils::snprintf(buf,sizeof(buf),"zt1-%u_%u_%u-mac-x86combined-update",vMajor,vMinor,revision);
  305. return std::string(buf);
  306. #endif
  307. // ???
  308. #ifndef _updSupported
  309. return std::string();
  310. #endif
  311. #else
  312. return std::string();
  313. #endif // ZT_OFFICIAL_BUILD
  314. }
  315. bool Updater::parseUpdateFilename(const char *filename,unsigned int &vMajor,unsigned int &vMinor,unsigned int &revision)
  316. {
  317. std::vector<std::string> byDash(Utils::split(filename,"-","",""));
  318. if (byDash.size() < 2)
  319. return false;
  320. std::vector<std::string> byUnderscore(Utils::split(byDash[1].c_str(),"_","",""));
  321. if (byUnderscore.size() < 3)
  322. return false;
  323. vMajor = Utils::strToUInt(byUnderscore[0].c_str());
  324. vMinor = Utils::strToUInt(byUnderscore[1].c_str());
  325. revision = Utils::strToUInt(byUnderscore[2].c_str());
  326. return true;
  327. }
  328. void Updater::_requestNextChunk()
  329. {
  330. // assumes _lock is locked
  331. if (!_download)
  332. return;
  333. unsigned long whichChunk = 0;
  334. std::vector<bool>::iterator ptr(std::find(_download->haveChunks.begin(),_download->haveChunks.end(),false));
  335. if (ptr == _download->haveChunks.end()) {
  336. unsigned char digest[64];
  337. SHA512::hash(digest,_download->data.data(),_download->data.length());
  338. if (memcmp(digest,_download->sha512,64)) {
  339. LOG("retrying download of %s -- SHA-512 mismatch, file corrupt!",_download->filename.c_str());
  340. std::fill(_download->haveChunks.begin(),_download->haveChunks.end(),false);
  341. whichChunk = 0;
  342. } else {
  343. LOG("successfully downloaded and authenticated %s, launching update...",_download->filename.c_str());
  344. delete _download;
  345. _download = (_Download *)0;
  346. return;
  347. }
  348. } else {
  349. whichChunk = std::distance(_download->haveChunks.begin(),ptr);
  350. }
  351. 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());
  352. Packet outp(_download->currentlyReceivingFrom,_r->identity.address(),Packet::VERB_FILE_BLOCK_REQUEST);
  353. outp.append(_download->sha512,16);
  354. outp.append((uint32_t)(whichChunk * ZT_UPDATER_CHUNK_SIZE));
  355. if (whichChunk == (_download->haveChunks.size() - 1))
  356. outp.append((uint16_t)_download->lastChunkSize);
  357. else outp.append((uint16_t)ZT_UPDATER_CHUNK_SIZE);
  358. _r->sw->send(outp,true);
  359. }
  360. } // namespace ZeroTier