Membership.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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 within its max delta from the timestamp of our network config and newer than any blacklist cutoff time
  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. const uint64_t delta = (ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts);
  140. return ((delta <= nconf.credentialTimeMaxDelta)&&(ts > _blacklistBefore));
  141. }
  142. /**
  143. * @param nconf Network configuration
  144. * @param id Tag ID
  145. * @return Pointer to tag or NULL if not found
  146. */
  147. inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
  148. {
  149. const TState *t = _tags.get(id);
  150. return ((t) ? (((t->lastReceived != 0)&&(isCredentialTimestampValid(nconf,t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
  151. }
  152. /**
  153. * @param nconf Network configuration
  154. * @param ids Array to store IDs into
  155. * @param values Array to store values into
  156. * @param maxTags Capacity of ids[] and values[]
  157. * @return Number of tags added to arrays
  158. */
  159. inline unsigned int getAllTags(const NetworkConfig &nconf,uint32_t *ids,uint32_t *values,unsigned int maxTags) const
  160. {
  161. unsigned int n = 0;
  162. uint32_t *id = (uint32_t *)0;
  163. TState *ts = (TState *)0;
  164. Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
  165. while (i.next(id,ts)) {
  166. if ((ts->lastReceived)&&(isCredentialTimestampValid(nconf,ts->tag))) {
  167. if (n >= maxTags)
  168. return n;
  169. ids[n] = *id;
  170. values[n] = ts->tag.value();
  171. }
  172. }
  173. return n;
  174. }
  175. /**
  176. * @param nconf Network configuration
  177. * @param id Capablity ID
  178. * @return Pointer to capability or NULL if not found
  179. */
  180. inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
  181. {
  182. std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
  183. return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(isCredentialTimestampValid(nconf,c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
  184. }
  185. /**
  186. * Validate and add a credential if signature is okay and it's otherwise good
  187. *
  188. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  189. */
  190. int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com);
  191. /**
  192. * Validate and add a credential if signature is okay and it's otherwise good
  193. *
  194. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  195. */
  196. int addCredential(const RuntimeEnvironment *RR,const Tag &tag);
  197. /**
  198. * Validate and add a credential if signature is okay and it's otherwise good
  199. *
  200. * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
  201. */
  202. int addCredential(const RuntimeEnvironment *RR,const Capability &cap);
  203. /**
  204. * Blacklist COM, tags, and capabilities before this time
  205. *
  206. * @param ts Blacklist cutoff
  207. */
  208. inline void blacklistBefore(const uint64_t ts)
  209. {
  210. _blacklistBefore = ts;
  211. }
  212. /**
  213. * Clean up old or stale entries
  214. *
  215. * @return Time of most recent activity in this Membership
  216. */
  217. inline uint64_t clean(const uint64_t now)
  218. {
  219. uint64_t lastAct = _lastPushedCom;
  220. for(std::map<uint32_t,CState>::iterator i(_caps.begin());i!=_caps.end();) {
  221. const uint64_t la = std::max(i->second.lastPushed,i->second.lastReceived);
  222. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME) {
  223. _caps.erase(i++);
  224. } else {
  225. ++i;
  226. if (la > lastAct)
  227. lastAct = la;
  228. }
  229. }
  230. uint32_t *i = (uint32_t *)0;
  231. TState *ts = (TState *)0;
  232. Hashtable<uint32_t,TState>::Iterator tsi(_tags);
  233. while (tsi.next(i,ts)) {
  234. const uint64_t la = std::max(ts->lastPushed,ts->lastReceived);
  235. if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME)
  236. _tags.erase(*i);
  237. else if (la > lastAct)
  238. lastAct = la;
  239. }
  240. return lastAct;
  241. }
  242. private:
  243. // Last time we checked if credential push was needed
  244. uint64_t _lastPushAttempt;
  245. // Last time we pushed our COM to this peer
  246. uint64_t _lastPushedCom;
  247. // Time before which to blacklist credentials from this peer
  248. uint64_t _blacklistBefore;
  249. // COM from this peer
  250. CertificateOfMembership _com;
  251. // Capability-related state (we need an ordered container here, hence std::map)
  252. std::map<uint32_t,CState> _caps;
  253. // Tag-related state
  254. Hashtable<uint32_t,TState> _tags;
  255. };
  256. } // namespace ZeroTier
  257. #endif