Membership.hpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #ifndef ZT_MEMBERSHIP_HPP
  19. #define ZT_MEMBERSHIP_HPP
  20. #include <stdint.h>
  21. #include <map>
  22. #include "Constants.hpp"
  23. #include "../include/ZeroTierOne.h"
  24. #include "CertificateOfMembership.hpp"
  25. #include "Capability.hpp"
  26. #include "Tag.hpp"
  27. #include "Hashtable.hpp"
  28. #include "NetworkConfig.hpp"
  29. namespace ZeroTier {
  30. class RuntimeEnvironment;
  31. class Network;
  32. /**
  33. * A container for certificates of membership and other network credentials
  34. *
  35. * This is kind of analogous to a join table between Peer and Network. It is
  36. * presently held by the Network object for each participating Peer.
  37. *
  38. * This is not thread safe. It must be locked externally.
  39. */
  40. class Membership
  41. {
  42. private:
  43. // Tags and related state
  44. struct TState
  45. {
  46. TState() : lastPushed(0),lastReceived(0) {}
  47. // Last time we pushed OUR tag to this peer (with this ID)
  48. uint64_t lastPushed;
  49. // Last time we received THEIR tag (with this ID)
  50. uint64_t lastReceived;
  51. // THEIR tag
  52. Tag tag;
  53. };
  54. // Credentials and related state
  55. struct CState
  56. {
  57. CState() : lastPushed(0),lastReceived(0) {}
  58. // Last time we pushed OUR capability to this peer (with this ID)
  59. uint64_t lastPushed;
  60. // Last time we received THEIR capability (with this ID)
  61. uint64_t lastReceived;
  62. // THEIR capability
  63. Capability cap;
  64. };
  65. public:
  66. /**
  67. * A wrapper to iterate through member capabilities in ascending order of capability ID and return only valid ones
  68. */
  69. class CapabilityIterator
  70. {
  71. public:
  72. CapabilityIterator(const Membership &m) :
  73. _m(m),
  74. _i(m._caps.begin()),
  75. _e(m._caps.end())
  76. {
  77. }
  78. inline const Capability *next(const NetworkConfig &nconf)
  79. {
  80. while (_i != _e) {
  81. if ((_i->second.lastReceived)&&(_m.isCredentialTimestampValid(nconf,_i->second.cap)))
  82. return &((_i++)->second.cap);
  83. else ++_i;
  84. }
  85. return (const Capability *)0;
  86. }
  87. private:
  88. const Membership &_m;
  89. std::map<uint32_t,CState>::const_iterator _i,_e;
  90. };
  91. friend class CapabilityIterator;
  92. Membership() :
  93. _lastUpdatedMulticast(0),
  94. _lastPushAttempt(0),
  95. _lastPushedCom(0),
  96. _blacklistBefore(0),
  97. _com(),
  98. _caps(),
  99. _tags(8)
  100. {
  101. }
  102. /**
  103. * Send COM and other credentials to this peer if needed
  104. *
  105. * This checks last pushed times for our COM and for other credentials and
  106. * sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
  107. *
  108. * @param RR Runtime environment
  109. * @param now Current time
  110. * @param peerAddress Address of member peer (the one that this Membership describes)
  111. * @param nconf My network config
  112. * @param cap Capability to send or 0 if none
  113. */
  114. void sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap);
  115. /**
  116. * Check whether we should push MULTICAST_LIKEs to this peer
  117. *
  118. * @param now Current time
  119. * @return True if we should update multicasts
  120. */
  121. inline bool shouldLikeMulticasts(const uint64_t now) const { return ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD); }
  122. /**
  123. * Set time we last updated multicasts for this peer
  124. *
  125. * @param now Current time
  126. */
  127. inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; }
  128. /**
  129. * @param nconf Our network config
  130. * @return True if this peer is allowed on this network at all
  131. */
  132. inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
  133. {
  134. if (nconf.isPublic())
  135. return true;
  136. if ((_blacklistBefore)&&(_com.timestamp().first <= _blacklistBefore))
  137. return false;
  138. return nconf.com.agreesWith(_com);
  139. }
  140. /**
  141. * Check whether a capability or tag is within its max delta from the timestamp of our network config and newer than any blacklist cutoff time
  142. *
  143. * @param cred Credential to check -- must have timestamp() accessor method
  144. * @return True if credential is NOT expired
  145. */
  146. template<typename C>
  147. inline bool isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred) const
  148. {
  149. const uint64_t ts = cred.timestamp();
  150. const uint64_t delta = (ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts);
  151. return ((delta <= nconf.credentialTimeMaxDelta)&&(ts > _blacklistBefore));
  152. }
  153. /**
  154. * @param nconf Network configuration
  155. * @param id Tag ID
  156. * @return Pointer to tag or NULL if not found
  157. */
  158. inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
  159. {
  160. const TState *t = _tags.get(id);
  161. return ((t) ? (((t->lastReceived != 0)&&(isCredentialTimestampValid(nconf,t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
  162. }
  163. /**
  164. * @param nconf Network configuration
  165. * @param ids Array to store IDs into
  166. * @param values Array to store values into
  167. * @param maxTags Capacity of ids[] and values[]
  168. * @return Number of tags added to arrays
  169. */
  170. inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const
  171. {
  172. unsigned int n = 0;
  173. uint32_t *id = (uint32_t *)0;
  174. TState *ts = (TState *)0;
  175. Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
  176. while (i.next(id,ts)) {
  177. if ((ts->lastReceived)&&(isCredentialTimestampValid(nconf,ts->tag))) {
  178. if (n >= maxTags)
  179. return n;
  180. ids[n] = *id;
  181. values[n] = ts->tag.value();
  182. }
  183. }
  184. return n;
  185. }
  186. /**
  187. * @param nconf Network configuration
  188. * @param id Capablity ID
  189. * @return Pointer to capability or NULL if not found
  190. */
  191. inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
  192. {
  193. std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
  194. return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(isCredentialTimestampValid(nconf,c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
  195. }
  196. /**
  197. * Validate and add a credential if signature is okay and it's otherwise good
  198. *
  199. * @param RR Runtime environment
  200. * @param com Certificate of membership
  201. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  202. */
  203. int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com);
  204. /**
  205. * Validate and add a credential if signature is okay and it's otherwise good
  206. *
  207. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  208. */
  209. int addCredential(const RuntimeEnvironment *RR,const Tag &tag);
  210. /**
  211. * Validate and add a credential if signature is okay and it's otherwise good
  212. *
  213. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  214. */
  215. int addCredential(const RuntimeEnvironment *RR,const Capability &cap);
  216. /**
  217. * Blacklist COM, tags, and capabilities before this time
  218. *
  219. * @param ts Blacklist cutoff
  220. */
  221. inline void blacklistBefore(const uint64_t ts) { _blacklistBefore = ts; }
  222. /**
  223. * Clean up old or stale entries
  224. *
  225. * @param nconf Network config
  226. */
  227. inline void clean(const NetworkConfig &nconf)
  228. {
  229. for(std::map<uint32_t,CState>::iterator i(_caps.begin());i!=_caps.end();) {
  230. if (!isCredentialTimestampValid(nconf,i->second.cap)) {
  231. _caps.erase(i++);
  232. } else {
  233. ++i;
  234. }
  235. }
  236. uint32_t *i = (uint32_t *)0;
  237. TState *ts = (TState *)0;
  238. Hashtable<uint32_t,TState>::Iterator tsi(_tags);
  239. while (tsi.next(i,ts)) {
  240. if (!isCredentialTimestampValid(nconf,ts->tag))
  241. _tags.erase(*i);
  242. }
  243. }
  244. private:
  245. // Last time we pushed MULTICAST_LIKE(s)
  246. uint64_t _lastUpdatedMulticast;
  247. // Last time we checked if credential push was needed
  248. uint64_t _lastPushAttempt;
  249. // Last time we pushed our COM to this peer
  250. uint64_t _lastPushedCom;
  251. // Time before which to blacklist credentials from this peer
  252. uint64_t _blacklistBefore;
  253. // COM from this peer
  254. CertificateOfMembership _com;
  255. // Capability-related state (we need an ordered container here, hence std::map)
  256. std::map<uint32_t,CState> _caps;
  257. // Tag-related state
  258. Hashtable<uint32_t,TState> _tags;
  259. };
  260. } // namespace ZeroTier
  261. #endif