|
@@ -92,7 +92,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid) :
|
|
|
com.deserialize2(p,e);
|
|
|
if (!com)
|
|
|
break;
|
|
|
- _membershipCertificates.insert(std::pair< Address,CertificateOfMembership >(com.issuedTo(),com));
|
|
|
+ _certInfo[com.issuedTo()].com = com;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -125,19 +125,22 @@ Network::~Network()
|
|
|
|
|
|
clean();
|
|
|
|
|
|
- std::string buf("ZTMCD0");
|
|
|
Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.mcerts",_id);
|
|
|
- Mutex::Lock _l(_lock);
|
|
|
|
|
|
- if ((!_config)||(_config->isPublic())||(_membershipCertificates.size() == 0)) {
|
|
|
+ Mutex::Lock _l(_lock);
|
|
|
+ if ((!_config)||(_config->isPublic())||(_certInfo.empty())) {
|
|
|
RR->node->dataStoreDelete(n);
|
|
|
- return;
|
|
|
+ } else {
|
|
|
+ std::string buf("ZTMCD0");
|
|
|
+ Hashtable< Address,_RemoteMemberCertificateInfo >::Iterator i(_certInfo);
|
|
|
+ Address *a = (Address *)0;
|
|
|
+ _RemoteMemberCertificateInfo *ci = (_RemoteMemberCertificateInfo *)0;
|
|
|
+ while (i.next(a,ci)) {
|
|
|
+ if (ci->com)
|
|
|
+ ci->com.serialize2(buf);
|
|
|
+ }
|
|
|
+ RR->node->dataStorePut(n,buf,true);
|
|
|
}
|
|
|
-
|
|
|
- for(std::map<Address,CertificateOfMembership>::iterator c(_membershipCertificates.begin());c!=_membershipCertificates.end();++c)
|
|
|
- c->second.serialize2(buf);
|
|
|
-
|
|
|
- RR->node->dataStorePut(n,buf,true);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -284,11 +287,12 @@ bool Network::validateAndAddMembershipCertificate(const CertificateOfMembership
|
|
|
return false;
|
|
|
|
|
|
Mutex::Lock _l(_lock);
|
|
|
- CertificateOfMembership &old = _membershipCertificates[cert.issuedTo()];
|
|
|
|
|
|
- // Nothing to do if the cert hasn't changed -- we get duplicates due to zealous cert pushing
|
|
|
- if (old == cert)
|
|
|
- return true; // but if it's a duplicate of one we already accepted, return is 'true'
|
|
|
+ {
|
|
|
+ const _RemoteMemberCertificateInfo *ci = _certInfo.get(cert.issuedTo());
|
|
|
+ if ((ci)&&(ci->com == cert))
|
|
|
+ return true; // we already have it
|
|
|
+ }
|
|
|
|
|
|
// Check signature, log and return if cert is invalid
|
|
|
if (cert.signedBy() != controller()) {
|
|
@@ -322,9 +326,8 @@ bool Network::validateAndAddMembershipCertificate(const CertificateOfMembership
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // If we made it past authentication, update cert
|
|
|
- if (cert.revision() != old.revision())
|
|
|
- old = cert;
|
|
|
+ // If we made it past authentication, add or update cert in our cert info store
|
|
|
+ _certInfo[cert.issuedTo()].com = cert;
|
|
|
|
|
|
return true;
|
|
|
}
|
|
@@ -333,9 +336,9 @@ bool Network::peerNeedsOurMembershipCertificate(const Address &to,uint64_t now)
|
|
|
{
|
|
|
Mutex::Lock _l(_lock);
|
|
|
if ((_config)&&(!_config->isPublic())&&(_config->com())) {
|
|
|
- uint64_t &lastPushed = _lastPushedMembershipCertificate[to];
|
|
|
- if ((now - lastPushed) > (ZT_NETWORK_AUTOCONF_DELAY / 2)) {
|
|
|
- lastPushed = now;
|
|
|
+ _RemoteMemberCertificateInfo &ci = _certInfo[to];
|
|
|
+ if ((now - ci.lastPushed) > (ZT_NETWORK_AUTOCONF_DELAY / 2)) {
|
|
|
+ ci.lastPushed = now;
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -352,23 +355,16 @@ void Network::clean()
|
|
|
|
|
|
if ((_config)&&(_config->isPublic())) {
|
|
|
// Open (public) networks do not track certs or cert pushes at all.
|
|
|
- _membershipCertificates.clear();
|
|
|
- _lastPushedMembershipCertificate.clear();
|
|
|
+ _certInfo.clear();
|
|
|
} else if (_config) {
|
|
|
- // Clean certificates that are no longer valid from the cache.
|
|
|
- for(std::map<Address,CertificateOfMembership>::iterator c=(_membershipCertificates.begin());c!=_membershipCertificates.end();) {
|
|
|
- if (_config->com().agreesWith(c->second))
|
|
|
- ++c;
|
|
|
- else _membershipCertificates.erase(c++);
|
|
|
- }
|
|
|
-
|
|
|
- // Clean entries from the last pushed tracking map if they're so old as
|
|
|
- // to be no longer relevant.
|
|
|
- uint64_t forgetIfBefore = now - (ZT_PEER_ACTIVITY_TIMEOUT * 16); // arbitrary reasonable cutoff
|
|
|
- for(std::map<Address,uint64_t>::iterator lp(_lastPushedMembershipCertificate.begin());lp!=_lastPushedMembershipCertificate.end();) {
|
|
|
- if (lp->second < forgetIfBefore)
|
|
|
- _lastPushedMembershipCertificate.erase(lp++);
|
|
|
- else ++lp;
|
|
|
+ // Clean obsolete entries from private network cert info table
|
|
|
+ Hashtable< Address,_RemoteMemberCertificateInfo >::Iterator i(_certInfo);
|
|
|
+ Address *a = (Address *)0;
|
|
|
+ _RemoteMemberCertificateInfo *ci = (_RemoteMemberCertificateInfo *)0;
|
|
|
+ const uint64_t forgetIfBefore = now - (ZT_PEER_ACTIVITY_TIMEOUT * 16); // arbitrary reasonable cutoff
|
|
|
+ while (i.next(a,ci)) {
|
|
|
+ if ((ci->lastPushed < forgetIfBefore)&&(!ci->com.agreesWith(_config->com())))
|
|
|
+ _certInfo.erase(*a);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -506,12 +502,10 @@ bool Network::_isAllowed(const Address &peer) const
|
|
|
return false;
|
|
|
if (_config->isPublic())
|
|
|
return true;
|
|
|
-
|
|
|
- std::map<Address,CertificateOfMembership>::const_iterator pc(_membershipCertificates.find(peer));
|
|
|
- if (pc == _membershipCertificates.end())
|
|
|
- return false; // no certificate on file
|
|
|
-
|
|
|
- return _config->com().agreesWith(pc->second); // is other cert valid against ours?
|
|
|
+ const _RemoteMemberCertificateInfo *ci = _certInfo.get(peer);
|
|
|
+ if (!ci)
|
|
|
+ return false;
|
|
|
+ return _config->com().agreesWith(ci->com);
|
|
|
} catch (std::exception &exc) {
|
|
|
TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer.toString().c_str(),exc.what());
|
|
|
} catch ( ... ) {
|