mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-07 19:24:13 +00:00
Bunch more refactoring and work on revocations, etc.
This commit is contained in:
parent
46049a1ef6
commit
eac3667ec1
@ -517,7 +517,7 @@ enum ZT_VirtualNetworkRuleType
|
||||
ZT_NETWORK_RULE_ACTION_TEE = 2,
|
||||
|
||||
/**
|
||||
* Exactly like TEE but frames are dropped if previous TEEs were not acknowledged by the observer
|
||||
* Exactly like TEE but mandates ACKs from observer
|
||||
*/
|
||||
ZT_NETWORK_RULE_ACTION_WATCH = 3,
|
||||
|
||||
|
@ -67,7 +67,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
|
||||
return _doHELLO(RR,false);
|
||||
}
|
||||
|
||||
SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
|
||||
const SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
|
||||
if (peer) {
|
||||
if (!trusted) {
|
||||
if (!dearmor(peer->key())) {
|
||||
@ -100,7 +100,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
|
||||
case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer);
|
||||
case Packet::VERB_NETWORK_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,peer);
|
||||
case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,peer);
|
||||
case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer);
|
||||
case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,peer);
|
||||
case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer);
|
||||
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer);
|
||||
case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer);
|
||||
@ -131,12 +131,18 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
||||
|
||||
//TRACE("ERROR %s from %s(%s) in-re %s",Packet::errorString(errorCode),peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb));
|
||||
|
||||
/* Security note: we do not gate doERROR() with expectingReplyTo() to
|
||||
* avoid having to log every outgoing packet ID. Instead we put the
|
||||
* logic to determine whether we should consider an ERROR in each
|
||||
* error handler. In most cases these are only trusted in specific
|
||||
* circumstances. */
|
||||
|
||||
switch(errorCode) {
|
||||
|
||||
case Packet::ERROR_OBJ_NOT_FOUND:
|
||||
// Object not found, currently only meaningful from network controllers.
|
||||
if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
network->setNotFound();
|
||||
}
|
||||
@ -147,7 +153,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
||||
// consider it meaningful from network controllers. This would indicate
|
||||
// that the queried node does not support acting as a controller.
|
||||
if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
network->setNotFound();
|
||||
}
|
||||
@ -161,7 +167,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
||||
|
||||
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
|
||||
// Peers can send this in response to frames if they do not have a recent enough COM from us
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
const uint64_t now = RR->node->now();
|
||||
if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) )
|
||||
network->pushCredentialsNow(peer->address(),now);
|
||||
@ -169,7 +175,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
||||
|
||||
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
|
||||
// Network controller: network access denied.
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
network->setAccessDenied();
|
||||
} break;
|
||||
@ -177,9 +183,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
||||
case Packet::ERROR_UNWANTED_MULTICAST: {
|
||||
// Members of networks can use this error to indicate that they no longer
|
||||
// want to receive multicasts on a given channel.
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
if ((network)&&(network->gate(peer,verb(),packetId()))) {
|
||||
MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14));
|
||||
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14));
|
||||
TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str());
|
||||
RR->mc->remove(network->id(),mg,peer->address());
|
||||
}
|
||||
@ -371,7 +377,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
||||
const uint64_t inRePacketId = at<uint64_t>(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID);
|
||||
bool trustEstablished = false;
|
||||
|
||||
// Don't parse OK packets that are not in response to a packet ID we sent
|
||||
if (!RR->node->expectingReplyTo(inRePacketId)) {
|
||||
TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId());
|
||||
return true;
|
||||
@ -450,7 +455,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
||||
|
||||
case Packet::VERB_MULTICAST_GATHER: {
|
||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
|
||||
SharedPtr<Network> network(RR->node->network(nwid));
|
||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||
if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) {
|
||||
trustEstablished = true;
|
||||
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
|
||||
@ -467,7 +472,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
||||
|
||||
//TRACE("%s(%s): OK(MULTICAST_FRAME) %.16llx/%s flags %.2x",peer->address().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),flags);
|
||||
|
||||
SharedPtr<Network> network(RR->node->network(nwid));
|
||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||
if (network) {
|
||||
unsigned int offset = 0;
|
||||
|
||||
@ -683,6 +688,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
|
||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||
outp.append((uint8_t)Packet::VERB_EXT_FRAME);
|
||||
outp.append((uint64_t)packetId());
|
||||
outp.append((uint64_t)nwid);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
@ -727,7 +733,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
|
||||
try {
|
||||
const uint64_t now = RR->node->now();
|
||||
|
||||
uint64_t authOnNetwork[256];
|
||||
uint64_t authOnNetwork[256]; // cache for approved network IDs
|
||||
unsigned int authOnNetworkCount = 0;
|
||||
SharedPtr<Network> network;
|
||||
bool trustEstablished = false;
|
||||
@ -786,7 +792,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
||||
while ((p < size())&&((*this)[p])) {
|
||||
p += com.deserialize(*this,p);
|
||||
if (com) {
|
||||
SharedPtr<Network> network(RR->node->network(com.networkId()));
|
||||
const SharedPtr<Network> network(RR->node->network(com.networkId()));
|
||||
if (network) {
|
||||
switch (network->addCredential(com)) {
|
||||
case Membership::ADD_REJECTED:
|
||||
@ -803,11 +809,11 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
||||
}
|
||||
++p; // skip trailing 0 after COMs if present
|
||||
|
||||
if (p < size()) { // check if new capabilities and tags fields are present
|
||||
if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations
|
||||
const unsigned int numCapabilities = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numCapabilities;++i) {
|
||||
p += cap.deserialize(*this,p);
|
||||
SharedPtr<Network> network(RR->node->network(cap.networkId()));
|
||||
const SharedPtr<Network> network(RR->node->network(cap.networkId()));
|
||||
if (network) {
|
||||
switch (network->addCredential(cap)) {
|
||||
case Membership::ADD_REJECTED:
|
||||
@ -825,7 +831,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
||||
const unsigned int numTags = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numTags;++i) {
|
||||
p += tag.deserialize(*this,p);
|
||||
SharedPtr<Network> network(RR->node->network(tag.networkId()));
|
||||
const SharedPtr<Network> network(RR->node->network(tag.networkId()));
|
||||
if (network) {
|
||||
switch (network->addCredential(tag)) {
|
||||
case Membership::ADD_REJECTED:
|
||||
@ -843,8 +849,18 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
||||
const unsigned int numRevocations = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numRevocations;++i) {
|
||||
p += revocation.deserialize(*this,p);
|
||||
SharedPtr<Network> network(RR->node->network(revocation.networkId()));
|
||||
const SharedPtr<Network> network(RR->node->network(revocation.networkId()));
|
||||
if (network) {
|
||||
switch(network->addCredential(peer->address(),revocation)) {
|
||||
case Membership::ADD_REJECTED:
|
||||
break;
|
||||
case Membership::ADD_ACCEPTED_NEW:
|
||||
case Membership::ADD_ACCEPTED_REDUNDANT:
|
||||
trustEstablished = true;
|
||||
break;
|
||||
case Membership::ADD_DEFERRED_FOR_WHOIS:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -879,6 +895,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
||||
try {
|
||||
if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) {
|
||||
dconf->wrapWithSignature(ZT_NETWORKCONFIG_DICT_KEY_SIGNATURE,RR->identity.privateKeyPair());
|
||||
|
||||
const unsigned int totalSize = dconf->sizeBytes();
|
||||
unsigned int chunkIndex = 0;
|
||||
while (chunkIndex < totalSize) {
|
||||
@ -957,7 +974,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
const uint64_t nwid = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
|
||||
|
@ -146,7 +146,7 @@ private:
|
||||
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
|
@ -167,24 +167,9 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||
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;
|
||||
}
|
||||
}
|
||||
have->lastReceived = RR->node->now();
|
||||
have->tag = tag;
|
||||
std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>());
|
||||
}
|
||||
if (!have) have = _newTag(tag.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->tag = tag;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
@ -212,28 +197,114 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||
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;
|
||||
}
|
||||
}
|
||||
have->lastReceived = RR->node->now();
|
||||
have->cap = cap;
|
||||
std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>());
|
||||
}
|
||||
if (!have) have = _newCapability(cap.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->cap = cap;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev)
|
||||
{
|
||||
switch(rev.verify(RR)) {
|
||||
default:
|
||||
return ADD_REJECTED;
|
||||
case 0: {
|
||||
const uint64_t now = RR->node->now();
|
||||
switch(rev.type()) {
|
||||
default:
|
||||
//case Revocation::CREDENTIAL_TYPE_ALL:
|
||||
return ( (_revokeCom(rev)||_revokeCap(rev,now)||_revokeTag(rev,now)) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT );
|
||||
case Revocation::CREDENTIAL_TYPE_COM:
|
||||
return (_revokeCom(rev) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_CAPABILITY:
|
||||
return (_revokeCap(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_TAG:
|
||||
return (_revokeTag(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::_RemoteTag *Membership::_newTag(const uint64_t id)
|
||||
{
|
||||
_RemoteTag *t;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) {
|
||||
if (_remoteTags[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
t = _remoteTags[i];
|
||||
break;
|
||||
} else if (_remoteTags[i]->lastReceived <= minlr) {
|
||||
t = _remoteTags[i];
|
||||
minlr = _remoteTags[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
t->id = id;
|
||||
t->lastReceived = 0;
|
||||
t->revocationThreshold = 0;
|
||||
t->tag = Tag();
|
||||
std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialSorter<_RemoteTag>());
|
||||
return t;
|
||||
}
|
||||
|
||||
Membership::_RemoteCapability *Membership::_newCapability(const uint64_t id)
|
||||
{
|
||||
_RemoteCapability *c;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) {
|
||||
if (_remoteCaps[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
c = _remoteCaps[i];
|
||||
break;
|
||||
} else if (_remoteCaps[i]->lastReceived <= minlr) {
|
||||
c = _remoteCaps[i];
|
||||
minlr = _remoteCaps[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
c->id = id;
|
||||
c->lastReceived = 0;
|
||||
c->revocationThreshold = 0;
|
||||
c->cap = Capability();
|
||||
std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialSorter<_RemoteCapability>());
|
||||
return c;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCom(const Revocation &rev)
|
||||
{
|
||||
if (rev.threshold() > _comRevocationThreshold) {
|
||||
_comRevocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCap(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCapability *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialSorter<_RemoteCapability>());
|
||||
_RemoteCapability *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCapability *)0;
|
||||
if (!have) have = _newCapability(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeTag(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteTag *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialSorter<_RemoteTag>());
|
||||
_RemoteTag *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteTag *)0;
|
||||
if (!have) have = _newTag(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include "Revocation.hpp"
|
||||
#include "NetworkConfig.hpp"
|
||||
|
||||
#define ZT_MEMBERSHIP_CRED_ID_UNUSED 0xffffffffffffffffULL
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
@ -48,7 +50,7 @@ private:
|
||||
// Tags and related state
|
||||
struct _RemoteTag
|
||||
{
|
||||
_RemoteTag() : id(0xffffffffffffffffULL),lastReceived(0),revocationThreshold(0) {}
|
||||
_RemoteTag() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {}
|
||||
// Tag ID (last 32 bits, first 32 bits are set in unused entries to sort them to end)
|
||||
uint64_t id;
|
||||
// Last time we received THEIR tag (with this ID)
|
||||
@ -62,7 +64,7 @@ private:
|
||||
// Credentials and related state
|
||||
struct _RemoteCapability
|
||||
{
|
||||
_RemoteCapability() : id(0xffffffffffffffffULL),lastReceived(0),revocationThreshold(0) {}
|
||||
_RemoteCapability() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {}
|
||||
// Capability ID (last 32 bits, first 32 bits are set in unused entries to sort them to end)
|
||||
uint64_t id;
|
||||
// Last time we received THEIR capability (with this ID)
|
||||
@ -114,7 +116,7 @@ public:
|
||||
inline const Capability *next()
|
||||
{
|
||||
for(;;) {
|
||||
if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != 0xffffffffffffffffULL)) {
|
||||
if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) {
|
||||
const Capability *tmp = &((*_i)->cap);
|
||||
if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) {
|
||||
++_i;
|
||||
@ -147,7 +149,7 @@ public:
|
||||
inline const Tag *next()
|
||||
{
|
||||
for(;;) {
|
||||
if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != 0xffffffffffffffffULL)) {
|
||||
if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) {
|
||||
const Tag *tmp = &((*_i)->tag);
|
||||
if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) {
|
||||
++_i;
|
||||
@ -242,7 +244,18 @@ public:
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Capability &cap);
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const Revocation &rev);
|
||||
|
||||
private:
|
||||
_RemoteTag *_newTag(const uint64_t id);
|
||||
_RemoteCapability *_newCapability(const uint64_t id);
|
||||
bool _revokeCom(const Revocation &rev);
|
||||
bool _revokeCap(const Revocation &rev,const uint64_t now);
|
||||
bool _revokeTag(const Revocation &rev,const uint64_t now);
|
||||
|
||||
template<typename C,typename CS>
|
||||
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred,const CS &state) const
|
||||
{
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include "Peer.hpp"
|
||||
|
||||
// Uncomment to make the rules engine dump trace info to stdout
|
||||
#define ZT_RULES_ENGINE_DEBUGGING 1
|
||||
//#define ZT_RULES_ENGINE_DEBUGGING 1
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
@ -1116,8 +1116,41 @@ Membership::AddCredentialResult Network::addCredential(const CertificateOfMember
|
||||
return result;
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Network::addCredential(const Revocation &rev)
|
||||
Membership::AddCredentialResult Network::addCredential(const Address &sentFrom,const Revocation &rev)
|
||||
{
|
||||
if (rev.networkId() != _id)
|
||||
return Membership::ADD_REJECTED;
|
||||
|
||||
Mutex::Lock _l(_lock);
|
||||
Membership &m = _membership(rev.target());
|
||||
|
||||
const Membership::AddCredentialResult result = m.addCredential(RR,_config,rev);
|
||||
|
||||
if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
|
||||
/* Fast propagation is done by using a very aggressive rumor mill
|
||||
* propagation algorithm. When we see a Revocation that we haven't
|
||||
* seen before we blast it to every known member. This leads to
|
||||
* a huge number of redundant messages, but eventually everybody
|
||||
* will get it. This helps revocation speed and also helps in cases
|
||||
* where the controller is under attack. It need only get one
|
||||
* revocation out and the rest is history. */
|
||||
Address *a = (Address *)0;
|
||||
Membership *m = (Membership *)0;
|
||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||
while (i.next(a,m)) {
|
||||
if ((*a != sentFrom)&&(*a != rev.signer())) {
|
||||
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||
outp.append((uint8_t)0x00); // no COM
|
||||
outp.append((uint16_t)0); // no capabilities
|
||||
outp.append((uint16_t)0); // no tags
|
||||
outp.append((uint16_t)1); // one revocation!
|
||||
rev.serialize(outp);
|
||||
RR->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Network::destroy()
|
||||
|
@ -299,7 +299,7 @@ public:
|
||||
/**
|
||||
* Validate a credential and learn it if it passes certificate and other checks
|
||||
*/
|
||||
Membership::AddCredentialResult addCredential(const Revocation &rev);
|
||||
Membership::AddCredentialResult addCredential(const Address &sentFrom,const Revocation &rev);
|
||||
|
||||
/**
|
||||
* Force push credentials (COM, etc.) to a peer now
|
||||
|
@ -40,7 +40,7 @@ const char *Packet::verbString(Verb v)
|
||||
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
|
||||
case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS";
|
||||
case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
|
||||
case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
|
||||
case VERB_NETWORK_CONFIG: return "NETWORK_CONFIG_REFRESH";
|
||||
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
|
||||
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
|
||||
case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS";
|
||||
|
@ -674,8 +674,8 @@ public:
|
||||
* superset of VERB_FRAME. They're used for bridging or when we
|
||||
* want to attach a certificate since FRAME does not support that.
|
||||
*
|
||||
* If the ACK flag (0x08) is set, an OK(EXT_FRAME) is sent with
|
||||
* no payload to acknowledge receipt of the frame.
|
||||
* OK payload (if ACK flag is set):
|
||||
* <[8] 64-bit network ID>
|
||||
*/
|
||||
VERB_EXT_FRAME = 0x07,
|
||||
|
||||
@ -738,9 +738,14 @@ public:
|
||||
* <[8] 64-bit timestamp of netconf we currently have>
|
||||
*
|
||||
* This message requests network configuration from a node capable of
|
||||
* providing it. If the optional revision is included, a response is
|
||||
* only generated if there is a newer network configuration available.
|
||||
* providing it.
|
||||
*
|
||||
* Respones to this are always whole configs intended for the recipient.
|
||||
* For patches and other updates a NETWORK_CONFIG is sent instead.
|
||||
*
|
||||
* It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always,
|
||||
* but OK(NTEWORK_CONFIG_REQUEST) should be sent for compatibility.
|
||||
*
|
||||
* OK response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[2] 16-bit length of network configuration dictionary chunk>
|
||||
@ -754,9 +759,10 @@ public:
|
||||
VERB_NETWORK_CONFIG_REQUEST = 0x0b,
|
||||
|
||||
/**
|
||||
* Network configuration push:
|
||||
* Network configuration data push:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[8] 64-bit value used to group chunks in this push>
|
||||
* <[8] 64-bit config update ID (token to identify this update)>
|
||||
* <[1] flags>
|
||||
* <[2] 16-bit length of network configuration dictionary chunk>
|
||||
* <[...] network configuration dictionary (may be incomplete)>
|
||||
* <[4] 32-bit total length of assembled dictionary>
|
||||
@ -766,8 +772,16 @@ public:
|
||||
* carries the same payload as OK(NETWORK_CONFIG_REQUEST). There is an
|
||||
* extra number after network ID in this version that is used in place of
|
||||
* the in-re packet ID sent with OKs to group chunks together.
|
||||
*
|
||||
* Unlike OK(NETWORK_CONFIG_REQUEST) this can be sent by peers other than
|
||||
* network controllers. In that case the certificate inside the Dictionary
|
||||
* is used for verification purposes.
|
||||
*
|
||||
* Flags:
|
||||
* 0x01 - Patch, not whole config
|
||||
* 0x02 - Use fast P2P propagation
|
||||
*/
|
||||
VERB_NETWORK_CONFIG_REFRESH = 0x0c,
|
||||
VERB_NETWORK_CONFIG = 0x0c,
|
||||
|
||||
/**
|
||||
* Request endpoints for multicast distribution:
|
||||
|
@ -49,7 +49,7 @@ class Revocation
|
||||
public:
|
||||
enum CredentialType
|
||||
{
|
||||
CREDENTIAL_TYPE_NIL = 0,
|
||||
CREDENTIAL_TYPE_ALL = 0,
|
||||
CREDENTIAL_TYPE_COM = 1,
|
||||
CREDENTIAL_TYPE_CAPABILITY = 2,
|
||||
CREDENTIAL_TYPE_TAG = 3
|
||||
|
Loading…
x
Reference in New Issue
Block a user