summaryrefslogtreecommitdiff
path: root/node/Membership.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/Membership.cpp')
-rw-r--r--node/Membership.cpp234
1 files changed, 142 insertions, 92 deletions
diff --git a/node/Membership.cpp b/node/Membership.cpp
index 8c2ba673..d579d303 100644
--- a/node/Membership.cpp
+++ b/node/Membership.cpp
@@ -16,6 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <algorithm>
+
#include "Membership.hpp"
#include "RuntimeEnvironment.hpp"
#include "Peer.hpp"
@@ -28,28 +30,43 @@
namespace ZeroTier {
-void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,const Capability *cap)
+Membership::Membership() :
+ _lastUpdatedMulticast(0),
+ _lastPushAttempt(0),
+ _lastPushedCom(0),
+ _comRevocationThreshold(0)
+{
+ for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) _remoteTags[i] = &(_tagMem[i]);
+ for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) _remoteCaps[i] = &(_capMem[i]);
+}
+
+void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force)
{
- if ((now - _lastPushAttempt) < 2000ULL)
+ // This limits how often we go through this logic, which prevents us from
+ // doing all this for every single packet or other event.
+ if ( ((now - _lastPushAttempt) < 1000ULL) && (!force) )
return;
_lastPushAttempt = now;
try {
- bool unfinished;
+ unsigned int localTagPtr = 0;
+ bool needCom = ( (nconf.com) && ( ((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) );
do {
- unfinished = false;
Buffer<ZT_PROTO_MAX_PACKET_LENGTH> capsAndTags;
unsigned int appendedCaps = 0;
- if (cap) {
+ if (localCapabilityIndex >= 0) {
capsAndTags.addSize(2);
- std::map<uint32_t,CState>::iterator cs(_caps.find(cap->id()));
- if ((cs != _caps.end())&&((now - cs->second.lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY)) {
- cap->serialize(capsAndTags);
- cs->second.lastPushed = now;
+
+ if ( (_localCaps[localCapabilityIndex].id != nconf.capabilities[localCapabilityIndex].id()) || ((now - _localCaps[localCapabilityIndex].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
+ _localCaps[localCapabilityIndex].lastPushed = now;
+ _localCaps[localCapabilityIndex].id = nconf.capabilities[localCapabilityIndex].id();
+ nconf.capabilities[localCapabilityIndex].serialize(capsAndTags);
++appendedCaps;
}
+
capsAndTags.setAt<uint16_t>(0,(uint16_t)appendedCaps);
+ localCapabilityIndex = -1; // don't send this cap again on subsequent loops if force is true
} else {
capsAndTags.append((uint16_t)0);
}
@@ -57,22 +74,17 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint
unsigned int appendedTags = 0;
const unsigned int tagCountPos = capsAndTags.size();
capsAndTags.addSize(2);
- for(unsigned int i=0;i<nconf.tagCount;++i) {
- TState *const ts = _tags.get(nconf.tags[i].id());
- if ((now - ts->lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) {
- if ((capsAndTags.size() + sizeof(Tag)) >= (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership))) {
- unfinished = true;
+ for(;localTagPtr<nconf.tagCount;++localTagPtr) {
+ if ( (_localTags[localTagPtr].id != nconf.tags[localTagPtr].id()) || ((now - _localTags[localTagPtr].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
+ if ((capsAndTags.size() + sizeof(Tag)) >= (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership)))
break;
- }
- nconf.tags[i].serialize(capsAndTags);
- ts->lastPushed = now;
+ nconf.tags[localTagPtr].serialize(capsAndTags);
++appendedTags;
}
}
capsAndTags.setAt<uint16_t>(tagCountPos,(uint16_t)appendedTags);
- const bool needCom = ((nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY));
- if ( (needCom) || (appendedCaps) || (appendedTags) ) {
+ if (needCom||appendedCaps||appendedTags) {
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
if (needCom) {
nconf.com.serialize(outp);
@@ -80,110 +92,148 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint
}
outp.append((uint8_t)0x00);
outp.append(capsAndTags.data(),capsAndTags.size());
+ outp.append((uint16_t)0); // no revocations, these propagate differently
outp.compress();
RR->sw->send(outp,true);
+ needCom = false; // don't send COM again on subsequent loops if force is true
}
- } while (unfinished); // if there are many tags, etc., we can send more than one
+ } while (localTagPtr < nconf.tagCount);
} catch ( ... ) {
TRACE("unable to send credentials due to unexpected exception");
}
}
-int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com)
+const Capability *Membership::getCapability(const NetworkConfig &nconf,const uint32_t id) const
{
- if (_com == com) {
- TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId());
- return 0;
+ const _RemoteCapability *const *c = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)id,_RemoteCredentialSorter<_RemoteCapability>());
+ return ( ((c != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*c)->id == (uint64_t)id)) ? ((((*c)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*c)->cap,**c))) ? &((*c)->cap) : (const Capability *)0) : (const Capability *)0);
+}
+
+const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const
+{
+ const _RemoteTag *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialSorter<_RemoteTag>());
+ return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*t)->tag,**t))) ? &((*t)->tag) : (const Tag *)0) : (const Tag *)0);
+}
+
+Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com)
+{
+ const uint64_t newts = com.timestamp().first;
+ if (newts <= _comRevocationThreshold) {
+ TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId());
+ return ADD_REJECTED;
}
- const int vr = com.verify(RR);
+ const uint64_t oldts = _com.timestamp().first;
+ if (newts < oldts) {
+ TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId());
+ return ADD_REJECTED;
+ }
+ if ((newts == oldts)&&(_com == com)) {
+ TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (redundant)",com.issuedTo().toString().c_str(),com.networkId());
+ return ADD_ACCEPTED_REDUNDANT;
+ }
- if (vr == 0) {
- if (com.timestamp().first >= _com.timestamp().first) {
+ switch(com.verify(RR)) {
+ default:
+ TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (invalid signature or object)",com.issuedTo().toString().c_str(),com.networkId());
+ return ADD_REJECTED;
+ case 0:
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED (new)",com.issuedTo().toString().c_str(),com.networkId());
_com = com;
- } else {
- TRACE("addCredential(CertificateOfMembership) for %s on %.16llx ACCEPTED but not used (OK but older than current)",com.issuedTo().toString().c_str(),com.networkId());
- }
- } else {
- TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (%d)",com.issuedTo().toString().c_str(),com.networkId(),vr);
+ return ADD_ACCEPTED_NEW;
+ case 1:
+ return ADD_DEFERRED_FOR_WHOIS;
}
-
- return vr;
}
-int Membership::addCredential(const RuntimeEnvironment *RR,const Tag &tag)
+Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Tag &tag)
{
- TState *t = _tags.get(tag.id());
- if ((t)&&(t->lastReceived != 0)&&(t->tag == tag)) {
- TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId());
- return 0;
+ _RemoteTag *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialSorter<_RemoteTag>());
+ _RemoteTag *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteTag *)0;
+ if (have) {
+ if ( (!_isCredentialTimestampValid(nconf,tag,*have)) || (have->tag.timestamp() > tag.timestamp()) ) {
+ TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId());
+ return ADD_REJECTED;
+ }
+ if (have->tag == tag) {
+ TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId());
+ return ADD_ACCEPTED_REDUNDANT;
+ }
}
- const int vr = tag.verify(RR);
- if (vr == 0) {
- TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId());
- if (!t) {
- while (_tags.size() >= ZT_MAX_NETWORK_TAGS) {
- uint32_t oldest = 0;
- uint64_t oldestLastReceived = 0xffffffffffffffffULL;
- uint32_t *i = (uint32_t *)0;
- TState *ts = (TState *)0;
- Hashtable<uint32_t,TState>::Iterator tsi(_tags);
- while (tsi.next(i,ts)) {
- if (ts->lastReceived < oldestLastReceived) {
- oldestLastReceived = ts->lastReceived;
- oldest = *i;
+
+ switch(tag.verify(RR)) {
+ default:
+ TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId());
+ return ADD_REJECTED;
+ case 0:
+ TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId());
+ if (have) {
+ have->lastReceived = RR->node->now();
+ have->tag = tag;
+ } else {
+ uint64_t minlr = 0xffffffffffffffffULL;
+ for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) {
+ if (_remoteTags[i]->id == 0xffffffffffffffffULL) {
+ have = _remoteTags[i];
+ break;
+ } else if (_remoteTags[i]->lastReceived <= minlr) {
+ have = _remoteTags[i];
+ minlr = _remoteTags[i]->lastReceived;
}
}
- if (oldestLastReceived != 0xffffffffffffffffULL)
- _tags.erase(oldest);
+ have->lastReceived = RR->node->now();
+ have->tag = tag;
+ std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>());
}
- t = &(_tags[tag.id()]);
- }
- if (t->tag.timestamp() <= tag.timestamp()) {
- t->lastReceived = RR->node->now();
- t->tag = tag;
- }
- } else {
- TRACE("addCredential(Tag) for %s on %.16llx REJECTED (%d)",tag.issuedTo().toString().c_str(),tag.networkId(),vr);
+ return ADD_ACCEPTED_NEW;
+ case 1:
+ return ADD_DEFERRED_FOR_WHOIS;
}
- return vr;
}
-int Membership::addCredential(const RuntimeEnvironment *RR,const Capability &cap)
+Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap)
{
- std::map<uint32_t,CState>::iterator c(_caps.find(cap.id()));
- if ((c != _caps.end())&&(c->second.lastReceived != 0)&&(c->second.cap == cap)) {
- TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId());
- return 0;
+ _RemoteCapability *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialSorter<_RemoteCapability>());
+ _RemoteCapability *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCapability *)0;
+ if (have) {
+ if ( (!_isCredentialTimestampValid(nconf,cap,*have)) || (have->cap.timestamp() > cap.timestamp()) ) {
+ TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId());
+ return ADD_REJECTED;
+ }
+ if (have->cap == cap) {
+ TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId());
+ return ADD_ACCEPTED_REDUNDANT;
+ }
}
- const int vr = cap.verify(RR);
- if (vr == 0) {
- TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId());
- if (c == _caps.end()) {
- while (_caps.size() >= ZT_MAX_NETWORK_CAPABILITIES) {
- std::map<uint32_t,CState>::iterator oldest;
- uint64_t oldestLastReceived = 0xffffffffffffffffULL;
- for(std::map<uint32_t,CState>::iterator i(_caps.begin());i!=_caps.end();++i) {
- if (i->second.lastReceived < oldestLastReceived) {
- oldestLastReceived = i->second.lastReceived;
- oldest = i;
+
+ switch(cap.verify(RR)) {
+ default:
+ TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId());
+ return ADD_REJECTED;
+ case 0:
+ TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId());
+ if (have) {
+ have->lastReceived = RR->node->now();
+ have->cap = cap;
+ } else {
+ uint64_t minlr = 0xffffffffffffffffULL;
+ for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) {
+ if (_remoteCaps[i]->id == 0xffffffffffffffffULL) {
+ have = _remoteCaps[i];
+ break;
+ } else if (_remoteCaps[i]->lastReceived <= minlr) {
+ have = _remoteCaps[i];
+ minlr = _remoteCaps[i]->lastReceived;
}
}
- if (oldestLastReceived != 0xffffffffffffffffULL)
- _caps.erase(oldest);
+ have->lastReceived = RR->node->now();
+ have->cap = cap;
+ std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>());
}
- CState &c2 = _caps[cap.id()];
- c2.lastReceived = RR->node->now();
- c2.cap = cap;
- } else if (c->second.cap.timestamp() <= cap.timestamp()) {
- c->second.lastReceived = RR->node->now();
- c->second.cap = cap;
- }
- } else {
- TRACE("addCredential(Capability) for %s on %.16llx REJECTED (%d)",cap.issuedTo().toString().c_str(),cap.networkId(),vr);
+ return ADD_ACCEPTED_NEW;
+ case 1:
+ return ADD_DEFERRED_FOR_WHOIS;
}
- return vr;
}
} // namespace ZeroTier