2
0

Locator.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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: 2025-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];
  103. if (l > 0) {
  104. Utils::copy(data + p, e->second->data, (unsigned int)l);
  105. p += l;
  106. } else {
  107. data[p++] = 0;
  108. }
  109. }
  110. Utils::storeMachineEndian< uint16_t >(data + p, 0); // length of meta-data, currently always 0
  111. p += 2;
  112. if (!excludeSignature) {
  113. Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signature.size());
  114. p += 2;
  115. Utils::copy(data + p, m_signature.data(), m_signature.size());
  116. p += (int) m_signature.size();
  117. }
  118. return p;
  119. }
  120. int Locator::unmarshal(const uint8_t *data, const int len) noexcept
  121. {
  122. if (unlikely(len < 8))
  123. return -1;
  124. m_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data);
  125. int p = 8;
  126. int l = m_signer.unmarshal(data + p, len - p);
  127. if (l <= 0)
  128. return -1;
  129. p += l;
  130. if (unlikely(p + 2) > len)
  131. return -1;
  132. unsigned int endpointCount = Utils::loadBigEndian<uint16_t>(data + p);
  133. p += 2;
  134. if (unlikely(endpointCount > ZT_LOCATOR_MAX_ENDPOINTS))
  135. return -1;
  136. m_endpoints.resize(endpointCount);
  137. m_endpoints.shrink_to_fit();
  138. for (unsigned int i = 0;i < endpointCount;++i) {
  139. l = m_endpoints[i].first.unmarshal(data + p, len - p);
  140. if (l <= 0)
  141. return -1;
  142. p += l;
  143. if (unlikely(p + 1) > len)
  144. return -1;
  145. l = (int)data[p];
  146. if (l <= 0) {
  147. m_endpoints[i].second = EndpointAttributes::DEFAULT;
  148. ++p;
  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. p += l;
  153. }
  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. m_sortEndpoints();
  170. return p;
  171. }
  172. struct p_SortByEndpoint
  173. {
  174. // There can't be more than one of the same endpoint, so only need to sort
  175. // by endpoint.
  176. ZT_INLINE bool operator()(const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &a,const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &b) const noexcept
  177. { return a.first < b.first; }
  178. };
  179. void Locator::m_sortEndpoints() noexcept
  180. { std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint()); }
  181. } // namespace ZeroTier