mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-01-31 16:35:26 +00:00
Bunch of work on pushing and replication of tags and capabilities, and protocol cleanup.
This commit is contained in:
parent
67cb03742e
commit
7e6e56e2bc
@ -96,11 +96,6 @@ extern "C" {
|
||||
*/
|
||||
#define ZT_MAX_NETWORK_SPECIALISTS 256
|
||||
|
||||
/**
|
||||
* Maximum number of static physical to ZeroTier address mappings (typically relays, etc.)
|
||||
*/
|
||||
#define ZT_MAX_NETWORK_PINNED 16
|
||||
|
||||
/**
|
||||
* Maximum number of multicast group subscriptions per network
|
||||
*/
|
||||
@ -111,6 +106,16 @@ extern "C" {
|
||||
*/
|
||||
#define ZT_MAX_NETWORK_RULES 256
|
||||
|
||||
/**
|
||||
* Maximum number of per-node capabilities per network
|
||||
*/
|
||||
#define ZT_MAX_NETWORK_CAPABILITIES 64
|
||||
|
||||
/**
|
||||
* Maximum number of per-node tags per network
|
||||
*/
|
||||
#define ZT_MAX_NETWORK_TAGS 16
|
||||
|
||||
/**
|
||||
* Maximum number of direct network paths to a given peer
|
||||
*/
|
||||
@ -126,11 +131,6 @@ extern "C" {
|
||||
*/
|
||||
#define ZT_MAX_CAPABILITY_RULES 64
|
||||
|
||||
/**
|
||||
* Maximum length of a capbility's short descriptive name
|
||||
*/
|
||||
#define ZT_MAX_CAPABILITY_NAME_LENGTH 63
|
||||
|
||||
/**
|
||||
* Global maximum length for capability chain of custody (including initial issue)
|
||||
*/
|
||||
|
@ -109,6 +109,11 @@ public:
|
||||
*/
|
||||
inline uint64_t networkId() const { return _nwid; }
|
||||
|
||||
/**
|
||||
* @return Expiration time relative to network config timestamp
|
||||
*/
|
||||
inline uint64_t expiration() const { return _expiration; }
|
||||
|
||||
/**
|
||||
* Sign this capability and add signature to its chain of custody
|
||||
*
|
||||
|
@ -19,15 +19,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "MAC.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Filter.hpp"
|
||||
#include "Packet.hpp"
|
||||
#include "Switch.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
|
||||
// Returns true if packet appears valid; pos and proto will be set
|
||||
static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
|
||||
@ -61,8 +54,8 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig
|
||||
namespace ZeroTier {
|
||||
|
||||
bool Filter::run(
|
||||
const RuntimeEnvironment *RR,
|
||||
const uint64_t nwid,
|
||||
const bool receiving,
|
||||
const Address &ztSource,
|
||||
const Address &ztDest,
|
||||
const MAC &macSource,
|
||||
@ -72,8 +65,13 @@ bool Filter::run(
|
||||
const unsigned int etherType,
|
||||
const unsigned int vlanId,
|
||||
const ZT_VirtualNetworkRule *rules,
|
||||
const unsigned int ruleCount)
|
||||
const unsigned int ruleCount,
|
||||
const Tag *tags,
|
||||
const unsigned int tagCount,
|
||||
Address &sendCopyOfPacketTo)
|
||||
{
|
||||
sendCopyOfPacketTo.zero();
|
||||
|
||||
// For each set of rules we start by assuming that they match (since no constraints
|
||||
// yields a 'match all' rule).
|
||||
uint8_t thisSetMatches = 1;
|
||||
@ -92,6 +90,8 @@ bool Filter::run(
|
||||
// This set did match, so perform action!
|
||||
if (rt != ZT_NETWORK_RULE_ACTION_DROP) {
|
||||
if ((rt == ZT_NETWORK_RULE_ACTION_TEE)||(rt == ZT_NETWORK_RULE_ACTION_REDIRECT)) {
|
||||
sendCopyOfPacketTo = rules[rn].v.zt;
|
||||
/*
|
||||
// Tee and redirect both want this frame copied to somewhere else.
|
||||
Packet outp(Address(rules[rn].v.zt),RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
outp.append(nwid);
|
||||
@ -102,6 +102,7 @@ bool Filter::run(
|
||||
outp.append(frameData,frameLen);
|
||||
outp.compress();
|
||||
RR->sw->send(outp,true,nwid);
|
||||
*/
|
||||
}
|
||||
// For REDIRECT we will want to DROP at this node. For TEE we ACCEPT at this node but
|
||||
// also forward it along as we just did.
|
||||
@ -244,9 +245,20 @@ bool Filter::run(
|
||||
thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1]));
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE:
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL:
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY:
|
||||
for(unsigned int i=0;i<tagCount;++i) { // sequential scan is probably fastest since this is going to be <64 entries (usually only one or two)
|
||||
if (tags[i].id() == rules[rn].v.tag.id) {
|
||||
if (rt == ZT_NETWORK_RULE_MATCH_TAG_VALUE_RANGE) {
|
||||
thisRuleMatches = (uint8_t)((tags[i].value() >= rules[rn].v.tag.value[0])&&(tags[i].value() <= rules[rn].v.tag.value[1]));
|
||||
} else if (rt == ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ALL) {
|
||||
thisRuleMatches = (uint8_t)((tags[i].value() & rules[rn].v.tag.value[0]) == rules[rn].v.tag.value[0]);
|
||||
} else if (rt == ZT_NETWORK_RULE_MATCH_TAG_VALUE_BITS_ANY) {
|
||||
thisRuleMatches = (uint8_t)((tags[i].value() & rules[rn].v.tag.value[0]) != 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -21,15 +21,16 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "Address.hpp"
|
||||
#include "MAC.hpp"
|
||||
#include "Tag.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Address;
|
||||
class RuntimeEnvironment;
|
||||
class MAC;
|
||||
|
||||
/**
|
||||
* Network packet filter for rules engine
|
||||
*/
|
||||
@ -42,8 +43,8 @@ public:
|
||||
* This returns whether or not the packet should be accepted and may also
|
||||
* take other actions for e.g. the TEE and REDIRECT targets.
|
||||
*
|
||||
* @param RR ZeroTier runtime environment (context)
|
||||
* @param nwid ZeroTier network ID
|
||||
* @param receiving True if on receiving side, false on sending side
|
||||
* @param ztSource Source ZeroTier address
|
||||
* @param ztDest Destination ZeroTier address
|
||||
* @param macSource Ethernet layer source address
|
||||
@ -54,10 +55,14 @@ public:
|
||||
* @param vlanId 16-bit VLAN ID
|
||||
* @param rules Pointer to array of rules
|
||||
* @param ruleCount Number of rules
|
||||
* @param tags Tags associated with this node on this network
|
||||
* @param tagCount Number of tags
|
||||
* @param sendCopyOfPacketTo Result parameter: if non-NULL send a copy of this packet to another node
|
||||
* @return True if packet should be accepted for send or receive
|
||||
*/
|
||||
static bool run(
|
||||
const RuntimeEnvironment *RR,
|
||||
const uint64_t nwid,
|
||||
const bool receiving,
|
||||
const Address &ztSource,
|
||||
const Address &ztDest,
|
||||
const MAC &macSource,
|
||||
@ -67,7 +72,10 @@ public:
|
||||
const unsigned int etherType,
|
||||
const unsigned int vlanId,
|
||||
const ZT_VirtualNetworkRule *rules,
|
||||
const unsigned int ruleCount);
|
||||
const unsigned int ruleCount,
|
||||
const Tag *tags,
|
||||
const unsigned int tagCount,
|
||||
Address &sendCopyOfPacketTo);
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -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
|
||||
|
@ -172,7 +172,7 @@ private:
|
||||
bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doNETWORK_MEMBERSHIP_CERTIFICATE(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 _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
@ -180,11 +180,6 @@ private:
|
||||
bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doREQUEST_OBJECT(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
bool _doOBJECT_UPDATED(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||
|
||||
// Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to communicate
|
||||
void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid);
|
||||
|
||||
uint64_t _receiveTime;
|
||||
InetAddress _localAddress;
|
||||
|
154
node/Membership.hpp
Normal file
154
node/Membership.hpp
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MEMBERSHIP_HPP
|
||||
#define ZT_MEMBERSHIP_HPP
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "NetworkConfig.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Peer;
|
||||
|
||||
/**
|
||||
* Information related to a peer's participation on a network
|
||||
*
|
||||
* This structure is not thread-safe and must be locked during use.
|
||||
*/
|
||||
class Membership
|
||||
{
|
||||
private:
|
||||
struct TState
|
||||
{
|
||||
TState() : lastPushed(0),lastReceived(0) {}
|
||||
// Last time we pushed this tag to this peer
|
||||
uint64_t lastPushed;
|
||||
// Last time we received this tag from this peer
|
||||
uint64_t lastReceived;
|
||||
// Tag from peer
|
||||
Tag tag;
|
||||
};
|
||||
|
||||
struct CState
|
||||
{
|
||||
CState() : lastPushed(0),lastReceived(0) {}
|
||||
// Last time we pushed this capability to this peer
|
||||
uint64_t lastPushed;
|
||||
// Last time we received this capability from this peer
|
||||
uint64_t lastReceived;
|
||||
// Capability from peer
|
||||
Capability cap;
|
||||
};
|
||||
|
||||
public:
|
||||
Membership() :
|
||||
_lastPushedCom(0),
|
||||
_com(),
|
||||
_caps(8),
|
||||
_tags(8)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Send COM and other credentials to this peer if needed
|
||||
*
|
||||
* This checks last pushed times for our COM and for other credentials and
|
||||
* sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
|
||||
*
|
||||
* @param peer Peer that "owns" this membership
|
||||
* @param nconf Network configuration
|
||||
* @param now Current time
|
||||
* @param capIds Capability IDs that this peer might need
|
||||
* @param capCount Number of capability IDs
|
||||
* @param tagIds Tag IDs that this peer might need
|
||||
* @param tagCount Number of tag IDs
|
||||
*/
|
||||
void sendCredentialsIfNeeded(const Peer &peer,const NetworkConfig &nconf,const uint64_t now,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) const;
|
||||
|
||||
/**
|
||||
* @param nconf Network configuration
|
||||
* @param id Tag ID
|
||||
* @return Pointer to tag or NULL if not found
|
||||
*/
|
||||
inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
|
||||
{
|
||||
const TState *t = _tags.get(id);
|
||||
return ((t) ? (((t->lastReceived != 0)&&(t->tag.expiration() < nconf.timestamp)) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nconf Network configuration
|
||||
* @param id Capablity ID
|
||||
* @return Pointer to capability or NULL if not found
|
||||
*/
|
||||
inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
|
||||
{
|
||||
const CState *c = _caps.get(id);
|
||||
return ((c) ? (((c->lastReceived != 0)&&(c->cap.expiration() < nconf.timestamp)) ? &(c->cap) : (const Capability *)0) : (const Capability *)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old or stale entries
|
||||
*/
|
||||
inline void clean(const uint64_t now)
|
||||
{
|
||||
uint32_t *i = (uint32_t *)0;
|
||||
CState *cs = (CState *)0;
|
||||
Hashtable<uint32_t,CState>::Iterator csi(_caps);
|
||||
while (csi.next(i,cs)) {
|
||||
if ((now - std::max(cs->lastPushed,cs->lastReceived)) > (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 3))
|
||||
_caps.erase(*i);
|
||||
}
|
||||
|
||||
i = (uint32_t *)0;
|
||||
TState *ts = (TState *)0;
|
||||
Hashtable<uint32_t,TState>::Iterator tsi(_tags);
|
||||
while (tsi.next(i,ts)) {
|
||||
if ((now - std::max(ts->lastPushed,ts->lastReceived)) > (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 3))
|
||||
_tags.erase(*i);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Last time we pushed our COM to this peer
|
||||
uint64_t _lastPushedCom;
|
||||
|
||||
// COM from this peer
|
||||
CertificateOfMembership _com;
|
||||
|
||||
// Capability-related state
|
||||
Hashtable<uint32_t,CState> _caps;
|
||||
|
||||
// Tag-related state
|
||||
Hashtable<uint32_t,TState> _tags;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -216,6 +216,8 @@ void Network::requestConfiguration()
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MAJOR);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_ONE_VERSION_MINOR);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_ONE_VERSION_REVISION);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES);
|
||||
|
||||
if (controller() == RR->identity.address()) {
|
||||
if (RR->localNetworkController) {
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
#include "Dictionary.hpp"
|
||||
|
||||
/**
|
||||
@ -76,6 +78,8 @@ namespace ZeroTier {
|
||||
#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION "majv"
|
||||
#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION "minv"
|
||||
#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION "revv"
|
||||
#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES "Mr"
|
||||
#define ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES "Mcr"
|
||||
|
||||
// These dictionary keys are short so they don't take up much room.
|
||||
|
||||
@ -288,6 +292,32 @@ public:
|
||||
inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
|
||||
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
|
||||
|
||||
/**
|
||||
* Add a specialist or mask flags if already present
|
||||
*
|
||||
* This masks the existing flags if the specialist is already here or adds
|
||||
* it otherwise.
|
||||
*
|
||||
* @param a Address of specialist
|
||||
* @param f Flags (OR of specialist role/type flags)
|
||||
* @return True if successfully masked or added
|
||||
*/
|
||||
inline bool addSpecialist(const Address &a,const uint64_t f)
|
||||
{
|
||||
const uint64_t aint = a.toInt();
|
||||
for(unsigned int i=0;i<specialistCount;++i) {
|
||||
if ((specialists[i] & 0xffffffffffULL) == aint) {
|
||||
specialists[i] |= f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
|
||||
specialists[specialistCount++] = f | aint;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
inline void dump() const
|
||||
{
|
||||
@ -316,32 +346,6 @@ public:
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a specialist or mask flags if already present
|
||||
*
|
||||
* This masks the existing flags if the specialist is already here or adds
|
||||
* it otherwise.
|
||||
*
|
||||
* @param a Address of specialist
|
||||
* @param f Flags (OR of specialist role/type flags)
|
||||
* @return True if successfully masked or added
|
||||
*/
|
||||
inline bool addSpecialist(const Address &a,const uint64_t f)
|
||||
{
|
||||
const uint64_t aint = a.toInt();
|
||||
for(unsigned int i=0;i<specialistCount;++i) {
|
||||
if ((specialists[i] & 0xffffffffffULL) == aint) {
|
||||
specialists[i] |= f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
|
||||
specialists[specialistCount++] = f | aint;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Network ID that this configuration applies to
|
||||
*/
|
||||
@ -397,6 +401,16 @@ public:
|
||||
*/
|
||||
unsigned int ruleCount;
|
||||
|
||||
/**
|
||||
* Number of capabilities
|
||||
*/
|
||||
unsigned int capabilityCount;
|
||||
|
||||
/**
|
||||
* Number of tags
|
||||
*/
|
||||
unsigned int tagCount;
|
||||
|
||||
/**
|
||||
* Specialist devices
|
||||
*
|
||||
@ -416,10 +430,20 @@ public:
|
||||
InetAddress staticIps[ZT_MAX_ZT_ASSIGNED_ADDRESSES];
|
||||
|
||||
/**
|
||||
* Rules table
|
||||
* Base network rules
|
||||
*/
|
||||
ZT_VirtualNetworkRule rules[ZT_MAX_NETWORK_RULES];
|
||||
|
||||
/**
|
||||
* Capabilities for this node on this network
|
||||
*/
|
||||
Capability capabilities[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
|
||||
/**
|
||||
* Tags for this node on this network
|
||||
*/
|
||||
Tag tags[ZT_MAX_NETWORK_TAGS];
|
||||
|
||||
/**
|
||||
* Network type (currently just public or private)
|
||||
*/
|
||||
|
@ -38,7 +38,7 @@ const char *Packet::verbString(Verb v)
|
||||
case VERB_EXT_FRAME: return "EXT_FRAME";
|
||||
case VERB_ECHO: return "ECHO";
|
||||
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
|
||||
case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";
|
||||
case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS";
|
||||
case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
|
||||
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
|
||||
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
|
||||
@ -46,8 +46,6 @@ const char *Packet::verbString(Verb v)
|
||||
case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST";
|
||||
case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT";
|
||||
case VERB_REQUEST_PROOF_OF_WORK: return "REQUEST_PROOF_OF_WORK";
|
||||
case VERB_REQUEST_OBJECT: return "REQUEST_OBJECT";
|
||||
case VERB_OBJECT_UPDATED: return "OBJECT_UPDATED";
|
||||
}
|
||||
return "(unknown)";
|
||||
}
|
||||
|
215
node/Packet.hpp
215
node/Packet.hpp
@ -51,19 +51,23 @@
|
||||
* + Yet another multicast redesign
|
||||
* + New crypto completely changes key agreement cipher
|
||||
* 4 - 0.6.0 ... 1.0.6
|
||||
* + New identity format based on hashcash design
|
||||
* + BREAKING CHANGE: New identity format based on hashcash design
|
||||
* 5 - 1.1.0 ... 1.1.5
|
||||
* + Supports circuit test, proof of work, and echo
|
||||
* + Supports in-band world (root server definition) updates
|
||||
* + Clustering! (Though this will work with protocol v4 clients.)
|
||||
* + Otherwise backward compatible with protocol v4
|
||||
* 6 - 1.1.5 ... 1.1.10
|
||||
* + Deprecate old dictionary-based network config format
|
||||
* + Introduce new binary serialized network config and meta-data
|
||||
* 7 - 1.1.10 -- CURRENT
|
||||
* + Network configuration format revisions including binary values
|
||||
* 7 - 1.1.10 -- 1.2.0
|
||||
* + Introduce trusted paths for local SDN use
|
||||
* 8 - 1.2.0 -- CURRENT
|
||||
* + Multipart network configurations for large network configs
|
||||
* + Tags and Capabilities
|
||||
* + Inline push of CertificateOfMembership deprecated
|
||||
* + Certificates of representation for federation and mesh
|
||||
*/
|
||||
#define ZT_PROTO_VERSION 7
|
||||
#define ZT_PROTO_VERSION 8
|
||||
|
||||
/**
|
||||
* Minimum supported protocol version
|
||||
@ -523,7 +527,7 @@ public:
|
||||
/**
|
||||
* No operation (ignored, no reply)
|
||||
*/
|
||||
VERB_NOP = 0,
|
||||
VERB_NOP = 0x00,
|
||||
|
||||
/**
|
||||
* Announcement of a node's existence:
|
||||
@ -566,7 +570,7 @@ public:
|
||||
*
|
||||
* ERROR has no payload.
|
||||
*/
|
||||
VERB_HELLO = 1,
|
||||
VERB_HELLO = 0x01,
|
||||
|
||||
/**
|
||||
* Error response:
|
||||
@ -575,7 +579,7 @@ public:
|
||||
* <[1] error code>
|
||||
* <[...] error-dependent payload>
|
||||
*/
|
||||
VERB_ERROR = 2,
|
||||
VERB_ERROR = 0x02,
|
||||
|
||||
/**
|
||||
* Success response:
|
||||
@ -583,7 +587,7 @@ public:
|
||||
* <[8] in-re packet ID>
|
||||
* <[...] request-specific payload>
|
||||
*/
|
||||
VERB_OK = 3,
|
||||
VERB_OK = 0x03,
|
||||
|
||||
/**
|
||||
* Query an identity by address:
|
||||
@ -598,7 +602,7 @@ public:
|
||||
* If the address is not found, no response is generated. WHOIS requests
|
||||
* will time out much like ARP requests and similar do in L2.
|
||||
*/
|
||||
VERB_WHOIS = 4,
|
||||
VERB_WHOIS = 0x04,
|
||||
|
||||
/**
|
||||
* Meet another node at a given protocol address:
|
||||
@ -626,7 +630,7 @@ public:
|
||||
*
|
||||
* No OK or ERROR is generated.
|
||||
*/
|
||||
VERB_RENDEZVOUS = 5,
|
||||
VERB_RENDEZVOUS = 0x05,
|
||||
|
||||
/**
|
||||
* ZT-to-ZT unicast ethernet frame (shortened EXT_FRAME):
|
||||
@ -642,31 +646,29 @@ public:
|
||||
* ERROR may be generated if a membership certificate is needed for a
|
||||
* closed network. Payload will be network ID.
|
||||
*/
|
||||
VERB_FRAME = 6,
|
||||
VERB_FRAME = 0x06,
|
||||
|
||||
/**
|
||||
* Full Ethernet frame with MAC addressing and optional fields:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[1] flags>
|
||||
* [<[...] certificate of network membership>]
|
||||
* [<[...] certificate of network membership (DEPRECATED)>]
|
||||
* <[6] destination MAC or all zero for destination node>
|
||||
* <[6] source MAC or all zero for node of origin>
|
||||
* <[2] 16-bit ethertype>
|
||||
* <[...] ethernet payload>
|
||||
*
|
||||
* Flags:
|
||||
* 0x01 - Certificate of network membership is attached
|
||||
* 0x01 - Certificate of network membership attached (DEPRECATED)
|
||||
*
|
||||
* An extended frame carries full MAC addressing, making them a
|
||||
* superset of VERB_FRAME. They're used for bridging or when we
|
||||
* want to attach a certificate since FRAME does not support that.
|
||||
*
|
||||
* Multicast frames may not be sent as EXT_FRAME.
|
||||
*
|
||||
* ERROR may be generated if a membership certificate is needed for a
|
||||
* closed network. Payload will be network ID.
|
||||
*/
|
||||
VERB_EXT_FRAME = 7,
|
||||
VERB_EXT_FRAME = 0x07,
|
||||
|
||||
/**
|
||||
* ECHO request (a.k.a. ping):
|
||||
@ -676,7 +678,7 @@ public:
|
||||
* is generated. Response to ECHO requests is optional and ECHO may be
|
||||
* ignored if a node detects a possible flood.
|
||||
*/
|
||||
VERB_ECHO = 8,
|
||||
VERB_ECHO = 0x08,
|
||||
|
||||
/**
|
||||
* Announce interest in multicast group(s):
|
||||
@ -690,45 +692,76 @@ public:
|
||||
* controllers and root servers. In the current network, root servers
|
||||
* will provide the service of final multicast cache.
|
||||
*
|
||||
* If sending LIKEs to root servers for backward compatibility reasons,
|
||||
* VERB_NETWORK_MEMBERSHIP_CERTIFICATE must be sent as well ahead of
|
||||
* time so that roots can authenticate GATHER requests.
|
||||
* VERB_NETWORK_CREDENTIALS should be pushed along with this, especially
|
||||
* if using upstream (e.g. root) nodes as multicast databases. This allows
|
||||
* GATHERs to be authenticated.
|
||||
*
|
||||
* OK/ERROR are not generated.
|
||||
*/
|
||||
VERB_MULTICAST_LIKE = 9,
|
||||
VERB_MULTICAST_LIKE = 0x09,
|
||||
|
||||
/**
|
||||
* Network member certificate replication/push:
|
||||
* Network membership credential push:
|
||||
* <[...] serialized certificate of membership>
|
||||
* [ ... additional certificates may follow ...]
|
||||
* [<[...] additional certificates of membership>]
|
||||
* <[1] null byte for backward compatibility (see below)>
|
||||
* <[2] 16-bit number of capabilities>
|
||||
* <[...] one or more serialized Capability>
|
||||
* <[2] 16-bit number of tags>
|
||||
* <[...] one or more serialized Tags>
|
||||
*
|
||||
* This is sent in response to ERROR_NEED_MEMBERSHIP_CERTIFICATE and may
|
||||
* be pushed at any other time to keep exchanged certificates up to date.
|
||||
*
|
||||
* Protocol versions prior to 8 do not support capabilities or tags and
|
||||
* just expect an array of COMs. Adding a single NULL byte after the COM
|
||||
* array causes these older versions to harmlessly abort parsing and
|
||||
* ignore the newer fields. The new version checks for this null byte to
|
||||
* indicate the end of the COM array, since all serialized COMs begin with
|
||||
* non-zero bytes (see CertificateOfMembership).
|
||||
*
|
||||
* OK/ERROR are not generated.
|
||||
*/
|
||||
VERB_NETWORK_MEMBERSHIP_CERTIFICATE = 10,
|
||||
VERB_NETWORK_CREDENTIALS = 0x0a,
|
||||
|
||||
/**
|
||||
* DEPRECATED but still supported, interpreted as an object request:
|
||||
* Network configuration request:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[2] 16-bit length of request meta-data dictionary>
|
||||
* <[...] string-serialized request meta-data>
|
||||
* [<[8] 64-bit timestamp of netconf we currently have>]
|
||||
*
|
||||
* /controller/network/<network ID>/member/<requester address>
|
||||
*
|
||||
* When received in this manner the response is sent via the old
|
||||
* OK(NETWORK_CONFIG_REQUEST) instead of OK(REQUEST_OBJECT). If the
|
||||
* response is too large, a dictionary is sent with the single key
|
||||
* OVF set to 1. In this case REQUEST_OBJECT must be used.
|
||||
* 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.
|
||||
*
|
||||
* OK response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[2] 16-bit length of network configuration dictionary>
|
||||
* <[...] network configuration dictionary>
|
||||
* <[2] 16-bit length of network configuration dictionary field>
|
||||
* <[...] network configuration dictionary (or fragment)>
|
||||
* [<[4] 32-bit total length of assembled dictionary>]
|
||||
* [<[4] 32-bit index of fragment in this reply>]
|
||||
*
|
||||
* Fields after the dictionary are extensions to support multipart
|
||||
* sending of large network configs. If they are not present the
|
||||
* sent config must be assumed to be whole.
|
||||
*
|
||||
* ERROR response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
*/
|
||||
VERB_NETWORK_CONFIG_REQUEST = 11,
|
||||
VERB_NETWORK_CONFIG_REQUEST = 0x0b,
|
||||
|
||||
/**
|
||||
* Network configuration refresh request:
|
||||
* <[...] array of 64-bit network IDs>
|
||||
*
|
||||
* This can be sent by the network controller to inform a node that it
|
||||
* should now make a NETWORK_CONFIG_REQUEST.
|
||||
*
|
||||
* It does not generate an OK or ERROR message, and is treated only as
|
||||
* a hint to refresh now.
|
||||
*/
|
||||
VERB_NETWORK_CONFIG_REFRESH = 0x0c,
|
||||
|
||||
/**
|
||||
* Request endpoints for multicast distribution:
|
||||
@ -737,10 +770,10 @@ public:
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
* <[4] 32-bit ADI for multicast group being queried>
|
||||
* <[4] 32-bit requested max number of multicast peers>
|
||||
* [<[...] network certificate of membership>]
|
||||
* [<[...] network certificate of membership (DEPRECATED)>]
|
||||
*
|
||||
* Flags:
|
||||
* 0x01 - Network certificate of membership is attached
|
||||
* 0x01 - COM is attached (DEPRECATED)
|
||||
*
|
||||
* This message asks a peer for additional known endpoints that have
|
||||
* LIKEd a given multicast group. It's sent when the sender wishes
|
||||
@ -750,6 +783,9 @@ public:
|
||||
* More than one OK response can occur if the response is broken up across
|
||||
* multiple packets or if querying a clustered node.
|
||||
*
|
||||
* Send VERB_NETWORK_CREDENTIALS prior to GATHERing if doing so from
|
||||
* upstream nodes like root servers that are not involved in our network.
|
||||
*
|
||||
* OK response payload:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[6] MAC address of multicast group being queried>
|
||||
@ -761,13 +797,13 @@ public:
|
||||
*
|
||||
* ERROR is not generated; queries that return no response are dropped.
|
||||
*/
|
||||
VERB_MULTICAST_GATHER = 13,
|
||||
VERB_MULTICAST_GATHER = 0x0d,
|
||||
|
||||
/**
|
||||
* Multicast frame:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[1] flags>
|
||||
* [<[...] network certificate of membership>]
|
||||
* [<[...] network certificate of membership (DEPRECATED)>]
|
||||
* [<[4] 32-bit implicit gather limit>]
|
||||
* [<[6] source MAC>]
|
||||
* <[6] destination MAC (multicast address)>
|
||||
@ -776,7 +812,7 @@ public:
|
||||
* <[...] ethernet payload>
|
||||
*
|
||||
* Flags:
|
||||
* 0x01 - Network certificate of membership is attached
|
||||
* 0x01 - Network certificate of membership attached (DEPRECATED)
|
||||
* 0x02 - Implicit gather limit field is present
|
||||
* 0x04 - Source MAC is specified -- otherwise it's computed from sender
|
||||
*
|
||||
@ -791,11 +827,11 @@ public:
|
||||
* <[6] MAC address of multicast group>
|
||||
* <[4] 32-bit ADI for multicast group>
|
||||
* <[1] flags>
|
||||
* [<[...] network certficate of membership>]
|
||||
* [<[...] network certficate of membership (DEPRECATED)>]
|
||||
* [<[...] implicit gather results if flag 0x01 is set>]
|
||||
*
|
||||
* OK flags (same bits as request flags):
|
||||
* 0x01 - OK includes certificate of network membership
|
||||
* 0x01 - OK includes certificate of network membership (DEPRECATED)
|
||||
* 0x02 - OK includes implicit gather results
|
||||
*
|
||||
* ERROR response payload:
|
||||
@ -803,7 +839,9 @@ public:
|
||||
* <[6] multicast group MAC>
|
||||
* <[4] 32-bit multicast group ADI>
|
||||
*/
|
||||
VERB_MULTICAST_FRAME = 14,
|
||||
VERB_MULTICAST_FRAME = 0x0e,
|
||||
|
||||
// 0x0f is reserved for an old deprecated message
|
||||
|
||||
/**
|
||||
* Push of potential endpoints for direct communication:
|
||||
@ -839,7 +877,7 @@ public:
|
||||
*
|
||||
* OK and ERROR are not generated.
|
||||
*/
|
||||
VERB_PUSH_DIRECT_PATHS = 16,
|
||||
VERB_PUSH_DIRECT_PATHS = 0x10,
|
||||
|
||||
/**
|
||||
* Source-routed circuit test message:
|
||||
@ -855,9 +893,8 @@ public:
|
||||
* [ ... end of signed portion of request ... ]
|
||||
* <[2] 16-bit length of signature of request>
|
||||
* <[...] signature of request by originator>
|
||||
* <[2] 16-bit previous hop credential length (including type)>
|
||||
* [[1] previous hop credential type]
|
||||
* [[...] previous hop credential]
|
||||
* <[2] 16-bit length of additional fields>
|
||||
* [[...] additional fields]
|
||||
* <[...] next hop(s) in path>
|
||||
*
|
||||
* Flags:
|
||||
@ -867,9 +904,6 @@ public:
|
||||
* Originator credential types:
|
||||
* 0x01 - 64-bit network ID for which originator is controller
|
||||
*
|
||||
* Previous hop credential types:
|
||||
* 0x01 - Certificate of network membership
|
||||
*
|
||||
* Path record format:
|
||||
* <[1] 8-bit flags (unused, must be zero)>
|
||||
* <[1] 8-bit breadth (number of next hops)>
|
||||
@ -918,7 +952,7 @@ public:
|
||||
* <[8] 64-bit timestamp (echoed from original>
|
||||
* <[8] 64-bit test ID (echoed from original)>
|
||||
*/
|
||||
VERB_CIRCUIT_TEST = 17,
|
||||
VERB_CIRCUIT_TEST = 0x11,
|
||||
|
||||
/**
|
||||
* Circuit test hop report:
|
||||
@ -955,7 +989,7 @@ public:
|
||||
* If a test report is received and no circuit test was sent, it should be
|
||||
* ignored. This message generates no OK or ERROR response.
|
||||
*/
|
||||
VERB_CIRCUIT_TEST_REPORT = 18,
|
||||
VERB_CIRCUIT_TEST_REPORT = 0x12,
|
||||
|
||||
/**
|
||||
* Request proof of work:
|
||||
@ -998,63 +1032,7 @@ public:
|
||||
*
|
||||
* ERROR has no payload.
|
||||
*/
|
||||
VERB_REQUEST_PROOF_OF_WORK = 19,
|
||||
|
||||
/**
|
||||
* Request an object or a chunk of an object with optional meta-data:
|
||||
* <[8] 64-bit chunk offset>
|
||||
* <[2] 16-bit chunk length or 0 for any / sender-preferred>
|
||||
* <[2] 16-bit object path length in bytes>
|
||||
* <[...] object path>
|
||||
* <[2] 16-bit length of request meta-data dictionary>
|
||||
* <[...] request meta-data dictionary>
|
||||
*
|
||||
* This is used to request an object. Objects can be things like network
|
||||
* configs, software updates, etc. This provides an in-band way to
|
||||
* distribute such things and obsoletes the network config specific
|
||||
* messages. (They are still supported for backward compatibility.)
|
||||
*
|
||||
* The use of path and request/response meta-data makes the semantics of
|
||||
* this analogous to HTTP POST, and it could therefore be mapped to
|
||||
* HTTP POST requests to permit plugins that leverage the ZT protocol
|
||||
* to do out-of-band things like special authentication, etc.
|
||||
*
|
||||
* Large objects can be transferred via repeated calls with higher and
|
||||
* higher chunk offsets and then SHA-512 verified on receipt, but this is
|
||||
* not efficient. It should not be used heavily as an alternative to
|
||||
* TCP. It's a bit more like X-Modem and other old-school SEND/ACK
|
||||
* protocols. It is potentially a good idea for software updates since
|
||||
* it means that ZT can update itself even on networks with no "vanilla"
|
||||
* Internet access.
|
||||
*
|
||||
* OK and ERROR responses are optional but recommended. ERROR responses
|
||||
* can include OBJECT_NOT_FOUND.
|
||||
*
|
||||
* OK response payload:
|
||||
* <[16] first 16 bytes of SHA-512 of complete object>
|
||||
* <[8] 64-bit total object size>
|
||||
* <[8] 64-bit chunk offset>
|
||||
* <[2] 16-bit length of chunk payload>
|
||||
* <[...] chunk payload>
|
||||
*/
|
||||
VERB_REQUEST_OBJECT = 20,
|
||||
|
||||
/**
|
||||
* Notification of a remote object update:
|
||||
* <[8] 64-bit total object size or 0 if unspecified here>
|
||||
* <[16] first 16 bytes of SHA-512 of object (if size specified)>
|
||||
* <[2] 16-bit length of object path>
|
||||
* <[...] object path>
|
||||
* <[2] 16-bit length of meta-data dictionary>
|
||||
* <[...] meta-data dictionary>
|
||||
*
|
||||
* This can be sent to notify another peer that an object has updated and
|
||||
* should be re-requested. The receiving peer is not required to do anything
|
||||
* or send anything in response to this. If the first size field is zero, the
|
||||
* SHA-512 hash is also unspecified and should be zero. This means that the
|
||||
* object was updated but must be re-requested.
|
||||
*/
|
||||
VERB_OBJECT_UPDATED = 21
|
||||
VERB_REQUEST_PROOF_OF_WORK = 0x13
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1063,31 +1041,28 @@ public:
|
||||
enum ErrorCode
|
||||
{
|
||||
/* No error, not actually used in transit */
|
||||
ERROR_NONE = 0,
|
||||
ERROR_NONE = 0x00,
|
||||
|
||||
/* Invalid request */
|
||||
ERROR_INVALID_REQUEST = 1,
|
||||
ERROR_INVALID_REQUEST = 0x01,
|
||||
|
||||
/* Bad/unsupported protocol version */
|
||||
ERROR_BAD_PROTOCOL_VERSION = 2,
|
||||
ERROR_BAD_PROTOCOL_VERSION = 0x02,
|
||||
|
||||
/* Unknown object queried */
|
||||
ERROR_OBJ_NOT_FOUND = 3,
|
||||
ERROR_OBJ_NOT_FOUND = 0x03,
|
||||
|
||||
/* HELLO pushed an identity whose address is already claimed */
|
||||
ERROR_IDENTITY_COLLISION = 4,
|
||||
ERROR_IDENTITY_COLLISION = 0x04,
|
||||
|
||||
/* Verb or use case not supported/enabled by this node */
|
||||
ERROR_UNSUPPORTED_OPERATION = 5,
|
||||
|
||||
/* Message to private network rejected -- no unexpired certificate on file */
|
||||
ERROR_NEED_MEMBERSHIP_CERTIFICATE = 6,
|
||||
ERROR_UNSUPPORTED_OPERATION = 0x05,
|
||||
|
||||
/* Tried to join network, but you're not a member */
|
||||
ERROR_NETWORK_ACCESS_DENIED_ = 7, /* extra _ to avoid Windows name conflict */
|
||||
ERROR_NETWORK_ACCESS_DENIED_ = 0x07, /* extra _ at end to avoid Windows name conflict */
|
||||
|
||||
/* Multicasts to this group are not wanted */
|
||||
ERROR_UNWANTED_MULTICAST = 8
|
||||
ERROR_UNWANTED_MULTICAST = 0x08
|
||||
};
|
||||
|
||||
//#ifdef ZT_TRACE
|
||||
|
169
node/Peer.hpp
169
node/Peer.hpp
@ -31,7 +31,6 @@
|
||||
#include "../include/ZeroTierOne.h"
|
||||
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Path.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Utils.hpp"
|
||||
@ -44,10 +43,6 @@
|
||||
#include "Mutex.hpp"
|
||||
#include "NonCopyable.hpp"
|
||||
|
||||
// Very rough computed estimate: (8 + 256 + 80 + (16 * 64) + (128 * 256) + (128 * 16))
|
||||
// 1048576 provides tons of headroom -- overflow would just cause peer not to be persisted
|
||||
#define ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE 1048576
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
@ -362,31 +357,6 @@ public:
|
||||
*/
|
||||
void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
|
||||
|
||||
/**
|
||||
* Check network COM agreement with this peer
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param com Another certificate of membership
|
||||
* @return True if supplied COM agrees with ours, false if not or if we don't have one
|
||||
*/
|
||||
bool networkMembershipCertificatesAgree(uint64_t nwid,const CertificateOfMembership &com) const;
|
||||
|
||||
/**
|
||||
* Check the validity of the COM and add/update if valid and new
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param com Externally supplied COM
|
||||
*/
|
||||
bool validateAndSetNetworkMembershipCertificate(uint64_t nwid,const CertificateOfMembership &com);
|
||||
|
||||
/**
|
||||
* @param nwid Network ID
|
||||
* @param now Current time
|
||||
* @param updateLastPushedTime If true, go ahead and update the last pushed time regardless of return value
|
||||
* @return Whether or not this peer needs another COM push from us
|
||||
*/
|
||||
bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime);
|
||||
|
||||
/**
|
||||
* Perform periodic cleaning operations
|
||||
*
|
||||
@ -434,138 +404,12 @@ public:
|
||||
else return std::pair<InetAddress,InetAddress>();
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b) const
|
||||
{
|
||||
Mutex::Lock _l(_networkComs_m);
|
||||
|
||||
const unsigned int recSizePos = b.size();
|
||||
b.addSize(4); // space for uint32_t field length
|
||||
|
||||
b.append((uint16_t)1); // version of serialized Peer data
|
||||
|
||||
_id.serialize(b,false);
|
||||
|
||||
b.append((uint64_t)_lastUsed);
|
||||
b.append((uint64_t)_lastReceive);
|
||||
b.append((uint64_t)_lastUnicastFrame);
|
||||
b.append((uint64_t)_lastMulticastFrame);
|
||||
b.append((uint64_t)_lastAnnouncedTo);
|
||||
b.append((uint64_t)_lastDirectPathPushSent);
|
||||
b.append((uint64_t)_lastDirectPathPushReceive);
|
||||
b.append((uint64_t)_lastPathSort);
|
||||
b.append((uint16_t)_vProto);
|
||||
b.append((uint16_t)_vMajor);
|
||||
b.append((uint16_t)_vMinor);
|
||||
b.append((uint16_t)_vRevision);
|
||||
b.append((uint32_t)_latency);
|
||||
b.append((uint16_t)_directPathPushCutoffCount);
|
||||
|
||||
b.append((uint16_t)_numPaths);
|
||||
for(unsigned int i=0;i<_numPaths;++i)
|
||||
_paths[i].serialize(b);
|
||||
|
||||
b.append((uint32_t)_networkComs.size());
|
||||
{
|
||||
uint64_t *k = (uint64_t *)0;
|
||||
_NetworkCom *v = (_NetworkCom *)0;
|
||||
Hashtable<uint64_t,_NetworkCom>::Iterator i(const_cast<Peer *>(this)->_networkComs);
|
||||
while (i.next(k,v)) {
|
||||
b.append((uint64_t)*k);
|
||||
b.append((uint64_t)v->ts);
|
||||
v->com.serialize(b);
|
||||
}
|
||||
}
|
||||
|
||||
b.append((uint32_t)_lastPushedComs.size());
|
||||
{
|
||||
uint64_t *k = (uint64_t *)0;
|
||||
uint64_t *v = (uint64_t *)0;
|
||||
Hashtable<uint64_t,uint64_t>::Iterator i(const_cast<Peer *>(this)->_lastPushedComs);
|
||||
while (i.next(k,v)) {
|
||||
b.append((uint64_t)*k);
|
||||
b.append((uint64_t)*v);
|
||||
}
|
||||
}
|
||||
|
||||
b.template setAt<uint32_t>(recSizePos,(uint32_t)(b.size() - (recSizePos + 4))); // set size
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Peer from a serialized instance
|
||||
*
|
||||
* @param renv Runtime environment
|
||||
* @param myIdentity This node's identity
|
||||
* @param b Buffer containing serialized Peer data
|
||||
* @param p Pointer to current position in buffer, will be updated in place as buffer is read (value/result)
|
||||
* @return New instance of Peer or NULL if serialized data was corrupt or otherwise invalid (may also throw an exception via Buffer)
|
||||
*/
|
||||
template<unsigned int C>
|
||||
static inline SharedPtr<Peer> deserializeNew(const RuntimeEnvironment *renv,const Identity &myIdentity,const Buffer<C> &b,unsigned int &p)
|
||||
{
|
||||
const unsigned int recSize = b.template at<uint32_t>(p); p += 4;
|
||||
if ((p + recSize) > b.size())
|
||||
return SharedPtr<Peer>(); // size invalid
|
||||
if (b.template at<uint16_t>(p) != 1)
|
||||
return SharedPtr<Peer>(); // version mismatch
|
||||
p += 2;
|
||||
|
||||
Identity npid;
|
||||
p += npid.deserialize(b,p);
|
||||
if (!npid)
|
||||
return SharedPtr<Peer>();
|
||||
|
||||
SharedPtr<Peer> np(new Peer(renv,myIdentity,npid));
|
||||
|
||||
np->_lastUsed = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastReceive = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastUnicastFrame = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastMulticastFrame = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastAnnouncedTo = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastDirectPathPushSent = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastDirectPathPushReceive = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastPathSort = b.template at<uint64_t>(p); p += 8;
|
||||
np->_vProto = b.template at<uint16_t>(p); p += 2;
|
||||
np->_vMajor = b.template at<uint16_t>(p); p += 2;
|
||||
np->_vMinor = b.template at<uint16_t>(p); p += 2;
|
||||
np->_vRevision = b.template at<uint16_t>(p); p += 2;
|
||||
np->_latency = b.template at<uint32_t>(p); p += 4;
|
||||
np->_directPathPushCutoffCount = b.template at<uint16_t>(p); p += 2;
|
||||
|
||||
const unsigned int numPaths = b.template at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numPaths;++i) {
|
||||
if (i < ZT_MAX_PEER_NETWORK_PATHS) {
|
||||
p += np->_paths[np->_numPaths++].deserialize(b,p);
|
||||
} else {
|
||||
// Skip any paths beyond max, but still read stream
|
||||
Path foo;
|
||||
p += foo.deserialize(b,p);
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int numNetworkComs = b.template at<uint32_t>(p); p += 4;
|
||||
for(unsigned int i=0;i<numNetworkComs;++i) {
|
||||
_NetworkCom &c = np->_networkComs[b.template at<uint64_t>(p)]; p += 8;
|
||||
c.ts = b.template at<uint64_t>(p); p += 8;
|
||||
p += c.com.deserialize(b,p);
|
||||
}
|
||||
|
||||
const unsigned int numLastPushed = b.template at<uint32_t>(p); p += 4;
|
||||
for(unsigned int i=0;i<numLastPushed;++i) {
|
||||
const uint64_t nwid = b.template at<uint64_t>(p); p += 8;
|
||||
const uint64_t ts = b.template at<uint64_t>(p); p += 8;
|
||||
np->_lastPushedComs.set(nwid,ts);
|
||||
}
|
||||
|
||||
return np;
|
||||
}
|
||||
|
||||
private:
|
||||
void _doDeadPathDetection(Path &p,const uint64_t now);
|
||||
Path *_getBestPath(const uint64_t now);
|
||||
Path *_getBestPath(const uint64_t now,int inetAddressFamily);
|
||||
|
||||
unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; // computed with key agreement, not serialized
|
||||
unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH];
|
||||
|
||||
const RuntimeEnvironment *RR;
|
||||
uint64_t _lastUsed;
|
||||
@ -586,17 +430,6 @@ private:
|
||||
unsigned int _latency;
|
||||
unsigned int _directPathPushCutoffCount;
|
||||
|
||||
struct _NetworkCom
|
||||
{
|
||||
_NetworkCom() {}
|
||||
_NetworkCom(uint64_t t,const CertificateOfMembership &c) : ts(t),com(c) {}
|
||||
uint64_t ts;
|
||||
CertificateOfMembership com;
|
||||
};
|
||||
Hashtable<uint64_t,_NetworkCom> _networkComs;
|
||||
Hashtable<uint64_t,uint64_t> _lastPushedComs;
|
||||
Mutex _networkComs_m;
|
||||
|
||||
AtomicCounter __refCount;
|
||||
};
|
||||
|
||||
|
@ -47,36 +47,7 @@ Topology::Topology(const RuntimeEnvironment *renv) :
|
||||
_trustedPathCount(0),
|
||||
_amRoot(false)
|
||||
{
|
||||
std::string alls(RR->node->dataStoreGet("peers.save"));
|
||||
const uint8_t *all = reinterpret_cast<const uint8_t *>(alls.data());
|
||||
RR->node->dataStoreDelete("peers.save");
|
||||
|
||||
Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> *deserializeBuf = new Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>();
|
||||
unsigned int ptr = 0;
|
||||
while ((ptr + 4) < alls.size()) {
|
||||
try {
|
||||
const unsigned int reclen = ( // each Peer serialized record is prefixed by a record length
|
||||
((((unsigned int)all[ptr]) & 0xff) << 24) |
|
||||
((((unsigned int)all[ptr + 1]) & 0xff) << 16) |
|
||||
((((unsigned int)all[ptr + 2]) & 0xff) << 8) |
|
||||
(((unsigned int)all[ptr + 3]) & 0xff)
|
||||
);
|
||||
unsigned int pos = 0;
|
||||
deserializeBuf->copyFrom(all + ptr,reclen + 4);
|
||||
SharedPtr<Peer> p(Peer::deserializeNew(RR,RR->identity,*deserializeBuf,pos));
|
||||
ptr += pos;
|
||||
if (!p)
|
||||
break; // stop if invalid records
|
||||
if (p->address() != RR->identity.address())
|
||||
_peers.set(p->address(),p);
|
||||
} catch ( ... ) {
|
||||
break; // stop if invalid records
|
||||
}
|
||||
}
|
||||
delete deserializeBuf;
|
||||
|
||||
clean(RR->node->now());
|
||||
|
||||
// Get cached world if present
|
||||
std::string dsWorld(RR->node->dataStoreGet("world"));
|
||||
World cachedWorld;
|
||||
if (dsWorld.length() > 0) {
|
||||
@ -87,6 +58,8 @@ Topology::Topology(const RuntimeEnvironment *renv) :
|
||||
cachedWorld = World(); // clear if cached world is invalid
|
||||
}
|
||||
}
|
||||
|
||||
// Use default or cached world depending on which is shinier
|
||||
World defaultWorld;
|
||||
{
|
||||
Buffer<ZT_DEFAULT_WORLD_LENGTH> wtmp(ZT_DEFAULT_WORLD,ZT_DEFAULT_WORLD_LENGTH);
|
||||
|
@ -705,6 +705,9 @@ public:
|
||||
}
|
||||
authToken = _trimString(authToken);
|
||||
|
||||
// Clean up any legacy files if present
|
||||
OSUtils::rm((_homePath + ZT_PATH_SEPARATOR_S + "peers.save").c_str());
|
||||
|
||||
_node = new Node(
|
||||
OSUtils::now(),
|
||||
this,
|
||||
|
Loading…
x
Reference in New Issue
Block a user