summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2016-08-04 09:02:35 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2016-08-04 09:02:35 -0700
commitf057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9 (patch)
tree5cc5ca0eea2ddea5e06655c31292f906f53875a8 /node
parent7e6e56e2bce240a8d3a4f2825d3f110109a541b6 (diff)
downloadinfinitytier-f057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9.tar.gz
infinitytier-f057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9.zip
More work on tags and capabilities.
Diffstat (limited to 'node')
-rw-r--r--node/Capability.cpp52
-rw-r--r--node/Capability.hpp38
-rw-r--r--node/CertificateOfMembership.cpp33
-rw-r--r--node/CertificateOfMembership.hpp12
-rw-r--r--node/IncomingPacket.cpp27
-rw-r--r--node/LockingPtr.hpp99
-rw-r--r--node/Membership.hpp92
-rw-r--r--node/Peer.hpp33
-rw-r--r--node/Tag.cpp45
-rw-r--r--node/Tag.hpp11
-rw-r--r--node/Topology.cpp4
11 files changed, 393 insertions, 53 deletions
diff --git a/node/Capability.cpp b/node/Capability.cpp
new file mode 100644
index 00000000..07eb41a9
--- /dev/null
+++ b/node/Capability.cpp
@@ -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
diff --git a/node/Capability.hpp b/node/Capability.hpp
index d050b2b8..48282708 100644
--- a/node/Capability.hpp
+++ b/node/Capability.hpp
@@ -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;
diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp
index 55537fd9..7b99f2c7 100644
--- a/node/CertificateOfMembership.cpp
+++ b/node/CertificateOfMembership.cpp
@@ -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
diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp
index 8fae8b08..a04f8255 100644
--- a/node/CertificateOfMembership.hpp
+++ b/node/CertificateOfMembership.hpp
@@ -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
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 352e4faa..6548bda6 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -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
diff --git a/node/LockingPtr.hpp b/node/LockingPtr.hpp
new file mode 100644
index 00000000..c373129a
--- /dev/null
+++ b/node/LockingPtr.hpp
@@ -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
diff --git a/node/Membership.hpp b/node/Membership.hpp
index 93d347e7..642d46c6 100644
--- a/node/Membership.hpp
+++ b/node/Membership.hpp
@@ -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:
}
/**
+ * 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 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 void clean(const uint64_t now)
+ 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:
diff --git a/node/Peer.hpp b/node/Peer.hpp
index d8c44ebe..8b50f429 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -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 {
@@ -385,6 +387,34 @@ public:
}
/**
+ * 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
*
* @param a Peer A
@@ -430,6 +460,9 @@ private:
unsigned int _latency;
unsigned int _directPathPushCutoffCount;
+ Hashtable<uint64_t,Membership> _memberships;
+ Mutex _memberships_m;
+
AtomicCounter __refCount;
};
diff --git a/node/Tag.cpp b/node/Tag.cpp
new file mode 100644
index 00000000..1ad17251
--- /dev/null
+++ b/node/Tag.cpp
@@ -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
diff --git a/node/Tag.hpp b/node/Tag.hpp
index a4bc4479..dcf2eb20 100644
--- a/node/Tag.hpp
+++ b/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;
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 725eed31..ef1c1698 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -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)