Membership.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. _lastPushedCom(0),
  97. _blacklistBefore(0),
  98. _com(),
  99. _caps(),
  100. _tags(8)
  101. {
  102. }
  103. /**
  104. * Send COM and other credentials to this peer if needed
  105. *
  106. * This checks last pushed times for our COM and for other credentials and
  107. * sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
  108. *
  109. * @param RR Runtime environment
  110. * @param now Current time
  111. * @param peerAddress Address of member peer
  112. * @param com My network certificate of membership (if any) (not the one here, but ours -- in NetworkConfig)
  113. * @param cap Capability to send or 0 if none
  114. * @param tags Tags that this peer might need
  115. * @param tagCount Number of tag IDs
  116. * @return True if we pushed something
  117. */
  118. bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const CertificateOfMembership &com,const Capability *cap,const Tag **tags,const unsigned int tagCount);
  119. /**
  120. * @param nconf Our network config
  121. * @return True if this peer is allowed on this network at all
  122. */
  123. inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
  124. {
  125. if (nconf.isPublic())
  126. return true;
  127. if ((_blacklistBefore)&&(_com.timestamp().first <= _blacklistBefore))
  128. return false;
  129. return nconf.com.agreesWith(_com);
  130. }
  131. /**
  132. * Check whether a capability or tag is expired
  133. *
  134. * @param cred Credential to check -- must have timestamp() accessor method
  135. * @return True if credential is NOT expired
  136. */
  137. template<typename C>
  138. inline bool isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred) const
  139. {
  140. const uint64_t ts = cred.timestamp();
  141. return ( ( (ts >= nconf.timestamp) || ((nconf.timestamp - ts) <= nconf.credentialTimeToLive) ) && (ts > _blacklistBefore) );
  142. }
  143. /**
  144. * @param nconf Network configuration
  145. * @param id Tag ID
  146. * @return Pointer to tag or NULL if not found
  147. */
  148. inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
  149. {
  150. const TState *t = _tags.get(id);
  151. return ((t) ? (((t->lastReceived != 0)&&(isCredentialTimestampValid(nconf,t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
  152. }
  153. /**
  154. * @param nconf Network configuration
  155. * @param ids Array to store IDs into
  156. * @param values Array to store values into
  157. * @param maxTags Capacity of ids[] and values[]
  158. * @return Number of tags added to arrays
  159. */
  160. inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const
  161. {
  162. unsigned int n = 0;
  163. uint32_t *id = (uint32_t *)0;
  164. TState *ts = (TState *)0;
  165. Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
  166. while (i.next(id,ts)) {
  167. if ((ts->lastReceived)&&(isCredentialTimestampValid(nconf,ts->tag))) {
  168. if (n >= maxTags)
  169. return n;
  170. ids[n] = *id;
  171. values[n] = ts->tag.value();
  172. }
  173. }
  174. return n;
  175. }
  176. /**
  177. * @param nconf Network configuration
  178. * @param id Capablity ID
  179. * @return Pointer to capability or NULL if not found
  180. */
  181. inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
  182. {
  183. std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
  184. return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(isCredentialTimestampValid(nconf,c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
  185. }
  186. /**
  187. * Validate and add a credential if signature is okay and it's otherwise good
  188. *
  189. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  190. */
  191. int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com);
  192. /**
  193. * Validate and add a credential if signature is okay and it's otherwise good
  194. *
  195. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  196. */
  197. int addCredential(const RuntimeEnvironment *RR,const Tag &tag);
  198. /**
  199. * Validate and add a credential if signature is okay and it's otherwise good
  200. *
  201. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  202. */
  203. int addCredential(const RuntimeEnvironment *RR,const Capability &cap);
  204. /**
  205. * Blacklist COM, tags, and capabilities before this time
  206. *
  207. * @param ts Blacklist cutoff
  208. */
  209. inline void blacklistBefore(const uint64_t ts)
  210. {
  211. _blacklistBefore = ts;
  212. }
  213. /**
  214. * Clean up old or stale entries
  215. *
  216. * @return Time of most recent activity in this Membership
  217. */
  218. inline uint64_t clean(const uint64_t now)
  219. {
  220. uint64_t lastAct = _lastPushedCom;
  221. for(std::map<uint32_t,CState>::iterator i(_caps.begin());i!=_caps.end();) {
  222. const uint64_t la = std::max(i->second.lastPushed,i->second.lastReceived);
  223. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) {
  224. _caps.erase(i++);
  225. } else {
  226. ++i;
  227. if (la > lastAct)
  228. lastAct = la;
  229. }
  230. }
  231. uint32_t *i = (uint32_t *)0;
  232. TState *ts = (TState *)0;
  233. Hashtable<uint32_t,TState>::Iterator tsi(_tags);
  234. while (tsi.next(i,ts)) {
  235. const uint64_t la = std::max(ts->lastPushed,ts->lastReceived);
  236. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME)
  237. _tags.erase(*i);
  238. else if (la > lastAct)
  239. lastAct = la;
  240. }
  241. return lastAct;
  242. }
  243. private:
  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