mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-18 20:47:53 +00:00
More work on tags and capabilities.
This commit is contained in:
parent
7e6e56e2bc
commit
f057bb63cd
52
node/Capability.cpp
Normal file
52
node/Capability.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "Capability.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
int Capability::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
try {
|
||||
Buffer<(sizeof(Capability) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
for(unsigned int c=0;c<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++c) {
|
||||
if (!_custody[c].to)
|
||||
return ((c == 0) ? -1 : 0);
|
||||
if (!_custody[c].from)
|
||||
return -1;
|
||||
const Identity id(RR->topology->getIdentity(_custody[c].from));
|
||||
if (id) {
|
||||
if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature))
|
||||
return -1;
|
||||
} else {
|
||||
RR->sw->requestWhois(_custody[c].from);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
@ -130,11 +130,11 @@ public:
|
||||
inline bool sign(const Identity &from,const Address &to)
|
||||
{
|
||||
try {
|
||||
Buffer<(sizeof(Capability) * 2)> tmp;
|
||||
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
|
||||
if (!(_custody[i].to)) {
|
||||
_custody[i].to = to;
|
||||
_custody[i].from = from.address();
|
||||
Buffer<(sizeof(Capability) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
_custody[i].signature = from.sign(tmp.data(),tmp.size());
|
||||
return true;
|
||||
@ -145,22 +145,12 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify this capability's chain of custody
|
||||
*
|
||||
* This returns a tri-state result. A return value of zero indicates that
|
||||
* the chain of custody is valid and all signatures are okay. A positive
|
||||
* return value means at least one WHOIS was issued for a missing signing
|
||||
* identity and we should retry later. A negative return value means that
|
||||
* this chain or one of its signature is BAD and this capability should
|
||||
* be discarded.
|
||||
*
|
||||
* Note that the entire chain is checked regardless of verifyInChain.
|
||||
* Verify this capability's chain of custody and signatures
|
||||
*
|
||||
* @param RR Runtime environment to provide for peer lookup, etc.
|
||||
* @param verifyInChain Also check to ensure that this capability was at some point properly issued to this peer (if non-null)
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or chain
|
||||
*/
|
||||
int verify(const RuntimeEnvironment *RR,const Address &verifyInChain) const;
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
template<unsigned int C>
|
||||
static inline void serializeRules(Buffer<C> &b,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
|
||||
@ -403,9 +393,31 @@ public:
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if a given address is a 'to' address in the custody chain
|
||||
*
|
||||
* This does not actually do certificate checking. That must be done with verify().
|
||||
*
|
||||
* @param a Address to check
|
||||
* @return True if address is present
|
||||
*/
|
||||
inline bool wasIssuedTo(const Address &a) const
|
||||
{
|
||||
for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
|
||||
if (!_custody[i].to)
|
||||
break;
|
||||
else if (_custody[i].to == a)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Provides natural sort order by ID
|
||||
inline bool operator<(const Capability &c) const { return (_id < c._id); }
|
||||
|
||||
inline bool operator==(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) == 0); }
|
||||
inline bool operator!=(const Capability &c) const { return (memcmp(this,&c,sizeof(Capability)) != 0); }
|
||||
|
||||
private:
|
||||
uint64_t _nwid;
|
||||
uint64_t _expiration;
|
||||
|
@ -17,6 +17,9 @@
|
||||
*/
|
||||
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
@ -182,7 +185,7 @@ bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) c
|
||||
|
||||
bool CertificateOfMembership::sign(const Identity &with)
|
||||
{
|
||||
uint64_t *const buf = new uint64_t[_qualifierCount * 3];
|
||||
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
|
||||
unsigned int ptr = 0;
|
||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||
buf[ptr++] = Utils::hton(_qualifiers[i].id);
|
||||
@ -193,38 +196,32 @@ bool CertificateOfMembership::sign(const Identity &with)
|
||||
try {
|
||||
_signature = with.sign(buf,ptr * sizeof(uint64_t));
|
||||
_signedBy = with.address();
|
||||
delete [] buf;
|
||||
return true;
|
||||
} catch ( ... ) {
|
||||
_signedBy.zero();
|
||||
delete [] buf;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CertificateOfMembership::verify(const Identity &id) const
|
||||
int CertificateOfMembership::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
if (!_signedBy)
|
||||
return false;
|
||||
if (id.address() != _signedBy)
|
||||
return false;
|
||||
if ((!_signedBy)||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS))
|
||||
return -1;
|
||||
|
||||
uint64_t *const buf = new uint64_t[_qualifierCount * 3];
|
||||
const Identity id(RR->topology->getIdentity(_signedBy));
|
||||
if (!id) {
|
||||
RR->sw->requestWhois(_signedBy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
|
||||
unsigned int ptr = 0;
|
||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||
buf[ptr++] = Utils::hton(_qualifiers[i].id);
|
||||
buf[ptr++] = Utils::hton(_qualifiers[i].value);
|
||||
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
|
||||
}
|
||||
|
||||
bool valid = false;
|
||||
try {
|
||||
valid = id.verify(buf,ptr * sizeof(uint64_t),_signature);
|
||||
delete [] buf;
|
||||
} catch ( ... ) {
|
||||
delete [] buf;
|
||||
}
|
||||
return valid;
|
||||
return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
@ -46,10 +46,12 @@
|
||||
/**
|
||||
* Maximum number of qualifiers allowed in a COM (absolute max: 65535)
|
||||
*/
|
||||
#define ZT_NETWORK_COM_MAX_QUALIFIERS 256
|
||||
#define ZT_NETWORK_COM_MAX_QUALIFIERS 8
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* Certificate of network membership
|
||||
*
|
||||
@ -275,12 +277,12 @@ public:
|
||||
bool sign(const Identity &with);
|
||||
|
||||
/**
|
||||
* Verify certificate against an identity
|
||||
* Verify this COM and its signature
|
||||
*
|
||||
* @param id Identity to verify against
|
||||
* @return True if certificate is signed by this identity and verification was successful
|
||||
* @param RR Runtime environment for looking up peers
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
|
||||
*/
|
||||
bool verify(const Identity &id) const;
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
/**
|
||||
* @return True if signed
|
||||
|
@ -443,11 +443,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
||||
|
||||
unsigned int offset = 0;
|
||||
|
||||
if ((flags & 0x01) != 0) {
|
||||
// OK(MULTICAST_FRAME) includes certificate of membership update
|
||||
if ((flags & 0x01) != 0) { // deprecated but still used by older peers
|
||||
CertificateOfMembership com;
|
||||
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS);
|
||||
peer->validateAndSetNetworkMembershipCertificate(nwid,com);
|
||||
LockingPtr<Membership> m = peer->membership(com.networkId(),true);
|
||||
if (m) m->addCredential(RR,RR->node->now(),com);
|
||||
}
|
||||
|
||||
if ((flags & 0x02) != 0) {
|
||||
@ -583,10 +583,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
|
||||
const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS];
|
||||
|
||||
unsigned int comLen = 0;
|
||||
if ((flags & 0x01) != 0) {
|
||||
if ((flags & 0x01) != 0) { // deprecated but still used by old peers
|
||||
CertificateOfMembership com;
|
||||
comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
|
||||
peer->validateAndSetNetworkMembershipCertificate(network->id(),com);
|
||||
LockingPtr<Membership> m = peer->membership(com.networkId(),true);
|
||||
if (m) m->addCredential(RR,RR->node->now(),com);
|
||||
}
|
||||
|
||||
if (!network->isAllowed(peer)) {
|
||||
@ -698,6 +699,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
|
||||
bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
const uint64_t now = RR->node->now();
|
||||
CertificateOfMembership com;
|
||||
Capability cap;
|
||||
Tag tag;
|
||||
@ -705,7 +707,9 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
||||
unsigned int p = ZT_PACKET_IDX_PAYLOAD;
|
||||
while ((p < size())&&((*this)[p])) {
|
||||
p += com.deserialize(*this,p);
|
||||
peer->validateAndSetNetworkMembershipCertificate(com.networkId(),com);
|
||||
LockingPtr<Membership> m = peer->membership(com.networkId(),true);
|
||||
if (!m) return true; // sanity check
|
||||
m->addCredential(RR,now,com);
|
||||
}
|
||||
++p; // skip trailing 0 after COMs if present
|
||||
|
||||
@ -713,10 +717,16 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
||||
const unsigned int numCapabilities = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numCapabilities;++i) {
|
||||
p += cap.deserialize(*this,p);
|
||||
LockingPtr<Membership> m = peer->membership(cap.networkId(),true);
|
||||
if (!m) return true; // sanity check
|
||||
m->addCredential(RR,now,cap);
|
||||
}
|
||||
const unsigned int numTags = at<uint16_t>(p); p += 2;
|
||||
for(unsigned int i=0;i<numTags;++i) {
|
||||
p += tag.deserialize(*this,p);
|
||||
LockingPtr<Membership> m = peer->membership(tag.networkId(),true);
|
||||
if (!m) return true; // sanity check
|
||||
m->addCredential(RR,now,tag);
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,10 +864,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
|
||||
// Offset -- size of optional fields added to position of later fields
|
||||
unsigned int offset = 0;
|
||||
|
||||
if ((flags & 0x01) != 0) {
|
||||
if ((flags & 0x01) != 0) { // deprecated but still used by older peers
|
||||
CertificateOfMembership com;
|
||||
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM);
|
||||
peer->validateAndSetNetworkMembershipCertificate(nwid,com);
|
||||
LockingPtr<Membership> m = peer->membership(com.networkId(),true);
|
||||
if (m) m->addCredential(RR,RR->node->now(),com);
|
||||
}
|
||||
|
||||
// Check membership after we've read any included COM, since
|
||||
|
99
node/LockingPtr.hpp
Normal file
99
node/LockingPtr.hpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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_LOCKINGPTR_HPP
|
||||
#define ZT_LOCKINGPTR_HPP
|
||||
|
||||
#include "Mutex.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A simple pointer that locks and holds a mutex until destroyed
|
||||
*
|
||||
* Care must be taken when using this. It's not very sophisticated and does
|
||||
* not handle being copied except for the simple return use case. When it is
|
||||
* copied it hands off the mutex to the copy and clears it in the original,
|
||||
* meaning that the mutex is unlocked when the last LockingPtr<> in a chain
|
||||
* of such handoffs is destroyed. If this chain of handoffs "forks" (more than
|
||||
* one copy is made) then non-determinism may ensue.
|
||||
*
|
||||
* This does not delete or do anything else with the pointer. It also does not
|
||||
* take care of locking the lock. That must be done beforehand.
|
||||
*/
|
||||
template<typename T>
|
||||
class LockingPtr
|
||||
{
|
||||
public:
|
||||
LockingPtr() :
|
||||
_ptr((T *)0),
|
||||
_lock((Mutex *)0)
|
||||
{
|
||||
}
|
||||
|
||||
LockingPtr(T *obj,Mutex *lock) :
|
||||
_ptr(obj),
|
||||
_lock(lock)
|
||||
{
|
||||
}
|
||||
|
||||
LockingPtr(const LockingPtr &p) :
|
||||
_ptr(p._ptr),
|
||||
_lock(p._lock)
|
||||
{
|
||||
const_cast<LockingPtr *>(&p)->_lock = (Mutex *)0;
|
||||
}
|
||||
|
||||
~LockingPtr()
|
||||
{
|
||||
if (_lock)
|
||||
_lock->unlock();
|
||||
}
|
||||
|
||||
inline LockingPtr &operator=(const LockingPtr &p)
|
||||
{
|
||||
_ptr = p._ptr;
|
||||
_lock = p._lock;
|
||||
const_cast<LockingPtr *>(&p)->_lock = (Mutex *)0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator bool() const throw() { return (_ptr != (T *)0); }
|
||||
inline T &operator*() const throw() { return *_ptr; }
|
||||
inline T *operator->() const throw() { return _ptr; }
|
||||
|
||||
/**
|
||||
* @return Raw pointer to held object
|
||||
*/
|
||||
inline T *ptr() const throw() { return _ptr; }
|
||||
|
||||
inline bool operator==(const LockingPtr &sp) const throw() { return (_ptr == sp._ptr); }
|
||||
inline bool operator!=(const LockingPtr &sp) const throw() { return (_ptr != sp._ptr); }
|
||||
inline bool operator>(const LockingPtr &sp) const throw() { return (_ptr > sp._ptr); }
|
||||
inline bool operator<(const LockingPtr &sp) const throw() { return (_ptr < sp._ptr); }
|
||||
inline bool operator>=(const LockingPtr &sp) const throw() { return (_ptr >= sp._ptr); }
|
||||
inline bool operator<=(const LockingPtr &sp) const throw() { return (_ptr <= sp._ptr); }
|
||||
|
||||
private:
|
||||
T *_ptr;
|
||||
Mutex *_lock;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -32,9 +32,16 @@
|
||||
#include "Hashtable.hpp"
|
||||
#include "NetworkConfig.hpp"
|
||||
|
||||
// Expiration time for capability and tag cache
|
||||
#define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 4)
|
||||
|
||||
// Expiration time for Memberships (used in Peer::clean())
|
||||
#define ZT_MEMBERSHIP_EXPIRATION_TIME (ZT_MEMBERSHIP_STATE_EXPIRATION_TIME * 4)
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class Peer;
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* Information related to a peer's participation on a network
|
||||
@ -81,15 +88,17 @@ public:
|
||||
* This checks last pushed times for our COM and for other credentials and
|
||||
* sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
|
||||
*
|
||||
* @param RR Runtime environment
|
||||
* @param now Current time
|
||||
* @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
|
||||
* @return True if we pushed something
|
||||
*/
|
||||
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;
|
||||
bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) const;
|
||||
|
||||
/**
|
||||
* @param nconf Network configuration
|
||||
@ -114,25 +123,98 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old or stale entries
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
|
||||
*/
|
||||
inline void clean(const uint64_t now)
|
||||
inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com)
|
||||
{
|
||||
if (com.issuedTo() != RR->identity.address())
|
||||
return -1;
|
||||
if (_com == com)
|
||||
return 0;
|
||||
const int vr = com.verify(RR);
|
||||
if (vr == 0)
|
||||
_com = com;
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
|
||||
*/
|
||||
inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag)
|
||||
{
|
||||
if (tag.issuedTo() != RR->identity.address())
|
||||
return -1;
|
||||
TState *t = _tags.get(tag.networkId());
|
||||
if ((t)&&(t->lastReceived != 0)&&(t->tag == tag))
|
||||
return 0;
|
||||
const int vr = tag.verify(RR);
|
||||
if (vr == 0) {
|
||||
if (!t)
|
||||
t = &(_tags[tag.networkId()]);
|
||||
t->lastReceived = now;
|
||||
t->tag = tag;
|
||||
}
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
|
||||
*/
|
||||
inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap)
|
||||
{
|
||||
if (!cap.wasIssuedTo(RR->identity.address()))
|
||||
return -1;
|
||||
CState *c = _caps.get(cap.networkId());
|
||||
if ((c)&&(c->lastReceived != 0)&&(c->cap == cap))
|
||||
return 0;
|
||||
const int vr = cap.verify(RR);
|
||||
if (vr == 0) {
|
||||
if (!c)
|
||||
c = &(_caps[cap.networkId()]);
|
||||
c->lastReceived = now;
|
||||
c->cap = cap;
|
||||
}
|
||||
return vr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up old or stale entries
|
||||
*
|
||||
* @return Time of most recent activity in this Membership
|
||||
*/
|
||||
inline uint64_t clean(const uint64_t now)
|
||||
{
|
||||
uint64_t lastAct = _lastPushedCom;
|
||||
|
||||
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))
|
||||
const uint64_t la = std::max(cs->lastPushed,cs->lastReceived);
|
||||
if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME)
|
||||
_caps.erase(*i);
|
||||
else if (la > lastAct)
|
||||
lastAct = la;
|
||||
}
|
||||
|
||||
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))
|
||||
const uint64_t la = std::max(ts->lastPushed,ts->lastReceived);
|
||||
if ((now - la) > ZT_MEMBERSHIP_STATE_EXPIRATION_TIME)
|
||||
_tags.erase(*i);
|
||||
else if (la > lastAct)
|
||||
lastAct = la;
|
||||
}
|
||||
|
||||
return lastAct;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -40,8 +40,10 @@
|
||||
#include "SharedPtr.hpp"
|
||||
#include "AtomicCounter.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "Membership.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "NonCopyable.hpp"
|
||||
#include "LockingPtr.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
@ -384,6 +386,34 @@ public:
|
||||
return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the membership record for this network, possibly creating if missing
|
||||
*
|
||||
* @param networkId Network ID
|
||||
* @param createIfMissing If true, create a Membership record if there isn't one
|
||||
* @return Single-scope locking pointer (see LockingPtr.hpp) to Membership or NULL if not found and createIfMissing is false
|
||||
*/
|
||||
inline LockingPtr<Membership> membership(const uint64_t networkId,bool createIfMissing)
|
||||
{
|
||||
_memberships_m.lock();
|
||||
try {
|
||||
if (createIfMissing) {
|
||||
return LockingPtr<Membership>(&(_memberships[networkId]),&_memberships_m);
|
||||
} else {
|
||||
Membership *m = _memberships.get(networkId);
|
||||
if (m) {
|
||||
return LockingPtr<Membership>(m,&_memberships_m);
|
||||
} else {
|
||||
_memberships_m.unlock();
|
||||
return LockingPtr<Membership>();
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {
|
||||
_memberships_m.unlock();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a common set of addresses by which two peers can link, if any
|
||||
*
|
||||
@ -430,6 +460,9 @@ private:
|
||||
unsigned int _latency;
|
||||
unsigned int _directPathPushCutoffCount;
|
||||
|
||||
Hashtable<uint64_t,Membership> _memberships;
|
||||
Mutex _memberships_m;
|
||||
|
||||
AtomicCounter __refCount;
|
||||
};
|
||||
|
||||
|
45
node/Tag.cpp
Normal file
45
node/Tag.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "Tag.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "Topology.hpp"
|
||||
#include "Switch.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
int Tag::verify(const RuntimeEnvironment *RR) const
|
||||
{
|
||||
if (!_signedBy)
|
||||
return -1;
|
||||
const Identity id(RR->topology->getIdentity(_signedBy));
|
||||
if (!id) {
|
||||
RR->sw->requestWhois(_signedBy);
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
Buffer<(sizeof(Tag) * 2)> tmp;
|
||||
this->serialize(tmp,true);
|
||||
return (id.verify(tmp.data(),tmp.size(),_signature) ? 0 : -1);
|
||||
} catch ( ... ) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
11
node/Tag.hpp
11
node/Tag.hpp
@ -76,7 +76,6 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline uint64_t networkId() const { return _nwid; }
|
||||
inline uint64_t expiration() const { return _expiration; }
|
||||
inline uint32_t id() const { return _id; }
|
||||
@ -106,9 +105,9 @@ public:
|
||||
* Check this tag's signature
|
||||
*
|
||||
* @param RR Runtime environment to allow identity lookup for signedBy
|
||||
* @return True if signature is present and valid
|
||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or tag
|
||||
*/
|
||||
bool verify(const RuntimeEnvironment *RR);
|
||||
int verify(const RuntimeEnvironment *RR) const;
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b,const bool forSign = false) const
|
||||
@ -156,6 +155,12 @@ public:
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
// Provides natural sort order by ID
|
||||
inline bool operator<(const Tag &t) const { return (_id < t._id); }
|
||||
|
||||
inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
|
||||
inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
|
||||
|
||||
private:
|
||||
uint64_t _nwid;
|
||||
uint64_t _expiration;
|
||||
|
@ -169,7 +169,9 @@ SharedPtr<Peer> Topology::getPeer(const Address &zta)
|
||||
|
||||
Identity Topology::getIdentity(const Address &zta)
|
||||
{
|
||||
{
|
||||
if (zta == RR->identity.address()) {
|
||||
return RR->identity;
|
||||
} else {
|
||||
Mutex::Lock _l(_lock);
|
||||
const SharedPtr<Peer> *const ap = _peers.get(zta);
|
||||
if (ap)
|
||||
|
@ -1,5 +1,6 @@
|
||||
OBJS=\
|
||||
node/C25519.o \
|
||||
node/Capability.o \
|
||||
node/CertificateOfMembership.o \
|
||||
node/Cluster.o \
|
||||
node/DeferredPackets.o \
|
||||
@ -7,6 +8,7 @@ OBJS=\
|
||||
node/Identity.o \
|
||||
node/IncomingPacket.o \
|
||||
node/InetAddress.o \
|
||||
node/Membership.o \
|
||||
node/Multicaster.o \
|
||||
node/Network.o \
|
||||
node/NetworkConfig.o \
|
||||
@ -20,6 +22,7 @@ OBJS=\
|
||||
node/SelfAwareness.o \
|
||||
node/SHA512.o \
|
||||
node/Switch.o \
|
||||
node/Tag.o \
|
||||
node/Topology.o \
|
||||
node/Utils.o \
|
||||
osdep/BackgroundResolver.o \
|
||||
|
Loading…
Reference in New Issue
Block a user