Locator.cpp 8.9 KB

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