Topology.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  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. #ifndef ZT_TOPOLOGY_HPP
  14. #define ZT_TOPOLOGY_HPP
  15. #include <cstring>
  16. #include <vector>
  17. #include <algorithm>
  18. #include <utility>
  19. #include <set>
  20. #include "Constants.hpp"
  21. #include "Address.hpp"
  22. #include "Identity.hpp"
  23. #include "Peer.hpp"
  24. #include "Path.hpp"
  25. #include "Mutex.hpp"
  26. #include "InetAddress.hpp"
  27. #include "Hashtable.hpp"
  28. #include "SharedPtr.hpp"
  29. #include "ScopedPtr.hpp"
  30. #include "Fingerprint.hpp"
  31. namespace ZeroTier {
  32. class RuntimeEnvironment;
  33. /**
  34. * Database of network topology
  35. */
  36. class Topology
  37. {
  38. public:
  39. Topology(const RuntimeEnvironment *renv,void *tPtr);
  40. ~Topology();
  41. /**
  42. * Add peer to database
  43. *
  44. * This will not replace existing peers. In that case the existing peer
  45. * record is returned.
  46. *
  47. * @param peer Peer to add
  48. * @return New or existing peer (should replace 'peer')
  49. */
  50. SharedPtr<Peer> add(void *tPtr,const SharedPtr<Peer> &peer);
  51. /**
  52. * Get a peer from its address
  53. *
  54. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  55. * @param zta ZeroTier address of peer
  56. * @param loadFromCached If false do not load from cache if not in memory (default: true)
  57. * @return Peer or NULL if not found
  58. */
  59. ZT_INLINE SharedPtr<Peer> peer(void *tPtr,const Address &zta,const bool loadFromCached = true)
  60. {
  61. {
  62. RWMutex::RLock l(_peers_l);
  63. const SharedPtr<Peer> *const ap = _peers.get(zta);
  64. if (ap)
  65. return *ap;
  66. }
  67. {
  68. SharedPtr<Peer> p;
  69. if (loadFromCached) {
  70. _loadCached(tPtr,zta,p);
  71. if (p) {
  72. RWMutex::Lock l(_peers_l);
  73. SharedPtr<Peer> &hp = _peers[zta];
  74. if (hp)
  75. return hp;
  76. hp = p;
  77. }
  78. }
  79. return p;
  80. }
  81. }
  82. /**
  83. * Get a peer by its 384-bit identity public key hash
  84. *
  85. * @param hash Identity hash
  86. * @return Peer or NULL if no peer is currently in memory for this hash (cache is not checked in this case)
  87. */
  88. ZT_INLINE SharedPtr<Peer> peerByHash(const Fingerprint &hash)
  89. {
  90. RWMutex::RLock _l(_peers_l);
  91. const SharedPtr<Peer> *const ap = _peersByIdentityHash.get(hash);
  92. if (ap)
  93. return *ap;
  94. return SharedPtr<Peer>();
  95. }
  96. /**
  97. * Get a peer by its incoming short probe packet payload
  98. *
  99. * @param probe Short probe payload (in big-endian byte order)
  100. * @return Peer or NULL if no peer is currently in memory matching this probe (cache is not checked in this case)
  101. */
  102. ZT_INLINE SharedPtr<Peer> peerByProbe(const uint64_t probe)
  103. {
  104. RWMutex::RLock _l(_peers_l);
  105. const SharedPtr<Peer> *const ap = _peersByIncomingProbe.get(probe);
  106. if (ap)
  107. return *ap;
  108. return SharedPtr<Peer>();
  109. }
  110. /**
  111. * Get a Path object for a given local and remote physical address, creating if needed
  112. *
  113. * @param l Local socket
  114. * @param r Remote address
  115. * @return Pointer to canonicalized Path object or NULL on error
  116. */
  117. ZT_INLINE SharedPtr<Path> path(const int64_t l,const InetAddress &r)
  118. {
  119. const uint64_t k = _pathHash(l,r);
  120. {
  121. RWMutex::RLock lck(_paths_l);
  122. SharedPtr<Path> *const p = _paths.get(k);
  123. if (p)
  124. return *p;
  125. }
  126. {
  127. SharedPtr<Path> p(new Path(l,r));
  128. RWMutex::Lock lck(_paths_l);
  129. SharedPtr<Path> &p2 = _paths[k];
  130. if (p2)
  131. return p2;
  132. p2 = p;
  133. return p;
  134. }
  135. }
  136. /**
  137. * @return Current best root server
  138. */
  139. ZT_INLINE SharedPtr<Peer> root() const
  140. {
  141. RWMutex::RLock l(_peers_l);
  142. if (_rootPeers.empty())
  143. return SharedPtr<Peer>();
  144. return _rootPeers.front();
  145. }
  146. /**
  147. * @param id Identity to check
  148. * @return True if this identity corresponds to a root
  149. */
  150. ZT_INLINE bool isRoot(const Identity &id) const
  151. {
  152. RWMutex::RLock l(_peers_l);
  153. return (_roots.count(id) > 0);
  154. }
  155. /**
  156. * Apply a function or function object to all peers
  157. *
  158. * This locks the peer map during execution, so calls to get() etc. during
  159. * eachPeer() will deadlock.
  160. *
  161. * @param f Function to apply
  162. * @tparam F Function or function object type
  163. */
  164. template<typename F>
  165. ZT_INLINE void eachPeer(F f) const
  166. {
  167. RWMutex::RLock l(_peers_l);
  168. Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
  169. Address *a = nullptr;
  170. SharedPtr<Peer> *p = nullptr;
  171. while (i.next(a,p))
  172. f(*((const SharedPtr<Peer> *)p));
  173. }
  174. /**
  175. * Apply a function or function object to all peers
  176. *
  177. * This locks the peer map during execution, so calls to get() etc. during
  178. * eachPeer() will deadlock.
  179. *
  180. * @param f Function to apply
  181. * @tparam F Function or function object type
  182. */
  183. template<typename F>
  184. ZT_INLINE void eachPeerWithRoot(F f) const
  185. {
  186. RWMutex::RLock l(_peers_l);
  187. std::vector<uintptr_t> rootPeerPtrs;
  188. rootPeerPtrs.reserve(_rootPeers.size());
  189. for(std::vector< SharedPtr<Peer> >::const_iterator rp(_rootPeers.begin());rp!=_rootPeers.end();++rp)
  190. rootPeerPtrs.push_back((uintptr_t)rp->ptr());
  191. std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
  192. try {
  193. Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
  194. Address *a = nullptr;
  195. SharedPtr<Peer> *p = nullptr;
  196. while (i.next(a,p))
  197. f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)p->ptr()));
  198. } catch ( ... ) {} // should not throw
  199. }
  200. /**
  201. * Iterate through all paths in the system
  202. *
  203. * @tparam F Function to call for each path
  204. * @param f
  205. */
  206. template<typename F>
  207. ZT_INLINE void eachPath(F f) const
  208. {
  209. RWMutex::RLock l(_paths_l);
  210. Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
  211. uint64_t *k = nullptr;
  212. SharedPtr<Path> *p = nullptr;
  213. while (i.next(k,p))
  214. f(*((const SharedPtr<Path> *)p));
  215. }
  216. /**
  217. * @param allPeers vector to fill with all current peers
  218. */
  219. void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const;
  220. /**
  221. * Get info about a path
  222. *
  223. * The supplied result variables are not modified if no special config info is found.
  224. *
  225. * @param physicalAddress Physical endpoint address
  226. * @param mtu Variable set to MTU
  227. * @param trustedPathId Variable set to trusted path ID
  228. */
  229. ZT_INLINE void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId)
  230. {
  231. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  232. if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
  233. trustedPathId = _physicalPathConfig[i].second.trustedPathId;
  234. mtu = _physicalPathConfig[i].second.mtu;
  235. return;
  236. }
  237. }
  238. }
  239. /**
  240. * Get the outbound trusted path ID for a physical address, or 0 if none
  241. *
  242. * @param physicalAddress Physical address to which we are sending the packet
  243. * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
  244. */
  245. ZT_INLINE uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
  246. {
  247. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  248. if (_physicalPathConfig[i].first.containsAddress(physicalAddress))
  249. return _physicalPathConfig[i].second.trustedPathId;
  250. }
  251. return 0;
  252. }
  253. /**
  254. * Check whether in incoming trusted path marked packet is valid
  255. *
  256. * @param physicalAddress Originating physical address
  257. * @param trustedPathId Trusted path ID from packet (from MAC field)
  258. */
  259. ZT_INLINE bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
  260. {
  261. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  262. if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress)))
  263. return true;
  264. }
  265. return false;
  266. }
  267. /**
  268. * Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
  269. */
  270. void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
  271. /**
  272. * Add a root server's identity to the root server set
  273. *
  274. * @param tPtr Thread pointer
  275. * @param id Root server identity
  276. * @param bootstrap If non-NULL, a bootstrap address to attempt to find this root
  277. */
  278. void addRoot(void *tPtr,const Identity &id,const InetAddress &bootstrap);
  279. /**
  280. * Remove a root server's identity from the root server set
  281. *
  282. * @param id Root server identity
  283. * @return True if root found and removed, false if not found
  284. */
  285. bool removeRoot(const Identity &id);
  286. /**
  287. * Sort roots in asecnding order of apparent latency
  288. *
  289. * @param now Current time
  290. */
  291. void rankRoots(int64_t now);
  292. /**
  293. * Do periodic tasks such as database cleanup
  294. */
  295. void doPeriodicTasks(void *tPtr,int64_t now);
  296. /**
  297. * Save all currently known peers to data store
  298. */
  299. void saveAll(void *tPtr);
  300. private:
  301. // Load cached peer and set 'peer' to it, if one is found.
  302. void _loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer);
  303. // This is a secure random integer created at startup to salt the calculation of path hash map keys
  304. static const uint64_t s_pathHashSalt;
  305. // Get a hash key for looking up paths by their local port and destination address
  306. ZT_INLINE uint64_t _pathHash(int64_t l,const InetAddress &r) const
  307. {
  308. if (r.family() == AF_INET) {
  309. return Utils::hash64(s_pathHashSalt ^ (uint64_t)(reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr)) + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port) + (uint64_t)l;
  310. } else if (r.family() == AF_INET6) {
  311. #ifdef ZT_NO_UNALIGNED_ACCESS
  312. uint64_t h = s_pathHashSalt;
  313. for(int i=0;i<16;++i) {
  314. h += (uint64_t)((reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[i]);
  315. h += (h << 10U);
  316. h ^= (h >> 6U);
  317. }
  318. #else
  319. uint64_t h = Utils::hash64(s_pathHashSalt ^ (reinterpret_cast<const uint64_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[0] + reinterpret_cast<const uint64_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[1]));
  320. #endif
  321. return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) + (uint64_t)l;
  322. } else {
  323. return Utils::fnv1a32(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
  324. }
  325. }
  326. const RuntimeEnvironment *const RR;
  327. RWMutex _peers_l;
  328. RWMutex _paths_l;
  329. std::pair< InetAddress,ZT_PhysicalPathConfiguration > _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
  330. unsigned int _numConfiguredPhysicalPaths;
  331. Hashtable< Address,SharedPtr<Peer> > _peers;
  332. Hashtable< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
  333. Hashtable< Fingerprint,SharedPtr<Peer> > _peersByIdentityHash;
  334. Hashtable< uint64_t,SharedPtr<Path> > _paths;
  335. std::set< Identity > _roots; // locked by _peers_l
  336. std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
  337. };
  338. } // namespace ZeroTier
  339. #endif