Topology.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  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 "SharedPtr.hpp"
  28. #include "ScopedPtr.hpp"
  29. #include "Fingerprint.hpp"
  30. #include "Containers.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 = _getPathKey(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. for(Map< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i) // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
  169. f(i->second);
  170. }
  171. /**
  172. * Apply a function or function object to all peers
  173. *
  174. * This locks the peer map during execution, so calls to get() etc. during
  175. * eachPeer() will deadlock.
  176. *
  177. * @param f Function to apply
  178. * @tparam F Function or function object type
  179. */
  180. template<typename F>
  181. ZT_INLINE void eachPeerWithRoot(F f) const
  182. {
  183. RWMutex::RLock l(_peers_l);
  184. std::vector<uintptr_t> rootPeerPtrs;
  185. rootPeerPtrs.reserve(_rootPeers.size());
  186. for(std::vector< SharedPtr<Peer> >::const_iterator rp(_rootPeers.begin());rp!=_rootPeers.end();++rp) // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
  187. rootPeerPtrs.push_back((uintptr_t)rp->ptr());
  188. std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
  189. try {
  190. for(Map< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i) // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
  191. f(i->second,std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)i->second.ptr()));
  192. } catch ( ... ) {} // should not throw
  193. }
  194. /**
  195. * Iterate through all paths in the system
  196. *
  197. * @tparam F Function to call for each path
  198. * @param f
  199. */
  200. template<typename F>
  201. ZT_INLINE void eachPath(F f) const
  202. {
  203. RWMutex::RLock l(_paths_l);
  204. for(Map< uint64_t,SharedPtr<Path> >::const_iterator i(_paths.begin());i!=_paths.end();++i) // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
  205. f(i->second);
  206. }
  207. /**
  208. * @param allPeers vector to fill with all current peers
  209. */
  210. void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const;
  211. /**
  212. * Get info about a path
  213. *
  214. * The supplied result variables are not modified if no special config info is found.
  215. *
  216. * @param physicalAddress Physical endpoint address
  217. * @param mtu Variable set to MTU
  218. * @param trustedPathId Variable set to trusted path ID
  219. */
  220. ZT_INLINE void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId)
  221. {
  222. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  223. if (_physicalPathConfig[i].first.containsAddress(physicalAddress)) {
  224. trustedPathId = _physicalPathConfig[i].second.trustedPathId;
  225. mtu = _physicalPathConfig[i].second.mtu;
  226. return;
  227. }
  228. }
  229. }
  230. /**
  231. * Get the outbound trusted path ID for a physical address, or 0 if none
  232. *
  233. * @param physicalAddress Physical address to which we are sending the packet
  234. * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
  235. */
  236. ZT_INLINE uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
  237. {
  238. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  239. if (_physicalPathConfig[i].first.containsAddress(physicalAddress))
  240. return _physicalPathConfig[i].second.trustedPathId;
  241. }
  242. return 0;
  243. }
  244. /**
  245. * Check whether in incoming trusted path marked packet is valid
  246. *
  247. * @param physicalAddress Originating physical address
  248. * @param trustedPathId Trusted path ID from packet (from MAC field)
  249. */
  250. ZT_INLINE bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
  251. {
  252. for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i<j;++i) {
  253. if ((_physicalPathConfig[i].second.trustedPathId == trustedPathId)&&(_physicalPathConfig[i].first.containsAddress(physicalAddress)))
  254. return true;
  255. }
  256. return false;
  257. }
  258. /**
  259. * Set or clear physical path configuration (called via Node::setPhysicalPathConfiguration)
  260. */
  261. void setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
  262. /**
  263. * Add a root server's identity to the root server set
  264. *
  265. * @param tPtr Thread pointer
  266. * @param id Root server identity
  267. * @param bootstrap If non-NULL, a bootstrap address to attempt to find this root
  268. */
  269. void addRoot(void *tPtr,const Identity &id,const InetAddress &bootstrap);
  270. /**
  271. * Remove a root server's identity from the root server set
  272. *
  273. * @param id Root server identity
  274. * @return True if root found and removed, false if not found
  275. */
  276. bool removeRoot(const Identity &id);
  277. /**
  278. * Sort roots in asecnding order of apparent latency
  279. *
  280. * @param now Current time
  281. */
  282. void rankRoots(int64_t now);
  283. /**
  284. * Do periodic tasks such as database cleanup
  285. */
  286. void doPeriodicTasks(void *tPtr,int64_t now);
  287. /**
  288. * Save all currently known peers to data store
  289. */
  290. void saveAll(void *tPtr);
  291. private:
  292. // Load cached peer and set 'peer' to it, if one is found.
  293. void _loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer);
  294. // This is a secure random integer created at startup to salt the calculation of path hash map keys
  295. static const uint64_t s_pathHashSalt;
  296. // This gets an integer key from an InetAddress for looking up paths.
  297. ZT_INLINE uint64_t _getPathKey(int64_t l,const InetAddress &r) const
  298. {
  299. if (r.family() == AF_INET) {
  300. return 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;
  301. } else if (r.family() == AF_INET6) {
  302. #ifdef ZT_NO_UNALIGNED_ACCESS
  303. uint64_t h = s_pathHashSalt;
  304. for(int i=0;i<16;++i) {
  305. h += (uint64_t)((reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[i]);
  306. h += (h << 10U);
  307. h ^= (h >> 6U);
  308. }
  309. #else
  310. uint64_t h = 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]);
  311. #endif
  312. return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) + (uint64_t)l;
  313. } else {
  314. return Utils::fnv1a32(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
  315. }
  316. }
  317. const RuntimeEnvironment *const RR;
  318. RWMutex _peers_l;
  319. RWMutex _paths_l;
  320. std::pair< InetAddress,ZT_PhysicalPathConfiguration > _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
  321. unsigned int _numConfiguredPhysicalPaths;
  322. Map< Address,SharedPtr<Peer> > _peers;
  323. Map< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
  324. Map< Fingerprint,SharedPtr<Peer> > _peersByIdentityHash;
  325. Map< uint64_t,SharedPtr<Path> > _paths;
  326. std::set< Identity > _roots; // locked by _peers_l
  327. std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
  328. };
  329. } // namespace ZeroTier
  330. #endif