DBM.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
  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. * You can be released from the requirements of the license by purchasing
  21. * a commercial license. Buying such a license is mandatory as soon as you
  22. * develop commercial closed-source software that incorporates or links
  23. * directly against ZeroTier software without disclosing the source code
  24. * of your own application.
  25. */
  26. #include "DBM.hpp"
  27. #include "../version.h"
  28. #include "../node/Salsa20.hpp"
  29. #include "../node/Poly1305.hpp"
  30. #include "../node/SHA512.hpp"
  31. #include "../osdep/OSUtils.hpp"
  32. #define ZT_STORED_OBJECT_TYPE__CLUSTER_NODE_STATUS (ZT_STORED_OBJECT__MAX_TYPE_ID + 1)
  33. #define ZT_STORED_OBJECT_TYPE__CLUSTER_DEFINITION (ZT_STORED_OBJECT__MAX_TYPE_ID + 2)
  34. namespace ZeroTier {
  35. // We generate the cluster ID from our address and version info since this is
  36. // not at all designed to allow interoperation between versions (or endians)
  37. // in the same cluster.
  38. static inline uint64_t _mkClusterId(const Address &myAddress)
  39. {
  40. uint64_t x = ZEROTIER_ONE_VERSION_MAJOR;
  41. x <<= 8;
  42. x += ZEROTIER_ONE_VERSION_MINOR;
  43. x <<= 8;
  44. x += ZEROTIER_ONE_VERSION_REVISION;
  45. x <<= 40;
  46. x ^= myAddress.toInt();
  47. #if __BYTE_ORDER == __BIG_ENDIAN
  48. ++x;
  49. #endif;
  50. return x;
  51. }
  52. void DBM::onUpdate(uint64_t from,const _MapKey &k,const _MapValue &v,uint64_t rev)
  53. {
  54. char p[4096];
  55. char tmp[ZT_DBM_MAX_VALUE_SIZE];
  56. if (_persistentPath((ZT_StoredObjectType)k.type,k.key,p,sizeof(p))) {
  57. // Reduce unnecessary disk writes
  58. FILE *f = fopen(p,"r");
  59. if (f) {
  60. long n = (long)fread(tmp,1,sizeof(tmp),f);
  61. fclose(f);
  62. if ((n == (long)v.len)&&(!memcmp(v.data,tmp,n)))
  63. return;
  64. }
  65. // Write to disk if file has changed or was not already present
  66. f = fopen(p,"w");
  67. if (f) {
  68. if (fwrite(data,len,1,f) != 1)
  69. fprintf(stderr,"WARNING: error writing to %s (I/O error)" ZT_EOL_S,p);
  70. fclose(f);
  71. if (type == ZT_STORED_OBJECT_IDENTITY_SECRET)
  72. OSUtils::lockDownFile(p,false);
  73. } else {
  74. fprintf(stderr,"WARNING: error writing to %s (cannot open)" ZT_EOL_S,p);
  75. }
  76. }
  77. }
  78. void DBM::onDelete(uint64_t from,const _MapKey &k)
  79. {
  80. char p[4096];
  81. if (_persistentPath((ZT_StoredObjectType)k.type,k.key,p,sizeof(p)))
  82. OSUtils::rm(p);
  83. }
  84. DBM::_vsdm_cryptor::_vsdm_cryptor(const Identity &secretIdentity)
  85. {
  86. uint8_t s512[64];
  87. SHA512::hash(h512,secretIdentity.privateKeyPair().priv.data,ZT_C25519_PRIVATE_KEY_LEN);
  88. memcpy(_key,s512,sizeof(_key));
  89. }
  90. void DBM::_vsdm_cryptor::encrypt(void *d,unsigned long l)
  91. {
  92. if (l >= 24) { // sanity check
  93. uint8_t key[32];
  94. uint8_t authKey[32];
  95. uint8_t auth[16];
  96. uint8_t *const iv = reinterpret_cast<uint8_t *>(d) + (l - 16);
  97. Utils::getSecureRandom(iv,16);
  98. memcpy(key,_key,32);
  99. for(unsigned long i=0;i<8;++i)
  100. _key[i] ^= iv[i];
  101. Salsa20 s20(key,iv + 8);
  102. memset(authKey,0,32);
  103. s20.crypt12(authKey,authKey,32);
  104. s20.crypt12(d,d,l - 24);
  105. Poly1305::compute(auth,d,l - 24,authKey);
  106. memcpy(reinterpret_cast<uint8_t *>(d) + (l - 24),auth,8);
  107. }
  108. }
  109. bool DBM::_vsdm_cryptor::decrypt(void *d,unsigned long l)
  110. {
  111. if (l >= 24) { // sanity check
  112. uint8_t key[32];
  113. uint8_t authKey[32];
  114. uint8_t auth[16];
  115. uint8_t *const iv = reinterpret_cast<uint8_t *>(d) + (l - 16);
  116. memcpy(key,_key,32);
  117. for(unsigned long i=0;i<8;++i)
  118. _key[i] ^= iv[i];
  119. Salsa20 s20(key,iv + 8);
  120. memset(authKey,0,32);
  121. s20.crypt12(authKey,authKey,32);
  122. Poly1305::compute(auth,d,l - 24,authKey);
  123. if (!Utils::secureEq(reinterpret_cast<uint8_t *>(d) + (l - 24),auth,8))
  124. return false;
  125. s20.crypt12(d,d,l - 24);
  126. return true;
  127. }
  128. return false;
  129. }
  130. DBM::DBM(const Identity &secretIdentity,uint64_t clusterMemberId,const std::string &basePath,Node *node) :
  131. _basePath(basePath),
  132. _node(node),
  133. _startTime(OSUtils::now()),
  134. _m(_mkClusterId(secretIdentity.address()),clusterMemberId,false,_vsdm_cryptor(secretIdentity),_vsdm_watcher(this))
  135. {
  136. }
  137. DBM::~DBM()
  138. {
  139. }
  140. void DBM::put(const ZT_StoredObjectType type,const uint64_t key,const void *data,unsigned int len)
  141. {
  142. char p[4096];
  143. if (_m.put(_MapKey(key,(uint16_t)type),Value(OSUtils::now(),(uint16_t)len,data))) {
  144. if (_persistentPath(type,key,p,sizeof(p))) {
  145. FILE *f = fopen(p,"w");
  146. if (f) {
  147. if (fwrite(data,len,1,f) != 1)
  148. fprintf(stderr,"WARNING: error writing to %s (I/O error)" ZT_EOL_S,p);
  149. fclose(f);
  150. if (type == ZT_STORED_OBJECT_IDENTITY_SECRET)
  151. OSUtils::lockDownFile(p,false);
  152. } else {
  153. fprintf(stderr,"WARNING: error writing to %s (cannot open)" ZT_EOL_S,p);
  154. }
  155. }
  156. }
  157. }
  158. bool DBM::get(const ZT_StoredObjectType type,const uint64_t key,Value &value)
  159. {
  160. char p[4096];
  161. if (_m.get(_MapKey(key,(uint16_t)type),value))
  162. return true;
  163. if (_persistentPath(type,key,p,sizeof(p))) {
  164. FILE *f = fopen(p,"r");
  165. if (f) {
  166. long n = (long)fread(value.data,1,sizeof(value.data),f);
  167. value.len = (n > 0) ? (uint16_t)n : (uint16_t)0;
  168. fclose(f);
  169. value.ts = OSUtils::getLastModified(p);
  170. _m.put(_MapKey(key,(uint16_t)type),value);
  171. return true;
  172. }
  173. }
  174. return false;
  175. }
  176. void DBM::del(const ZT_StoredObjectType type,const uint64_t key)
  177. {
  178. char p[4096];
  179. _m.del(_MapKey(key,(uint16_t)type));
  180. if (_persistentPath(type,key,p,sizeof(p)))
  181. OSUtils::rm(p);
  182. }
  183. void DBM::clean()
  184. {
  185. }
  186. bool DBM::_persistentPath(const ZT_StoredObjectType type,const uint64_t key,char *p,unsigned int maxlen)
  187. {
  188. switch(type) {
  189. case ZT_STORED_OBJECT_IDENTITY_PUBLIC:
  190. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "identity.public",_basePath.c_str());
  191. return true;
  192. case ZT_STORED_OBJECT_IDENTITY_SECRET:
  193. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "identity.secret",_basePath.c_str());
  194. return true;
  195. case ZT_STORED_OBJECT_IDENTITY:
  196. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "iddb.d" ZT_PATH_SEPARATOR_S "%.10llx",_basePath.c_str(),key);
  197. return true;
  198. case ZT_STORED_OBJECT_NETWORK_CONFIG:
  199. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_basePath.c_str(),key);
  200. return true;
  201. case ZT_STORED_OBJECT_PLANET:
  202. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "planet",_basePath.c_str());
  203. return true;
  204. case ZT_STORED_OBJECT_MOON:
  205. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "moons.d" ZT_PATH_SEPARATOR_S "%.16llx.moon",_basePath.c_str(),key);
  206. return true;
  207. case (ZT_StoredObjectType)ZT_STORED_OBJECT_TYPE__CLUSTER_DEFINITION:
  208. Utils::snprintf(p,maxlen,"%s" ZT_PATH_SEPARATOR_S "cluster",_basePath.c_str());
  209. return true;
  210. default:
  211. return false;
  212. }
  213. }
  214. } // namespace ZeroTier