Bunch more refactoring and work on revocations, etc.

This commit is contained in:
Adam Ierymenko 2016-09-26 16:17:02 -07:00
parent 46049a1ef6
commit eac3667ec1
10 changed files with 220 additions and 72 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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
{

View File

@ -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()

View File

@ -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

View File

@ -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";

View File

@ -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:

View File

@ -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