Membership.hpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. // Expiration time for capability and tag cache
  30. #define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME 600000
  31. // Expiration time for Memberships (used in Peer::clean())
  32. #define ZT_MEMBERSHIP_EXPIRATION_TIME (ZT_MEMBERSHIP_STATE_EXPIRATION_TIME * 2)
  33. namespace ZeroTier {
  34. class RuntimeEnvironment;
  35. /**
  36. * A container for certificates of membership and other network credentials
  37. *
  38. * This is kind of analogous to a join table between Peer and Network. It is
  39. * presently held by the Network object for each participating Peer.
  40. *
  41. * This is not thread safe. It must be locked externally.
  42. */
  43. class Membership
  44. {
  45. private:
  46. // Tags and related state
  47. struct TState
  48. {
  49. TState() : lastPushed(0),lastReceived(0) {}
  50. // Last time we pushed OUR tag to this peer (with this ID)
  51. uint64_t lastPushed;
  52. // Last time we received THEIR tag (with this ID)
  53. uint64_t lastReceived;
  54. // THEIR tag
  55. Tag tag;
  56. };
  57. // Credentials and related state
  58. struct CState
  59. {
  60. CState() : lastPushed(0),lastReceived(0) {}
  61. // Last time we pushed OUR capability to this peer (with this ID)
  62. uint64_t lastPushed;
  63. // Last time we received THEIR capability (with this ID)
  64. uint64_t lastReceived;
  65. // THEIR capability
  66. Capability cap;
  67. };
  68. public:
  69. /**
  70. * A wrapper to iterate through member capabilities in ascending order of capability ID and return only valid ones
  71. */
  72. class CapabilityIterator
  73. {
  74. public:
  75. CapabilityIterator(const Membership &m) :
  76. _m(m),
  77. _i(m._caps.begin()),
  78. _e(m._caps.end())
  79. {
  80. }
  81. inline const Capability *next(const NetworkConfig &nconf)
  82. {
  83. while (_i != _e) {
  84. if ((_i->second.lastReceived)&&(_m.isCredentialTimestampValid(nconf,_i->second.cap)))
  85. return &((_i++)->second.cap);
  86. else ++_i;
  87. }
  88. return (const Capability *)0;
  89. }
  90. private:
  91. const Membership &_m;
  92. std::map<uint32_t,CState>::const_iterator _i,_e;
  93. };
  94. friend class CapabilityIterator;
  95. Membership() :
  96. _lastPushAttempt(0),
  97. _lastPushedCom(0),
  98. _blacklistBefore(0),
  99. _com(),
  100. _caps(),
  101. _tags(8)
  102. {
  103. }
  104. /**
  105. * Send COM and other credentials to this peer if needed
  106. *
  107. * This checks last pushed times for our COM and for other credentials and
  108. * sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
  109. *
  110. * @param RR Runtime environment
  111. * @param now Current time
  112. * @param peerAddress Address of member peer (the one that this Membership describes)
  113. * @param nconf My network config
  114. * @param cap Capability to send or 0 if none
  115. */
  116. void sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap);
  117. /**
  118. * @param nconf Our network config
  119. * @return True if this peer is allowed on this network at all
  120. */
  121. inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
  122. {
  123. if (nconf.isPublic())
  124. return true;
  125. if ((_blacklistBefore)&&(_com.timestamp().first <= _blacklistBefore))
  126. return false;
  127. return nconf.com.agreesWith(_com);
  128. }
  129. /**
  130. * Check whether a capability or tag is expired
  131. *
  132. * @param cred Credential to check -- must have timestamp() accessor method
  133. * @return True if credential is NOT expired
  134. */
  135. template<typename C>
  136. inline bool isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred) const
  137. {
  138. const uint64_t ts = cred.timestamp();
  139. return ( ( (ts >= nconf.timestamp) || ((nconf.timestamp - ts) <= nconf.credentialTimeToLive) ) && (ts > _blacklistBefore) );
  140. }
  141. /**
  142. * @param nconf Network configuration
  143. * @param id Tag ID
  144. * @return Pointer to tag or NULL if not found
  145. */
  146. inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
  147. {
  148. const TState *t = _tags.get(id);
  149. return ((t) ? (((t->lastReceived != 0)&&(isCredentialTimestampValid(nconf,t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
  150. }
  151. /**
  152. * @param nconf Network configuration
  153. * @param ids Array to store IDs into
  154. * @param values Array to store values into
  155. * @param maxTags Capacity of ids[] and values[]
  156. * @return Number of tags added to arrays
  157. */
  158. inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const
  159. {
  160. unsigned int n = 0;
  161. uint32_t *id = (uint32_t *)0;
  162. TState *ts = (TState *)0;
  163. Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
  164. while (i.next(id,ts)) {
  165. if ((ts->lastReceived)&&(isCredentialTimestampValid(nconf,ts->tag))) {
  166. if (n >= maxTags)
  167. return n;
  168. ids[n] = *id;
  169. values[n] = ts->tag.value();
  170. }
  171. }
  172. return n;
  173. }
  174. /**
  175. * @param nconf Network configuration
  176. * @param id Capablity ID
  177. * @return Pointer to capability or NULL if not found
  178. */
  179. inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
  180. {
  181. std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
  182. return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(isCredentialTimestampValid(nconf,c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
  183. }
  184. /**
  185. * Validate and add a credential if signature is okay and it's otherwise good
  186. *
  187. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  188. */
  189. int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com);
  190. /**
  191. * Validate and add a credential if signature is okay and it's otherwise good
  192. *
  193. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  194. */
  195. int addCredential(const RuntimeEnvironment *RR,const Tag &tag);
  196. /**
  197. * Validate and add a credential if signature is okay and it's otherwise good
  198. *
  199. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  200. */
  201. int addCredential(const RuntimeEnvironment *RR,const Capability &cap);
  202. /**
  203. * Blacklist COM, tags, and capabilities before this time
  204. *
  205. * @param ts Blacklist cutoff
  206. */
  207. inline void blacklistBefore(const uint64_t ts)
  208. {
  209. _blacklistBefore = ts;
  210. }
  211. /**
  212. * Clean up old or stale entries
  213. *
  214. * @return Time of most recent activity in this Membership
  215. */
  216. inline uint64_t clean(const uint64_t now)
  217. {
  218. uint64_t lastAct = _lastPushedCom;
  219. for(std::map<uint32_t,CState>::iterator i(_caps.begin());i!=_caps.end();) {
  220. const uint64_t la = std::max(i->second.lastPushed,i->second.lastReceived);
  221. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) {
  222. _caps.erase(i++);
  223. } else {
  224. ++i;
  225. if (la > lastAct)
  226. lastAct = la;
  227. }
  228. }
  229. uint32_t *i = (uint32_t *)0;
  230. TState *ts = (TState *)0;
  231. Hashtable<uint32_t,TState>::Iterator tsi(_tags);
  232. while (tsi.next(i,ts)) {
  233. const uint64_t la = std::max(ts->lastPushed,ts->lastReceived);
  234. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME)
  235. _tags.erase(*i);
  236. else if (la > lastAct)
  237. lastAct = la;
  238. }
  239. return lastAct;
  240. }
  241. private:
  242. // Last time we checked if credential push was needed
  243. uint64_t _lastPushAttempt;
  244. // Last time we pushed our COM to this peer
  245. uint64_t _lastPushedCom;
  246. // Time before which to blacklist credentials from this peer
  247. uint64_t _blacklistBefore;
  248. // COM from this peer
  249. CertificateOfMembership _com;
  250. // Capability-related state (we need an ordered container here, hence std::map)
  251. std::map<uint32_t,CState> _caps;
  252. // Tag-related state
  253. Hashtable<uint32_t,TState> _tags;
  254. };
  255. } // namespace ZeroTier
  256. #endif