diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-08-04 09:02:35 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-08-04 09:02:35 -0700 |
commit | f057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9 (patch) | |
tree | 5cc5ca0eea2ddea5e06655c31292f906f53875a8 /node | |
parent | 7e6e56e2bce240a8d3a4f2825d3f110109a541b6 (diff) | |
download | infinitytier-f057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9.tar.gz infinitytier-f057bb63cdc4bebc4608f4f2ed6da4656ddbc8a9.zip |
More work on tags and capabilities.
Diffstat (limited to 'node')
-rw-r--r-- | node/Capability.cpp | 52 | ||||
-rw-r--r-- | node/Capability.hpp | 38 | ||||
-rw-r--r-- | node/CertificateOfMembership.cpp | 33 | ||||
-rw-r--r-- | node/CertificateOfMembership.hpp | 12 | ||||
-rw-r--r-- | node/IncomingPacket.cpp | 27 | ||||
-rw-r--r-- | node/LockingPtr.hpp | 99 | ||||
-rw-r--r-- | node/Membership.hpp | 92 | ||||
-rw-r--r-- | node/Peer.hpp | 33 | ||||
-rw-r--r-- | node/Tag.cpp | 45 | ||||
-rw-r--r-- | node/Tag.hpp | 11 | ||||
-rw-r--r-- | node/Topology.cpp | 4 |
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) |