Endpoint.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 "Endpoint.hpp"
  14. #include "Utils.hpp"
  15. namespace ZeroTier {
  16. char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
  17. {
  18. static const char *const s_endpointTypeChars = ZT_ENDPOINT_TYPE_CHAR_INDEX;
  19. static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow");
  20. static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow");
  21. switch (this->type) {
  22. default:
  23. s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_NIL];
  24. s[1] = 0;
  25. break;
  26. case ZT_ENDPOINT_TYPE_ZEROTIER:
  27. s[0] = s_endpointTypeChars[ZT_ENDPOINT_TYPE_ZEROTIER];
  28. s[1] = '-';
  29. zt().toString(s + 2);
  30. break;
  31. case ZT_ENDPOINT_TYPE_ETHERNET:
  32. case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
  33. case ZT_ENDPOINT_TYPE_BLUETOOTH:
  34. s[0] = s_endpointTypeChars[this->type];
  35. s[1] = '-';
  36. eth().toString(s + 2);
  37. break;
  38. case ZT_ENDPOINT_TYPE_IP:
  39. case ZT_ENDPOINT_TYPE_IP_UDP:
  40. case ZT_ENDPOINT_TYPE_IP_TCP:
  41. case ZT_ENDPOINT_TYPE_IP_HTTP2:
  42. s[0] = s_endpointTypeChars[this->type];
  43. s[1] = '-';
  44. ip().toString(s + 2);
  45. break;
  46. }
  47. return s;
  48. }
  49. bool Endpoint::fromString(const char *s) noexcept
  50. {
  51. memoryZero(this);
  52. if ((!s) || (!*s))
  53. return true;
  54. const char *start = strchr(s, '-');
  55. if (start++ != nullptr) {
  56. // Parse a fully qualified type-address format Endpoint.
  57. char tmp[16];
  58. for (unsigned int i=0;i<16;++i) {
  59. char ss = s[i];
  60. if (ss == '-') {
  61. tmp[i] = 0;
  62. break;
  63. }
  64. tmp[i] = ss;
  65. }
  66. tmp[15] = 0;
  67. this->type = (ZT_EndpointType)Utils::strToUInt(tmp);
  68. Fingerprint tmpfp;
  69. MAC tmpmac;
  70. switch (this->type) {
  71. case ZT_ENDPOINT_TYPE_NIL:
  72. break;
  73. case ZT_ENDPOINT_TYPE_ZEROTIER:
  74. if (!tmpfp.fromString(start))
  75. return false;
  76. this->value.fp = tmpfp;
  77. break;
  78. case ZT_ENDPOINT_TYPE_ETHERNET:
  79. case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
  80. case ZT_ENDPOINT_TYPE_BLUETOOTH:
  81. tmpmac.fromString(start);
  82. this->value.mac = tmpmac.toInt();
  83. break;
  84. case ZT_ENDPOINT_TYPE_IP:
  85. case ZT_ENDPOINT_TYPE_IP_UDP:
  86. case ZT_ENDPOINT_TYPE_IP_TCP:
  87. case ZT_ENDPOINT_TYPE_IP_HTTP2:
  88. if (!asInetAddress(this->value.ss).fromString(start))
  89. return false;
  90. default:
  91. return false;
  92. }
  93. } else if ((strchr(s, ':')) || (strchr(s, '.'))) {
  94. // Parse raw IP/port strings as IP_UDP endpoints.
  95. this->type = ZT_ENDPOINT_TYPE_IP_UDP;
  96. if (!asInetAddress(this->value.ss).fromString(s))
  97. return false;
  98. } else {
  99. // A naked '0' can be a NIL endpoint.
  100. if (Utils::strToUInt(s) != (unsigned int)ZT_ENDPOINT_TYPE_NIL)
  101. return false;
  102. }
  103. return true;
  104. }
  105. int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
  106. {
  107. switch (this->type) {
  108. //case ZT_ENDPOINT_TYPE_NIL:
  109. default:
  110. // NIL endpoints get serialized like NIL InetAddress instances.
  111. data[0] = ZT_ENDPOINT_TYPE_NIL;
  112. return 1;
  113. case ZT_ENDPOINT_TYPE_ZEROTIER:
  114. data[0] = 16 + ZT_ENDPOINT_TYPE_ZEROTIER;
  115. Address(this->value.fp.address).copyTo(data + 1);
  116. Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + 1 + ZT_ADDRESS_LENGTH, this->value.fp.hash);
  117. return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE;
  118. case ZT_ENDPOINT_TYPE_ETHERNET:
  119. case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
  120. case ZT_ENDPOINT_TYPE_BLUETOOTH:
  121. data[0] = 16 + (uint8_t)this->type;
  122. MAC(this->value.mac).copyTo(data + 1);
  123. return 7;
  124. case ZT_ENDPOINT_TYPE_IP_UDP:
  125. // Default UDP mode gets serialized to look exactly like an InetAddress.
  126. return asInetAddress(this->value.ss).marshal(data);
  127. case ZT_ENDPOINT_TYPE_IP:
  128. case ZT_ENDPOINT_TYPE_IP_TCP:
  129. case ZT_ENDPOINT_TYPE_IP_HTTP2:
  130. // Other IP types get serialized as new version Endpoint instances with type.
  131. data[0] = 16 + (uint8_t)this->type;
  132. return 1 + asInetAddress(this->value.ss).marshal(data + 1);
  133. }
  134. }
  135. int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept
  136. {
  137. memoryZero(this);
  138. if (unlikely(len <= 0))
  139. return -1;
  140. // Serialized endpoints with type bytes less than 16 are passed through
  141. // to the unmarshal method of InetAddress and considered UDP endpoints.
  142. // This allows backward compatibility with old endpoint fields in the
  143. // protocol that were serialized InetAddress instances.
  144. if (data[0] < 16) {
  145. switch (data[0]) {
  146. case 0:
  147. return 1;
  148. case 4:
  149. case 6:
  150. this->type = ZT_ENDPOINT_TYPE_IP_UDP;
  151. return asInetAddress(this->value.ss).unmarshal(data, len);
  152. }
  153. return -1;
  154. }
  155. switch ((this->type = (ZT_EndpointType)(data[0] - 16))) {
  156. case ZT_ENDPOINT_TYPE_NIL:
  157. return 1;
  158. case ZT_ENDPOINT_TYPE_ZEROTIER:
  159. if (len >= (1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE)) {
  160. this->value.fp.address = Address(data + 1).toInt();
  161. Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(this->value.fp.hash, data + 1 + ZT_ADDRESS_LENGTH);
  162. return 1 + ZT_ADDRESS_LENGTH + ZT_FINGERPRINT_HASH_SIZE;
  163. }
  164. return -1;
  165. case ZT_ENDPOINT_TYPE_ETHERNET:
  166. case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
  167. case ZT_ENDPOINT_TYPE_BLUETOOTH:
  168. if (len >= 7) {
  169. MAC tmp;
  170. tmp.setTo(data + 1);
  171. this->value.mac = tmp.toInt();
  172. return 7;
  173. }
  174. return -1;
  175. case ZT_ENDPOINT_TYPE_IP:
  176. case ZT_ENDPOINT_TYPE_IP_UDP:
  177. case ZT_ENDPOINT_TYPE_IP_TCP:
  178. case ZT_ENDPOINT_TYPE_IP_HTTP2:
  179. return asInetAddress(this->value.ss).unmarshal(data + 1, len - 1);
  180. default:
  181. break;
  182. }
  183. // Unrecognized types can still be passed over in a valid stream if they are
  184. // prefixed by a 16-bit size. This allows forward compatibility with future
  185. // endpoint types.
  186. this->type = ZT_ENDPOINT_TYPE_NIL;
  187. if (len < 3)
  188. return -1;
  189. const int unrecLen = 1 + (int) Utils::loadBigEndian<uint16_t>(data + 1);
  190. return (unrecLen > len) ? -1 : unrecLen;
  191. }
  192. bool Endpoint::operator==(const Endpoint &ep) const noexcept
  193. {
  194. if (this->type == ep.type) {
  195. switch(this->type) {
  196. case ZT_ENDPOINT_TYPE_ZEROTIER:
  197. return zt() == ep.zt();
  198. case ZT_ENDPOINT_TYPE_ETHERNET:
  199. case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
  200. case ZT_ENDPOINT_TYPE_BLUETOOTH:
  201. return this->value.mac == ep.value.mac;
  202. case ZT_ENDPOINT_TYPE_IP:
  203. case ZT_ENDPOINT_TYPE_IP_UDP:
  204. case ZT_ENDPOINT_TYPE_IP_TCP:
  205. case ZT_ENDPOINT_TYPE_IP_HTTP2:
  206. return ip() == ep.ip();
  207. default:
  208. return true;
  209. }
  210. }
  211. return false;
  212. }
  213. bool Endpoint::operator<(const Endpoint &ep) const noexcept
  214. {
  215. if (this->type == ep.type) {
  216. switch(this->type) {
  217. case ZT_ENDPOINT_TYPE_ZEROTIER:
  218. return zt() < ep.zt();
  219. case ZT_ENDPOINT_TYPE_ETHERNET:
  220. case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
  221. case ZT_ENDPOINT_TYPE_BLUETOOTH:
  222. return this->value.mac < ep.value.mac;
  223. case ZT_ENDPOINT_TYPE_IP:
  224. case ZT_ENDPOINT_TYPE_IP_UDP:
  225. case ZT_ENDPOINT_TYPE_IP_TCP:
  226. case ZT_ENDPOINT_TYPE_IP_HTTP2:
  227. return ip() < ep.ip();
  228. default:
  229. return true;
  230. }
  231. }
  232. return (int)this->type < (int)ep.type;
  233. }
  234. } // namespace ZeroTier
  235. extern "C" {
  236. char *ZT_Endpoint_toString(
  237. const ZT_Endpoint *ep,
  238. char *buf,
  239. int capacity)
  240. {
  241. if ((!ep) || (!buf) || (capacity < ZT_ENDPOINT_STRING_SIZE_MAX))
  242. return nullptr;
  243. return reinterpret_cast<const ZeroTier::Endpoint *>(ep)->toString(buf);
  244. }
  245. int ZT_Endpoint_fromString(
  246. ZT_Endpoint *ep,
  247. const char *str)
  248. {
  249. if ((!ep) || (!str))
  250. return ZT_RESULT_ERROR_BAD_PARAMETER;
  251. return reinterpret_cast<ZeroTier::Endpoint *>(ep)->fromString(str) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
  252. }
  253. } // C API