Locator.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #include "Locator.hpp"
  14. #include "Identity.hpp"
  15. #include <algorithm>
  16. namespace ZeroTier {
  17. const SharedPtr< const Locator::EndpointAttributes > Locator::EndpointAttributes::DEFAULT(new Locator::EndpointAttributes());
  18. Locator::Locator(const char *const str) noexcept :
  19. __refCount(0)
  20. {
  21. if (!fromString(str)) {
  22. m_ts = 0;
  23. m_signer.zero();
  24. m_endpoints.clear();
  25. m_signature.clear();
  26. }
  27. }
  28. bool Locator::add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a)
  29. {
  30. for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::iterator i(m_endpoints.begin());i!=m_endpoints.end();++i) {
  31. if (i->first == ep) {
  32. i->second = ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT;
  33. return true;
  34. }
  35. }
  36. if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) {
  37. m_endpoints.push_back(std::pair<Endpoint, SharedPtr< const EndpointAttributes > >(ep, ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT));
  38. return true;
  39. }
  40. return false;
  41. }
  42. struct p_SortByEndpoint
  43. {
  44. // There can't be more than one of the same endpoint, so only need to sort
  45. // by endpoint.
  46. ZT_INLINE bool operator()(const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &a,const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &b) const noexcept
  47. { return a.first < b.first; }
  48. };
  49. bool Locator::sign(const int64_t ts, const Identity &id) noexcept
  50. {
  51. m_ts = ts;
  52. m_signer = id.fingerprint();
  53. std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint());
  54. uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX];
  55. const unsigned int signlen = marshal(signdata, true);
  56. const unsigned int siglen = id.sign(signdata, signlen, m_signature.data(), m_signature.capacity());
  57. if (siglen == 0)
  58. return false;
  59. m_signature.unsafeSetSize(siglen);
  60. return true;
  61. }
  62. bool Locator::verify(const Identity &id) const noexcept
  63. {
  64. try {
  65. if ((m_ts > 0) && (m_signer == id.fingerprint())) {
  66. uint8_t signdata[ZT_LOCATOR_MARSHAL_SIZE_MAX];
  67. const unsigned int signlen = marshal(signdata, true);
  68. return id.verify(signdata, signlen, m_signature.data(), m_signature.size());
  69. }
  70. } catch (...) {} // fail verify on any unexpected exception
  71. return false;
  72. }
  73. char *Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept
  74. {
  75. static_assert(ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1), "overflow");
  76. uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX];
  77. Address(m_signer.address).toString(s);
  78. s[ZT_ADDRESS_LENGTH_HEX] = '@';
  79. Utils::b32e(bin, marshal(bin, false), s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
  80. return s;
  81. }
  82. bool Locator::fromString(const char *s) noexcept
  83. {
  84. if (!s)
  85. return false;
  86. if (strlen(s) < (ZT_ADDRESS_LENGTH_HEX + 1))
  87. return false;
  88. uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX];
  89. const int bl = Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), bin, ZT_LOCATOR_MARSHAL_SIZE_MAX);
  90. if ((bl <= 0) || (bl > ZT_LOCATOR_MARSHAL_SIZE_MAX))
  91. return false;
  92. return unmarshal(bin, bl) > 0;
  93. }
  94. int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept
  95. {
  96. Utils::storeBigEndian<uint64_t>(data, (uint64_t) m_ts);
  97. int p = 8;
  98. int l = m_signer.marshal(data + p);
  99. if (l <= 0)
  100. return -1;
  101. p += l;
  102. Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_endpoints.size());
  103. p += 2;
  104. for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) {
  105. l = e->first.marshal(data + p);
  106. if (l <= 0)
  107. return -1;
  108. p += l;
  109. l = (int)e->second->data[0] + 1;
  110. Utils::copy(data + p, e->second->data, (unsigned int)l);
  111. p += l;
  112. }
  113. Utils::storeMachineEndian< uint16_t >(data + p, 0); // length of meta-data, currently always 0
  114. p += 2;
  115. if (!excludeSignature) {
  116. Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signature.size());
  117. p += 2;
  118. Utils::copy(data + p, m_signature.data(), m_signature.size());
  119. p += (int) m_signature.size();
  120. }
  121. return p;
  122. }
  123. int Locator::unmarshal(const uint8_t *data, const int len) noexcept
  124. {
  125. if (unlikely(len < 8))
  126. return -1;
  127. m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data);
  128. int p = 8;
  129. int l = m_signer.unmarshal(data + p, len - p);
  130. if (l <= 0)
  131. return -1;
  132. p += l;
  133. if (unlikely(p + 2) > len)
  134. return -1;
  135. unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + p);
  136. p += 2;
  137. if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS))
  138. return -1;
  139. m_endpoints.resize(endpointCount);
  140. m_endpoints.shrink_to_fit();
  141. for (unsigned int i = 0;i < endpointCount;++i) {
  142. l = m_endpoints[i].first.unmarshal(data + p, len - p);
  143. if (l <= 0)
  144. return -1;
  145. p += l;
  146. l = (int)data[p] + 1;
  147. if (l <= 1) {
  148. m_endpoints[i].second = EndpointAttributes::DEFAULT;
  149. } else {
  150. m_endpoints[i].second.set(new EndpointAttributes());
  151. Utils::copy(const_cast< uint8_t * >(m_endpoints[i].second->data), data + p, (unsigned int)l);
  152. }
  153. p += l;
  154. }
  155. if (unlikely((p + 2) > len))
  156. return -1;
  157. p += 2 + (int) Utils::loadBigEndian<uint16_t>(data + p);
  158. if (unlikely((p + 2) > len))
  159. return -1;
  160. const unsigned int siglen = Utils::loadBigEndian<uint16_t>(data + p);
  161. p += 2;
  162. if (unlikely((siglen > ZT_SIGNATURE_BUFFER_SIZE) || ((p + (int) siglen) > len)))
  163. return -1;
  164. m_signature.unsafeSetSize(siglen);
  165. Utils::copy(m_signature.data(), data + p, siglen);
  166. p += (int)siglen;
  167. if (unlikely(p > len))
  168. return -1;
  169. return p;
  170. }
  171. } // namespace ZeroTier
  172. extern "C" {
  173. ZT_Locator *ZT_Locator_create(
  174. int64_t ts,
  175. const ZT_Endpoint *endpoints,
  176. const ZT_EndpointAttributes *endpointAttributes, // TODO: not used yet
  177. unsigned int endpointCount,
  178. const ZT_Identity *signer)
  179. {
  180. try {
  181. if ((ts <= 0) || (!endpoints) || (endpointCount == 0) || (!signer))
  182. return nullptr;
  183. ZeroTier::Locator *loc = new ZeroTier::Locator();
  184. for (unsigned int i = 0;i < endpointCount;++i)
  185. loc->add(reinterpret_cast< const ZeroTier::Endpoint * >(endpoints)[i], ZeroTier::Locator::EndpointAttributes::DEFAULT);
  186. if (!loc->sign(ts, *reinterpret_cast< const ZeroTier::Identity * >(signer))) {
  187. delete loc;
  188. return nullptr;
  189. }
  190. return reinterpret_cast<ZT_Locator *>(loc);
  191. } catch (...) {
  192. return nullptr;
  193. }
  194. }
  195. ZT_Locator *ZT_Locator_fromString(const char *str)
  196. {
  197. try {
  198. if (!str)
  199. return nullptr;
  200. ZeroTier::Locator *loc = new ZeroTier::Locator();
  201. if (!loc->fromString(str)) {
  202. delete loc;
  203. return nullptr;
  204. }
  205. return reinterpret_cast<ZT_Locator *>(loc);
  206. } catch ( ... ) {
  207. return nullptr;
  208. }
  209. }
  210. ZT_Locator *ZT_Locator_unmarshal(
  211. const void *data,
  212. unsigned int len)
  213. {
  214. try {
  215. if ((!data) || (len == 0))
  216. return nullptr;
  217. ZeroTier::Locator *loc = new ZeroTier::Locator();
  218. if (loc->unmarshal(reinterpret_cast<const uint8_t *>(data), (int) len) <= 0) {
  219. delete loc;
  220. return nullptr;
  221. }
  222. return reinterpret_cast<ZT_Locator *>(loc);
  223. } catch (...) {
  224. return nullptr;
  225. }
  226. }
  227. int ZT_Locator_marshal(const ZT_Locator *loc, void *buf, unsigned int bufSize)
  228. {
  229. if ((!loc) || (bufSize < ZT_LOCATOR_MARSHAL_SIZE_MAX))
  230. return -1;
  231. return reinterpret_cast<const ZeroTier::Locator *>(loc)->marshal(reinterpret_cast<uint8_t *>(buf), (int) bufSize);
  232. }
  233. char *ZT_Locator_toString(
  234. const ZT_Locator *loc,
  235. char *buf,
  236. int capacity)
  237. {
  238. if ((!loc) || (capacity < ZT_LOCATOR_STRING_SIZE_MAX))
  239. return nullptr;
  240. return reinterpret_cast<const ZeroTier::Locator *>(loc)->toString(buf);
  241. }
  242. const ZT_Fingerprint *ZT_Locator_fingerprint(const ZT_Locator *loc)
  243. {
  244. if (!loc)
  245. return nullptr;
  246. return (ZT_Fingerprint *) (&(reinterpret_cast<const ZeroTier::Locator *>(loc)->signer()));
  247. }
  248. int64_t ZT_Locator_timestamp(const ZT_Locator *loc)
  249. {
  250. if (!loc)
  251. return 0;
  252. return reinterpret_cast<const ZeroTier::Locator *>(loc)->timestamp();
  253. }
  254. unsigned int ZT_Locator_endpointCount(const ZT_Locator *loc)
  255. {
  256. return (loc) ? (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()) : 0;
  257. }
  258. const ZT_Endpoint *ZT_Locator_endpoint(const ZT_Locator *loc, const unsigned int ep)
  259. {
  260. if (!loc)
  261. return nullptr;
  262. if (ep >= (unsigned int) (reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints().size()))
  263. return nullptr;
  264. return reinterpret_cast<const ZT_Endpoint *>(&(reinterpret_cast<const ZeroTier::Locator *>(loc)->endpoints()[ep]));
  265. }
  266. int ZT_Locator_verify(const ZT_Locator *loc, const ZT_Identity *signer)
  267. {
  268. if ((!loc) || (!signer))
  269. return 0;
  270. return reinterpret_cast<const ZeroTier::Locator *>(loc)->verify(*reinterpret_cast<const ZeroTier::Identity *>(signer)) ? 1 : 0;
  271. }
  272. void ZT_Locator_delete(ZT_Locator *loc)
  273. {
  274. if (loc)
  275. delete reinterpret_cast<ZeroTier::Locator *>(loc);
  276. }
  277. } // C API functions