Bunch of work on pushing and replication of tags and capabilities, and protocol cleanup.
This commit is contained in:
parent
67cb03742e
commit
7e6e56e2bc
14 changed files with 409 additions and 464 deletions
|
@ -38,6 +38,9 @@
|
|||
#include "Node.hpp"
|
||||
#include "DeferredPackets.hpp"
|
||||
#include "Filter.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -106,7 +109,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
|
|||
case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,peer);
|
||||
case Packet::VERB_ECHO: return _doECHO(RR,peer);
|
||||
case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,peer);
|
||||
case Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return _doNETWORK_MEMBERSHIP_CERTIFICATE(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_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer);
|
||||
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer);
|
||||
|
@ -155,22 +158,10 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||
break;
|
||||
|
||||
case Packet::ERROR_IDENTITY_COLLISION:
|
||||
if (RR->topology->isRoot(peer->identity()))
|
||||
if (RR->topology->isUpstream(peer->identity()))
|
||||
RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
|
||||
break;
|
||||
|
||||
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
|
||||
/* Note: certificates are public so it's safe to push them to anyone
|
||||
* who asks. */
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
if ((network)&&(network->hasConfig())&&(network->config().com)) {
|
||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
|
||||
network->config().com.serialize(outp);
|
||||
outp.armor(peer->key(),true);
|
||||
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
|
||||
}
|
||||
} break;
|
||||
|
||||
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
|
||||
SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
|
||||
if ((network)&&(network->controller() == peer->address()))
|
||||
|
@ -218,9 +209,13 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
|
|||
uint64_t worldTimestamp = 0;
|
||||
{
|
||||
unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY);
|
||||
if (ptr < size()) // ZeroTier One < 1.0.3 did not include physical destination address info
|
||||
|
||||
// Get external surface address if present (was not in old versions)
|
||||
if (ptr < size())
|
||||
ptr += externalSurfaceAddress.deserialize(*this,ptr);
|
||||
if ((ptr + 16) <= size()) { // older versions also did not include World IDs or timestamps
|
||||
|
||||
// Get world ID and world timestamp if present (was not in old versions)
|
||||
if ((ptr + 16) <= size()) {
|
||||
worldId = at<uint64_t>(ptr); ptr += 8;
|
||||
worldTimestamp = at<uint64_t>(ptr);
|
||||
}
|
||||
|
@ -295,7 +290,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
|
|||
}
|
||||
|
||||
if (externalSurfaceAddress)
|
||||
RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isRoot(id),RR->node->now());
|
||||
RR->sa->iam(id.address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now());
|
||||
|
||||
Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
|
||||
outp.append((unsigned char)Packet::VERB_HELLO);
|
||||
|
@ -379,13 +374,15 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||
return true;
|
||||
}
|
||||
|
||||
const bool trusted = RR->topology->isRoot(peer->identity());
|
||||
|
||||
InetAddress externalSurfaceAddress;
|
||||
unsigned int ptr = ZT_PROTO_VERB_HELLO__OK__IDX_REVISION + 2;
|
||||
if (ptr < size()) // ZeroTier One < 1.0.3 did not include this field
|
||||
|
||||
// Get reported external surface address if present (was not on old versions)
|
||||
if (ptr < size())
|
||||
ptr += externalSurfaceAddress.deserialize(*this,ptr);
|
||||
if ((trusted)&&((ptr + 2) <= size())) { // older versions also did not include this field, and right now we only use if from a root
|
||||
|
||||
// Handle world updates from root servers if present (was not on old versions)
|
||||
if (((ptr + 2) <= size())&&(RR->topology->isRoot(peer->identity()))) {
|
||||
World worldUpdate;
|
||||
const unsigned int worldLen = at<uint16_t>(ptr); ptr += 2;
|
||||
if (worldLen > 0) {
|
||||
|
@ -401,17 +398,13 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
|
||||
|
||||
if (externalSurfaceAddress)
|
||||
RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,trusted,RR->node->now());
|
||||
RR->sa->iam(peer->address(),_localAddress,_remoteAddress,externalSurfaceAddress,RR->topology->isUpstream(peer->identity()),RR->node->now());
|
||||
} break;
|
||||
|
||||
case Packet::VERB_WHOIS: {
|
||||
if (RR->topology->isRoot(peer->identity())) {
|
||||
if (RR->topology->isUpstream(peer->identity())) {
|
||||
const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
|
||||
// Right now we can skip this since OK(WHOIS) is only accepted from
|
||||
// roots. In the future it should be done if we query less trusted
|
||||
// sources.
|
||||
//if (id.locallyValidate())
|
||||
RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr<Peer>(new Peer(RR,RR->identity,id))));
|
||||
RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr<Peer>(new Peer(RR,RR->identity,id))));
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -544,7 +537,6 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||
if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
|
||||
if (!network->isAllowed(peer)) {
|
||||
TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id());
|
||||
_sendErrorNeedCertificate(RR,peer,network->id());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -599,7 +591,6 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
|
|||
|
||||
if (!network->isAllowed(peer)) {
|
||||
TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
|
||||
_sendErrorNeedCertificate(RR,peer,network->id());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -704,20 +695,34 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
CertificateOfMembership com;
|
||||
Capability cap;
|
||||
Tag tag;
|
||||
|
||||
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
|
||||
while (ptr < size()) {
|
||||
ptr += com.deserialize(*this,ptr);
|
||||
unsigned int p = ZT_PACKET_IDX_PAYLOAD;
|
||||
while ((p < size())&&((*this)[p])) {
|
||||
p += com.deserialize(*this,p);
|
||||
peer->validateAndSetNetworkMembershipCertificate(com.networkId(),com);
|
||||
}
|
||||
++p; // skip trailing 0 after COMs if present
|
||||
|
||||
peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP);
|
||||
if (p < size()) { // check if new capabilities and tags fields are present
|
||||
const unsigned int numCapabilities = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numCapabilities;++i) {
|
||||
p += cap.deserialize(*this,p);
|
||||
}
|
||||
const unsigned int numTags = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numTags;++i) {
|
||||
p += tag.deserialize(*this,p);
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP);
|
||||
} catch ( ... ) {
|
||||
TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
|
||||
TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -859,7 +864,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
|
|||
// that cert might be what we needed.
|
||||
if (!network->isAllowed(peer)) {
|
||||
TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id());
|
||||
_sendErrorNeedCertificate(RR,peer,network->id());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1069,22 +1073,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
|
|||
// into the one we send along to next hops.
|
||||
const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf;
|
||||
|
||||
// Get previous hop's credential, if any
|
||||
const unsigned int previousHopCredentialLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
|
||||
CertificateOfMembership previousHopCom;
|
||||
if (previousHopCredentialLength >= 1) {
|
||||
switch((*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]) {
|
||||
case 0x01: { // network certificate of membership for previous hop
|
||||
const unsigned int phcl = previousHopCom.deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 32 + vlf);
|
||||
if (phcl != (previousHopCredentialLength - 1)) {
|
||||
TRACE("dropped CIRCUIT_TEST from %s(%s): previous hop COM invalid (%u != %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),phcl,(previousHopCredentialLength - 1));
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
vlf += previousHopCredentialLength;
|
||||
// Add length of second "additional fields" section.
|
||||
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
|
||||
|
||||
// Check credentials (signature already verified)
|
||||
NetworkConfig originatorCredentialNetworkConfig;
|
||||
|
@ -1166,13 +1156,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
|
|||
if (breadth > 0) {
|
||||
Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
|
||||
outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature);
|
||||
const unsigned int previousHopCredentialPos = outp.size();
|
||||
outp.append((uint16_t)0); // no previous hop credentials: default
|
||||
if ((originatorCredentialNetworkConfig)&&(!originatorCredentialNetworkConfig.isPublic())&&(originatorCredentialNetworkConfig.com)) {
|
||||
outp.append((uint8_t)0x01); // COM
|
||||
originatorCredentialNetworkConfig.com.serialize(outp);
|
||||
outp.setAt<uint16_t>(previousHopCredentialPos,(uint16_t)(outp.size() - (previousHopCredentialPos + 2)));
|
||||
}
|
||||
outp.append((uint16_t)0); // no additional fields
|
||||
if (remainingHopsPtr < size())
|
||||
outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
|
||||
|
||||
|
@ -1241,7 +1225,7 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const
|
|||
try {
|
||||
// If this were allowed from anyone, it would itself be a DOS vector. Right
|
||||
// now we only allow it from roots and controllers of networks you have joined.
|
||||
bool allowed = RR->topology->isRoot(peer->identity());
|
||||
bool allowed = RR->topology->isUpstream(peer->identity());
|
||||
if (!allowed) {
|
||||
std::vector< SharedPtr<Network> > allNetworks(RR->node->allNetworks());
|
||||
for(std::vector< SharedPtr<Network> >::const_iterator n(allNetworks.begin());n!=allNetworks.end();++n) {
|
||||
|
@ -1300,16 +1284,6 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doREQUEST_OBJECT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doOBJECT_UPDATED(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void IncomingPacket::computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16])
|
||||
{
|
||||
unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function
|
||||
|
@ -1388,15 +1362,4 @@ bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficult
|
|||
return true;
|
||||
}
|
||||
|
||||
void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid)
|
||||
{
|
||||
Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
|
||||
outp.append((unsigned char)verb());
|
||||
outp.append(packetId());
|
||||
outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
|
||||
outp.append(nwid);
|
||||
outp.armor(peer->key(),true);
|
||||
RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue