Locator.cpp 8.3 KB

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